本文整理一套可复用的流程:将 Ultralytics YOLOv8 的 PyTorch 权重(.pt)导出为 ONNX(.onnx),再通过地平线工具链编译为 BPU 可执行的 .bin,并补充一个常见坑:部分 bbox 输出头的反量化(Dequantize)节点需要移除,否则后处理结果可能异常。
资源下载 :RDK X5 主板资料(百度网盘) 提取码: f1w1
前置准备 安装 bpu_infer_lib(示例) 1 pip install bpu_infer_lib_x5 -i http://sdk.d-robotics.cc:8080/simple/ --trusted-host sdk.d-robotics.cc
Python 镜像源(示例) 1 pip3 install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple
Git 配置(SSH 方式,示例)
生成 SSH 密钥对
添加公钥到 Gitee → 设置 → SSH 公钥
修改远程仓库地址
1 git remote set-url origin git@gitee.com:你的用户名/仓库.git
提交代码
1 2 3 git add . git commit -m "提交信息" git push origin master
1. 环境与项目准备
拉取 Ultralytics 仓库并按官方文档配置环境
1 git clone https://github.com/ultralytics/ultralytics.git
下载预训练权重(以 YOLOv8n Detect 为例)
1 2 cd ultralytics wget https://github.com/ultralytics/assets/releases/download/v8.2.0/yolov8n.pt
2. 导出前:修改 Detect 输出头(关键) 目标:把三个特征层的 Bounding Box 信息和 Classify 信息拆分输出,一共 6 个输出头,并确保输出顺序固定(否则后续编译/解析可能报错)。
文件:./ultralytics/ultralytics/nn/modules/head.py 位置:Detect 类的 forward 方法(建议先备份原始实现,例如重命名为 forward_,训练时再切回)。
1 2 3 4 5 6 def forward (self, x ): result = [] for i in range (self .nl): result.append(self .cv3[i](x[i]).permute(0 , 2 , 3 , 1 ).contiguous()) result.append(self .cv2[i](x[i]).permute(0 , 2 , 3 , 1 ).contiguous()) return result
如果导出的 ONNX 输出头顺序与预期不一致,可以通过调整 append 的顺序来对齐。
3. 导出为 ONNX 如果出现命令行 yolo/ultralytics 版本混乱,建议先确认当前 Python 环境中 ultralytics 的实际加载路径。
1 2 conda list | grep ultralytics pip list | grep ultralytics
如存在已安装的包,可先卸载,避免与本地仓库源码冲突:
1 2 conda uninstall ultralytics pip uninstall ultralytics
定位实际加载目录(示例):
1 python -c "import ultralytics; print(ultralytics.__path__)"
执行导出(按需修改 imgsz):
1 2 from ultralytics import YOLO YOLO('yolov8n.pt' ).export(imgsz=640 , format ='onnx' , simplify=True , opset=11 )
4. PTQ 量化与编译(hb_mapper) 参考工具链手册与 OE 包(OpenExplore)进行模型检查,确保算子均可在 BPU 上执行,然后进行编译。
示例命令:
1 2 hb_mapper checker --model-type onnx --march bayes-e --model yolov8n.onnx hb_mapper makertbin --model-type onnx --config config_yolov8_detect_nv12.yaml
5. 移除 bbox 输出头的反量化节点(常见坑) 在某些配置下,bbox 相关输出头会带反量化节点,若直接使用可能导致后处理结果不正确。一个经验口诀:尺寸里带 64 的输出往往对应 4 * REG (REG=16) 的 bbox 分支,常见需要处理。
从 hb_mapper makertbin 日志确认输出名称(示例):
1 2 3 4 5 6 7 Graph output: output0: shape=[1, 80, 80, 1], dtype=FLOAT32 326: shape=[1, 40, 40, 64], dtype=FLOAT32 334: shape=[1, 20, 20, 1], dtype=FLOAT32 342: shape=[1, 80, 80, 64], dtype=FLOAT32 350: shape=[1, 40, 40, 1], dtype=FLOAT32 358: shape=[1, 20, 20, 64], dtype=FLOAT32
进入编译产物目录(示例):
1 cd yolov8n_bayese_640x640_nv12
生成 hb_model_modifier.log 并查找 Dequantize 节点(示例):
1 hb_model_modifier yolov8n_bayese_640x640_nv12.bin
日志里常能看到类似名称(示例):
1 2 3 /model.22/cv2.0/cv2.0.2/Conv_output_0_HzDequantize /model.22/cv2.1/cv2.1.2/Conv_output_0_HzDequantize /model.22/cv2.2/cv2.2.2/Conv_output_0_HzDequantize
移除上述节点(名称以你实际导出的为准):
1 2 3 4 hb_model_modifier yolov8n_detect_bayese_224x224_nv12.bin \ -r /model.22/cv2.0/cv2.0.2/Conv_output_0_HzDequantize \ -r /model.22/cv2.1/cv2.1.2/Conv_output_0_HzDequantize \ -r /model.22/cv2.2/cv2.2.2/Conv_output_0_HzDequantize
最终产物通常形如 *_modified.bin,即可用于板端推理或对接 TROS 功能包。
6. 简要部署建议
NCHW 输入模型:可用 OpenCV + numpy 准备输入数据。
NV12 输入模型:可用 codec/jpu/vpu/gpu 等硬件模块准备输入数据,或直接对接对应中间件/功能包。