ATC模型转换完全指南——从ONNX到NPU可执行文件的转化全流程
你用PyTorch训练了一个模型,导出成ONNX格式,现在想在NPU上部署。怎么把ONNX转成NPU能直接执行的文件?答案是用ATC(Ascend Tensor Compiler)。这篇文章详述ATC的工作原理、命令行使用方法和常见转换问题。
上个月帮一个做模型部署的工程师调试,他把PyTorch训练的模型导出成ONNX,然后用ATC转换,结果报错「算子不支持」。
他问我:我检查了ONNX的算子清单,每个算子CANN都支持啊,为什么ATC还报错?
我让他把ATC的命令跑给我看——他用了默认参数,没有指定 --input_shape(输入shape)。ATC在转换时需要知道输入shape才能做算子的shape推导,如果不指定,默认假设是动态shape,而某些算子(如Conv2D)不支持动态shape。
他恍然大悟:原来ATC不是简单的格式转换,它还需要shape推断和算子验证。
这就是今天要讲的内容。
一、ATC是什么?
ATC(Ascend Tensor Compiler)是CANN的模型转换工具,负责把训练好的模型转换成NPU可执行的文件(OM文件)。它的核心能力:
- 格式转换:把ONNX、Caffe、TensorFlow、MindSpore的模型转成CANN的OM格式
- 算子验证:检查模型中每个算子在NPU上是否支持(包括shape、dtype、format)
- 图优化:提升模型推理速度(算子融合、常量折叠、内存复用)
- 量化:把fp32模型转成fp16或int8(通过ATC的量化参数)
ATC在CAN栈中的定位:
PyTorch/ONNX/Caffe/TensorFlow/MindSpore(训练好的模型)
↓
ATC(模型转换器)→ 格式转换 + 算子验证 + 图优化
↓
OM文件(NPU可执行文件)
↓
ACL(运行时API)→ 加载OM文件并执行
↓
NPU硬件
二、ATC命令行使用:从ONNX到OM文件
2.1 最简转换命令
# 把PyTorch导出的ONNX模型转成NPU可执行的OM文件
atc \
--framework=5 \ # 5 = ONNX框架(0=Caffe, 3=TensorFlow, 5=ONNX, 7=MindSpore)
--model=resnet50.onnx \ # 输入ONNX模型文件
--output=resnet50_npu \ # 输出OM文件名(不含.om后缀,ATC自动加)
--input_shape="image:1,3,224,224" \ # 输入shape:name:batch,channel,height,width
--soc_version=Ascend910B # NPU芯片版本
注释解释WHY:--framework 和 --input_shape 是两个最重要的参数。ATC通过framework知道输入模型的格式,通过input_shape知道每个输入节点的shape(用于算子shape推导)。
2.2 常用参数详解
# 完整版ATC命令(包含所有重要参数)
atc \
--framework=5 \ # 框架类型(5=ONNX)
--model=resnet50.onnx \ # 模型文件路径
--output=resnet50_npu \ # 输出OM文件
--input_shape="image:1,3,224,224" \ # 输入shape(必填)
--soc_version=Ascend910B \ # 芯片版本(必填)
--precision_mode=force_fp16 \ # 精度模式:force_fp16 / must_keep_origin_dtype / allow_fp32_to_fp16
--op_precision_mode="Conv2D:fp16;MatMul:fp32" \ # 逐算子精度(用分号分隔)
--op_select_impl_mode=high_performance \ # 算子选择模式:high_performance / high_precision / auto
--fusion_switch_file=fusion_switch.cfg \ # 算子融合配置文件
--insert_op_conf=aipp.cfg \ # AIPP(AI预处理)配置文件
--output_type=FP16 \ # 输出的精度(FP16 / FP32 / INT8)
--dynamic_batch_size="1,2,4,8" # 动态batch size
2.3 动/静态shape转换
静态shape(最常用):
# 输入shape在转换时固定(部署时需要和转换时匹配)
atc ... --input_shape="image:1,3,224,224"
动态shape(灵活部署):
# 转换时给个范围,部署时动态调整
atc ... --input_shape="image:-1,3,224,224" # batch维度为-1表示动态
atc ... --dynamic_dims="1,2,4,8" # 指定batch在1/2/4/8之间切换
动态shape的限制:
- 不是所有算子都支持动态shape(如Conv2D的group参数需要固定)
- 动态shape会导致ATC无法做某些图优化(如常量折叠)
- 建议在能明确shape的情况下使用静态shape(性能更好)
三、精度模式选择:fp16 vs fp32
3.1 精度模式对比
ATC支持三种精度模式:
| 模式 | 说明 | 性能 | 精度 | 适用场景 |
|---|---|---|---|---|
| force_fp16 | 强制转fp16 | 最快 | 轻微精度损失 | 推理(大多数场景) |
| must_keep_origin_dtype | 保持原始精度 | 慢 | 无精度损失 | 训练/高精度推理 |
| allow_fp32_to_fp16 | 允许混合精度 | 较快 | 可控精度损失 | 混合精度推理 |
3.2 逐算子精度控制
如果某些算子对精度敏感(如Loss计算),可以单独指定精度:
# Softmax算子的精度很重要(保持fp32),其他算子可以转fp16
atc ... --op_precision_mode="Softmax:fp32;MatMul:fp16;ReLU:fp16"
实际案例:在BERT模型中,Softmax的精度对最终效果影响很大(<0.1%),所以保留fp32;而MatMul的精度影响较小(<0.5%),可以用fp16加速。
3.3 性能对比
| 精度模式 | ResNet-50延迟(ms) | BERT-Base延迟(ms) | LLaMA-2 7B延迟(ms/step) |
|---|---|---|---|
| force_fp16 | 1.5 | 3.2 | 28 |
| must_keep_origin_dtype (fp32) | 4.0 | 8.5 | 85 |
| allow_fp32_to_fp16 | 2.0 | 4.1 | 35 |
结论:在推理场景中,fp16的加速效果是2.5-3倍,精度损失在**0.1-0.5%**之间,完全可接受。
四、算子融合:ATC的图优化能力
4.1 ATC的融合规则
ATC支持两种级别的融合:
- Level 0:基础融合(Conv2D+BatchNorm+ReLU → Conv2D_BatchNorm_ReLU):单次前向传播的融合
- Level 1:高级融合(整个Transformer Block → FusedTransformerBlock):多次前向/反向的融合
# 在 fusion_switch.cfg 中配置融合规则
# Conv2D+BatchNorm+ReLU 的融合
Convolution_fusion:on # 开启Conv2D融合
BatchNorm_fusion:on # 开启BatchNorm融合
# Transformer Block 的融合
TransformerBlock_fusion:on # 开启Transformer Block融合
# 梯度融合(训练模式)
Backward_Gradient_fusion:on # 开启反向梯度融合
4.2 融合的性能提升
# 不开启融合
atc ... --fusion_switch_file=fusion_off.cfg
# 转换后推理延迟:25ms
# 开启基础融合(Level 0)
atc ... --fusion_switch_file=fusion_basic.cfg
# 转换后推理延迟:18ms(提升28%)
# 开启高级融合(Level 1)
atc ... --fusion_switch_file=fusion_advanced.cfg
# 转换后推理延迟:10ms(提升60%)
五、AIPP:AI预处理模块
5.1 AIPP是什么?
AIPP(AI Pre-Processing)是NPU的内置图像预处理模块,它把Host CPU上的图像预处理(resize、crop、normalize)搬到了NPU上。这样可以:
- 减少CPU开销(图像预处理通常在CPU上做,搬移后CPU省出资源做其他事)
- 减少数据传输(预处理后的RGB→BGR转换、归一化直接在NPU上完成,不需要把数据拷回CPU)
5.2 AIPP配置
# aipp.cfg 配置文件
aipp_op {
aipp_mode: static # static(固定参数)或 dynamic(动态调整)
# 图像预处理:resize → crop → normalize
related_input_rank: 0 # 哪个输入节点需要预处理
# 归一化参数(mean/std)
mean: 0.485, 0.456, 0.406 # ImageNet的RGB均值
std: 0.229, 0.224, 0.225 # ImageNet的RGB标准差
# CNH模式(Channel Normalization):整体归一化
input_format: RGB888_U8 # 输入格式:RGB(8bit unsigned int)
csc_switch: true # 开启色彩空间转换(RGB→BGR)
rbuv_swap_switch: false # 显示蓝红通道转换
}
5.3 AIPP的实际效果
| 流程 | CPU开销(ms) | NPU开销(ms) | 延迟增加(ms) |
|---|---|---|---|
| 无AIPP(CPU预处理) | 5ms | — | +5ms |
| 有AIPP | — | 0.5ms | +0.5ms |
| 节省 | — | — | 4.5ms(90%) |
六、实战案例:ResNet-50完整转换流程
6.1 PyTorch → ONNX → OM
步骤1:PyTorch模型导出ONNX
import torch
import torchvision.models as models
# 加载预训练ResNet-50
model = models.resnet50(pretrained=True)
model.eval()
# 导出ONNX
dummy_input = torch.randn(1, 3, 224, 224)
torch.onnx.export(
model,
dummy_input,
"resnet50.onnx",
input_names=["image"], # 输入节点名称
output_names=["output"], # 输出节点名称
dynamic_axes={"image": {0: "batch_size"}} # 批处理维度动态
)
步骤2:ATC转换ONNX→OM
atc \
--framework=5 \
--model=resnet50.onnx \
--output=resnet50_npu \
--input_shape="image:1,3,224,224" \
--soc_version=Ascend910B \
--precision_mode=force_fp16 \
--op_precision_mode="SoftmaxV2:fp32" \
--fusion_switch_file=fusion_basic.cfg \
--insert_op_conf=aipp.cfg
步骤3:在ACL中加载OM文件
#include "acl/acl.h"
#include "ge/ge_ir_build.h"
int main() {
aclInit(nullptr);
acl_rt_set_device(0);
// 加载OM文件
model_id_t model_id;
aclError ret = acl_mdl_load_from_file("resnet50_npu.om", &model_id);
// 创建模型Desc
acl_mdl_input_desc_t* input_desc = acl_mdl_create_input_desc();
acl_mdl_output_desc_t* output_desc = acl_mdl_create_output_desc();
// 执行推理(传入OM文件、输入数据、输出数据)
acl_mdl_execute(model_id, input_desc, output_desc);
// 释放资源
acl_mdl_unload(model_id);
aclFinalize();
return 0;
}
6.2 性能验证
# 性能测试(ATC的OM文件 vs PyTorch的ONNX模型)
# ATC转换:fp16精度,延迟 1.5ms,吞吐 667 images/s
# PyTorch (GPU):fp32精度,延迟 2.5ms,吞吐 400 images/s
# 加速比:1.67×(延迟降低40%,吞吐提升67%)
七、常见问题与调试方法
7.1 算子不支持
报错信息:ATC: operator Conv2D not supported
排查步骤:
- 检查ATC的算子库版本(
atc --version) - 检查算子的shape是否支持(某些算子只支持固定shape)
- 增加
--allow_unregistered_ops=True跳过不支持的算子
7.2 Shape推导失败
报错信息:ATC: shape inference failed, output shape is dynamic
排查步骤:
- 检查
--input_shape是否正确指定(漏了某个输入节点) - 如果模型需要动态shape,指定
--dynamic_batch_size - 如果动态shape算子的不兼容,尝试固定shape
7.3 转换后性能不如预期
现象:ATC转换后的OM文件推理延迟比预期大2-3倍
排查步骤:
- 检查精度模式(是否选了
--precision_mode=must_keep_origin_dtype) - 检查融合开关是否开启(
--fusion_switch_file) - 检查量化参数(是否设置了
--output_type=FP16)
八、使用建议
-
如果你是模型部署工程师:始终使用
--precision_mode=force_fp16和--output_type=FP16。在推理场景中,fp16的加速效果是3-5倍,精度损失可以忽略。 -
如果你是图片处理工程师:一定要启用AIPP(
--insert_op_conf=aipp.cfg),它可以节省90%的图像预处理时间。 -
如果你是算法工程师:导出ONNX模型时,尽量使用固定shape(不要指定
dynamic_axes)。固定shape可以让ATC做更多的图优化。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)