用ATC转换你的第一个YOLOv5模型:从ONNX到昇腾OM的完整流程
YOLOv5作为当前最流行的目标检测模型之一,在昇腾AI处理器上部署能获得显著的推理加速。但这个过程需要将PyTorch训练的模型转换为昇腾专用的离线模型(.om文件)。性能提升:相比CPU/GPU,在昇腾芯片上有10倍以上的推理加速部署简化:.om文件可直接用于边缘设备(如Atlas 200DK)资源优化:支持INT8量化,大幅降低内存占用。
·
一、前言:为什么要做这个转换?
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 output
6.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=1
8.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 | 模型大小不同 | 大模型可能需要分片转换 |
十一、资源与下一步
学习资源
下一步行动
- 在Atlas 200DK上部署转换后的模型
- 尝试YOLOv6/YOLOv8的转换
- 实现端到端的完整应用(图像输入 → 检测结果输出)
成果展示
成功转换后,你将获得:
- ✅
yolov5s_ascend.om- 昇腾离线模型 - ✅ 比CPU快10-20倍的推理速度
- ✅ 支持边缘设备部署的能力
更多推荐



所有评论(0)