概述
官网,ONNX是Open Neural Network Exchange的缩写,作为一种开放开源(GitHub,21.2K Star,4K Fork)的神经网络交换格式,能够实现不同深度学习框架间的模型转换与共享,使得基于ONNX的模型可以在多种环境下高效运行。
在LLM之前(机器学习和深度学习时代)就是非常流行的模型格式(模型通用语言),跨框架+模型的中间表示(Intermediate Representation,IR)格式。
核心特性:
- 跨框架互操作性:在PyTorch中训练的模型可以导出为ONNX格式,再被TensorFlow、MXNet等其他框架读取
- 标准化算子集:定义统一的数学运算和神经网络操作标准
- Protocol Buffers序列化:使用Google的Protobuf作为底层序列化协议,
.onnx文件包含完整的计算图结构和权重参数 - 版本化管理:通过
opset_version管理算子集的演进
支持各种不同格式的模型之间的互相转换:
- TensorFlow
- PyTorch
- TensorRT
- Keras
- CNTK
- Caffe
- TVM
- mxnet
- ncnn
定位(三大目标):
- 将模型从任何框架转换为ONNX格式;
- 将ONNX格式转换为任何其他的框架;
- 使用推理引擎运行ONNX模型,让推理更快速。
生态图


如上图,大模型推理系统三个组成部分:
- 硬件:硬件并行化,CPU、GPU、TPU底层加速原理有很大差异,但都追求最大并行化;
- 软件:模型本身不变化,优化计算图的两种方向:
- Low-level库:如英伟达提供的
cuDNN包可更好地在GPU上处理; - 图编译器:如AI编译器TVM、GLOW主要优化前向传播或后向传播。
- Low-level库:如英伟达提供的
- 算法:算法类方法会改变模型或架构来加速推理,如剪枝、量化、蒸馏、压缩。
应用场景:
- 移动端:很多手机APP后台就是通过ONNX把大模型从PyTorch转到CoreML或NNAPI;
- 医学影像:用PyTorch训练CT/MRI的病灶检测模型,ONNX+OpenVINO可把模型部署到普通CPU服务器;
- 智能家居和IoT:ONNX能把PyTorch模型转成适合ARM芯片的TensorRT引擎;
- 云端推理服务:HuggingFace、Azure、AWS都支持直接加载ONNX模型,一键部署为云端推理API。
优点
- 跨平台性强:PyTorch、TensorFlow、Scikit-learn、XGBoost甚至部分大模型都能导出到ONNX;
- 部署灵活:支持CPU、GPU、ARM、FPGA、NPU,基本覆盖主流硬件;
- 推理速度快:ONNX Runtime、TensorRT等配合下,能比原始框架提升2~5倍速度;
- 生态丰富:微软、AWS、Intel、NVIDIA等巨头都在推,社区活跃。
缺点
- 不支持所有算子:新模型里的自定义层可能需要手动写插件;
- 调试成本高:模型一旦转换失败,错误信息可能晦涩难懂;
- 大模型适配慢:像GPT-4这种超大模型,ONNX生态还在追赶;
- 版本兼容问题:不同框架或
opset可能导致兼容性问题。
趋势
- 支持大模型:正在适配Transformer、LLM的常见算子;
- 轻量化结合:支持量化、蒸馏,让大模型能跑在手机上;
- 推理引擎一体化:未来可能直接一键导出+自动优化+多硬件部署,极大降低门槛;
- 云边端协同:成为AI模型在云端与边缘之间的桥梁,打通全链路。
Converter
即ONNX Converter,转换器,用于在不同框架和ONNX之间转换的工具:
torch.onnx.export():PyTorch转ONNXtf2onnx:TensorFlow转ONNXonnx2tf:ONNX转TensorFlowonnx2pytorch:ONNX转PyTorchonnx2keras:ONNX转Keras
格式
ONNX使用Protocol Buffers格式存储模型,直接利用Protobuf的IR(onnx.proto)和编译器能力(protoc),将模型的计算图结构序列化为二进制文件。
可直接使用Protobuf将ONNX模型转换为可读的文本:
bash
wget https://github.com/onnx/onnx/raw/main/onnx/onnx.proto
wget https://github.com/onnx/models/blob/main/validated/vision/classification/mnist/model/mnist-8.onnx
protoc --decode=onnx.ModelProto --proto_path=E:/ipynb onnx.proto < ./mnist-8.onnx > ./mnist.onnx.txt
得到mnist.onnx.txt文件,主要由三部分组成:
- 可扩展的计算图模型的定义
- 标准数据类型定义
- 内部算子定义
onnx.proto 文件定义Model、Graph、Node、Tensor等核心数据结构,是理解和操作ONNX文件的底层基础。
ModelProto
├── ir_version: 版本号
├── opset_import: 算子集版本
├── GraphProto
│ ├── node[]: 计算节点列表
│ ├── initializer[]: 权重张量
│ ├── input[]: 输入定义
│ └── output[]: 输出定义
└── metadata_props: 元数据
量化
ONNX支持多种量化方式,将模型从FP32压缩为INT8/FP16,减少模型体积并提升推理速度:
- 动态量化:推理时动态计算量化参数
- 静态量化:使用校准数据集预计算量化参数
- 量化感知训练(QAT):在训练过程中模拟量化效果
参考大模型基础之量化。
算子
参考官方文档。
每个ONNX版本对应一个算子集版本号opset_version。随着版本演进,新算子被加入,老算子被废弃。导出模型时需指定opset_version,决定模型中可用的算子范围。
- Opset 11:常见基础算子
- Opset 15:支持更多Transformer相关算子
- Opset 17-18:扩展更多高级算子
- Opset 20+:最新算子集支持
前两者结合,即为IR;算子包含基本算子和函数算子Functions,后者表示复合操作,由其他算子组合而成的一个子图。如果一个运行时没有实现某个函数算子,就将函数算子替换为其子图的具体实现,称为内联。
IR定义计算图结构:

计算图本质上是一个有向无环图DGA:
- 节点:表示具体操作,如卷积、Softmax算子;
- 边:表示Tensor,张量;
- 控制流:特殊节点;
- 节点依赖关系:特殊边,表示节点之间的依赖关系
算子操作符组成:
- 算子类型,如Conv2D、Softmax
- 属性:算子参数,如卷积的kernel_size、stride、paddin
- 输入/输出张量信息:如张量的Shape、DType
model,graph,node,tensor等数据结构
计算图
ONNX,定义一套标准化的计算图表示方式,用于描述神经网络模型的结构和权重。
PyTorch训练的模型会变成一个计算图,继而在对应的硬件上运行,如果计算图可以表示为一个中间表示IR,则图编译器(或AI编译器)就很容易在不同设备上优化,IR可以理解为一种通用表示。

AI框架和AI编译器的区别:
- AI框架可能会使用一些新的算子,但AI编译器可能没有实现;
- 一些算子的实现方式可能不一样;
- 有些编译器只能和某些框架适配,如Intel的OpenVino编译器只能用于TensorFlow,不适合PyTorch。
ONNX是一种通用模型计算图格式,大部分AI框架/AI编译器都支持它。
AI编译器将不同AI框架中的高级计算图映射为特定硬件上的执行操作,会进行一系列优化:
- 图重写:图结构决定操作OP的执行顺序,而作业调度(Job scheduling)考虑如何将OP执行顺序最佳化:
- 删除一些节点或边
- 算子融合
- 子图替代
- 删除无用的层
- 算子融合:将多个连续的操作合并为一个复合操作,在计算图中,由很多细粒度的算子组成,每个操作都要独立的计算和读写内存,可以将多个连续的操作合并为一个复合操作,这样可以减少中间结果的存储和读取,也能充分利用硬件专有的Kernel(如专为矩阵乘操作的Tensor Core)。比如,convolution、ReLU、BatchNorm可以融合为计算图中的一个节点(算子)

- 算子分配与调度优化
上述两个优化基本上是和硬件无关的,对于图编译器来说,最终操作要运行在各种硬件上,它充当了硬件的抽象,选择不同的算子运行在特定硬件上(GPU、NPU、CPU),比如卷积操作适合 GPU运行,标量运算适合CPU运行;通过考虑跨硬件依赖关系,合理调度执行的顺序,最终提升运行效率。
目前大部分 AI 框架都有自己的计算图表示方法和优化目标,可以根据需求开发大模型,但大模型部署越来越多样化(比如边缘设备运行,一个框架部署到另外一个框架支持的环境),那么不同框架开发出来的模型跨平台部署或性能优化就非常困难了。
这时候计算图如果有一个统一的中间表示 IR,用于屏蔽不同框架之间的差异,从而让不同 AI 编译器去优化,ONNX 就是这样一个通用 IR。
实战
转换
PyTorch转换为ONNX:
py
import torch
import torch.nn as nn
# 定义模型
class SimpleClassifier(nn.Module):
def __init__(self):
super(SimpleClassifier, self).__init__()
self.fc = nn.Linear(768, 2) # BERT输出768维
def forward(self, x):
return self.fc(x)
# 初始化模型
model = SimpleClassifier()
model.eval()
dummy_input = torch.randn(1, 768)
torch.onnx.export(
model,
dummy_input,
"classifier.onnx",
input_names=["input"],
output_names=["output"],
dynamic_axes={"input": {0: "batch_size"}, "output": {0: "batch_size"}},
opset_version=17
)
解读:
dynamic_axes:保证输入输出支持动态Batch;opset_version:版本号,建议选13+,兼容性更好。
推理
使用ONNX Runtime:
py
import onnxruntime as ort
import numpy as np
# 加载模型
session = ort.InferenceSession("classifier.onnx")
input_data = np.random.randn(1, 768).astype(np.float32)
inputs = {"input": input_data}
# 推理
outputs = session.run(None, inputs)
print("推理结果:", outputs[0])
FastAPI
集成FastAPI,部署为服务:
py
from fastapi import FastAPI
import uvicorn
app = FastAPI()
session = ort.InferenceSession("classifier.onnx")
@app.post("/predict")
def predict(data: list):
input_data = np.array(data, dtype=np.float32).reshape(1, -1)
result = session.run(None, {"input": input_data})
return {"prediction": result[0].tolist()}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
ONNX Runtime
官网,简称ORT,微软官方开源(GitHub,21.2K Star,4.1K Fork)跨平台、高性能运行时推理引擎,支持CPU/GPU/NPU,专门用于执行ONNX模型,负责将ONNX格式的模型加载到内存中,并利用硬件加速能力高效运行推理。
核心特性:
- 多语言API:支持Python、C++、C#、Java、JavaScript、Rust
- 跨平台支持:Linux、Windows、macOS、Android、iOS,甚至Web浏览器
- Execution Providers机制:通过插件式的执行提供者,支持不同硬件后端
- 图优化技术:自动进行算子融合、常量折叠、内存优化等
- 训练加速:除了推理,还支持大模型训练加速
核心概念
- 运行时:ORT之所以可在不同的硬件设备上运行,抽象一个API,称为Execution Providers(EP),如CUDA EP。
- EP:EP 是对某个硬件的一种抽象,每个 EP 向 ORT 说明其硬件支持的能力,比如支持的算子、GPU显存管理、异构调度执行。EP一般由ORT官方和厂商合作开发,如cuDNN调用。如果没有算子分配给 EP 执行,那 ORT 会有回退机制,如让CPU去执行,确保模型能够总是能够运行。两种类型:
- Kernel EP,如CPUExecutionProvider、CUDAExecutionProvider,ORT官方实现的;
- Runtime EP,一般是硬件厂商实现的,如TensorRTExecutionProvider,用于专门的优化。
- Graph图优化:ONNX模型就是一个计算图,ORT就是对计算图进行优化。图优化分为离线和在线模式;也可分为三层优化:
- 基础优化:保留语义的图重写,和具体后端硬件无关,在图分区之前运行,包括常量折叠、冗余节点删除(如Identity、Slice、Unsqueeze、Dropout)、算子融合。
- 扩展优化:包括更复杂的节点集成,只适用于分配给CPU、CUDA和ROCm执行的节点,也就是说和硬件有关,或者和特定模型架构有关。
- 张量内存布局优化:改变数据布局,让硬件更好优化
- 图转换:图优化可从其他角度理解,如从模型的应用水平分析看,优化一般被称为图转换,图转换包含图优化。分为三个层次:
- 无条件转换:计算图生成后可以立刻进行的图转换,如Cast、Memcpy等操作确保张量类型和设备一致
- 通用转换:和设备无关的转换,比如在推理阶段移除计算图中的Dropout;
- EP级别转换:图转换一种分类:
- 全局模式:图转换会对整个计算图进行转换,在ORT中该接口称为Graph Transformer;
- 局部模式:图转换对某个子图或一些节点进行转换,在ORT中该接口称为Rewriting Rule。
- Graph Partitioning:图分区。和EP有关,ORT根据可用EP将模型图划分为多个子图(每个子图是某个EP连续能处理的节点),每个子图对应一个不同的EP,ORT提供一个默认EP(cpu),如果没有找到更高效的EP处理子图,就使用默认的EP处理。
图分区的具体技术实际上也很简单,按照特定顺序考虑可用的EP,为每个EP分配其能够处理的最大子图,采用贪婪搜索的模式。
最终图转换和图分区将原始模型图转换为由分配给默认EP或其他已注册EP的算子组成的新图,ORT执行引擎负责运行该图,也可以叫做图调度和执行。 - 整体架构
从组件的角度理解,如下图:

整体比较简单:- 加载ONNX模型;
- 转换成内存中的图结构;
- 图分区,根据支持情况拆分子图;
- 并行调度器运行各个子图,交由不同EP执行
从图优化和图分区处理流程角度理解,更详细:

涵盖核心流程: - ONNX模型加载成中间表示IR;
- 进行平台无关的图优化(如节点融合)
- 进行图分区;
- 针对每个EP做定制优化;
- 使用顺序或并行调度执行EP;
- 各个EP负责具体执行子图
- ORT主要目标:
- 充分使用硬件能力:最大限度地自动利用不同硬件平台上的加速器(如GPU)和运行时;
- 提供硬件工作的抽象接口:为自定义加速器和运行时提供正确的抽象和运行时支持,这种抽象为EP,它定义并向ORT公开功能;
- 兼容性:不奢望模型在一个EP上完全运行,可在异构设备上协同工作,强调兼容性
- 图转换:ORT的核心功能,为模型计算图转换提供优化功能:全局优化,具体算子优化。
EP
Execution Providers,执行提供者,通过插件化的架构,允许同一个ONNX模型在不同硬件上无缝切换运行:
| 执行提供者 | 硬件平台 | 使用场景 |
|---|---|---|
| CPUExecutionProvider | CPU | 通用推理,无GPU环境 |
| CUDAExecutionProvider | NVIDIA GPU | GPU加速推理 |
| TensorrtExecutionProvider | NVIDIA GPU | 通过TensorRT进一步优化 |
| DirectMLExecutionProvider | Windows GPU | 支持AMD/Intel/NVIDIA GPU |
| OpenVINOExecutionProvider | Intel CPU/GPU/VPU | Intel硬件优化 |
| CoreMLExecutionProvider | Apple Silicon | macOS/iOS优化 |
| XNNPACKExecutionProvider | CPU/移动端 | 移动端和边缘设备 |
| WebGPUExecutionProvider | 浏览器 | Web端推理 |
| ACLExecutionProvider | ARM CPU | ARM架构优化 |
| ROCmExecutionProvider | AMD GPU | AMD GPU加速 |
选择不同EP
py
import onnxruntime as ort
# CPU推理
session_cpu = ort.InferenceSession('model.onnx')
# GPU推理(CUDA)
session_gpu = ort.InferenceSession('model.onnx', providers=['CUDAExecutionProvider', 'CPUExecutionProvider'])
# TensorRT推理(NVIDIA GPU上极致优化)
session_trt = ort.InferenceSession('model.onnx', providers=['TensorrtExecutionProvider', 'CUDAExecutionProvider'])
ORT图优化
图转换,分为四个层次,参考core/optimizer/graph_transformer_level.h代码:
c
enum class TransformerLevel : int {
Default = 0, // required transformers only
Level1, // basic optimizations
Level2, // extended optimizations
Level3, // layout optimizations
// The max level should always be same as the last level.
MaxLevel = Level3
};
解读:
- Default层次:不管如何配置,都会进行无条件转换,大部分情况是图转换前就优化,也有图转换后再做优化
- Level1:基础优化,和后端EP无关,通用型优化,如常量折叠、算子融合
- Level2:扩展优化,一般针对特定后端EP进行算子融合优化
- Level3:Layout布局优化,目前就只有一个NhwcTransformer
拓展
Olive
功能:微调、量化。
olive quantize子命令可支持各种量化方法,包括AWQ、GPTQ、BitsAndBytes、ORT静态方法。
量化示例:
bash
olive quantize --model_name_or_path meta-llama/Llama-3.2-1B-Instruct --algorithm awq --output_path models/llama/awq --log_level 1
# 带校准数据
olive quantize --algorithm gptq \
--model_name_or_path meta-llama/Llama-3.2-1B-Instruct \
--data_name wikitext --subset wikitext-2-raw-v1 \
--split train --max_samples 128 --output_path models/gptq
优化示例:
bash
olive auto-opt \
--model_name_or_path models/llama/awq \
--device cpu \
--provider CPUExecutionProvider \
--use_ort_genai \
--output_path models/llama/onnx \
--log_level 1
将量化模型优化为ONNX模型。
先量化再微调,量化带来的损失可能在微调过程中得以校准:
bash
olive quantize --model_name_or_path meta-llama/Llama-3.2-1B-Instruct \
--trust_remote_code --algorithm awq \
--output_path models/llama/awq --log_level 1
olive finetune --method lora --model_name_or_path models/llama/awq \
--data_name xxyyzzz/phrase_classification \
--text_template "<|start_header_id|>user<|end_header_id|>\n{phrase}<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n{tone}" \
--max_steps 100 --output_path ./models/llama/ft --log_level 1
# 自动优化
olive auto-opt --model_name_or_path models/llama/ft/model \
--adapter_path models/llama/ft/adapter --device cpu \
--provider CPUExecutionProvider --use_ort_genai \
--output_path models/llama/onnx --log_level 1
可视化
ONNX可视化工具有很多,参考模型可视化项目。