RDKX5的TROS部署自己的yolov8输出结构全是F32,该怎么调整?

你好!你的问题定位非常准确,核心原因确实是输出数据类型不匹配导致的段错误

问题结论

你的猜测完全正确dnn_node_example 的 YOLOv8 parser 底层代码期望 bbox 分支输出是 S32(int32),但你编译出来的模型全是 F32(float32)。当 parser 用 int32 指针读取 float32 数据时,会导致数值解析错误,进而引发内存越界和段错误(exit code -11)。


原因分析

1. 为什么官方模型输出是 S32?

官方的 YOLOv8 模型在导出 ONNX 时,对 bbox 分支做了反量化处理,将浮点数输出转换为 int32 格式。这是通过修改 YOLOv8 的 head.py 中的 forward 函数实现的。

2. 你的模型为什么全是 F32?

你使用的 export_yolo26_detect_bpu.py 脚本没有对 bbox 输出进行反量化,导致编译器默认保持 F32 输出。


解决方案

方案一:修改 ONNX 导出脚本(推荐)

需要在导出 ONNX 时,对 bbox 分支添加反量化操作。参考社区已有的 YOLOv8 部署案例,修改你的导出脚本:

步骤 1:找到并修改 Detect_forward 函数

在你的导出脚本中(或参考 rdk_model_zoo 中的示例),需要添加类似以下的反量化逻辑:

def Detect_forward(self, x):
    result = []
    for i in range(self.nl):
        # bbox 分支:添加反量化,将 float 转为 int32
        bbox = self.cv2[i](x[i])  # (B, 4*reg_max, H, W)
        # 关键:对 bbox 输出进行反量化
        bbox = (bbox * 255.0).to(torch.int32)  # 或者使用合适的 scale
        
        # cls 分支:保持 float32
        cls = self.cv3[i](x[i])  # (B, nc, H, W)
        
        # 注意输出顺序:先 bbox 后 cls
        result.append(bbox)
        result.append(cls)
    return result

步骤 2:重新导出 ONNX

cd /path/to/your/export_script
python export_yolo26_detect_bpu.py --pt your_model.pt --imgsz 640 640 --opset 11

步骤 3:验证 ONNX 输出类型

python3 -c "
import onnx
model = onnx.load('best.onnx')
for output in model.graph.output:
    elem_type = output.type.tensor_type.elem_type
    shape = [d.dim_value for d in output.type.tensor_type.shape.dim]
    print(f'{output.name}: shape={shape}, type={elem_type}')
"

期望看到 bbox 分支的类型是 7(int32),cls 分支是 1(float32)


方案二:使用社区验证过的导出脚本

如果不想自己修改,可以直接使用社区已验证的 YOLOv8 导出脚本:

  1. 参考帖子:RDKX5 部署 yolov8 模型到 dnn_node_example 节点报错
  2. 下载并修改 export_monkey_patch.py,确保 bbox 输出有反量化
  3. 重新导出 → 量化 → 部署

方案三:检查 hb_mapper 配置(备选)

在你的 yaml 配置中,可以尝试添加量化相关参数,强制对输出进行量化:

model_parameters:
  onnx_model: './best.onnx'
  march: "bayes-e"
  layer_out_dump: False
  working_dir: 'model_output'
  output_model_file_prefix: 'yolov8_cow'
  # 添加以下参数
  output_quantize: True  # 尝试启用输出量化

input_parameters:
  input_name: "images"
  input_shape: ''
  input_type_rt: 'nv12'
  input_layout_rt: ''
  input_type_train: 'rgb'
  input_layout_train: 'NCHW'
  norm_type: 'data_scale'
  scale_value: 0.003921568627451

calibration_parameters:
  cal_data_dir: './cal_bin'
  cal_data_type: 'float32'
  calibration_type: 'default'

compiler_parameters:
  compile_mode: 'latency'
  debug: False
  optimize_level: 'O3'

注意:这个方案不一定有效,因为输出量化通常需要在 ONNX 层面处理。


快速验证

重新编译模型后,在板子上验证输出类型:

python3 << 'EOF'
from hobot_dnn import pyeasy_dnn as dnn
models = dnn.load('/home/sunrise/yolov8/cow.bin')
model = models[0]
print(f"Model outputs: {len(model.outputs)}")
for i, out in enumerate(model.outputs):
    p = out.properties
    print(f"Output[{i}]: shape={p.shape}, layout={p.layout}, type={p.dtype}")
EOF

期望输出(bbox 分支应该是 int32):

Output[0]: shape=(1, 80, 80, 5), layout=NHWC, type=int32    # bbox_P3
Output[1]: shape=(1, 80, 80, 64), layout=NHWC, type=float32 # cls_P3
Output[2]: shape=(1, 40, 40, 5), layout=NHWC, type=int32    # bbox_P4
Output[3]: shape=(1, 40, 40, 64), layout=NHWC, type=float32 # cls_P4
Output[4]: shape=(1, 20, 20, 5), layout=NHWC, type=int32    # bbox_P5
Output[5]: shape=(1, 20, 20, 64), layout=NHWC, type=float32 # cls_P5

相关资源


总结

  1. 问题根源:bbox 输出缺少反量化,导致类型不匹配
  2. 解决方法:修改 ONNX 导出脚本,对 bbox 分支添加反量化操作
  3. 验证方式:检查 bin 模型输出类型,确保 bbox 是 int32

建议优先采用方案一,直接修改导出脚本。如果遇到问题,可以把修改后的脚本发到社区,大家一起帮你调试!