RDKX5部署yolov8模型到 dnn_node_example节点报错

问题分析

核心原因:YOLOv8 的输出格式与 dnn_node_example 期望的标准检测模型格式不匹配,导致后处理时访问非法内存(段错误 exit code -11)。

从你的输出头看:

[(1, 80, 80, 1), (1, 80, 80, 64), (1, 40, 40, 1), (1, 40, 40, 64), (1, 20, 20, 1), (1, 20, 20, 64)]

这是 YOLOv8 的解耦头格式(cls + reg 分开),而 dnn_node_example 期望的是耦合头格式(如 YOLOv3/v5)。

让我先搜索社区是否有 YOLOv8 部署的相关案例:

问题分析

根据你的报错日志,核心问题是 dnn_example_node 进程段错误崩溃(exit code -11),导致 WebSocket 收不到 AI 数据。

从你的输出头信息来看:

[(1, 80, 80, 1), (1, 80, 80, 64), (1, 40, 40, 1), (1, 40, 40, 64), (1, 20, 20, 1), (1, 20, 20, 64)]

问题定位:输出头格式错误!

你的模型输出是 NHWC 格式(6 个输出头),但 dnn_node_example 的 YOLOv8 parser 期望的是 NCHW 格式,且输出顺序应该是 bbox 在前,cls 在后


解决方案

步骤 1:修正 ONNX 导出脚本

你的 export_monkey_patch.py 中的 Detect_forward 函数有问题。需要修改输出顺序和格式:

def Detect_forward(self, x):
    result = []
    for i in range(self.nl):
        # 先输出 bbox,再输出 cls(关键!)
        bbox = self.cv2[i](x[i])  # (B, 64, H, W) - bbox
        cls = self.cv3[i](x[i])   # (B, nc, H, W) - cls
        
        # 保持 NCHW 格式,不要 permute
        result.append(bbox)
        result.append(cls)
    return result

关键修改点:

  1. 输出顺序:先 bbox 后 cls(你当前代码是先 cls 后 bbox)
  2. 保持 NCHW:不要调用 .permute(0, 2, 3, 1)(你当前代码做了 permute 变成 NHWC)

步骤 2:重新导出 ONNX 模型

cd D:\zhinengche\OriginCar\yolo\yolov8
python export_monkey_patch.py --pt datasets/runs/detect/train/weights/best.pt --imgsz 640 640 --opset 11

导出后验证 ONNX 模型输出:

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

期望输出(NCHW 格式):

bbox_P3: [1, 64, 80, 80]
cls_P3: [1, 1, 80, 80]  # 如果是单类别
bbox_P4: [1, 64, 40, 40]
cls_P4: [1, 1, 40, 40]
bbox_P5: [1, 64, 20, 20]
cls_P5: [1, 1, 20, 20]

步骤 3:重新量化模型

使用修正后的 ONNX 重新量化:

cd /workspace
hb_mapper makertbin --config obstacle_config.yaml --model-type onnx

注意检查 obstacle_config.yaml

input_parameters:
  input_name: 'images'
  input_type_rt: 'nv12'
  input_type_train: 'rgb'
  input_layout_rt: 'NHWC'      # 板端输入布局(BPU 要求)
  input_layout_train: 'NCHW'   # 训练时布局(保持 NCHW)
  input_shape: '1x3x640x640'
  norm_type: 'data_scale'
  scale_value: '0.003921568627451'  # 1/255

步骤 4:验证 bin 模型输出

在板子上验证新模型的输出格式:

python3 << 'EOF'
from hobot_dnn import pyeasy_dnn as dnn

models = dnn.load('/home/sunrise/yiqiang_ws/src/origincar/models/obstacle.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

期望输出

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

步骤 5:检查配置文件

确认 yolov8workconfig.json 配置正确:

{
  "model_file": "/home/sunrise/yiqiang_ws/src/origincar/models/obstacle.bin",
  "dnn_Parser": "yolov8",
  "model_output_count": 6,
  "reg_max": 16,
  "class_num": 1,
  "cls_names_list": "/home/sunrise/yiqiang_ws/src/origincar/models/obstacles.list",
  "strides": [8, 16, 32],
  "score_threshold": 0.25,
  "nms_threshold": 0.7,
  "nms_top_k": 300
}

快速验证

如果还是不确定,先用板子自带的官方模型测试 TROS 是否正常:

# 使用官方模型测试
ros2 launch dnn_node_example dnn_node_example.launch.py

如果官方模型能跑通,说明是你的模型格式问题;如果官方模型也崩溃,说明系统环境问题。


相关资源

建议先执行步骤 1 和步骤 2,修正导出脚本后重新导出 ONNX,这是最关键的问题点。