图简化解决什么问题
跳转到“图简化解决什么问题”模型导出后,图中可能留有常量计算、多余的形状变换或可化简的运算。ONNX Simplifier 尝试改写这些结构,使图更简单,便于运行时优化。节点数下降不直接等于延迟下降;目标后端可能已经做了相同优化,也可能对某种改写不够友好。
简化应保持目标输入范围内的输出语义。它不等于量化,也不负责自动补齐 TensorRT 不支持的任意算子。项目说明
保留输入文件,另存简化结果
跳转到“保留输入文件,另存简化结果”先按 ONNX 基础 生成 affine.onnx,然后执行:
from pathlib import Pathimport numpy as npimport onnximport onnxruntime as ortfrom onnxsim import simplify
source = Path("affine.onnx")target = Path("affine.simplified.onnx")if source.resolve() == target.resolve(): raise ValueError("keep the original model in a separate file")
original = onnx.load(source)onnx.checker.check_model(original, full_check=True)simplified, check_ok = simplify( original, check_n=3, test_input_shapes={"x": [2, 3]})if not check_ok: raise RuntimeError("simplifier comparison failed")onnx.checker.check_model(simplified, full_check=True)onnx.save(simplified, target)
before = ort.InferenceSession(str(source), providers=["CPUExecutionProvider"])after = ort.InferenceSession(str(target), providers=["CPUExecutionProvider"])assert [item.name for item in before.get_outputs()] == [ item.name for item in after.get_outputs()]assert after.get_inputs()[0].shape == ["N", 3]rng = np.random.default_rng(53)for batch in (1, 2, 8): x = rng.normal(size=(batch, 3)).astype(np.float32) expected = before.run(None, {"x": x}) actual = after.run(None, {"x": x}) for left, right in zip(expected, actual): np.testing.assert_allclose(right, left, rtol=1e-6, atol=1e-6)print("nodes:", len(original.graph.node), "->", len(simplified.graph.node))print("dynamic batches 1, 2, 8 passed")check_n=3 要求工具进行三次测试;test_input_shapes 给动态输入指定测试时使用的尺寸。它与把模型输入永久固定为某个尺寸的选项含义不同。本例随后独立检查 1、2、8 三种批量,并确认符号维仍在。
这个 Mul → Add 小图已经简洁,节点数可能保持为 2。不能为了追求“优化比例”而把没有变化误判为失败。
命令行写法
跳转到“命令行写法”在普通终端中使用下面的形式,具体选项以当前安装版本的帮助为准:
python -m onnxsim --helppython -m onnxsim affine.onnx affine.simplified.onnx原 ES6D 项目的文件名也可沿用这个分离输入输出的原则:
python -m onnxsim models/es6d/estimator_weigh.onnx models/es6d/estimator_weigh_simplify.onnxJupyter 中的 !python ... 是笔记本的 shell escape,不能把前面的 ! 原样复制到普通 Bash 命令里。
“check 通过”的边界
跳转到““check 通过”的边界”随机样本只能验证已经覆盖的输入,不是对所有输入的等价性证明。实际发布前继续检查:
| 项目 | 要求 |
|---|---|
| 接口 | 输入输出名称、数量、dtype、形状约定保持预期 |
| 数值 | 使用真实样本和边界尺寸,对每个输出逐一比较 |
| 特殊分支 | 空目标、阈值附近、极端取值、动态尺寸等按业务覆盖 |
| 后端 | 简化后仍能被目标运行时或 TensorRT 解析 |
| 性能 | 同设备、同尺寸、同精度、同计时边界测量 |
| 追溯 | 保存原模型、简化模型、版本、命令、模型哈希与验收结果 |
若简化导致不兼容,先定位具体改写和后端约束;不要通过忽略失败断言,把问题留给线上推理。
本页 Python 示例已用 ONNX 1.23.1、ONNX Runtime 1.30.0、onnxsim 0.7.3 执行。ES6D 命令保留原项目路径含义,未提供该模型文件,因此没有声称验证过其转换结果。