前面十二篇都在 MLIR 和底层细节里打转。这一篇抬头看一眼整个领域:主流的 AI 编译器各自在哪一层、核心思想是什么、彼此有什么区别。重点讲 TVM,最后整理了两个常被问到的问题。
一、三个层次
计算图层 整个模型的算子图:融合、常量折叠、布局变换
TVM Relay/Relax、XLA HLO、PyTorch FX
↓
算子层 单个算子怎么写成高效的循环和指令
TVM TIR、Triton、TileLang、Halide、MLIR linalg
↓
代码生成 生成机器码
LLVM、NVPTX、各家芯片的后端
还要区分三类东西:
- 基础设施 :MLIR、LLVM,用来搭建编译器;
- 编译器 :TVM、XLA、IREE、Inductor,搭好的编译器;
- 推理引擎:TensorRT,侧重从现成实现中挑选最快的。
二、TVM
开源的端到端深度学习编译器,TileLang 就建在它之上。
两层 IR
- Relay / Relax:计算图层。Relay 是早期版本;Relax 较新,对动态形状支持更好,并且能把图层和算子层放在同一个程序里一起优化。
- TIR(Tensor IR):算子层,描述循环、缓冲区和内存层级。TileLang 程序会先变成 TIR。
核心思想:计算与调度分离
这个思想最早来自 Halide。
- 计算 :只描述算什么,例如
C[i, j] = sum(A[i, k] * B[k, j])。 - 调度 :单独描述怎么算,用一组原语:
split:切块reorder:换迭代序vectorize:向量化bind:绑定到 GPU 线程compute_at:在哪一层循环里计算(相当于融合)
同一份计算换不同调度,就得到不同的实现。我在自己的 MLIR 项目里手写的迭代序交换、两级 tiling 和向量化,用 TVM 写就是几行调度原语。
自动调优
好的调度很难手写,TVM 让机器去搜:
- AutoTVM:人写调度模板并留出参数(如块大小),机器搜参数。
- Ansor:不需要模板,自动生成调度结构,再用代价模型加进化搜索找最优。
- MetaSchedule:较新的统一框架,在 TIR 上搜索。
BYOC(Bring Your Own Codegen)
把计算图中的某些子图切出来,交给芯片厂商自己的编译器或库处理,其余部分仍由 TVM 编译。这是很多 NPU 厂商接入 TVM 的方式。
三、其他几个
XLA:Google 的编译器,用于 TPU、JAX 和 TensorFlow。计算图 IR 叫 HLO,以激进的算子融合著称。StableHLO 是一个稳定、可移植的算子集,可作为框架和编译器之间的交换格式,属于 OpenXLA 项目。
IREE:完全基于 MLIR 的端到端编译器加运行时。linalg 的切块与融合、bufferization 在其中都是主角;编译器生成调度好的计算单元,由轻量运行时执行。想看 MLIR 在真实项目里怎么用,IREE 是最好的参考。
TorchInductor:torch.compile 的后端。Dynamo 抓取 FX 图,Inductor 做融合,GPU 上生成 Triton,CPU 上生成 C++。
Triton:块级 kernel DSL,编译器基于 MLIR,从 Python 降到 TTIR、TTGIR 再到 LLVM IR 和 PTX。
Halide:最早用于图像处理,提出"计算与调度分离",TVM 继承了这一思想。
TensorRT:NVIDIA 的推理引擎,不是通用编译器。主要做层融合、低精度(INT8、FP8 校准),以及针对具体 GPU 从多个现成 kernel 中挑选最快的。生成的引擎绑定特定 GPU。
四、对比
| 定位 | 图层 IR | 算子层 | 特点 | |
|---|---|---|---|---|
| TVM | 端到端编译器 | Relay / Relax | TIR | 计算与调度分离,自动调优,BYOC |
| XLA | 端到端编译器 | HLO | 自身代码生成 | 激进融合,TPU 主力 |
| IREE | 编译器 + 运行时 | 基于 MLIR | linalg 等 | 全 MLIR,跨平台 |
| Inductor | PyTorch 后端 | FX | 生成 Triton / C++ | 与 PyTorch 无缝衔接 |
| TensorRT | 推理引擎 | 内部 | 现成 kernel 库 | 挑选最快实现,低精度 |
| MLIR | 编译器基础设施 | 自定义 | 自定义 | 用来搭建上面这些 |
五、两个常见问题
TVM 和 MLIR 有什么区别?
TVM 是一个完整的编译器,有固定的 IR(Relax 和 TIR)和一整套调度、自动调优工具,拿来就能编译模型。MLIR 是搭建编译器的基础设施,本身不规定 IR,而是提供定义 dialect、写 pass、逐层降级的框架,Triton 和 IREE 都是用它搭起来的。前者更开箱即用,后者更灵活,适合为新硬件定制。
为什么 NPU 厂商常用 TVM 或 MLIR?
自研芯片硬件差异很大,需要定制编译流程。TVM 可以通过 BYOC 把模型中适合 NPU 的部分交给厂商自己的后端,复用它的前端和图优化;MLIR 则可以为芯片定义专门的 dialect,比如表示片上存储和 DMA,从高层一路降到芯片指令。