AI-深度学习

海思NPU模型转换 04 导出和整理ONNX

展开合集目录
  1. 海思NPU模型转换 01 平台工具与文档地图
  2. 海思NPU模型转换 02 搭建转换环境
  3. 海思NPU模型转换 03 拿到模型后的检查
  4. 海思NPU模型转换 04 导出和整理ONNX
  5. 海思NPU模型转换 05 预处理与AIPP
  6. 海思NPU模型转换 06 校准数据与量化
  7. 海思NPU模型转换 07 执行ATC转换
  8. 海思NPU模型转换 08 输出与后处理约定
  9. 海思NPU模型转换 09 PC仿真与精度比对
  10. 海思NPU模型转换 10 板端最小推理闭环
  11. 海思NPU模型转换 11 转换失败与性能排查
  12. 海思NPU模型转换 12 项目案例与交付清单
  13. 海思NPU模型转换 A 附录A文档检索表
  14. 海思NPU模型转换 B 附录BATC与AIPP参数表
  15. 海思NPU模型转换 C 附录C错误现象与排查表
  16. 海思NPU模型转换 D 附录D项目目录及交付模板
海思NPU模型转换 04 导出和整理ONNX的封面

系列编排日期为 2026 年 8 月;技术基线核对与教学代码 CPU 验证日期为 2026-10-12。适用 Hi3516CV610 与本系列注明的 SDK/工具版本,实测范围见第 12 章。

返回系列目录 · 本篇属于 12 章与 4 份附录。

导出 ONNX 的目标是保存推理语义,并让目标工具链看到稳定的计算图。固定尺寸、改写算子、折叠常量和裁剪输出都是模型变更,需要有变更前后的数值对照。

导出前固定推理条件

设置模型为 evaluation 模式,关闭梯度,固定 batch、输入名称和输出名称,并保存原始框架的输出。Dropout、BatchNorm 或训练分支没有切到推理状态,会使导出基准本身不稳定。

对于多分支网络,要明确导出原始 head 还是解码后的结果。保留原始 head 通常更方便在 CPU 和板端之间逐张量比较,但会增加 CPU 后处理;后处理硬化可以减少部分 CPU 工作,却改变输出约定。两条路线都必须写清楚。

导出代码只作为模型专用入口

以下展示 PyTorch 导出的基本组织形式,model、输入分辨率及输出名必须来自实际模型定义:

model.eval()
example = torch.zeros(1, 3, 320, 320, dtype=torch.float32)
with torch.no_grad():
    reference = model(example)
    torch.onnx.export(
        model, example, "model.onnx",
        input_names=["input"],
        output_names=["output"],
        opset_version=11,
        do_constant_folding=True,
    )

这段代码采用项目旧版 PyTorch 导出思路,不能替代所有版本的模型导出脚本;多输出模型必须逐一命名。opset 11 是示例选择,依据应当是所用算子和 ATC 规格,而不是“越低越兼容”。使用新导出器时,还应记录导出器模式和是否发生回退。

静态化不能只改输入标签

把 [1,3,640,640] 改成 [1,3,320,320] 后,图中的固定 reshape、grid、anchor、位置编码和输出维度可能仍然依赖 640。可靠做法是优先从原框架以目标尺寸重新导出,再检查整图维度和实际执行。

YuNet 2023mar 的教学脚本针对已知结构固定 320 输入,同时清除旧中间 shape 注释并更新 12 个输出的维度,再执行 checker 和 ORT。这个处理仅对指定结构成立;脚本会核对输入名和输出名,不应作为通用 ONNX 改尺寸工具使用。

320 输入下 stride 8、16、32 对应的位置数为 1600、400、100。cls 和 obj 的最后一维为 1,bbox 为 4,kps 为 10。维度数量变化必须同步到后处理,不能仍遍历 640 输入的 8400 个位置。

输入缩放的等价变换

原始 YuNet 首层计算可写为:

y = W * x + b
x_new = x / 255
W_new = W * 255
y_new = W_new * x_new + b

实数运算下两者等价,浮点实现允许存在舍入误差。该变换使外部 UINT8 图像经 AIPP 除以 255 后,仍对应原图接收 0~255 FLOAT 的语义。首层 bias 保持不变。

成立条件包括:缩放位置与首层一致、所有受影响输入路径都被处理、没有额外重复归一化。存在其他输入分支、非线性预处理或输入被多个不同首层消费时,不能只修改碰到的第一个 Conv。教学脚本限定到该 YuNet 文件结构,并做所有输出的 CPU 比较。

简化与算子替换的验证

若使用简化工具,保留 export.onnx 与 simplified.onnx 两个文件及工具版本。先比较输出集合和 shape,再用真实图逐输出检查 MAE、最大绝对误差和解码结果。单次随机输入通过不代表边界尺寸、极暗图和饱和值都等价。

不支持的算子优先从导出配置和等价图变换解决。例如将能离线计算的常量移出运行时、固定可以确定的 shape,或在有证明的条件下替换成已支持表达。把不认识的节点直接删除通常会改变计算语义。

本阶段交付

保留原始权重、导出脚本、导出模型、每次改图后的模型、CPU 基准、改动说明和误差报告。文件名能描述用途即可,真正的身份由哈希确定。ATC 编译使用哪一个文件,应在命令和 manifest 中明确,避免调试的模型与实际转换的模型不是同一份。

上一篇 拿到模型后的检查 · 系列目录 · 下一篇 预处理与AIPP