ATC模型转换完全指南——从ONNX到NPU可执行文件的转化全流程
你用PyTorch训练了一个模型导出成ONNX格式现在想在NPU上部署。怎么把ONNX转成NPU能直接执行的文件答案是用ATCAscend Tensor Compiler。这篇文章详述ATC的工作原理、命令行使用方法和常见转换问题。上个月帮一个做模型部署的工程师调试他把PyTorch训练的模型导出成ONNX然后用ATC转换结果报错「算子不支持」。他问我我检查了ONNX的算子清单每个算子CANN都支持啊为什么ATC还报错我让他把ATC的命令跑给我看——他用了默认参数没有指定--input_shape输入shape。ATC在转换时需要知道输入shape才能做算子的shape推导如果不指定默认假设是动态shape而某些算子如Conv2D不支持动态shape。他恍然大悟原来ATC不是简单的格式转换它还需要shape推断和算子验证。这就是今天要讲的内容。一、ATC是什么ATCAscend 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\--framework5\# 5 ONNX框架0Caffe, 3TensorFlow, 5ONNX, 7MindSpore--modelresnet50.onnx\# 输入ONNX模型文件--outputresnet50_npu\# 输出OM文件名不含.om后缀ATC自动加--input_shapeimage:1,3,224,224\# 输入shapename:batch,channel,height,width--soc_versionAscend910B# NPU芯片版本注释解释WHY--framework和--input_shape是两个最重要的参数。ATC通过framework知道输入模型的格式通过input_shape知道每个输入节点的shape用于算子shape推导。2.2 常用参数详解# 完整版ATC命令包含所有重要参数atc\--framework5\# 框架类型5ONNX--modelresnet50.onnx\# 模型文件路径--outputresnet50_npu\# 输出OM文件--input_shapeimage:1,3,224,224\# 输入shape必填--soc_versionAscend910B\# 芯片版本必填--precision_modeforce_fp16\# 精度模式force_fp16 / must_keep_origin_dtype / allow_fp32_to_fp16--op_precision_modeConv2D:fp16;MatMul:fp32\# 逐算子精度用分号分隔--op_select_impl_modehigh_performance\# 算子选择模式high_performance / high_precision / auto--fusion_switch_filefusion_switch.cfg\# 算子融合配置文件--insert_op_confaipp.cfg\# AIPPAI预处理配置文件--output_typeFP16\# 输出的精度FP16 / FP32 / INT8--dynamic_batch_size1,2,4,8# 动态batch size2.3 动/静态shape转换静态shape最常用# 输入shape在转换时固定部署时需要和转换时匹配atc...--input_shapeimage:1,3,224,224动态shape灵活部署# 转换时给个范围部署时动态调整atc...--input_shapeimage:-1,3,224,224# batch维度为-1表示动态atc...--dynamic_dims1,2,4,8# 指定batch在1/2/4/8之间切换动态shape的限制不是所有算子都支持动态shape如Conv2D的group参数需要固定动态shape会导致ATC无法做某些图优化如常量折叠建议在能明确shape的情况下使用静态shape性能更好三、精度模式选择fp16 vs fp323.1 精度模式对比ATC支持三种精度模式模式说明性能精度适用场景force_fp16强制转fp16最快轻微精度损失推理大多数场景must_keep_origin_dtype保持原始精度慢无精度损失训练/高精度推理allow_fp32_to_fp16允许混合精度较快可控精度损失混合精度推理3.2 逐算子精度控制如果某些算子对精度敏感如Loss计算可以单独指定精度# Softmax算子的精度很重要保持fp32其他算子可以转fp16atc...--op_precision_modeSoftmax:fp32;MatMul:fp16;ReLU:fp16实际案例在BERT模型中Softmax的精度对最终效果影响很大0.1%所以保留fp32而MatMul的精度影响较小0.5%可以用fp16加速。3.3 性能对比精度模式ResNet-50延迟msBERT-Base延迟msLLaMA-2 7B延迟ms/stepforce_fp161.53.228must_keep_origin_dtype (fp32)4.08.585allow_fp32_to_fp162.04.135结论在推理场景中fp16的加速效果是2.5-3倍精度损失在**0.1-0.5%**之间完全可接受。四、算子融合ATC的图优化能力4.1 ATC的融合规则ATC支持两种级别的融合Level 0基础融合Conv2DBatchNormReLU → Conv2D_BatchNorm_ReLU单次前向传播的融合Level 1高级融合整个Transformer Block → FusedTransformerBlock多次前向/反向的融合# 在 fusion_switch.cfg 中配置融合规则# Conv2DBatchNormReLU 的融合Convolution_fusion:on# 开启Conv2D融合BatchNorm_fusion:on# 开启BatchNorm融合# Transformer Block 的融合TransformerBlock_fusion:on# 开启Transformer Block融合# 梯度融合训练模式Backward_Gradient_fusion:on# 开启反向梯度融合4.2 融合的性能提升# 不开启融合atc...--fusion_switch_filefusion_off.cfg# 转换后推理延迟25ms# 开启基础融合Level 0atc...--fusion_switch_filefusion_basic.cfg# 转换后推理延迟18ms提升28%# 开启高级融合Level 1atc...--fusion_switch_filefusion_advanced.cfg# 转换后推理延迟10ms提升60%五、AIPPAI预处理模块5.1 AIPP是什么AIPPAI Pre-Processing是NPU的内置图像预处理模块它把Host CPU上的图像预处理resize、crop、normalize搬到了NPU上。这样可以减少CPU开销图像预处理通常在CPU上做搬移后CPU省出资源做其他事减少数据传输预处理后的RGB→BGR转换、归一化直接在NPU上完成不需要把数据拷回CPU5.2 AIPP配置# aipp.cfg 配置文件aipp_op{aipp_mode: static# static固定参数或 dynamic动态调整# 图像预处理resize → crop → normalizerelated_input_rank:0# 哪个输入节点需要预处理# 归一化参数mean/stdmean:0.485,0.456,0.406# ImageNet的RGB均值std:0.229,0.224,0.225# ImageNet的RGB标准差# CNH模式Channel Normalization整体归一化input_format: RGB888_U8# 输入格式RGB8bit unsigned intcsc_switch:true# 开启色彩空间转换RGB→BGRrbuv_swap_switch:false# 显示蓝红通道转换}5.3 AIPP的实际效果流程CPU开销msNPU开销ms延迟增加ms无AIPPCPU预处理5ms—5ms有AIPP—0.5ms0.5ms节省——4.5ms90%六、实战案例ResNet-50完整转换流程6.1 PyTorch → ONNX → OM步骤1PyTorch模型导出ONNXimporttorchimporttorchvision.modelsasmodels# 加载预训练ResNet-50modelmodels.resnet50(pretrainedTrue)model.eval()# 导出ONNXdummy_inputtorch.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}}# 批处理维度动态)步骤2ATC转换ONNX→OMatc\--framework5\--modelresnet50.onnx\--outputresnet50_npu\--input_shapeimage:1,3,224,224\--soc_versionAscend910B\--precision_modeforce_fp16\--op_precision_modeSoftmaxV2:fp32\--fusion_switch_filefusion_basic.cfg\--insert_op_confaipp.cfg步骤3在ACL中加载OM文件#includeacl/acl.h#includege/ge_ir_build.hintmain(){aclInit(nullptr);acl_rt_set_device(0);// 加载OM文件model_id_t model_id;aclError retacl_mdl_load_from_file(resnet50_npu.om,model_id);// 创建模型Descacl_mdl_input_desc_t*input_descacl_mdl_create_input_desc();acl_mdl_output_desc_t*output_descacl_mdl_create_output_desc();// 执行推理传入OM文件、输入数据、输出数据acl_mdl_execute(model_id,input_desc,output_desc);// 释放资源acl_mdl_unload(model_id);aclFinalize();return0;}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_opsTrue跳过不支持的算子7.2 Shape推导失败报错信息ATC: shape inference failed, output shape is dynamic排查步骤检查--input_shape是否正确指定漏了某个输入节点如果模型需要动态shape指定--dynamic_batch_size如果动态shape算子的不兼容尝试固定shape7.3 转换后性能不如预期现象ATC转换后的OM文件推理延迟比预期大2-3倍排查步骤检查精度模式是否选了--precision_modemust_keep_origin_dtype检查融合开关是否开启--fusion_switch_file检查量化参数是否设置了--output_typeFP16八、使用建议如果你是模型部署工程师始终使用--precision_modeforce_fp16和--output_typeFP16。在推理场景中fp16的加速效果是3-5倍精度损失可以忽略。如果你是图片处理工程师一定要启用AIPP--insert_op_confaipp.cfg它可以节省90%的图像预处理时间。如果你是算法工程师导出ONNX模型时尽量使用固定shape不要指定dynamic_axes。固定shape可以让ATC做更多的图优化。