RDKX5量化yolov11,最后使用工具链说我数据大小错误

root@4f6ec2300d23:/data/calibration_npy# hb_mapper makertbin --model-type onnx --config /data/yolov11.yaml
2025-08-14 14:32:32,024 INFO log will be stored in /data/calibration_npy/hb_mapper_makertbin.log
2025-08-14 14:32:32,024 INFO Start hb_mapper…
2025-08-14 14:32:32,024 INFO hbdk version 3.49.15
2025-08-14 14:32:32,024 INFO horizon_nn version 1.1.0
2025-08-14 14:32:32,024 INFO hb_mapper version 1.24.3
2025-08-14 14:32:32,024 INFO Start Model Convert…
2025-08-14 14:32:32,029 INFO Using onnx model file: /data/yolo11n.onnx
2025-08-14 14:32:32,053 INFO Model has 1 inputs according to model file
2025-08-14 14:32:32,057 INFO Model name not given in yaml_file, using model name from model file: [‘images’]
2025-08-14 14:32:32,069 INFO Model input shape not given in yaml_file, using shape from model file: [[1, 3, 640, 640]]
2025-08-14 14:32:32,070 INFO nv12 input type rt received.
2025-08-14 14:32:32,070 WARNING The calibration dir name suffix is not the same as the value float32 of the parameter cal_data_type, the parameter setting will prevail
2025-08-14 14:32:32,071 INFO custom_op does not exist, skipped
2025-08-14 14:32:32,071 WARNING Input node images’s input_source not set, it will be set to pyramid by default
2025-08-14 14:32:32,076 INFO *******************************************
2025-08-14 14:32:32,076 INFO First calibration picture name: 000000000009.npy
2025-08-14 14:32:32,077 INFO First calibration picture md5:
715a32075edc4738cc0ebd9227466b38 /data/calibration_npy/000000000009.npy
2025-08-14 14:32:32,089 INFO *******************************************
2025-08-14 14:32:32,094 ERROR load cal data for input ‘images’ error
2025-08-14 14:32:32,098 ERROR cannot reshape array of size 1228832 into shape (1,3,640,640)
root@4f6ec2300d23:/data/calibration_npy# ls
000000000009.npy 000000000164.npy 000000000394.npy 000000000540.npy
000000000025.npy 000000000165.npy 000000000395.npy 000000000542.npy
000000000030.npy 000000000196.npy 000000000397.npy 000000000544.npy
000000000034.npy 000000000241.npy 000000000400.npy 000000000560.npy
000000000036.npy 000000000247.npy 000000000404.npy 000000000562.npy
000000000042.npy 000000000257.npy 000000000419.npy 000000000564.npy
000000000049.npy 000000000260.npy 000000000428.npy 000000000569.npy
000000000061.npy 000000000263.npy 000000000431.npy 000000000572.npy
000000000064.npy 000000000283.npy 000000000436.npy 000000000575.npy
000000000071.npy 000000000307.npy 000000000443.npy 000000000581.npy
000000000072.npy 000000000308.npy 000000000450.npy 000000000590.npy
000000000074.npy 000000000309.npy 000000000459.npy 000000000595.npy
000000000077.npy 000000000312.npy 000000000471.npy 000000000597.npy
000000000078.npy 000000000315.npy 000000000472.npy 000000000599.npy
000000000081.npy 000000000321.npy 000000000474.npy 000000000605.npy
000000000086.npy 000000000322.npy 000000000488.npy 000000000612.npy
000000000092.npy 000000000326.npy 000000000491.npy 000000000620.npy
000000000094.npy 000000000328.npy 000000000502.npy 000000000623.npy
000000000109.npy 000000000332.npy 000000000508.npy 000000000626.npy
000000000110.npy 000000000338.npy 000000000510.npy 000000000629.npy
000000000113.npy 000000000349.npy 000000000514.npy 000000000643.npy
000000000127.npy 000000000357.npy 000000000520.npy 000000000650.npy
000000000136.npy 000000000359.npy 000000000529.npy hb_mapper_makertbin.log
000000000138.npy 000000000368.npy 000000000531.npy
000000000142.npy 000000000370.npy 000000000532.npy
000000000151.npy 000000000389.npy 000000000536.npy
root@4f6ec2300d23:/data/calibration_npy# ls /data
calibration_images yolo11n.onnx yolov11_workdir
calibration_npy yolov11.yaml
root@4f6ec2300d23:/data/calibration_npy# cat yolov11.yaml
cat: yolov11.yaml: No such file or directory
root@4f6ec2300d23:/data/calibration_npy# cd /data
root@4f6ec2300d23:/data# ls
calibration_images yolo11n.onnx yolov11_workdir
calibration_npy yolov11.yaml
root@4f6ec2300d23:/data# cat yolov11.yaml
model_parameters:
onnx_model: ‘/data/yolo11n.onnx’
march: “bayes-e”
working_dir: ‘/data/yolov11_workdir’
output_model_file_prefix: ‘yolov11_rdkx5’

input_parameters:
input_type_rt: ‘nv12’
input_type_train: ‘rgb’
input_layout_train: ‘NCHW’
norm_type: ‘data_scale’
scale_value: 0.003921568627451

calibration_parameters:
cal_data_dir: ‘/data/calibration_npy’
cal_data_type: ‘float32’

compiler_parameters:
compile_mode: ‘latency’
optimize_level: ‘O3’
debug: False
root@4f6ec2300d23:/data#
这是我的报错,需要如何修改这个图片的验证集,或者去哪搞这个正确的数据

你好,RDK X5 YOLO相关可以参考Model Zoo这个新版本的,可以一键完成校准数据准备,yaml准备等内容 rdk_model_zoo/demos/Vision/ultralytics_YOLO at main · D-Robotics/rdk_model_zoo


你好,我按照您发的链接下载了.bin文件也在RDK上跑通了,不过我是调用rtsp的视频流作为输入,目前存在几个问题:1.画框的偏移,我调用的函数是官方的,2.还是我原帖的问题,按照论坛里超哥的方法把onnx转为bin这一步里面图片验证集的参数规格能否具体给出,我的报错是2025-08-14 14:32:32,098 ERROR cannot reshape array of size 1228832 into shape (1,3,640,640),但是我的图片已经是float32的640X640我还给他转成。npy格式了,下面是我的代码。

#!/usr/bin/env python3
# Copyright (c) 2024,WuChao D-Robotics.
# 注意:此程序在 RDK 板端运行
# 改动:支持 RTSP 视频流实时推理

import os
import cv2
import numpy as np
from time import time
import argparse
import logging

# 日志配置
logging.basicConfig(
    level=logging.INFO,
    format='[%(name)s] [%(asctime)s.%(msecs)03d] [%(levelname)s] %(message)s',
    datefmt='%H:%M:%S')
logger = logging.getLogger("RDK_YOLO_RTSP")

# ---------- 依赖检查 ----------
try:
    from scipy.special import softmax
except ImportError:
    logger.warning("scipy 未安装,正在自动安装...")
    os.system("pip3 install scipy -i https://pypi.tuna.tsinghua.edu.cn/simple")
    from scipy.special import softmax

try:
    from hobot_dnn import pyeasy_dnn as dnn
except ImportError:
    logger.error("未找到 hobot_dnn,请使用板端系统 Python3 环境")
    exit(1)

# ---------- 主程序 ----------
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--model-path', type=str,
                        default='/home/sunrise/rdk_model_zoo/demos/Vision/ultralytics_YOLO/py/yolo13_detect.bin',
                        help='量化 *.bin 模型路径')
    parser.add_argument('--rtsp', type=str,
                        default='rtsp://192.168.1.120:8554/test',
                        help='RTSP 流地址')
    parser.add_argument('--classes-num', type=int, default=80)
    parser.add_argument('--nms-thres', type=float, default=0.7)
    parser.add_argument('--score-thres', type=float, default=0.25)
    parser.add_argument('--reg', type=int, default=16)
    parser.add_argument('--strides', type=lambda s: list(map(int, s.split(','))),
                        default=[8, 16, 32])
    opt = parser.parse_args()
    logger.info(opt)


    # 初始化模型
    model = Ultralytics_YOLO_Detect_Bayese_YUV420SP(
        model_path=opt.model_path,
        classes_num=opt.classes_num,
        nms_thres=opt.nms_thres,
        score_thres=opt.score_thres,
        reg=opt.reg,
        strides=opt.strides
    )

    # 打开 RTSP 流
    cap = cv2.VideoCapture(opt.rtsp, cv2.CAP_FFMPEG)
    if not cap.isOpened():
        logger.error("无法打开 RTSP 流: {}".format(opt.rtsp))
        exit(1)
    logger.info("已连接 RTSP: {}".format(opt.rtsp))

    # 降低缓存,减少延迟
    cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)

    # 主循环
    while True:
        ret, frame = cap.read()
        if not ret:
            logger.warning("读取帧失败,重试中...")
            continue

        # 推理
        input_tensor = model.preprocess_yuv420sp(frame)
        outputs = model.c2numpy(model.forward(input_tensor))
        results = model.postProcess(outputs)

        # 画框
        for class_id, score, x1, y1, x2, y2 in results:
            draw_detection(frame, (x1, y1, x2, y2), score, class_id)

        # 本地显示(需要桌面环境)
        cv2.imshow("RTSP YOLO Detection - RDK", frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    cap.release()
    cv2.destroyAllWindows()

# ---------- 以下与原始文件一致,无改动 ----------
class Ultralytics_YOLO_Detect_Bayese_YUV420SP:
    def __init__(self, model_path, classes_num, nms_thres, score_thres, reg, strides):
        begin_time = time()
        self.quantize_model = dnn.load(model_path)
        logger.debug("Load model time = %.2f ms" % (1000 * (time() - begin_time)))

        self.REG = reg
        self.CLASSES_NUM = classes_num
        self.SCORE_THRESHOLD = score_thres
        self.NMS_THRESHOLD = nms_thres
        self.CONF_THRES_RAW = -np.log(1 / self.SCORE_THRESHOLD - 1)
        self.input_H, self.input_W = self.quantize_model[0].inputs[0].properties.shape[2:4]
        self.strides = strides

        self.weights_static = np.arange(reg, dtype=np.float32)[np.newaxis, np.newaxis, :]

        self.grids = []
        for stride in self.strides:
            grid_h, grid_w = self.input_H // stride, self.input_W // stride
            yv, xv = np.meshgrid(np.arange(grid_h), np.arange(grid_w), indexing='ij')
            grid = np.stack([yv, xv], axis=-1).reshape(-1, 2) + 0.5
            self.grids.append(grid)

    def preprocess_yuv420sp(self, img):
        self.img_h, self.img_w = img.shape[:2]
        scale = min(self.input_H / self.img_h, self.input_W / self.img_w)
        new_w, new_h = int(self.img_w * scale), int(self.img_h * scale)
        self.x_shift = (self.input_W - new_w) // 2
        self.y_shift = (self.input_H - new_h) // 2

        resized = cv2.resize(img, (new_w, new_h))
        letter = cv2.copyMakeBorder(resized,
                                    self.y_shift, self.input_H - new_h - self.y_shift,
                                    self.x_shift, self.input_W - new_w - self.x_shift,
                                    cv2.BORDER_CONSTANT, value=(127, 127, 127))
        return self.bgr2nv12(letter)

    def bgr2nv12(self, bgr_img):
        height, width = bgr_img.shape[:2]
        yuv420p = cv2.cvtColor(bgr_img, cv2.COLOR_BGR2YUV_I420)
        y = yuv420p[:height, :]
        uv = yuv420p[height:, :]
        uv = uv.reshape((2, height // 2, width // 2)).transpose(1, 2, 0).reshape(height // 2, width)
        nv12 = np.empty(height * 3 // 2 * width, dtype=np.uint8)
        nv12[:height * width] = y.flatten()
        nv12[height * width:] = uv.flatten()
        return nv12

    def forward(self, input_tensor):
        return self.quantize_model[0].forward(input_tensor)

    def c2numpy(self, outputs):
        return [t.buffer for t in outputs]

    def postProcess(self, outputs):
        clses = [outputs[0].reshape(-1, self.CLASSES_NUM),
                 outputs[2].reshape(-1, self.CLASSES_NUM),
                 outputs[4].reshape(-1, self.CLASSES_NUM)]
        bboxes = [outputs[1].reshape(-1, self.REG * 4),
                  outputs[3].reshape(-1, self.REG * 4),
                  outputs[5].reshape(-1, self.REG * 4)]

        dbboxes, ids, scores = [], [], []
        for cls, bbox, stride, grid in zip(clses, bboxes, self.strides, self.grids):
            max_scores = np.max(cls, axis=1)
            mask = max_scores >= self.CONF_THRES_RAW
            cls_sel, bbox_sel = cls[mask], bbox[mask]
            if cls_sel.size == 0:
                continue
            ids.append(np.argmax(cls_sel, axis=1))
            scores.append(1 / (1 + np.exp(-max_scores[mask])))
            ltrb = softmax(bbox_sel.reshape(-1, 4, self.REG), axis=2)
            ltrb = np.sum(ltrb * self.weights_static, axis=2)
            grid_sel = grid[np.where(mask)[0]]
            xy1 = (grid_sel - ltrb[:, :2]) * stride
            xy2 = (grid_sel + ltrb[:, 2:]) * stride
            dbboxes.append(np.hstack([xy1, xy2]))

        if not dbboxes:
            return []

        dbboxes = np.vstack(dbboxes)
        scores = np.hstack(scores)
        ids = np.hstack(ids)
        xywh = np.hstack([(dbboxes[:, :2] + dbboxes[:, 2:]) / 2,
                          dbboxes[:, 2:] - dbboxes[:, :2]])
        results = []
        for i in range(self.CLASSES_NUM):
            idx = ids == i
            if not idx.any():
                continue
            boxes = xywh[idx]
            sc = scores[idx]
            indices = cv2.dnn.NMSBoxes(boxes, sc, self.SCORE_THRESHOLD, self.NMS_THRESHOLD)
            for j in indices:
                x1, y1, x2, y2 = dbboxes[idx][j]
                x1 = max(0, min(int((x1 - self.x_shift) / (self.input_W / self.img_w)), self.img_w))
                y1 = max(0, min(int((y1 - self.y_shift) / (self.input_H / self.img_h)), self.img_h))
                x2 = max(0, min(int((x2 - self.x_shift) / (self.input_W / self.img_w)), self.img_w))
                y2 = max(0, min(int((y2 - self.y_shift) / (self.input_H / self.img_h)), self.img_h))
                results.append((i, sc[j], x1, y1, x2, y2))
        return results

# ---------- 画图 ----------
coco_names = [
    "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light", 
    "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow", 
    "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", 
    "skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard", "tennis racket", "bottle", 
    "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple", "sandwich", "orange", 
    "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch", "potted plant", "bed", 
    "dining table", "toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone", "microwave", "oven", 
    "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear", "hair drier", "toothbrush"
    ]
#my
# rdk_colors = [
#     (56, 56, 255), (151, 157, 255), (31, 112, 255), (29, 178, 255),
#     (49, 210, 207), (10, 249, 72), (23, 204, 146), (134, 219, 61),
#     (52, 147, 26), (187, 212, 0), (168, 153, 44), (255, 194, 0),
#     (147, 69, 52), (255, 115, 100), (236, 24, 0), (255, 56, 132),
#     (133, 0, 82), (255, 56, 203), (200, 149, 255), (199, 55, 255)
# ]

#offical
rdk_colors = [
    (56, 56, 255), (151, 157, 255), (31, 112, 255), (29, 178, 255),(49, 210, 207), (10, 249, 72), (23, 204, 146), (134, 219, 61),
    (52, 147, 26), (187, 212, 0), (168, 153, 44), (255, 194, 0),(147, 69, 52), (255, 115, 100), (236, 24, 0), (255, 56, 132),
    (133, 0, 82), (255, 56, 203), (200, 149, 255), (199, 55, 255)]

#my
# def draw_detection(img, bbox, score, class_id) -> None:
#     x1, y1, x2, y2 = map(int, bbox)          # 确保坐标是 int
#     color = tuple(map(int, rdk_colors[class_id % len(rdk_colors)]))  # 确保颜色是 int 元组
#     cv2.rectangle(img, (x1, y1), (x2, y2), color, 2)

#     label = f"{coco_names[class_id]}:{score:.2f}"
#     (w, h), _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)
#     cv2.rectangle(img, (x1, y1 - h - 4), (x1 + w, y1), color, -1)
#     cv2.putText(img, label, (x1, y1 - 2), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1, cv2.LINE_AA)

#offical
def draw_detection(img, bbox, score, class_id) -> None:
    """
    Draws a detection bounding box and label on the image.

    Parameters:
        img (np.array): The input image.
        bbox (tuple[int, int, int, int]): A tuple containing the bounding box coordinates (x1, y1, x2, y2).
        score (float): The detection score of the object.
        class_id (int): The class ID of the detected object.
    """
    x1, y1, x2, y2 = bbox
    color = rdk_colors[class_id%20]
    cv2.rectangle(img, (x1, y1), (x2, y2), color, 2)
    label = f"{coco_names[class_id]}: {score:.2f}"
    (label_width, label_height), _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)
    label_x, label_y = x1, y1 - 10 if y1 - 10 > label_height else y1 + 10
    cv2.rectangle(
        img, (label_x, label_y - label_height), (label_x + label_width, label_y + label_height), color, cv2.FILLED
    )
    cv2.putText(img, label, (label_x, label_y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1, cv2.LINE_AA)


if __name__ == "__main__":
    main()

我的目标和框体有误差是我自己的代码的问题,不过我还是想问自己使用官方的工具链的时候验证图片集合的参数是如何的,我看帖子里也没有明确的表示这个图片集合是咋样的,或者能否有渠道提供?

这块的话可以参考工具链手册的这一章节,有比较详细的介绍和描述:
6.3.3. 校准数据准备 — Horizon Open Explorer

本质其实就是需要送入onnx模型之前的已经预处理过的数据,无论你是通过工具链来处理还是自己预先处理

这里面x86/mapper.py脚本中也有校准数据集准备过程,可以参考源码学习一下

比较详细完整的整个链路的话可以参考: 万字长文,学弟一看就会的RDKX5模型转换及部署,你确定不学? - 板卡使用 / RDK Model Zoo - 地瓜机器人论坛