AI 编译器:TVM、MLIR 与 torch.compile 的算子编译优化

AI 编译器把「计算图」编译成「针对特定硬件的高效代码」——从图优化、算子融合到代码生成与后端调度。本文系统讲解 TVM、MLIR、torch.compile 三大编译栈的原理、IR 层级、调度原语、后端代码生成,以及如何在推理生产中落地。

深度学习推理的性能天花板,很多时候不在模型结构,而在**「算子怎么落到硬件上」**。传统做法是「手写 Kernel」(cuBLAS/cuDNN)——但新算子层出不穷,手写永远追不上。AI 编译器换了个思路:把计算图编译成目标硬件的高效代码,用「图优化 + 算子融合 + 调度 + 代码生成」代替「手写 Kernel」。本文把 TVM、MLIR、torch.compile 三大编译栈讲透:它们解决什么、IR 怎么分层、调度怎么做、后端怎么生成,以及推理生产怎么用。

前置:/ai-kernel-fusion-optimization/(算子融合与 CUDA Graph)、/ai-cuda-basics/(GPU 线程模型)、/ai-tensorrt/(TensorRT 引擎构建)、/ai-onnx-runtime/(跨平台推理)。

目录

1. 为什么需要 AI 编译器:手写 Kernel 的困境

先看传统路径的问题:

手写 Kernel 的困境:
□ 新算子(FlashAttention/量化新算法)→ 手写很慢
□ 硬件多样性(NVIDIA/AMD/Intel/ARM/NPU)→ 每硬件一份
□ 手工优化(内存布局/向量化/分块)→ 靠专家经验
□ 演进慢:模型迭代速度 >> 算子库更新速度

AI 编译器解决的问题:
□ 自动生成:从计算图自动生成高效 Kernel
□ 可移植:一套描述 → 多硬件后端
□ 可调优:自动搜索最优调度(分块/向量化/展开)
□ 融合:跨算子融合减少内存访问(见融合篇)

传统 vs 编译器:
□ 传统:人写 Kernel(准但慢,覆盖有限)
□ 编译器:机器生成(快覆盖,质量接近手写)

工程要点:AI 编译器的价值是**「用编译换手写」**——新算子自动生成、多硬件可移植、调度自动搜索。它不能完全替代手写 Kernel(极致性能仍要人工),但把「80% 的普通算子」自动化,是推理引擎进化的核心方向。

2. 编译栈的总体架构:前端、优化、后端

一个 AI 编译器是「三段式」编译器:

前端(Frontend):模型 → 计算图 IR
□ 从 PyTorch/ONNX/TensorFlow 导入模型
□ 转换成「框架无关」的计算图 IR
□ 完成第一层图优化(常量折叠、死代码消除)

中端(Optimization):图 IR → 优化后的图/张量 IR
□ 算子融合、图重写、内存规划
□ 张量级优化(布局转换、代数化简)

后端(Backend):优化 IR → 目标代码
□ 调度选择(分块/向量化/并行)
□ 代码生成(生成 CUDA/C++/OpenCL/汇编)
□ 编译成可执行 Kernel + 加载

关键:三层解耦 → 前端支持多框架,后端支持多硬件
数据流示例:
PyTorch 模型 → (前端) 计算图 → (中端) 融合优化 → (后端) CUDA Kernel
                ONNX 模型  →  计算图   →  优化图   →  目标代码

工程要点:三段式架构的核心是**「前后端解耦」**——前端吸收多框架,后端辐射多硬件,中端做与框架、硬件都无关的优化。理解「图优化在哪层、调度在哪层」,才能读懂每个编译器栈的文档。

3. IR 层级:计算图、张量与调度

编译器里「中间表示(IR)」是层层降级的:

IR 层级:
□ 高层 IR(计算图):算子级别的 DAG(add/matmul/softmax)
  → 做图优化(融合、常量折叠)
□ 张量 IR:逐算子展开成「循环 + 内存操作」
  → 表达分块、数据布局
□ 调度 IR / 代码生成 IR:循环变换 + 向量化 + 并行
  → 决定最终怎么跑

层级之间的「降低」(lowering):
高层算子 → 展开成低层循环 → 调度变换 → 目标代码
每个降低步骤都有对应的「可优化点」
例:softmax 的降低
高层:Softmax(x)                      # 一个算子
张量级:exp(x) → sum → div             # 拆成基础操作
调度级:分块计算、在线 softmax、向量化  # 决定怎么跑

工程要点:IR 分层让「优化」有清晰的位置——图优化在高 IR,调度优化在低 IR。降低过程是「从抽象到具体」,每层降低都打开了新的优化空间(融合、分块、向量化)。理解 IR 层级,就知道「某个优化该在哪一层做」。

4. 图优化:算子融合、常量折叠与内存规划

编译器的中端核心是图优化:

主要优化:
□ 算子融合(Fusion):多个算子合成一个
  例:conv + bn + relu → 一个融合 Kernel
  → 减少「中间结果的显存读写」(带宽收益,见融合篇)
□ 常量折叠:常数子图 → 编译期算好
□ 死代码消除:无用分支/节点删除
□ 内存规划:张量内存复用(in-place / 别名分析)
□ 布局转换:NCHW → NHWC 等(匹配硬件偏好)

融合的收益来源:
中间张量不进显存(留在寄存器/片上内存)
→ 对带宽受限的推理,这是最大的单点优化
融合示例:
x → conv → bn → relu → y
融合成:kernel_conv_bn_relu(x) → y
→ 省去 conv 输出、bn 输出的两次显存往返

工程要点:图优化的重点是**「融合 + 内存」**——算子融合砍带宽(推理最痛),内存规划省显存。图优化与框架、硬件无关,是「任何编译器栈的第一层优化」,也是推理引擎(TensorRT/vLLM)都在做的核心优化。

5. 调度原语:分块、向量化与并行化

调度(Schedule)决定「一个算子怎么跑」——是编译器性能的灵魂:

核心调度原语:
□ 分块(Tiling/Split):把大循环切成小块
  → 匹配片上内存/缓存大小,减少重复读
□ 向量化(Vectorize):相邻元素并行处理(SIMD)
  → 利用 GPU 的向量单元 / CPU 的 SIMD
□ 并行化(Parallelize):循环维度映射到线程
  → GPU:线程块/线程分配
□ 展开(Unroll):展开循环体减少分支开销
□ 重排序(Reorder):循环嵌套顺序(影响缓存局部性)

调度的目标:
□ 最大化「数据复用」:片上/寄存器反复用
□ 最大化「带宽利用」:合并访问、充分加载
□ 最小化「同步/分支」开销
调度例(矩阵乘):
分块:把 M×N×K 切成 tile(如 64×64×64)
向量化:内层乘加用向量指令
并行:每个线程块算一个 tile
重排序:让 tile 的加载与计算重叠(流水线)

工程要点:调度是编译器里**「最接近硬件」**的优化层——分块控片上内存、向量化控 SIMD、并行化控线程。调度写得好不好,决定生成的 Kernel 是「能跑」还是「快一个数量级」。这也是 TVM 用「自动搜索调度」的原因(人找最优调度太慢)。

6. TVM:AutoTVM 与 Ansor 自动调优

TVM 是开源的经典 AI 编译器,核心是「可编程调度 + 自动调优」:

TVM 架构:
□ Relay(图 IR)+ TensorIR(张量 IR)
□ TVMScript:用 Python 表达「算子 + 调度」(可读)
□ 自动调优:让机器搜索最优调度

自动调优两条路:
□ AutoTVM:模板 + 搜索(预定义调度模板,搜索参数)
□ Ansor:程序生成 + 搜索(自动生成调度候选)
  → Ansor 更自动化,覆盖更广

搜索策略:
□ 随机/遗传/贝叶斯搜索
□ 在真实硬件上测量(硬件在环)
□ 调优成本高(GPU 上几小时)→ 调优一次、保存 artifact
# TVMScript 调度示例(概念)
@T.prim_func
def matmul(A: T.Tensor, B: T.Tensor, C: T.Tensor):
    ...
    T.parallel(M)          # 并行
    T.vectorize(K)         # 向量化
# 或用 Ansor 自动搜索这些调度参数

工程要点:TVM 的独特点是**「调度可编程 + 自动搜索」**——TVMScript 让调度写成人能读的代码,Ansor 让机器自动搜最优调度。代价是「自动调优要在真实硬件上花时间」,适合「离线调优一次、上线复用 artifact」的场景。

7. MLIR:多级 IR 与硬件抽象

MLIR(Multi-Level IR)是 LLVM 项目的编译器基础设施,思路更底层:

MLIR 的核心思想:
□ 多级 IR:不是一层 IR,而是「一系列」dialect(方言)
□ Dialect:每种 IR 风格是一个 dialect
  (tensor/arith/memref/gpu/llvm 等)
□ 渐进降低:从高层 dialect 逐级降到低层
  → 每级只做「该级能做的优化」

MLIR 的价值:
□ 可组合:不同框架/后端共享 IR 基础设施
□ 可移植:一套基础设施 → 多硬件(GPU/CPU/TPU/FPGA)
□ 可定制:新的硬件后端 = 新增 dialect + 降低路径

在 AI 推理的角色:
□ ONNX-MLIR、torch-mlir 等用 MLIR 做中间层
□ 与 TVM 的关系:MLIR 偏「基础设施」,TVM 偏「完整编译栈」
MLIR 降低路径(示意):
onnx dialect → linalg dialect → affine dialect → gpu dialect → llvm
(框架算子)   (张量/循环)   (仿射循环)     (GPU 调度)   (目标码)

工程要点:MLIR 的思路是**「多级 dialect + 渐进降低」**——每级 IR 做自己擅长的优化,最终降到 LLVM/目标码。它更像「编译器的地基」,适合要「深度定制硬件后端」的团队;大多数用户通过 torch-mlir/ONNX-MLIR 间接触碰它。

8. torch.compile:PyTorch 侧的训练/推理编译

PyTorch 2.x 的 torch.compile 把编译带进了主流深度学习:

torch.compile 做什么:
□ 把 PyTorch 模型「图化」→ 图优化 + 算子编译
□ 动态图 → 捕获成图 → 编译优化 → 生成 Triton Kernel
□ 一行代码:model = torch.compile(model)

底层技术:
□ TorchDynamo:动态图捕获(Python 层字节码分析)
□ TorchInductor:图 → Triton/C++ 代码生成
□ Triton:GPU 上的「类 Python」编程语言(写 Kernel 简单)
□ 与 CUDAGraph 结合:进一步减少启动开销

收益:
□ 训练:自动融合 + 内核优化 → 提速
□ 推理:同模型代码「编译后」延迟/吞吐提升
□ 开发友好:不用换框架、不用手写 Kernel
import torch
model = torch.compile(model, mode="reduce-overhead")
out = model(x)   # 编译 + 执行(首次编译慢,之后走缓存)

工程要点:torch.compile 的价值是**「一行代码拿到编译收益」**——Triton 让写 Kernel 变简单,TorchDynamo/Inductor 自动做图化与代码生成。它是「PyTorch 生态的编译器入口」,训练/推理都受益;代价是首次编译有开销,生产要缓存编译产物。

9. 推理生产落地:编译栈与推理引擎的结合

AI 编译器在生产里很少「单独用」,多是嵌入推理引擎:

结合形态:
□ 推理引擎(TensorRT/vLLM/Triton)内部就用编译技术
  → TensorRT 的图优化 + Kernel 选择 = 编译器思想
  → vLLM 的融合算子(FlashAttention 等)是手工/编译混合
□ torch.compile 产物 → 导出 ONNX/TensorRT → 部署
□ 编译栈直出:TVM 编译整个模型 → 部署 artifact

生产流程(推荐):
1. 训练后 → 导出(ONNX/IR)
2. 编译器(TVM/torch.compile)→ 优化 + 生成 Kernel
3. 离线调优(搜索调度/校准量化)→ 保存 artifact
4. 部署 artifact → 推理引擎加载执行

关键:离线编译、在线执行
□ 编译/调优是离线任务(花时间)
□ 推理是执行编译产物(快)
选型路径:
PyTorch 生态内 → torch.compile + Triton
跨框架/跨硬件 → ONNX + TVM/ONNX-MLIR
极致性能 + NVIDIA → TensorRT(内部含编译器栈)

工程要点:编译栈的生产落地是**「离线编译 + 在线执行」**——编译与调优在离线做(几小时可接受),线上加载编译产物。选型看生态:PyTorch 内用 torch.compile,跨框架用 TVM/ONNX 路线,NVIDIA 极致性能用 TensorRT。不要在生产运行时做编译/调优。

10. 速查表与一句话记忆

问题一句话答案
为什么需要手写 Kernel 追不上新算子与多硬件
架构什么样前端(图 IR)/ 中端(优化)/ 后端(代码生成)
IR 怎么分层计算图 → 张量 → 调度,逐级降低
图优化做什么融合、常量折叠、内存规划
调度是什么分块/向量化/并行化/展开
TVM 特点可编程调度 + Ansor 自动搜索
MLIR 是什么多级 dialect 的编译器基础设施
torch.compile一行代码,Dynamo + Inductor + Triton
生产怎么用离线编译 + 在线执行,嵌入推理引擎

一句话记忆:AI 编译器 = 三段式(前端图 IR/中端优化/后端代码生成)+ IR 逐级降低(图→张量→调度)+ 图优化融合(省带宽)+ 调度原语(分块/向量化/并行)+ TVM 自动搜索(Ansor)+ MLIR 多级 dialect(基础设施)+ torch.compile(一行代码 + Triton)——用「编译自动生成 Kernel」替代「人肉手写 Kernel」。

延伸阅读

  • /ai-kernel-fusion-optimization/ — 算子融合与 CUDA Graph
  • /ai-cuda-basics/ — GPU 线程与内存模型
  • /ai-tensorrt/ — TensorRT 引擎构建
  • /ai-onnx-runtime/ — 跨平台推理与图优化
  • /ai-cuda-libraries/ — 手写 Kernel 的替代库
  • 高性能计算专题 — 编译器与内核优化
  • C++ 专题 — 底层编译与代码生成

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「ai」更多文章

  1. 类别不平衡与异常检测:从重采样到半监督方法
  2. Embedding 深入:对比学习、双塔架构与向量检索工程
  3. MLOps 治理与可复现:模型注册、漂移监控与合规