一、前言:为什么要做这个转换?
YOLOv5作为当前最流行的目标检测模型之一,在昇腾AI处理器上部署能获得显著的推理加速。但这个过程需要将PyTorch训练的模型转换为昇腾专用的离线模型(.om文件)。
转换的价值:
- 性能提升:相比CPU/GPU,在昇腾芯片上有10倍以上的推理加速
- 部署简化:.om文件可直接用于边缘设备(如Atlas 200DK)
- 资源优化:支持INT8量化,大幅降低内存占用
二、环境准备:确保你的工具链完整
2.1 环境检查清单
# 1. 确认ATC已安装 atc --version # 应输出类似:ATC version: 7.0.0.alpha # 2. 检查Python环境 python3 --version pip3 list | grep -E "(torch|onnx|numpy)" # 3. 确认芯片型号(选择正确的soc_version) # Ascend310, Ascend310P, Ascend710等 # 如果不知道,默认用Ascend310(最常用)2.2 获取YOLOv5源码和模型
# 克隆YOLOv5官方仓库 git clone https://github.com/ultralytics/yolov5.git cd yolov5 # 安装依赖(建议使用虚拟环境) pip install -r requirements.txt onnx>=1.12.0 # 下载预训练权重 wget https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s.pt三、第一步:从PyTorch到ONNX的转换
3.1 标准导出方法
# 基本导出命令 python export.py --weights yolov5s.pt \ --include onnx \ --img-size 640 640 \ --batch-size 1 \ --opset 12 # 参数详解: # --weights: 预训练权重文件 # --img-size: 输入图像尺寸(必须与训练时一致) # --batch-size: 批处理大小(建议从1开始) # --opset: ONNX算子集版本(建议12或13,兼容性更好)3.2 验证ONNX模型
import onnx import onnxruntime import numpy as np # 加载并验证ONNX模型 onnx_model = onnx.load("yolov5s.onnx") onnx.checker.check_model(onnx_model) print("✓ ONNX模型结构验证通过") # 使用ONNX Runtime测试推理 ort_session = onnxruntime.InferenceSession("yolov5s.onnx") # 创建随机输入测试 x = np.random.randn(1, 3, 640, 640).astype(np.float32) ort_inputs = {ort_session.get_inputs()[0].name: x} ort_outputs = ort_session.run(None, ort_inputs) print(f"输入形状: {x.shape}") print(f"输出数量: {len(ort_outputs)}") print(f"第一个输出形状: {ort_outputs[0].shape}")四、第二步:关键步骤 - ONNX模型优化
4.1 为什么要优化?
原始的YOLOv5 ONNX模型包含一些昇腾不支持的算子或结构,需要进行调整。
# 方法一:使用YOLOv5自带的简化工具 python -m onnxsim yolov5s.onnx yolov5s-sim.onnx # 方法二:使用ONNX官方优化器(更推荐) python -c """ import onnx from onnxsim import simplify model = onnx.load('yolov5s.onnx') model_simp, check = simplify(model) assert check, "简化验证失败" onnx.save(model_simp, 'yolov5s-sim.onnx') print(f'简化完成,原始节点数:{len(model.graph.node)},简化后:{len(model_simp.graph.node)}') """4.2 常见问题修复
如果遇到不支持的算子,可以尝试以下方法:
# 创建自定义算子映射文件(custom_op.yaml) custom_ops = """ op_properties: - op_name: "NonMaxSuppression" custom_op_flag: true compute_capacity: "high" """ with open("custom_op.yaml", "w") as f: f.write(custom_ops)五、第三步:核心环节 - ATC模型转换
5.1 基础转换命令
# 基础ATC转换命令 atc --model=yolov5s-sim.onnx \ --framework=5 \ --output=yolov5s_ascend \ --soc_version=Ascend310 \ --input_format=NCHW \ --input_shape="images:1,3,640,640" \ --insert_op_conf=aipp_yolov5.config \ --log=info \ --out_nodes="output:0;422:0"5.2 关键参数详解
参数1:图像预处理配置(--insert_op_conf)
创建aipp_yolov5.config文件:
aipp_op { aipp_mode: static input_format : RGB888_U8 src_image_size_w : 640 src_image_size_h : 640 # 归一化参数 (x/255) mean_chn_0 : 0 mean_chn_1 : 0 mean_chn_2 : 0 var_reci_chn_0 : 0.003921568627451 var_reci_chn_1 : 0.003921568627451 var_reci_chn_2 : 0.003921568627451 # YOLOv5需要的transpose (HWC->CHW) matrix_r0c0: 1; matrix_r0c1: 0; matrix_r0c2: 0 matrix_r1c0: 0; matrix_r1c1: 1; matrix_r1c2: 0 matrix_r2c0: 0; matrix_r2c1: 0; matrix_r2c2: 1 input_bias_0: 0; input_bias_1: 0; input_bias_2: 0 }参数2:动态形状支持(多Batch/多分辨率)
# 支持动态Batch(1-8,4最优) atc --model=yolov5s-sim.onnx \ --framework=5 \ --output=yolov5s_dynamic_batch \ --soc_version=Ascend310 \ --input_format=NCHW \ --input_shape="images:-1,3,640,640" \ --dynamic_batch_size="1,2,4,8" \ --dynamic_image_size="640,640" \ --insert_op_conf=aipp_yolov5.config参数3:INT8量化(性能提升关键)
# 准备校准数据(需要少量标注数据) python3.7 calibrate_yolo.py \ --model yolov5s-sim.onnx \ --data ./coco128.yaml \ --output yolov5s_calibration # 带量化的ATC转换 atc --model=yolov5s-sim.onnx \ --framework=5 \ --output=yolov5s_int8 \ --soc_version=Ascend310 \ --input_format=NCHW \ --input_shape="images:1,3,640,640" \ --insert_op_conf=aipp_yolov5.config \ --quantize_calibration_file=yolov5s_calibration.json \ --quantization_algorithms=weight_quantization六、第四步:转换结果验证
6.1 检查输出文件
# 查看生成的OM文件 ls -lh yolov5s_ascend.om # 应该能看到类似:yolov5s_ascend.om (约45MB) # 使用msame工具验证推理 git clone https://gitee.com/ascend/tools.git cd tools/msame ./build.sh ./msame --model ../yolov5s_ascend.om --input input.bin --output output6.2 Python推理验证脚本
import numpy as np from ais_bench.infer.interface import InferSession # 初始化昇腾推理会话 device_id = 0 model = InferSession(device_id, "yolov5s_ascend.om") # 准备输入数据 fake_input = np.random.randn(1, 3, 640, 640).astype(np.float32) # 执行推理 outputs = model.infer([fake_input]) # 解析YOLOv5输出 print("推理成功!输出信息:") for i, out in enumerate(outputs): print(f" 输出{i}: shape={out.shape}, dtype={out.dtype}, min={out.min():.4f}, max={out.max():.4f}") # 与ONNX结果对比(可选) def compare_results(onnx_output, ascend_output, threshold=1e-3): # 实现精度对比逻辑 pass七、常见错误与解决方案
错误1:Unsupported op type: NonMaxSuppression
原因:YOLOv5后处理中的NMS算子在昇腾上需要自定义实现
解决方案:
- 方案A(推荐):导出时移除后处理
python export.py --weights yolov5s.pt \ --include onnx \ --img-size 640 640 \ --batch-size 1 \ --opset 12 \ --simplify \ --nms # 使用内置NMS或导出不带NMS的模型- 方案B:使用ATC自定义算子功能
# 在ATC命令中添加 --op_name_map=op_name_map.json创建op_name_map.json:
{ "NonMaxSuppression": "CustomNonMaxSuppression" }错误2:Shape inference failed
原因:动态形状或维度不匹配
解决方案:
# 明确指定所有维度 --input_shape="images:1,3,640,640" \ --output_type="FP16" \ --precision_mode=allow_fp32_to_fp16错误3:内存不足
解决方案:
# 使用内存优化参数 --auto_tune_mode="RL,GA" \ --buffer_optimize=off_optimize \ --enable_small_channel=1八、性能优化技巧
8.1 转换参数调优
# 完整优化参数示例 atc --model=yolov5s-sim.onnx \ --framework=5 \ --output=yolov5s_optimized \ --soc_version=Ascend310 \ --input_format=NCHW \ --input_shape="images:1,3,640,640" \ --insert_op_conf=aipp_yolov5.config \ --precision_mode=allow_mix_precision \ --fusion_switch_file=fusion_switch.cfg \ --op_select_implmode=high_precision \ --optypelist_for_implmode="Gelu,Add" \ --enable_small_channel=18.2 创建融合规则文件(fusion_switch.cfg)
{ "switch": { "GraphFusion": { "enable": true, "pass_list": ["ConcatOptimize", "ReshapeFusion"] }, "MemoryOptimization": { "enable": true, "memory_optimization_priority": "memory_first" } } }九、完整脚本:一键转换工具
创建convert_yolov5.sh:
#!/bin/bash # YOLOv5一键转换脚本 # 用法:./convert_yolov5.sh yolov5s.pt Ascend310 MODEL_PT=$1 SOC_VERSION=${2:-Ascend310} MODEL_NAME=$(basename $MODEL_PT .pt) echo "开始转换 ${MODEL_NAME} ..." # 步骤1:导出ONNX python export.py --weights $MODEL_PT \ --include onnx \ --img-size 640 640 \ --batch-size 1 \ --opset 12 \ --simplify # 步骤2:简化模型 python -m onnxsim ${MODEL_NAME}.onnx ${MODEL_NAME}-sim.onnx # 步骤3:ATC转换 atc --model=${MODEL_NAME}-sim.onnx \ --framework=5 \ --output=${MODEL_NAME}_${SOC_VERSION} \ --soc_version=$SOC_VERSION \ --input_format=NCHW \ --input_shape="images:1,3,640,640" \ --insert_op_conf=aipp_yolov5.config \ --log=info # 步骤4:验证 if [ -f "${MODEL_NAME}_${SOC_VERSION}.om" ]; then echo "✓ 转换成功!" echo " 输入模型: ${MODEL_NAME}.pt" echo " 输出模型: ${MODEL_NAME}_${SOC_VERSION}.om" echo " 芯片版本: ${SOC_VERSION}" else echo "✗ 转换失败,请检查日志" fi十、进阶:不同YOLOv5版本的注意事项
| 版本 | 关键区别 | ATC转换建议 |
| YOLOv5 v6.0+ | 输出层改变 | 使用--out_nodes指定正确输出节点 |
| YOLOv5 v7.0 | 支持分类头 | 确认是否需要多任务输出 |
| YOLOv5n/s/m/l/x | 模型大小不同 | 大模型可能需要分片转换 |
十一、资源与下一步
学习资源
- 昇腾官方模型仓- 查看官方YOLOv5转换脚本
- ATC命令参考- 完整参数说明
- 昇腾论坛- 提问和交流
下一步行动
- 在Atlas 200DK上部署转换后的模型
- 尝试YOLOv6/YOLOv8的转换
- 实现端到端的完整应用(图像输入 → 检测结果输出)
成果展示
成功转换后,你将获得:
- ✅
yolov5s_ascend.om- 昇腾离线模型 - ✅ 比CPU快10-20倍的推理速度
- ✅ 支持边缘设备部署的能力