一文搞懂 AI 推理部署:算子融合、TVM、TensorRT 与 ONNX Runtime
一文搞懂 AI 推理部署:算子融合、TVM、TensorRT 与 ONNX Runtime
写给刚接触 AI Infra 的你:为什么模型训练完不能直接上线?中间那一堆"编译器""运行时"到底是什么关系?这篇文章带你从头理清。
引言:一个模型的上岗之路
假设你用 PyTorch 训好了一个图像分类模型,准确率不错。现在老板说:“把它部署到线上服务,要求单次推理延迟低于 10ms。”
你兴冲冲地把模型加载进 Flask 接口,一压测——延迟 50ms,GPU 利用率才 30%。问题出在哪?
原来,训练好的模型和"能高效跑在生产环境的模型"之间,隔着一整个优化世界。这个世界的主角,就是本文要讲的几个概念:算子融合(Operator Fusion)、TVM、TensorRT、ONNX Runtime。
在展开之前,先记住一张全景图,后文会反复回到它:
1 | ┌─────────────────────────────────────────────┐ |
一、算子融合:推理优化的第一课
1.1 为什么模型跑得慢?
深度神经网络本质上是一张"算子(Operator)的计算图"。算子就是卷积、矩阵乘、ReLU、BatchNorm 这些基本运算单元。
问题在于:现代 GPU 的算力增长远快于内存带宽增长,导致"算得快,喂不饱"。当模型执行到一串小算子时,会出现两个经典瓶颈:
瓶颈一:kernel 启动开销。 GPU 上每执行一个算子,都要经历一次 kernel 启动、同步、读写显存的过程。如果一张图里有 100 个连续的逐元素小算子,光是启动开销就可能比计算本身还贵。
瓶颈二:无效的显存读写。 看这个最常见的组合:
1 | Y = Conv(X) → Z = BN(Y) → A = ReLU(Z) |
按最朴素的方式执行,每一步都要:把结果写回显存 → 下一个算子再从显存读出来。中间结果 Y 和 Z 明明只"活"了一瞬间,却要经历两次完整的显存往返。对于带宽敏感的场景,这是巨大的浪费。
1.2 融合:把三趟运输变成一趟
算子融合的思路非常直观——把多个算子合并成一个 kernel,数据在寄存器/共享内存里直接传递,不落回显存:
1 | 融合前:Conv → [写显存] → BN → [写显存] → ReLU (3 次 kernel,2 次显存往返) |
经典的 Conv + BN + ReLU 三层融合,在真实场景中可以带来 30% 以上的延迟降低。而在大模型推理中赫赫有名的 FlashAttention,本质上就是一次极致的手工算子融合——把 Attention 中的矩阵乘、缩放、Softmax、再矩阵乘融合成一个访存高度优化的 kernel,避免了巨大中间矩阵的显存读写。
1.3 训练侧和推理侧,谁在做融合?
一个常见误区是认为算子融合只是"推理侧的活"。实际上两边都做,但关注点不同:
| 维度 | 训练侧 | 推理侧 |
|---|---|---|
| 核心目标 | 提升 GPU 利用率、省显存(前向 + 反向都要跑) | 降低延迟、提升吞吐、支持更高并发 |
| 融合范围 | 前向图 + 反向图,还要考虑与梯度 AllReduce、优化器更新的融合 | 只需前向图,可激进删减(推理不需要 Dropout 和反向计算) |
| 硬约束 | 必须保证融合后可求导 | 无梯度约束,还能顺手做量化(FP16/INT8) |
| 典型工具 | XLA、torch.compile、NVIDIA Apex | TensorRT、ONNX Runtime、vLLM |
| 典型案例 | Norm + 残差 + 激活融合;优化器逐元素更新融合 | Conv + BN + ReLU 融合;FlashAttention |
一句话:训练侧的融合要"小心翼翼保正确",推理侧的融合可以"放开手脚拼性能"。随着 torch.compile 这类 JIT 编译技术普及,一套框架同时服务训练和推理越来越常见,但两侧的技术侧重点依然存在。
二、三大主角登场:TVM、TensorRT、ONNX Runtime
理解了算子融合,我们来看执行这类优化的工具。先给三者的"身份卡":
2.1 TVM:学院派的"全能编译器"
- 出身:华盛顿大学陈天奇团队,2017 年开源,Apache 顶级项目
- 定位:端到端深度学习编译器栈
- 最大特点:硬件无关。CPU、GPU、NPU、DSP、FPGA,甚至国产芯片,都能通过它的编译流程生成代码
TVM 的思路借鉴了 LLVM:把模型看作计算图,经过多层中间表示(IR)的转换——图优化、算子融合、循环分块、缓存优化、自动调优——最终生成针对目标硬件的机器码。你甚至可以用它的调度语言(TE/TIR)手写算子优化策略,或用 AutoTVM/Ansor 让机器自动搜索最优实现。
适合谁:需要部署到非 NVIDIA 硬件、做算子级研究、适配自研芯片的团队。灵活度最高,上手门槛也最高。
2.2 TensorRT:NVIDIA 阵营的"性能天花板"
- 出身:NVIDIA,2016 年发布,2024 年宣布开源
- 定位:NVIDIA GPU 专属的推理优化器和运行时
- 最大特点:极致性能 + 深度绑定 NVIDIA
TensorRT 拿到 ONNX 模型后,会做一整套硬件感知的优化:层融合、精度校准(FP32/FP16/INT8/FP8 甚至 FP4)、针对具体 GPU 架构的 kernel 自动调优、CUDA Graph 消除启动开销。最终产出一个高度定制化的 .engine 文件——这份"编译产物"和你的 GPU 型号是绑定的,换一张卡就要重新编译。
在 MLPerf 推理基准测试中,基于 TensorRT 的方案长期是 NVIDIA 平台的标配答案。大模型时代,它的兄弟项目 TensorRT-LLM 更是 LLM 推理优化的主力工具。
适合谁:硬件锁定 NVIDIA、追求最低延迟最高吞吐的生产环境(数据中心、自动驾驶、大模型服务)。
2.3 ONNX Runtime:微软的"通用胶水层"
- 出身:微软,开源(MIT 协议)
- 定位:跨平台高性能推理引擎
- 最大特点:兼容性 + 编排能力
ORT 有两个核心设计:
其一,ONNX 标准接口。 ONNX(Open Neural Network Exchange)是一种开放的模型交换格式,好比 AI 界的"通用翻译语言"——PyTorch、TensorFlow 训练的模型都能转成 ONNX 格式,任何支持 ONNX 的运行时都能执行它。这解决了"训练框架五花八门、部署环境五花八门"的对接难题。
其二,Execution Provider(EP)架构。 这是 ORT 最精妙的设计,也是理解它与另外两者关系的关键,下一节细讲。
适合谁:需要一套代码跨 CPU/GPU/多厂商硬件部署、或混合硬件环境的团队。
三、层级关系:谁在谁之上?
这是最容易混淆的部分。先纠正一个常见误解:三者不是简单的上下游流水线,而是"同层协作、角色分工"的结构——TVM 和 TensorRT 是平级的优化执行引擎,ORT 则常常站在它们之上,作为统一的推理入口和调度者。
3.1 一张图看清协作关系
1 | PyTorch / TensorFlow(训练框架) |
ORT 的 Execution Provider 机制是这样工作的:
- ORT 先对整张模型图做通用优化(常量折叠、算子融合、死代码消除);
- 根据 EP 的算子支持情况,把计算图切分成若干子图;
- TensorRT 能处理的子图交给 TensorRT 编译加速;不支持的算子回退到 CUDA EP 或 CPU EP 执行;
- 跨 EP 的数据拷贝由 ORT 自动插入和管理。
对使用者来说,你只跟 ORT 的 Session 打交道,背后的子图切分和调度完全透明——这就是"编排者"的角色。
3.2 用传统编译栈类比
如果熟悉编译原理,这张对照表能让你秒懂:
| AI 推理栈 | 传统编译栈类比 |
|---|---|
| PyTorch / TensorFlow 模型 | C++ / Rust 源代码 |
| ONNX 格式 | LLVM IR(中间表示) |
| TVM / TensorRT | 后端编译器(生成目标平台机器码) |
| ONNX Runtime | 运行时调度器(类似 JVM:解释 + JIT 触发) |
| cuDNN / cuBLAS | 数学库(类似 BLAS / MKL) |
核心区别在于:TVM 和 TensorRT 负责"把子图编译到极致性能",ORT 负责"决定何时、何地、由谁执行哪段代码"。前者是编译器,后者更偏运行时编排。
3.3 三者定位对比速查表
| 维度 | TVM | TensorRT | ONNX Runtime |
|---|---|---|---|
| 角色 | 全能编译器 | NVIDIA 专属优化引擎 | 推理编排运行时 |
| 硬件支持 | 几乎所有硬件 | 仅 NVIDIA GPU | 多后端(CUDA/ROCm/OpenVINO/CPU/NPU…) |
| 上游输入 | ONNX / 多框架前端 | ONNX(也可从框架直接转换) | ONNX / 直接接 PyTorch |
| 输出形态 | 编译好的代码模块 | 序列化的 .engine 文件 |
Session 对象,直接收发 tensor |
| 灵活度 | 最高(可自定义算子、后端) | 低(绑定 NVIDIA 生态) | 中(靠 EP 机制扩展) |
| 上手难度 | 高 | 中 | 低 |
四、实战选型:什么场景用什么组合?
理解了层级关系,选型思路就清晰了。三条典型路线:
路线一:NVIDIA 独占,追求极致性能
1 | PyTorch → ONNX → TensorRT 编译 → .engine 文件 → GPU 部署 |
跳过 ORT 的编排层,让 TensorRT 直接接管整张图,性能最优。适合硬件环境单一、性能敏感的场景(如自动驾驶、线上大模型服务)。
代价:.engine 文件与 GPU 型号绑定,换卡需重新编译;对不支持的算子需要自己写 plugin。
路线二:混合/跨平台环境,一套代码走天下
1 | PyTorch → ONNX → ONNX Runtime(统一入口) |
以 ORT 为统一推理接口,NVIDIA 卡上通过 TRT EP 享受接近原生的性能,其他硬件走对应后端。适合云厂商、SaaS 服务、桌面软件等硬件环境多样的场景。
路线三:非标准硬件或深度定制
1 | 任意模型 → TVM 编译(自定义算子 + 硬件后端)→ 目标芯片 |
绕开 ONNX 标准算子集的限制,对任意计算图做端到端编译。适合自研芯片适配、边缘设备、算子研究。
一个现实中常见的真相:大型 AI Infra 中三者常常配合出现而非二选一——ORT 管调度和兼容,TensorRT 管 NVIDIA 上的性能,TVM 管长尾硬件和定制算子。
五、总结:一张知识卡片带走全文
1 | ┌────────────────────────────────────────────────────┐ |
最后留一个思考题:如果让你部署一个 70B 的大语言模型到由 8 张 NVIDIA H100 组成的服务器上,同时还要支持一部分客户使用国产 NPU,你会怎么组合这三件工具?
欢迎在评论区聊聊你的方案。下一篇,我们聊聊大模型推理特有的优化技术——KV Cache、PagedAttention 和连续批处理。