跳到主要内容

ONNX 教程

欢迎学习 ONNX (Open Neural Network Exchange)!本教程将带你系统掌握 ONNX 的核心概念、模型导出、推理部署以及性能优化的完整流程。

什么是 ONNX?

ONNX(开放神经网络交换)是一种开放的模型表示格式,由微软、亚马逊、Meta(原 Facebook)等公司于 2017 年联合推出并开源。它的核心目标是解决深度学习领域长期存在的"框架锁定"问题——在不同训练框架和推理引擎之间建立一座标准化的桥梁。

深度学习的发展催生了众多优秀的框架:PyTorch 以其动态图和易用性在研究领域占据主导地位,TensorFlow 则在生产部署方面积累了大量用户。然而,用 PyTorch 训练的模型想要部署到 TensorRT 上加速,或者 TensorFlow 模型想要在 ONNX Runtime 中运行,都需要额外的转换工作。ONNX 正是为了解决这个问题而生。

ONNX 定义了一套标准化的算子集合和数据格式,任何支持 ONNX 的框架都可以读取和执行模型,无需关心模型最初是在哪里训练的。这就像是深度学习领域的"通用语言"。

ONNX 的核心优势

特性说明
框架互操作性在 PyTorch 中训练,在 TensorFlow 中推理,或使用 TensorRT 加速,一次导出,处处可用
硬件广泛支持NVIDIA TensorRT、Intel OpenVINO、AMD ROCm、华为昇腾等主流硬件平台均原生支持 ONNX
版本兼容性通过 Opset 机制保证模型的前向兼容性,旧版本模型在新版本推理引擎中仍可运行
易于优化标准化的图结构使得模型优化工具(如 onnx-simplifier、ONNX GraphSurgeon)能够高效工作
生产级稳定性ONNX Runtime 作为微软官方维护的推理引擎,已被 Windows、Azure 等产品大规模验证

ONNX 模型文件结构

一个 .onnx 文件本质上是一个 Protocol Buffers 序列化文件,包含以下核心组件:

  • ModelProto:模型的根节点,包含版本信息、生产者信息等元数据
  • GraphProto:定义计算图的结构,包括节点、边、输入输出
  • NodeProto:每个计算节点,包含算子类型、输入输出名称、属性等
  • TensorProto:存储模型的权重参数
  • OpsetImport:声明模型使用的算子集版本

ONNX 生态概览

训练框架支持

框架导出方式支持程度
PyTorchtorch.onnx.export()官方支持,最完善
TensorFlow/Kerastf2onnx社区维护,覆盖广泛
Scikit-learnsklearn-onnx传统机器学习模型支持
MXNetmxnet.contrib.onnx官方支持
JAXjax2onnx实验性支持

推理引擎选择

引擎特点适用场景
ONNX Runtime跨平台、易用、官方维护通用推理、快速部署
TensorRTNVIDIA GPU 专属、极致性能实时推理、大模型部署
OpenVINOIntel 硬件优化Intel CPU/GPU 部署
Triton Inference Server多模型服务、动态批处理生产环境、微服务架构

为什么学习 ONNX?

解决生产环境的核心痛点

在实际的 AI 工程中,训练和推理往往使用不同的工具链:

  • 训练阶段:选择 PyTorch,因为它提供了灵活的调试能力和活跃的学术社区支持
  • 推理阶段:选择 C++、TensorRT 或 ONNX Runtime,因为它们提供了更高的性能和更低的资源占用

这两个阶段之间存在巨大的鸿沟。如果没有 ONNX,你需要:

  1. 在 PyTorch 中训练模型
  2. 手动将模型权重导出为某种中间格式
  3. 在推理端重新构建模型结构
  4. 加载权重并验证结果一致性

这个过程不仅繁琐,而且容易出错。ONNX 的出现让这个过程变得简单可靠。

实际应用案例

案例一:模型服务化部署

某电商平台的商品识别模型最初在 PyTorch 中开发和训练。上线时,团队选择将模型导出为 ONNX 格式,部署在 ONNX Runtime 上。这样做的好处是:

  • 推理服务不需要安装 PyTorch,体积从 2GB 缩减到 200MB
  • Python 推理延迟从 50ms 降低到 15ms
  • 可以轻松切换到 TensorRT 获得更快的速度

案例二:多硬件平台适配

某自动驾驶公司需要将同一个感知模型部署到多种硬件:车载 NVIDIA Orin、边缘计算盒子、云端服务器。通过 ONNX 作为中间格式,他们只需要维护一个 .onnx 文件,各硬件平台上的推理引擎都能直接加载运行。

案例三:模型优化流水线

在模型上线前,通常会经历这样的流程:

每一步都有成熟的工具支持,形成标准化的工业流程。

核心概念:Opset 版本

ONNX 的算子集(Operator Set,简称 Opset)是理解 ONNX 的关键概念。每个 Opset 版本定义了一组标准算子及其行为规范。

Opset 版本演进

Opset发布时间主要更新
112019基础算子完善,广泛兼容
122019NonMaxSuppression 改进
132020更好的类型支持
142020CumSum、Trilu 等新算子
152021ScatterND、GatherND 增强
172022LayerNormalization 等新算子
18-212023-2024持续扩展新算子

如何选择 Opset 版本

选择 Opset 版本时需要考虑两个因素:

  1. 推理引擎的兼容性:目标推理引擎支持的 Opset 最高版本是多少?TensorRT 8.x 支持 Opset 17,而 ONNX Runtime 1.15 支持到 Opset 20。

  2. 模型算子需求:你的模型是否使用了某个 Opset 才引入的新算子?例如,如果模型使用了 LayerNormalization 算子,需要至少 Opset 17。

# 导出时指定 Opset 版本
torch.onnx.export(
model,
dummy_input,
"model.onnx",
opset_version=17 # 根据目标平台选择
)

实际建议是:在满足功能需求的前提下,选择较低的 Opset 版本以获得更广泛的兼容性。对于大多数视觉模型,Opset 14-17 是安全的选择。

环境安装

安装核心库

# 安装 ONNX 核心库和 ONNX Runtime
pip install onnx onnxruntime

# 安装模型简化工具
pip install onnx-simplifier

# 如果需要 GPU 推理
pip install onnxruntime-gpu

验证安装

import onnx
import onnxruntime as ort

# 检查版本
print(f"ONNX 版本: {onnx.__version__}")
print(f"ONNX Runtime 版本: {ort.__version__}")

# 检查可用的执行提供者(Execution Providers)
print(f"可用的执行提供者: {ort.get_available_providers()}")
# 输出示例: ['CPUExecutionProvider', 'CUDAExecutionProvider']

# 检查当前设备
print(f"当前推理设备: {ort.get_device()}")

常见安装问题

问题一:onnx 和 onnxruntime 版本不兼容

ONNX 和 ONNX Runtime 有版本依赖关系。如果遇到 onnx.onnx_cpp2py_export.checker.ValidationError 等错误,可能是版本不匹配。建议安装兼容版本:

# 推荐的版本组合
pip install onnx==1.15.0 onnxruntime==1.16.3

问题二:GPU 版本无法识别 CUDA

安装 onnxruntime-gpu 后仍然无法使用 GPU,可能是因为 CUDA 版本不匹配。ONNX Runtime GPU 版本对 CUDA 有特定要求:

ONNX Runtime GPUCUDAcuDNN
1.16.x11.8 / 12.x8.x
1.15.x11.88.x

检查 CUDA 是否正确安装:

import onnxruntime as ort

# 检查 CUDA 执行提供者是否可用
if 'CUDAExecutionProvider' in ort.get_available_providers():
print("GPU 推理可用")
else:
print("GPU 推理不可用,请检查 CUDA 安装")

教程目录

本教程按照实际工作流程组织,从模型导出到部署优化:

核心操作

  • PyTorch 导出 ONNX - 详解 torch.onnx.export 的每个参数,处理动态维度和复杂模型
  • TensorFlow 导出 ONNX - 使用 tf2onnx 转换 TensorFlow/Keras 模型
  • Python 推理 - ONNX Runtime Python API 完整指南,包括 IOBinding 和异步推理
  • C++ 部署 - 工业级 C++ 推理代码,涵盖内存管理和多线程

进阶主题

参考资料

学习建议

ONNX 看起来简单——不就是导出一个文件吗?但要在生产环境中用好它,需要理解很多细节:

  1. 先跑通基础流程:用最简单的模型完成导出-验证-推理的完整流程
  2. 理解 Opset 机制:这是解决兼容性问题的关键
  3. 掌握调试技巧:模型输出不一致时,知道如何定位问题
  4. 熟悉优化工具:onnx-simplifier、量化工具是性能调优的利器

接下来的章节将逐一展开这些主题。让我们从 PyTorch 模型导出开始。