你好!你的问题定位非常准确,核心原因确实是输出数据类型不匹配导致的段错误。
问题结论
你的猜测完全正确: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 导出脚本:
- 参考帖子:RDKX5 部署 yolov8 模型到 dnn_node_example 节点报错
- 下载并修改
export_monkey_patch.py,确保 bbox 输出有反量化 - 重新导出 → 量化 → 部署
方案三:检查 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
相关资源
总结
- 问题根源:bbox 输出缺少反量化,导致类型不匹配
- 解决方法:修改 ONNX 导出脚本,对 bbox 分支添加反量化操作
- 验证方式:检查 bin 模型输出类型,确保 bbox 是 int32
建议优先采用方案一,直接修改导出脚本。如果遇到问题,可以把修改后的脚本发到社区,大家一起帮你调试!