拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

一文教会昇腾ATC模型转换工具:把开源模型编译成NPU能跑的格式

一文教会昇腾ATC模型转换工具:把开源模型编译成NPU能跑的格式

昇腾 ATC 模型转换入门指南:把训练模型变成 NPU 能跑的 OM

一句话让Agent变成昇腾专家,昇腾任务轻松搞定。评测入口:请按这个开源仓接入昇腾图谱 https://gitcode.com/agent0/kg-tools

你花几天训练出一个深度学习模型,满怀期待地拷到昇腾开发板上,然后发现:板子根本不认识这个文件。

这不是板子的问题。训练框架产出的模型(ONNX、Caffe、TensorFlow 等)是为通用计算世界准备的,而昇腾 NPU 有一套自己的"方言"——数据要按它喜欢的格式排布、算子要用它能执行的形态、内存要提前规划好。中间必须有人做一次"翻译 + 备考",这个角色就是ATC。

这篇入门指南把 ATC 的使用场景、命令用法、内部流程、关键原理、常用参数和避坑事项一次讲清。所有关键事实都经昇腾知识图谱官方文档核实(文末附来源清单)。

一、ATC 是什么:模型的"编译器"

ATC(Ascend Tensor Compiler,昇腾张量编译器)是昇腾 CANN 异构计算架构下的模型转换工具。官方定义一句话:

ATC 可以将开源框架的网络模型以及 Ascend IR 定义的单算子描述文件(JSON 格式),转换为 AI 处理器支持的.om格式离线模型。

理解它最快的方式是类比 gcc:C 源码要经过 gcc 编译成可执行文件才能跑;同样,训练产出的模型文件要经过 ATC 编译成.om(Offline Model,离线模型)才能在昇腾设备上高效推理。

.c 源文件 --gcc--> 可执行文件 .onnx/.pb/.air 模型 --ATC--> .om 离线模型

而且 ATC 不只是"翻译"。转换过程中它会做算子调度优化、权重数据重排、内存使用优化——相当于翻译的同时还替你把考试重点复习了一遍。这也是它叫"编译器"而不是"格式转换器"的原因。

支持哪些输入

--framework参数告诉 ATC 输入模型来自哪个框架,注意填的是数字枚举,不是字符串:

–framework 取值对应格式说明
0Caffe双文件(结构 + 权重)输入,命令写法请查所用版本的官方 ATC 文档
1MindSpore.air格式模型
3TensorFlow.pb等
5ONNX最常用的路径,官方文档口径支持 ONNX 1.12.0(以所用 CANN 版本文档为准)

二、它能干什么:典型使用场景

场景一:训练到部署的主线。这是 ATC 最经典的用法:在训练机(比如 910B)上训练并导出 ONNX,用 ATC 转成 OM,拷到推理设备(比如香橙派等 310 系列板子)上,通过推理接口加载执行。CANN 官方教程里就有这样一条端到端实验路径。

场景二:没有 NPU 的机器上也能转。官方文档明确:模型转换阶段不依赖 AI 处理器。你可以在一台普通 x86 开发机上完成转换,把 OM 拷到目标设备运行。两个约束要记住:

  • --soc_version必须填转换后实际运行的芯片型号,转给谁就要填谁;
  • 只要--soc_version相同,不同产品只需转一次,同一份 OM 可以分别部署。

场景三:单算子编译。ATC 不只能转整网,还能把一个描述算子的 JSON 文件编译成单算子 OM(--singleop),算子开发调试时会用到。

什么时候不需要 ATC?也有不经过 ATC 的推理路径:在线推理可以用 GE(图引擎)接口构图后由 GeSession 直接编译执行;PyTorch 走图模式时由 TorchAir 组件对接 GE 编译。但对入门部署来说,"ATC 离线转 OM → 推理接口加载执行"是最主线、最通用的路径。

三、上手三步走:环境、芯片型号、第一条命令

第 1 步:装好 CANN,让 atc 命令可用

CANN 装好后,先 source 环境变量(以实际安装路径为准,不同版本路径略有差异):

# 常见路径(FAQ 口径):source/usr/local/Ascend/ascend-toolkit/set_env.sh# 新版 GE 文档口径为 /usr/local/Ascend/cann/set_env.sh# 带版本号目录的写法如 /usr/local/Ascend/cann-{version}/set_env.shecho$ASCEND_HOME_PATH# 有输出说明环境变量已生效

两个易踩的环境点:

  • CANN 8.5.0 及之后版本,转换时必须安装与目标 AI 处理器匹配的 ops 算子包,否则编译失败(文档两处一致强调);
  • 在非昇腾设备上装 Toolkit 做转换,还需把devlib目录加进LD_LIBRARY_PATH(详见官方环境准备文档)。

atc命令本体位于 CANN 安装目录的bin下(如/usr/local/Ascend/cann/bin),source 之后直接敲atc --help能出帮助就说明装好了。

第 2 步:查芯片型号,确定 --soc_version

npu-smi info

看回显里的Name字段,--soc_version的值就是Ascend+ Name。例如 Name 显示 910B1,参数就填--soc_version=Ascend910B1;常见值还有Ascend310P3、Ascend310B1等。

少数产品(如 950PR/950DT、A3 系列)要用npu-smi info -t board取 Chip Name 与 NPU Name 组合填写,具体以官方--soc_version文档为准。

第 3 步:跑第一条转换命令

最简 ONNX 示例(官方文档原文示例的整理版):

atc--model=$HOME/module/resnet50.onnx\--framework=5\--output=$HOME/module/out/resnet50\--soc_version=Ascend910B1
参数含义
--model原始模型文件路径与文件名
--framework=55 = ONNX(见第一节取值表)
--output输出路径与文件名(不带.om后缀,ATC 自动补上)
--soc_version目标芯片型号,必填

MindSpore 的.air模型同理,只需把 framework 换成 1:

atc--model=$HOME/module/ResNet50.air\--framework=1\--output=$HOME/module/out/ResNet50_air\--soc_version=Ascend910B1

一个更接近实战的例子

真实部署往往还要固定输入尺寸、开启日志、甚至把预处理塞进模型。下面这条 YOLOv7 命令来自官方样例,一次展示了这些常用参数:

atc--framework=5\--model=yolov7.onnx\--output=yolov7_bs1\--input_format=NCHW\--input_shape="images:1,3,640,640"\--log=error\--insert_op_conf=aipp.cfg\--soc_version=Ascend310P3
  • --input_format:输入数据格式。Caffe/MindSpore/ONNX 默认 NCHW,TensorFlow 默认 NHWC,与模型实际不符时显式指定;
  • --input_shape:把动态输入固定下来,格式"输入名:N,C,H,W"。ATC 是离线编译,原则上需要确定的 shape(动态分档见第五节);
  • --insert_op_conf:AIPP 预处理配置文件,见第五节详解。

转完怎么确认没翻车

atc--mode=1--om=$HOME/module/out/resnet50.om

--mode=1会把 OM 模型的输入输出 shape 和数据类型打出来,转换后先跑一下,核对输入名、维度、dtype 与预期一致,再上板。推理侧的标准流程是:aclmdlLoadFromFile加载 OM →aclmdlExecute执行推理(C/C++ 用 ACL 接口,Python 用 pyACL),本文不展开。

给新手的工程建议(来自官方迁移实践):转换前先用 Netron 打开模型核对输入输出名/维度/dtype;转换后做最小验证——OM 能加载 + 用 1~3 个固定输入跑通前向并保存输出范围,再去对精度。

四、ATC 里面发生了什么:运行流程与关键原理

一条atc命令敲下去到 OM 落盘,内部是一条完整的编译流水线。先看全景图,再逐段拆解:

Parser 解析

训练框架模型
.onnx / .pb / .air

中间态 IR Graph
(Ascend 图表示)

① 图准备
图规范化 · Shape 推理 · 量化准备

② 图优化
常量折叠 · 算子融合 · 公共子表达式消除
数据布局转换 NCHW/NHWC → NC1HWC0

③ 图拆分 / 引擎分区
按 AI Core / AI CPU 等引擎划分子图

④ 图构建
流分配 · 内存规划 · 任务生成

.om 离线模型
图结构 + 权重 + 算子二进制 + tiling 参数

拷贝到目标设备

aclmdlLoadFromFile 加载

aclmdlExecute 执行推理

逐阶段拆解

Parser 解析。把 ONNX/TensorFlow/MindSpore 的模型读进来,统一翻译成中间态 IR Graph——类似编译器把各种语言先变成统一的中间表示(IR),后面所有优化都在这份统一表示上做。ATC 本身是 GE(Graph Engine,图引擎,昇腾计算图编译和运行的控制中心)对外提供的命令行入口,这套流水线就是 GE 的编译器。

① 图准备。做规范化、Shape 推理、量化准备等预处理,把图整理成"标准体位"。

② 图优化。编译器的核心收益环节,重点认识三件事:

  1. 算子融合。把多个小算子合成一个大算子,分硬件无关与硬件相关两类:图融合做数学等价替换(比如 Convolution + BiasAdd 融合后直接在片上完成累加,Conv2D + BatchNorm 用数学推导合成一个算子);UB 融合则消除相邻算子之间"片上缓存 → 内存 → 片上缓存"的往返搬运,让数据留在 Unified Buffer 里流转。往返搬运是性能杀手,融合是图模式相对逐算子执行的核心优势。
  2. 常量折叠。输入全是常量的算子,编译期就在主机侧提前算好,替换成一个常量节点。典型的如维度计算——Shape/Reshape/Transpose 这类操作编译期就能求值,没必要留到运行时。进阶用户可用--ge.oo.level=O1 --ge.oo.constantFolding=true控制,融合 pass 级开关可用--fusion_switch_file。
  3. 数据布局转换。框架模型常用的 NCHW/NHWC 会被转成 AI 处理器统一的NC1HWC0五维格式(C0 对应矩阵单元 32B 对齐的元素数,fp16 时 C0=16),卷积权重则排成FRACTAL_Z分形格式送进 Cube 矩阵单元。入门篇记住"数据被重新排成硬件最喜欢的队形"即可,细节官方概述文档有图解。

此外还有公共子表达式消除(CSE)、死代码消除(DCE)等常规编译优化。

③ 图拆分 / 引擎分区。按引擎把图切分成子图——大部分算子跑在 AI Core 上,部分算子跑在 AI CPU 上,分区器负责划界。

④ 图构建。完成流分配、内存规划、任务生成,产出编译产物并序列化成 OM。你在部署后感受到的"加载即跑",就是因为这些调度决策都在这一步提前做完了。

OM 文件里装了什么

转出来的.om不是一个简单的权重容器,而是一个自包含的部署包,按分区组织:

分区内容
文件头ModelFileHeader,模型元信息
MODEL_DEF模型定义:图结构、算子属性
WEIGHTS_DATA权重数据(已按目标格式重排)
TBE_KERNELS编译后的算子二进制(kernel)
TILING_DATA预计算好的 tiling 参数(切块策略)
SO_BINS / CUSTOM_OPS算子 so 与自定义算子数据(按需打包)

用atc --mode=6 --om=model.om可以查看 OM 占用的关键资源信息和编译运行环境(包括当初的 atc 命令行和 soc_version)——排查"这模型是谁在哪儿转的"很有用。

为什么要"提前编译"

把编译挪到部署前完成,收益不是省的那几秒启动时间,而是:

  • 全局视角做优化。逐算子下发执行时每个算子各自为战;整图离线编译能看到全貌,融合、内存复用、多流并行、模型下沉这些优化才做得起来,有效减少 Host 与 Device 的调度交互;
  • 部署侧自包含。传统部署要在目标机装完整算子包(数百个 so)、严格保证编译运行环境算子包版本一致、还要管理环境变量;OM 把需要的都打包带走,部署形态干净得多;
  • 确定性与稳定性。一个真实的反例:某推理框架的 CANN 后端在运行时编译生成 OM 缓存,多卡并发写同一个缓存路径产生竞态问题——预编译 OM 文件可以完全避免这类运行时竞态。

(顺带一答常见疑问:“GPU 上不是运行时 JIT 吗,昇腾为啥搞离线?”——官方文档没有做这样的对照论述,这一段对比属于笔者的理解,供参考:两条路线本质都是"把硬件差异和优化时机放在不同的位置",昇腾选择把优化前置到转换期,换取部署期的确定性与极致性能。)

遇到不支持的算子怎么办

ATC 遇到算子库里没有的算子会直接报错、转换失败,报错会点名算子类型,长这样:

Op type NonMaxSuppression is not supported

别慌,按官方排错路径逐级尝试:

  1. 先化简模型:用 onnx-simplifier 或 auto_optimizer 消除/化简,有希望把不支持的融合算子拆成基本算子组合(官方推荐按 auto_optimizer → onnxslim → 原模型 逐个回退尝试);
  2. 等价算子替换:如 GroupNorm 换 InstanceNorm + LayerNorm 组合、bicubic 插值换 bilinear;
  3. 让 AIPP 承担:某些预处理类算子(如离线 resize)可下沉到 AIPP;
  4. 升级 CANN:算子支持随版本持续完善;
  5. 自定义算子:用 Ascend C 写 kernel 注册进算子库,ATC 即可使用(进阶话题)。

另外一个冷知识:dtype 不匹配导致的编译失败,可以通过自动插入 Cast 打通(AI CPU Cast 自动插入模式),详见官方文档。

五、主要参数速查

必选四件套

--model、--framework、--output、--soc_version,见第三节,不再赘述。

常用可选参数

参数干什么备注 / 默认
--input_format输入数据格式Caffe/MindSpore/ONNX 默认 NCHW;TensorFlow 默认 NHWC
--input_shape固定输入 shape,如"images:1,3,640,640"动态维度用-1占位,配合下面的动态参数
--dynamic_batch_sizebatch 分档,如"1,2,4,8"至少 2 档、最多 100 档;只支持 N 在首位;OM 会新增一个输入用于喂实际 batch 值(新手常踩)
--dynamic_image_size分辨率分档,如"416,416;832,832"与--input_shape配用(H、W 位填 -1);与 dynamic_batch_size 互斥
--output_type指定输出数据类型—
--out_nodes指定输出节点—
--core_type使用的 Core 类型默认 AiCore;含 Cube 算子的网络只能 AiCore
--external_weight权重外置为单独文件默认 0;适合超大模型拆分管理
--log转换日志级别默认 null(不出调试日志);排错加--log=debug
--insert_op_confAIPP 预处理配置文件见下文
--singleop单算子 JSON 编译算子开发场景

精度一族

参数取值默认说明
--precision_modeforce_fp32 / force_fp16 / allow_fp32_to_fp16 / allow_mix_precision / must_keep_origin_dtypeforce_fp16老版精度参数
--precision_mode_v2fp16 / origin / cube_fp16in_fp32out / mixed_float16 / mixed_bfloat16 / mixed_hif8fp16官方推荐改用,与老参数互斥
--op_select_implmodehigh_precision / high_performancehigh_performance算子实现选高精度还是高性能;某算子只实现一种模式时该参数对其不生效

一个诚实提醒:--optypelist_for_implmode(按算子列表指定 implmode)在网上老教程里出镜率不低,但官方文档已明示该功能停止演进、后续版本会废弃,请勿使用。另外--compression_optimize_conf是压缩优化的配置入口(含首层量化融合、训练后量化等特性),注意配了其中的 calibration 量化就不能再配高精度模式,两者会互相抵消收益。

AIPP:把预处理"焊"进模型

AIPP(AI Pre-Processing)把推理前的图像处理——色域转换(YUV→RGB)、抠图、归一化——以 Aipp 算子的形式固化进 OM,推理时用专用加速模块完成,省掉 CPU 上的预处理代码。开启方式就是--insert_op_conf=aipp.cfg,一份官方静态 AIPP 配置示例(YUV420SP 转 RGB + 通道减均值):

aipp_op { aipp_mode : static related_input_rank : 0 # 作用于第几个输入 src_image_size_w : 608 src_image_size_h : 608 crop : false input_format : YUV420SP_U8 csc_switch : true # 色域转换开关 + 转换矩阵 matrix_r0c0 : 298 matrix_r0c1 : 0 matrix_r0c2 : 409 matrix_r1c0 : 298 matrix_r1c1 : -100 matrix_r1c2 : -208 matrix_r2c0 : 298 matrix_r2c1 : 516 matrix_r2c2 : 0 input_bias_0 : 16 input_bias_1 : 128 input_bias_2 : 128 mean_chn_0 : 104 # 各通道减均值 mean_chn_1 : 117 mean_chn_2 : 123 }

约束提一句:静态 AIPP 与动态分辨率共用时,cfg 里不能开 Crop/Padding 且src_image_size_w/h须设 0。完整配置项见官方《AIPP 配置参考》。

–mode:ATC 的六种运行模式

取值作用
0默认,执行转换生成.om
1查看模型信息(输入输出 shape/dtype)——自检常用
3只做模型合法性预检查(生成 check_result.json)
5把 dump 出的图结构文件转 JSON,定位图问题用
6查看已有 OM 的资源占用与编译运行环境
30生成感知硬件调度的.exeom(加载更快、内存峰值更低;仅特定芯片支持)

顺手的两个环境变量

exportTE_PARALLEL_COMPILER=16# 算子并行编译进程数(1~32,默认 8),大网转换提速exportASCEND_SLOG_PRINT_TO_STDOUT=1# atc 日志直接打屏(默认只落盘)

六、避坑指南:常见报错与注意事项

排错总表(现象 → 原因 → 对策)

#现象原因对策
1Op type XXX is not supported算子库无该算子见第四节五步排错路径
2E10003 ... Value 1.1,2,4,8 for parameter --dynamic_batch_size is invalid档位值含非法字符(小数点)按提示改参数值,错误信息里的 Reason 写得很直白
3EZ0005 OP[xx] Nth input has incorrect shape size算子输入维度数不对核对--input_shape;用 DUMP_GE_GRAPH(见下)在图里找问题节点
4转换巨慢 / 内存耗尽失败动态档位过多过大;整网过大减少档位/调低数值;超大模型拆成多段分别转换(官方大模型实战做法);转换期可swapoff -a防止 swap 拖慢
5转换成功但推理结果不对精度模式、输入 dtype/layout、AIPP 配置问题同输入对比 onnxruntime 与 NPU 输出(余弦相似度/最大绝对误差);换 precision_mode 对照;日志里 grepreplace/fusion/unsupported
6OM 无法加载 / 执行报acl.mdl.execute error 507011soc_version 与实际设备不符npu-smi info查实际型号重转;atc --mode=1核对 OM 信息;勿复用旧 OM
7ModuleNotFoundError: No module named 'decorator'(或'te')Python 依赖缺失按提示 pip 安装;te报错说明装 CANN 时没带--pylocal,建议带参数重装

错误码怎么认

ATC 生态的错误码按前缀分家,认前缀就知道该往哪查:

前缀归属
E1xxxxGE 图编译/校验
E20101FE 算子融合
EE1011RTS 运行时
EH0001ACL
EZxxxxATC 工具专属(离线模型编译)

E*9*** 一类内部错误按报错信息排查无果的话,收集日志联系技术支持。各家族的 Symptom/Solution 结构说明都在官方 troubleshooting 手册里。

日志去哪看

  • 转换失败第一反应:加--log=debug重跑;
  • 日志格式形如[ERROR] GE(30741,atc.bin):2021-12-09-16:10:22.539 [error_manager.cc:263]...——方括号里的模块名就是定位思路:GE 开头查图编译/参数,FE 查算子融合,TEFUSION 查融合算子编译,TBE 查算子编译;
  • 落盘路径:$HOME/ascend/log/debug/plog/plog-<pid>-*.log(调试日志)、$HOME/ascend/log/run/plog/(运行日志);
  • 进阶:--op_debug_level=1生成 kernel 编译中间文件用于定位 AICore Error(会影响性能,仅排错时开);
  • 看图结构:export DUMP_GE_GRAPH=1各阶段图描述生成ge_onnx*.pbtxt,可以用 Netron 直接打开——肉眼看融合/拆分后的图,排 shape 问题神器。

版本与兼容(最容易忽略的坑)

  1. 升级顺序不能乱:固件 → 驱动 → CANN,顺序不可颠倒;升驱动后必须重启。查版本:cat /usr/local/Ascend/ascend-toolkit/latest/version.cfg、npu-smi info -v。
  2. OM 与 CANN 版本绑定:官方规则是运行环境 CANN 版本不低于转换环境即可——低版本 CANN 转出的 OM 可在高版本 CANN 上运行,兼容 4 个版本周期;社区经验进一步补充:同一大版本内小升级一般兼容,跨大版本不兼容。最稳的做法永远是在目标部署环境用当地 CANN 重转一次。
  3. OM 不跨芯片:910B 转的 OM 不能拿到 910A 上用;芯片型号 + CANN 版本共同决定模型支持范围。
  4. 两个特例场景要求更严:动态 shape 算子场景和昇腾虚拟化实例(vNPU)场景,转换环境的 CANN 版本必须与运行环境相同。

新手好习惯清单

  • 转换前 Netron 核对输入输出名/维度/dtype,转后atc --mode=1自检;
  • 固定输入跑通前向、对完精度(余弦相似度等)再上真实业务;msame、ais_bench 等工具可做 OM 精度/性能对比;
  • 模型与输出路径用纯英文、不含空格——这是经验习惯(官方未将其列为通用约束),但能少一类诡异问题;
  • 大网转换前评估内存,必要时分段转换。

七、写在最后

ATC 是昇腾部署链路的第一道门:一条命令背后,是"解析 → 图准备 → 图优化 → 分区 → 构建 → 序列化"的完整编译流水线,把框架模型变成针对目标芯片深度定制的自包含 OM。入门阶段记住三件事就够了——soc_version 填运行环境的芯片、shape 策略想清楚再转、报错先看模块名和日志。

想动手走一遍完整链路的话,CANN 官方 learning-hub 有现成实验:在 910B3 上训练导出 ONNX,再到香橙派(310B)上用 ATC 编译为 OM 并用推理接口执行——从训练板到边缘板,正好把本文所有知识点串起来。

本文涉及的 API 语义、参数默认值、报错样例与兼容规则,均经昇腾知识图谱(ascend.wiki)的官方文档节点核实,主要来源包括:GE 仓atc_tools/overview/atc_overview.md、atc_tools/CLI_options/系列参数文档、GE 编译器设计文档compiler.md、so_in_om.md、常量折叠与融合模式设计文档、AIPP 配置示例、官方 troubleshooting 错误码手册及 cann-recipes 实战样例。接入昇腾知识图谱 https://gitcode.com/agent0/kg-tools

返回列表