SuperAPI AI Directory

atc-model-converter

Office & productivity

View repository

Updated 10-15 17:19

About this skill

ATC Model Converter

A complete PT -> ONNX -> OM model conversion and end-to-end inference adaptation toolchain on Huawei Ascend NPU. Supports any standard PyTorch or ONNX model.

Supported CANN versions: 8.1.RC1, 8.3.RC1, 8.5.0+

⚠️ Environment Compatibility Warning: Python must be ≤ 3.10(3.10 recommended), NumPy must be < 2.0,ONNX opset 11 recommended. Violating these three rules is the most common cause of conversion failures. See FAQ.md。


Before You Start: Information the User Must Provide

Before executing any Workflow of this Skill, the Agent must first collect the following information from the user. If any item is missing, the Agent should proactively ask the user rather than guessing or skipping it.

Required Information Description Example
Model weight path .pt / .pth / .onnx local path or download address of the file /home/user/models/yolo26n.pt
Code repository address Git repository URL or local path of the project to which the model belongs https://github.com/ultralytics/ultralytics
Optional Information Description Default Behavior
Target task type Classification/Detection/Segmentation/Pose/OBB, etc. The Agent automatically identifies it from the code repository
Target input size Input resolution during model inference The Agent automatically discovers it through Workflow 1
Test images/data Sample inputs used to verify end-to-end inference The Agent uses random data or finds them from the repository

Standard opening template after the Agent collects the information:

收到以下信息:
- 模型权重:<path>
- 代码仓库:<url_or_path>
- 任务类型:<type_or_待确认>

我将按以下流程执行:
1. 分析代码仓库,发现模型参数 (Workflow 1)
2. 导出 ONNX (Workflow 2)
3. ATC 转换为 OM (Workflow 3)
4. 端到端推理适配 (Workflow 4)
5. 精度与推理验证 (Workflow 5)
6. 生成可复现 README (Workflow 6)

Workflow 1: Source Code Analysis & Parameter Discovery

Anti-Hardcoding Rule: When executing this Skill, the Agentis absolutely forbiddento guess or use any "common default values" (such as 640x640, 224x224, batch_size=1) as conversion parameters. All input_shape、input_names、opset_version and other key parametersmust be supported by evidence at the user's project code level. If they cannot be confirmed from the code, the user must be explicitly asked rather than silently filling in default values.

Phase 1: Static Analysis

After receiving the user's project path, the Agent should search for code clues in the following priority order and extract input_shape and preprocessing parameters:

1.1 Search the Preprocessing Pipeline

Search the project code for the following patterns and extract the target resolution:

# 搜索关键词(按优先级排列)
cv2.resize(img, (W, H))                     # OpenCV resize -> 提取 (W, H)
transforms.Resize((H, W))                   # torchvision -> 提取 (H, W),注意 HW 顺序
transforms.CenterCrop(size)                  # torchvision -> 提取 crop size
Image.resize((W, H))                         # PIL -> 提取 (W, H)
F.interpolate(x, size=(H, W))               # torch functional -> 提取 (H, W)
albumentations.Resize(height=H, width=W)     # albumentations -> 提取 H, W
# Agent 应执行的搜索命令示例
grep -rn "cv2.resize\|transforms.Resize\|Image.resize\|F.interpolate\|\.resize(" /path/to/project --include="*.py"
grep -rn "img_size\|image_size\|input_size\|imgsz\|resolution" /path/to/project --include="*.py" --include="*.yaml" --include="*.json"

1.2 Search Configuration Entry Points

Find CLI parameter definitions and shape information in configuration files:

# argparse 定义中的线索
parser.add_argument('--img-size', type=int, default=640)      # -> input H/W = 640
parser.add_argument('--batch-size', type=int, default=1)      # -> batch dimension
parser.add_argument('--input-size', nargs=2, default=[224,224]) # -> H, W

# 配置文件中的线索 (.yaml / .json / .cfg)
input_size: [3, 224, 224]    # -> C, H, W
image_shape: [640, 640]      # -> H, W
# Agent 应执行的搜索命令示例
grep -rn "add_argument.*size\|add_argument.*shape\|add_argument.*resolution\|add_argument.*dim" /path/to/project --include="*.py"
find /path/to/project -name "*.yaml" -o -name "*.yml" -o -name "*.json" -o -name "*.cfg" | head -20

1.3 Search the Model Forward Pass

Find the existing dummy_input or forward function signature in the code:

# 已有的导出代码
dummy_input = torch.randn(1, 3, 224, 224)   # -> 直接提取 shape
torch.onnx.export(model, dummy, ...)         # -> 查看 dummy 的定义

# forward 函数的类型注解或 docstring
def forward(self, x: Tensor) -> Tensor:
    """Args: x: (B, 3, H, W) input tensor"""  # -> 提取 channel=3

# 数据加载器中的线索
DataLoader(dataset, batch_size=8)            # -> batch dimension
# Agent 应执行的搜索命令示例
grep -rn "dummy_input\|dummy\|torch.randn\|torch.zeros\|torch.ones" /path/to/project --include="*.py"
grep -rn "def forward" /path/to/project --include="*.py"

1.4 Evidence Summary Template

After completing the static analysis, the Agent must output the evidence chain in the following format:

=== Parameter Discovery Report ===

input_shape: [1, 3, 640, 640]
  Evidence: found in config.yaml line 12: "input_size: [3, 640, 640]"
  Evidence: confirmed by transforms.py line 45: "transforms.Resize((640, 640))"

input_names: ["images"]
  Evidence: found in export.py line 30: 'input_names=["images"]'

opset_version: 11
  Evidence: found in export.py line 31: "opset_version=11"
  CANN compatibility: OK (CANN 8.3.RC1 supports opset 11)

Confidence: HIGH (multiple consistent sources)

Phase 2: Dynamic Probing

If and only ifstatic analysis cannot determine input_shape (e.g., logic is too deeply nested, shape is computed dynamically), the Agent should write and run a temporary probe script to capture real runtime tensor information.

Option A: Dataset Probe — Obtain the real input shape from the DataLoader

#!/usr/bin/env python3
"""Probe: Extract input tensor shape from the project's data pipeline."""
import sys
sys.path.insert(0, '/path/to/project')

# Import the project's dataset/dataloader
# (Agent 需要根据实际项目代码调整以下 import)
from dataset import create_dataloader  # 或其他数据加载入口

loader = create_dataloader(split='val', batch_size=1)
batch = next(iter(loader))

# Handle common batch formats
if isinstance(batch, (list, tuple)):
    tensor = batch[0]
elif isinstance(batch, dict):
    # Common keys: 'image', 'img', 'input', 'pixel_values'
    for key in ['image', 'img', 'input', 'pixel_values', 'x']:
        if key in batch:
            tensor = batch[key]
            break
else:
    tensor = batch

print(f"PROBE_RESULT: input_shape={list(tensor.shape)}, dtype={tensor.dtype}")

Option B: Model tracing probe — capture inputs via forward hook

#!/usr/bin/env python3
"""Probe: Capture model input shape via forward hook."""
import torch
import sys
sys.path.insert(0, '/path/to/project')

# Load model (Agent 需要根据实际项目代码调整)
model = torch.load('model.pt', map_location='cpu')
model.eval()

# Register hook on the first layer to capture input
captured = {}
def hook_fn(module, input, output):
    captured['input_shape'] = list(input[0].shape)
    captured['input_dtype'] = str(input[0].dtype)

first_layer = list(model.children())[0]
first_layer.register_forward_hook(hook_fn)

# Try common input shapes to see which one doesn't crash
for shape in [(1,3,224,224), (1,3,256,256), (1,3,384,384), (1,3,512,512), (1,3,640,640)]:
    try:
        with torch.no_grad():
            model(torch.randn(*shape))
        print(f"PROBE_RESULT: shape {shape} -> SUCCESS, captured={captured}")
        break
    except Exception as e:
        print(f"PROBE_RESULT: shape {shape} -> FAILED ({e})")

Option C: ONNX model self-inspection — if an ONNX file already exists

# 直接从已有 ONNX 模型提取全部 I/O 信息
python3 scripts/get_onnx_info.py model.onnx

Probe safety rules:

  • The probe script must be read-only and must not modify any files in the user's project
  • After the probe finishes executing, the Agent should report the findings to the user and request confirmation
  • If the probe also cannot determine the shape, the Agent must explicitly ask the user, rather than guessing

Phase 3: Post-processing Identification

The Agent should identify the post-processing type in the user's project to prepare for the subsequent Workflow 4 (End-to-End Inference Adaptation).

# 搜索后处理关键词
grep -rn "nms\|non_max_suppression\|softmax\|argmax\|sigmoid\|postprocess\|decode" /path/to/project --include="*.py"
Task type Typical post-processing Search keywords
Classification softmax/argmax -> label softmax, argmax, topk, class_names
Detection decode + NMS -> boxes nms, non_max_suppression, bbox, anchor
Segmentation argmax/threshold -> mask argmax, threshold, mask, palette
Pose decode -> keypoints keypoint, heatmap, joint, skeleton
Generation denormalize -> image denormalize, clamp, to_pil, save_image

Note: This phase only performs identification and recording; the actual inference script generation is completed in Workflow 4 .


Workflow 2: PyTorch → ONNX Export

Use export_onnx.py to export any standard PyTorch model to ONNX format.

Basic usage

# 导出 PyTorch 模型 (.pt / .pth)
python3 scripts/export_onnx.py \
    --pt_model model.pt \
    --output model.onnx \
    --input_shape 1,3,224,224

# 指定 opset 版本(默认 11,CANN 兼容性最佳)
python3 scripts/export_onnx.py \
    --pt_model model.pt \
    --output model.onnx \
    --input_shape 1,3,224,224 \
    --opset 13

Dynamic dimension export

# 动态 batch size
python3 scripts/export_onnx.py \
    --pt_model model.pt \
    --output model.onnx \
    --input_shape 1,3,224,224 \
    --dynamic_axes '{"input": {"0": "batch"}, "output": {"0": "batch"}}'

Exporting Torchvision pretrained models

python3 scripts/export_onnx.py \
    --torchvision resnet50 \
    --output resnet50.onnx \
    --input_shape 1,3,224,224

Framework-specific export

For models of specific frameworks, prefer the export method provided by the framework itself:

# HuggingFace Transformers example
from transformers import AutoModel
import torch
model = AutoModel.from_pretrained("bert-base-uncased")
model.eval()
dummy = torch.randint(0, 1000, (1, 128))
torch.onnx.export(model, dummy, "bert.onnx", opset_version=13,
                   input_names=["input_ids"], output_names=["output"])

Run python3 scripts/export_onnx.py --help to view the full parameter list. Supported formats: complete model (torch.save), TorchScript, checkpoint dict containing the "model" key. A pure state dict is not supported(requires a model architecture definition).


Workflow 3: ONNX Inspection & ATC Conversion

Step 1: Inspect the ONNX model

# 查看模型输入输出信息,获取推荐的 ATC 命令
python3 scripts/get_onnx_info.py model.onnx

Step 2: Environment configuration

# 自动检测 CANN 版本并配置环境
./scripts/setup_env.sh

# 验证环境
./scripts/check_env_enhanced.sh

For manual configuration and multi-version coexistence, refer to CANN_VERSIONS.md。

Step 3: Confirm the SoC version

The --soc_version in ATC conversion must exactly match the target device!

# 查询设备的 SoC 版本
npu-smi info | grep Name
# 输出: Name: 910B3  -> 使用: --soc_version=Ascend910B3
# 输出: Name: 310P3  -> 使用: --soc_version=Ascend310P3
Device SoC Version Query method
Atlas 910B3 Ascend910B3 npu-smi info | grep Name
Atlas 310P Ascend310P1/P3 npu-smi info | grep Name
Atlas 200I DK A2 Ascend310B4 npu-smi info | grep Name

Common errors:

[ACL ERROR] EE1001: supported socVersion=Ascend910B3,
but the model socVersion=Ascend910B

Fix: Use npu-smi info the exact SoC version output by , do not use abbreviations.

Step 4: ATC conversion

# 基本转换(ONNX 中为静态 shape 时可自动推断)
atc --model=model.onnx --framework=5 --output=model_om \
    --soc_version=Ascend910B3

# 显式指定 input shape
atc --model=model.onnx --framework=5 --output=model_om \
    --soc_version=Ascend910B3 \
    --input_shape="input:1,3,224,224"

# 使用 FP16 精度以提升性能
atc --model=model.onnx --framework=5 --output=model_om \
    --soc_version=Ascend910B3 \
    --input_shape="input:1,3,224,224" \
    --precision_mode=force_fp16

# 动态 batch size
atc --model=model.onnx --framework=5 --output=model_om \
    --soc_version=Ascend910B3 \
    --input_shape="input:-1,3,224,224" \
    --dynamic_batch_size="1,2,4,8"

Accelerated conversion:

export TE_PARALLEL_COMPILER=16  # 并行编译

For the complete ATC parameter reference, see PARAMETERS.md. For AIPP configuration, see AIPP_CONFIG.md。


Workflow 4: End-to-End Inference Adaptation

Objective: Based on the user-provided code repository, generate a complete end-to-end NPU inference script. This script reuses the original repository's preprocessing and post-processing logic, and only replaces the model inference part with the OM model. What the end user gets is ascript that can directly take raw data (images/text/audio) as input and output business results, rather than one that only outputs raw tensors infer_om.py。

Prerequisites

  • Workflow 1 is complete (parameters have been discovered)
  • Workflows 2-3 are complete (the OM model has been generated)
  • The user's code repository has been cloned locally

Step 1: Analyze the original inference pipeline

The Agent needs to find the complete inference entry point from the user repository and understand its three-stage structure:

# 搜索推理入口文件
grep -rn "def predict\|def infer\|def forward\|def __call__\|def run\b" /path/to/repo --include="*.py"
grep -rn "if __name__\|argparse\|click\|typer" /path/to/repo --include="*.py" | grep -i "infer\|predict\|detect\|demo\|test"

The Agent should identify the following three stages and record their code locations:

Stage What to identify Search keywords
Preprocessing Input data → model input tensor preprocess, transform, resize, normalize, letterbox, pad
Model inference Tensor → raw output tensor model(, forward(, session.run, torch.no_grad
Postprocessing Raw output → business result postprocess, nms, decode, softmax, argmax, draw, visualize

Output requirements: The Agent must generate an inference pipeline analysis report:

=== Inference Pipeline Analysis ===

入口文件: ultralytics/engine/predictor.py
预处理: ultralytics/data/augment.py :: LetterBox (line 420)
  - resize to imgsz with letterbox padding
  - BGR→RGB, HWC→CHW, /255.0 normalize
模型推理: ultralytics/nn/autobackend.py :: AutoBackend.forward() (line 180)
  - input: (1, 3, 640, 640) float32
  - output: (1, 84, 8400) float32
后处理: ultralytics/utils/ops.py :: non_max_suppression (line 200)
  - transpose if shape[1] < shape[2]
  - conf threshold + NMS
  - scale boxes back to original image size

Step 2: Build an end-to-end inference script

Based on the analysis results, the Agent generates a e2e_infer_om.py script, following these principles:

Core principle: maximize reuse, minimize rewriting

#!/usr/bin/env python3
"""End-to-end OM inference script — reuses <repo_name> pre/post-processing."""
import sys
import numpy as np
from ais_bench.infer.interface import InferSession

# ===== 复用原始仓库的预处理/后处理 =====
# Agent 应优先 import 用户仓库中的函数
# 仅当原始代码与 GPU/特定框架强耦合时,才改写为 NumPy 版本
sys.path.insert(0, '/path/to/repo')
# from <repo>.preprocess import preprocess_fn   # 优先复用
# from <repo>.postprocess import postprocess_fn  # 优先复用

def main():
    # 1. 加载输入数据(使用原始仓库的方式)
    # img = load_image(input_path)

    # 2. 预处理(复用原始仓库逻辑)
    # input_tensor = preprocess_fn(img)

    # 3. OM 推理(替换原始模型推理)
    session = InferSession(device_id=0, model_path="model.om")
    outputs = session.infer([input_tensor], mode='static')

    # 4. 后处理(复用原始仓库逻辑)
    # results = postprocess_fn(outputs, original_shape=img.shape)

    # 5. 输出业务结果
    # visualize(img, results, save_path="result.jpg")

if __name__ == "__main__":
    main()

Decision tree for the Agent when generating the script:

原始仓库的预处理/后处理函数能否直接 import?
├── YES → 直接 import 并调用(首选)
├── 需要少量修改(如 GPU→CPU)→ 复制函数并修改 tensor → numpy
└── 与框架深度耦合 → 基于原始逻辑用 numpy/opencv 重写,保留注释标注来源

Step 3: Verify the end-to-end result

The Agent must verify that the output of the end-to-end inference script is consistent with the output of the original inference pipeline:

# 1. 使用原始仓库运行推理,保存结果
python3 original_infer.py --input test.jpg --save-result original_result.json

# 2. 使用 e2e_infer_om.py 运行推理,保存结果
python3 e2e_infer_om.py --input test.jpg --save-result om_result.json

# 3. 对比业务结果(不是张量对比,是最终输出对比)
# 检测任务:对比 bounding box 坐标、类别、置信度
# 分类任务:对比 top-K 类别和概率
# 分割任务:对比 mask IoU

Verification pass criteria:

Task type Verification metric Pass threshold
Detection Box coordinate difference / class consistency / detection count consistency Coordinate difference < 1px, class 100% consistent
Classification Top-1 consistency / probability difference Top-1 consistent, probability difference < 0.01
Segmentation mask IoU > 0.99
Pose Keypoint coordinate difference < 2px

Step 4: Performance benchmark

# 端到端延迟(含预处理+推理+后处理)
python3 e2e_infer_om.py --input test.jpg --benchmark --warmup 5 --loops 100

The Agent should report:

=== End-to-End Performance ===
Preprocess:  X.XX ms
OM Inference: X.XX ms
Postprocess: X.XX ms
Total E2E:   X.XX ms (X.X FPS)

Workflow 5: Accuracy and inference verification

This Workflow includes two verification levels: raw tensor-level accuracy comparison (ONNX vs OM) and OM model inference smoke test.

5.1 OM inference smoke test

After conversion is complete, use infer_om.py together with ais_bench to quickly verify that the OM model can perform inference normally:

# 仅打印模型信息
python3 scripts/infer_om.py --model model.om --info

# 使用随机输入推理(shape 从模型元数据获取)
python3 scripts/infer_om.py --model model.om

# 使用实际输入数据推理
python3 scripts/infer_om.py --model model.om --input test.npy --output result.npy

# 性能基准测试(预热 + 多次迭代)
python3 scripts/infer_om.py --model model.om --warmup 5 --loop 100

Python API (quick reference):

from ais_bench.infer.interface import InferSession
import numpy as np

session = InferSession(device_id=0, model_path="model.om")
input_data = np.random.randn(*session.get_inputs()[0].shape).astype(np.float32)
outputs = session.infer([input_data], mode='static')
for i, out in enumerate(outputs):
    print(f"Output[{i}]: shape={out.shape}, dtype={out.dtype}")
session.free_resource()

For detailed ais_bench API usage and parameter descriptions, see INFERENCE.md。

5.2 ONNX vs OM accuracy comparison

Verify conversion accuracy by comparing the inference outputs of ONNX (CPU) and OM (NPU):

# 使用默认容差对比
python3 scripts/compare_precision.py \
    --onnx model.onnx --om model.om --input test.npy

# 自定义容差
python3 scripts/compare_precision.py \
    --onnx model.onnx --om model.om --input test.npy \
    --atol 1e-3 --rtol 1e-2

# 保存对比报告为 JSON
python3 scripts/compare_precision.py \
    --onnx model.onnx --om model.om --input test.npy \
    --output precision_report.json

# 保存差异数组用于分析
python3 scripts/compare_precision.py \
    --onnx model.onnx --om model.om --input test.npy \
    --save-diff diff_output/

Metric descriptions:

Metric Description Good value
cosine_similarity 1.0 = completely consistent > 0.99
max_abs_diff Maximum absolute error < 1e-3 (FP32)
mean_abs_diff Mean absolute error < 1e-5 (FP32)
outlier_ratio Proportion of elements exceeding tolerance < 1%
is_close Pass/fail determination based on atol/rtol True

Result interpretation:

  • cosine_sim > 0.999, outlier_ratio < 0.1%: Excellent conversion quality
  • cosine_sim > 0.99, outlier_ratio < 1%: Good, suitable for most scenarios
  • cosine_sim < 0.99: Needs investigation—try using --precision_mode=force_fp32

Note: For end2end models (such as YOLOv10 output (1,300,6)), raw tensor comparison may show lower cosine_similarity, because the values of low-confidence placeholder slots differ between CPU and NPU. In this case, the business result comparison in Workflow 4 Step 3 should be used as the standard.


Workflow 6: Generate an end-to-end reproducible README

After completing all steps in Workflow 1–5, the Agent must generate a README document that users can directly follow to reproduce. This is the last step of Skill execution and cannot be skipped.

The generated README is intended forusers who did not participate in the current session, who only need to follow the document from beginning to end to reproduce the entire model conversion and inference workflow.

Required sections

Environment information → Model introduction → Quick Start → Detailed steps (environment preparation, obtaining the model, exporting ONNX, ATC conversion, end-to-end inference) → Key challenges and solutions → File structure → Known limitations

Documentation quality requirements

Requirement Description
Copy-pasteable All commands must be complete and directly executable, with no ... omissions or <placeholder>
Has expected output Key steps must be accompanied by expected output examples
Record pitfalls Every error and workaround must be written into the "Key Challenges" section
Pin versions All pip install must include version numbers
Self-contained README + scripts/config files in the same directory = fully reproducible

For the complete README template and examples, see:references/EXAMPLE_README.md


Common troubleshooting

See FAQ.mdfor the complete troubleshooting decision tree covering common issues such as Python versions, NumPy compatibility, opset versions, and missing operators.


Resource index

scripts/

Export & conversion:

  • export_onnx.py - General-purpose PyTorch → ONNX export tool
  • get_onnx_info.py - View ONNX model input/output information
  • setup_env.sh - Automatically configure the CANN environment
  • check_env_enhanced.sh - Comprehensive environment compatibility check

Inference & testing:

  • infer_om.py - General-purpose OM model inference (based on ais_bench)
  • compare_precision.py - ONNX vs OM accuracy comparison

references/