静态图(Static Graph)——深度学习编译与执行的基石范式
3 秒看懂
静态图 = 先画完整张计算蓝图,再喂数据跑。 把所有算子、张量形状、依赖关系一次性”冻结”成一张有向无环图(DAG),编译器拿到全图后可以做极致优化(算子融合、内存规划、并行调度),但图一旦固化就无法运行时动态改变结构。它是深度学习从”研究玩具”走向”工业部署”的关键范式跃迁。
3 分钟产业解释
为什么一个”图”的概念值得产业级关注?
深度学习框架本质上要回答一个问题:怎么把用户写的 Python 数学表达变成能在 GPU/NPU 上高效跑的机器码?
这里存在两种根本范式:
| 范式 | 通俗描述 | 代表 |
|---|---|---|
| 静态图(Define-then-Run) | 先把整个计算流程”编译”成一张图,然后反复执行 | TF 1.x、ONNX、TensorRT、TVM |
| 动态图(Define-by-Run) | 写一行算一行,像 Python 原生执行 | PyTorch 默认模式、TF Eager |
静态图的核心价值在于:编译器拿到全图信息后,能做跨算子的全局优化——这在工业部署中直接转化为更低延迟、更高吞吐、更少显存占用。
产业位置: 今天的主流实践是 “训练用动态图(灵活),部署转静态图(高效)“。PyTorch 2.0 引入的 torch.compile 正是用 torch.fx 捕获计算图后编译为静态图执行,代表了两种范式的融合趋势。
15 分钟专家深入
1. 从”执行”到”编译”:范式分野的本质
动态图(Eager Mode):
# PyTorch 风格
a = x @ W1 + b1 # 立刻算
a = relu(a) # 立刻算
y = a @ W2 + b2 # 立刻算
- 优点: 和 Python 原生体验一致,
print、if、for随便用,调试零门槛。 - 代价: 每一步都要回 Python 解释器调度,无法做跨算子优化;每次执行都要重新调度内核。
静态图(Graph Mode):
# TensorFlow 1.x 风格 —— 先定义图,再启动 Session 执行
a = tf.matmul(x, W1) + b1
a = tf.nn.relu(a)
y = tf.matmul(a, W2) + b2
# 此时没有计算发生,只是在构建图
with tf.Session() as sess:
result = sess.run(y, feed_dict={x: data}) # 真正执行
- 核心差异: 整个计算流程被序列化为一张 DAG,编译器/运行时可以看到全貌。
2. 静态图的”全图视野”带来什么优化?
这是静态图的真正产业价值所在,分三个层次:
层次一:算子融合(Operator Fusion)
未融合:
MatMul → 写回显存 → BiasAdd → 写回显存 → ReLU → 写回显存
(3 次显存读写, 3 次内核启动开销)
融合后:
FusedMatMulBiasReLU → 写回显存
(1 次显存读写, 1 次内核启动)
融合将多个小算子合并为一个大算子,减少显存带宽消耗和 GPU kernel launch 开销。这在 Transformer 推理中尤为关键(如 QKV 投影的融合、Attention 中 softmax+scale 的融合)。
层次二:内存规划(Memory Planning / Liveness Analysis)
编译器对图做张量生命周期分析——哪些中间结果在同一时刻存活、哪些已不再需要。据此做:
- 原位复用(In-place operation): 输出复用输入的缓冲区
- 内存重用(Memory reuse): 生命周期不重叠的张量共享同一内存块
- 换入换出策略: 在显存紧张时将非活跃张量卸载到主机内存
在大型模型训练中(如数百层 Transformer),激活值的内存规划直接决定能否跑起来。
层次三:调度优化(Scheduling & Parallelism)
全图可见后,编译器可以:
- 识别无依赖的子图并行执行(如多头注意力的多个 head 并行计算、残差分支的独立前向与合并、无依赖算子间的水平融合)
- 重叠计算与通信(如 AllReduce 通信与下一层计算 overlap)
- 跨设备图切分(Graph Partitioning):自动决定哪些算子在哪个 GPU 上执行
3. 静态图的核心数据结构
┌─────────────────────────────────────────┐
│ Computation Graph (DAG) │
│ │
│ Node = Operator (算子) │
│ - op_type: "Conv2D", "MatMul", ... │
│ - attrs: kernel_size, stride, ... │
│ - inputs: [TensorRef, ...] │
│ - outputs: [TensorRef, ...] │
│ │
│ Edge = Tensor 数据流 │
│ - dtype: fp16, bf16, fp32, ... │
│ - shape: [batch, seq, hidden] │
│ - device placement │
│ │
│ Metadata: │
│ - Control dependencies │
│ - Training ops (optimizer, gradient) │
│ - Placement constraints │
└─────────────────────────────────────────┘
图的 IR(中间表示)是静态图系统的灵魂。不同框架/编译器有自己的 IR:
- TensorFlow: GraphDef / SavedModel(Protocol Buffer 序列化)
- ONNX: 开放标准 IR,跨框架互操作的桥梁
- MLIR(Multi-Level IR): Google 主导的多层级编译器基础设施,支持从高层图 IR 到低层硬件 IR 的逐层 lowering
- torch.fx: PyTorch 的图捕获 IR,用于
torch.compile的前端
4. 静态图的固有挑战
| 挑战 | 说明 |
|---|---|
| 动态形状(Dynamic Shape) | 序列长度、batch 大小不固定时,静态图需要为每种 shape 编译一个特化版本,或引入 shape 符号化抽象 |
| 控制流(Data-dependent branching) | if x > 0 这类数据依赖的分支在静态图中需要特殊算子(如 tf.cond、tf.while_loop),表达力受限 |
| 调试困难 | 图编译后的执行与用户原始代码失去直接对应关系,报错信息晦涩 |
| 迭代开销 | 研究阶段频繁修改模型结构时,每次都要重新”建图→编译”,开发体验差 |
技术原理
静态图构建与执行的完整流程
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ 用户 Python │ │ 图构建阶段 │ │ 图优化阶段 │
│ API 调用 │────▶│ (Build) │────▶│ (Optimize) │
│ │ │ │ │ │
│ tf.matmul() │ │ 生成 DAG IR │ │ 算子融合 │
│ tf.relu() │ │ 节点+边+属性 │ │ 常量折叠 │
│ tf.Variable │ │ │ │ 死代码消除 │
│ │ │ │ │ 布局转换 │
└──────────────┘ └──────────────┘ └──────────────┘
│
▼
┌──────────────┐ ┌──────────────┐
│ 执行阶段 │ │ 代码生成/ │
│ (Run) │◀────│ 内核编译 │
│ │ │ (CodeGen) │
│ Session.run()│ │ │
│ 或等价调用 │ │ 生成设备代码 │
│ │ │ 或调优内核库 │
└──────────────┘ └──────────────┘
静态图与动态图的关键机制对比
静态图 动态图
────── ──────
构建时机: 前向+反向全部构建完毕后才执行 每个 op 立即执行
图结构: 一次构建,反复执行(参数更新) 每次执行隐式重建图
Python 交互: 构建期有,执行期无(图已脱离Python) 每步都回 Python 调度
优化能力: 全图优化(融合/调度/内存规划) 仅单算子级别优化
控制流: 需专用算子(cond/while_loop) 原生 Python if/for
调试: 困难(需专用工具如 TensorBoard) 简单(标准 pdb/打印)
典型延迟: 内核启动少,调度开销低 每步有 Python 调度开销
静态图中的控制流处理
这是理解静态图”表达力边界”的关键:
# Python 原生控制流(动态图天然支持)
if x.sum() > 0:
y = x * 2
else:
y = x * -1
# 静态图中的等价表达(TensorFlow 1.x 为例)
y = tf.cond(
tf.reduce_sum(x) > 0,
lambda: x * 2,
lambda: x * -1
)
# 两条分支都会被编译进图,运行时根据条件选择执行哪条
# 代价:两条分支的内存都会被分配(或需要条件内存分配机制)
循环同理:
# 静态图中的循环(tf.while_loop)
result = tf.while_loop(
cond=lambda i, _: i < 10, # 循环条件
body=lambda i, acc: (i+1, acc+x), # 循环体
loop_vars=[0, tf.zeros_like(x)]
)
# 循环次数可以在运行时动态确定,不需要在图构建时已知最大值;
# 但若循环体内张量形状变化,需通过 shape_invariants 参数指定形状约束以避免编译冲突
图优化 Pass 示例
编译器对静态图施加的优化 Pass(以推理场景为例):
原始图:
Input → Conv2D → BatchNorm → ReLU → Conv2D → BatchNorm → ReLU → Output
Pass 1 - BN 融入 Conv(Fold BatchNorm):
Input → [Conv2D+BN_fused] → ReLU → [Conv2D+BN_fused] → ReLU → Output
(将 BN 的 scale/bias 合并到 Conv 的权重中, 推理时消除 BN 计算)
Pass 2 - 算子融合:
Input → [FusedConvBNReLU] → [FusedConvBNReLU] → Output
(Conv+BN+ReLU 合并为单个内核调用)
Pass 3 - 常量折叠 + 精度转换:
Input(fp16) → [FusedConvBNReLU(fp16)] → [FusedConvBNReLU(fp16)] → Output(fp16)
(将常量预计算, 并将精度降低以利用 Tensor Core)
这种多 Pass 流水线在 TensorRT、TVM、XLA 中是标准实践。
技术演进史
| 时期 | 事件 | 意义 |
|---|---|---|
| ~2017 | Google 发布 TensorFlow 1.0 | 静态图成为工业标准范式,“建图→Session 执行”流程主导了早期 AI 工业化 |
| ~2017 | ONNX 格式由 Meta(时称 Facebook)与 Microsoft 联合发起 | 静态图的开放互操作标准,打通训练→部署的跨框架流转 |
| ~2016–2017 | PyTorch 开源,以动态图(define-by-run)体验迅速崛起 | 研究社区大量转向动态图,倒逼 TF 等框架改善易用性 |
| ~2017 | TVM(陈天奇等)发布 | 将编译器技术引入深度学习,通过静态图的自动调优实现跨硬件部署 |
| ~2019 | TensorFlow 2.0 引入 Eager Execution 为默认模式 | TF 内部也承认动态图对研究的重要性,但保留 tf.function 实现图编译 |
| ~2019 | MLIR 由 Google Chris Lattner 提出并开源 | 多层级 IR 基础设施,统一从高层图到低层硬件的编译链路 |
| ~2020 | JAX 崛起(Google),以 jit 装饰器做 tracing-based 静态图编译 | 证明”Pythonic 体验 + 函数式语义 + 自动图捕获”的路线可行 |
| ~2023 | PyTorch 2.0 发布 torch.compile,引入 torch.fx + dynamo + Inductor | 动态图框架向静态图编译融合的标志性事件——“动态构建,静态执行” |
| ~2023–至今 | AI 编译器成为基础设施竞争焦点(Triton、XLA、MLIR 生态扩张) | 静态图编译不再是”TF vs PyTorch”的路线之争,而是所有框架的公共底座 |
核心趋势: 静态图没有”消亡”,而是从用户接口层退隐到编译器底层。用户写动态图代码,框架在背后捕获并编译为静态图执行。两种范式走向融合。
技术路线对比
| 维度 | 纯静态图(TF 1.x 风格) | 纯动态图(PyTorch Eager) | 混合模式(torch.compile / JAX jit) |
|---|---|---|---|
| 用户体验 | 差(反直觉的建图模式) | 优(等同 Python) | 良(Pythonic + 首次编译等待) |
| 调试难度 | 高 | 低 | 中(需理解 graph break 等概念) |
| 全图优化能力 | 强 | 无 | 强(编译阶段) |
| 动态形状支持 | 差(需 shape 符号化) | 天然支持 | 中(正在快速改善) |
| 控制流表达 | 受限(专用算子) | 原生 Python | 部分受限(需 traceable) |
| 推理部署性能 | 优秀 | 一般 | 优秀 |
| 跨设备图切分 | 成熟 | 手动 | 发展中 |
| 当前产业地位 | 遗留/部署主导 | 研究/训练主流 | 新范式方向 |
关键结论: 纯静态图作为用户接口已被动态图取代,但作为编译目标仍是所有高性能执行的基石。
上下游
上游:谁提供/需要静态图?
用户代码(Python)
│
▼
深度学习框架(PyTorch / TensorFlow / JAX / PaddlePaddle)
│
├── 图捕获(Graph Capture / Tracing)
│ • torch.fx / torch.dynamo
│ • tf.function / AutoGraph
│ • JAX jit (jaxpr)
│
▼
静态计算图 IR
│
├── 标准化格式:ONNX
└── 框架内部 IR:GraphDef / MLIR dialect
下游:静态图流向哪里?
静态图 IR
│
├──▶ 编译器后端(优化 + 代码生成)
│ ├── XLA(Google,服务 TPU/GPU)
│ ├── TensorRT(NVIDIA,GPU 推理加速)
│ ├── TVM / Apache TVM(跨硬件)
│ ├── Triton(OpenAI,GPU kernel 编写)
│ └── 各厂商自研编译器(昇腾 MindSpore 图编译等)
│
├──▶ 模型序列化与交换
│ └── ONNX → 各推理引擎(ONNX Runtime、TensorRT 等)
│
└──▶ 分布式执行引擎
└── 图切分 → 跨设备调度(多 GPU/多节点)
关键中间件:ONNX 的角色
ONNX(Open Neural Network Exchange)是静态图领域的”通用语言”:
- 定义了一套标准算子集(算子版本持续演进)
- 模型以 Protocol Buffer 格式序列化(
.onnx文件) - 训练框架导出 → ONNX → 推理引擎导入,是目前最广泛的跨框架部署路径
关键指标
评估静态图质量(或编译器效果)的核心指标:
| 指标 | 说明 |
|---|---|
| 首编译时间(Time-to-First-Inference) | 从图构建到首次可执行的耗时,静态图系统通常较长 |
| 推理延迟(Latency) | 单次前向传播耗时,静态图优化后的核心优势 |
| 吞吐量(Throughput) | 单位时间处理样本数,batch 越大静态图优势越明显 |
| 显存峰值(Peak Memory) | 图优化(内存重用/原位操作)可显著降低 |
| 算子融合率 | 融合算子数 / 总算子数,衡量编译器优化深度 |
| 图捕获覆盖率 | 能被成功编译的代码占比(混合模式下,未覆盖部分退回 eager) |
| 跨 shape 泛化能力 | 同一编译结果能覆盖多少种输入形状(动态 shape 支持) |
供需与市场数据
为什么静态图(编译优化)成为产业热点?
-
模型越来越大,部署成本飙升: 大语言模型推理成本是训练成本的持续消耗项。静态图编译优化(算子融合、量化、内存优化)是不改变模型就能降低推理成本的最直接手段。
-
硬件碎片化: NVIDIA GPU、AMD GPU、Google TPU、国产 NPU、移动端 NPU……硬件越来越多。静态图作为编译器的输入,是实现**“一次建图,多硬件部署”**的关键抽象层。
-
编译器人才稀缺: 能做 AI 编译器(融合编译器技术 + 深度学习 domain knowledge)的团队全球极少。掌握 MLIR、TVM、XLA 等技术的工程师成为各厂争夺的稀缺资源。
市场规模参考
静态图编译优化不是独立产品类别,而是嵌入在以下市场中:
- AI 编译器/推理优化工具链:嵌入在推理框架(TensorRT、ONNX Runtime、各厂自研引擎)中,整体推理优化市场随 AI 部署规模同步扩张。
- AI 基础设施软件:各云厂商/AI 公司均在自研或定制编译器栈,作为差异化竞争力的核心组成部分。
[未充分披露] 独立的”静态图编译”市场规模数据,因其作为技术组件嵌入更大系统中。可参考推理服务器/框架相关市场规模作为间接指标。
代表公司与资本映射
| 公司/组织 | 静态图相关布局 | 角色 |
|---|---|---|
| XLA(TPU/GPU 编译器)、MLIR(开源 IR 基础设施)、JAX(jit 编译)、TF SavedModel | 编译器基础设施主导者 | |
| NVIDIA | TensorRT(推理编译优化)、TensorRT-LLM、cuDNN 图级 API | GPU 推理优化的事实标准 |
| Meta / PyTorch | torch.compile(dynamo + Inductor)、torch.fx、ExecuTorch | 动态图→静态图融合的推动者 |
| Apache TVM 项目 | TVM / Unity(自动调优编译器,跨硬件) | 开源跨平台编译器代表 |
| OpenAI | Triton(GPU kernel DSL,被 Inductor 后端采用) | Kernel 编程新范式 |
| Microsoft | ONNX Runtime(跨平台推理引擎)、ONNX 标准联合主导 | 推理部署中间件 |
| 华为 | MindSpore 图编译(CANN 算子编译)、昇腾推理引擎 | 国产 AI 编译器自主路线 |
| 百度 | PaddlePaddle 静态图(早期定位 + PHI 算子库) | 国产框架代表 |
| Intel | OpenVINO(模型优化与推理部署)、oneDNN | 边缘推理优化 |
| Apple | Core ML(模型编译与部署)、MLX(动态+编译混合) | 端侧部署编译 |
投资逻辑
核心观点
静态图不是”一个产品”,而是 AI 基础设施中不可替代的编译优化层。
投资映射思路
-
“卖铲子”逻辑 —— 编译器/推理引擎厂商:
- NVIDIA(TensorRT 是其推理护城河的核心组件)
- 具备自研 AI 编译器能力的云厂商(Google、华为、百度等)在推理成本上有结构性优势
-
“路基”逻辑 —— 编译器基础设施:
- MLIR 已成为事实上的编译器 IR 标准,围绕 MLIR 的工具链和人才是稀缺资源
- Triton 等 kernel DSL 正在重塑 GPU 编程范式
-
“瓶颈”逻辑 —— 硬件碎片化催生编译器需求:
- 每出一款新 AI 芯片,都需要编译器适配。编译器能力直接决定硬件的实际可用性能
- 国产 AI 芯片的竞争,很大程度上是编译器生态的竞争
风险提示
- 编译器技术壁垒高但商业模式不易独立成立(通常嵌入更大产品中)
- 框架高度碎片化导致编译器生态分裂,标准统一进程不确定
- 硬件迭代速度快,编译器需持续跟进,研发投入大
常见误读纠偏
误读 1:“静态图已经被淘汰了,现在都用动态图”
纠偏: 静态图作为用户接口确实已非主流,但作为编译器目标从未离场——恰恰相反,它的重要性在增加。torch.compile 的本质就是把动态图代码捕获为静态图再编译执行。JAX 的 jit 同理。**“动态图做接口,静态图做执行”**是当前范式,不是静态图消亡。
误读 2:“静态图不能处理动态形状”
纠偏: 静态图处理动态形状确实更复杂,但并非不可能。解决方案包括:
- 形状符号化(Symbolic Shapes): 用符号变量表示未知维度,编译时生成含符号的通用内核,运行时特化
- 多版本编译: 为常见的几种 shape 各编译一个版本,运行时根据实际 shape 选择
- Dynamic Batching: 推理引擎层面将不同长度的请求 padding 到统一 shape
XLA 和 TensorRT 近年都在大幅改善动态 shape 支持。准确说法是”静态图处理动态 shape 的开销更高、更复杂”,而非”不能”。
误读 3:“TensorFlow = 静态图,PyTorch = 动态图”
纠偏: 这是 2017–2019 年的刻板印象。TF 2.x 默认 Eager + tf.function 图编译;PyTorch 2.0 的 torch.compile 本质也是图编译。两种框架都在融合两种范式,区别更多在于编译器实现路径和社区生态,而非”静态 vs 动态”的二元对立。
误读 4:“静态图一定比动态图快”
纠偏: 静态图提供了优化的可能性,但不自动等于更快。一张没有经过任何优化 Pass 的静态图,执行效率可能和动态图相当甚至更低(序列化/反序列化开销)。真正的性能优势来自于编译器优化(融合、调度、内存规划)。另外,如果模型很小(如简单 MLP),动态图的调度开销可以忽略,静态图的优势不显著。静态图的性能优势随模型复杂度和 batch size 增大而增大。
学习路径
入门(理解概念)
- PyTorch 官方文档
torch.compile教程 —— 从动态图到编译的体验 - TensorFlow
tf.function指南 —— 理解 AutoGraph 如何将 Python 转为图 - 动手:用 Netron 工具可视化一个 ONNX 模型,观察静态图的节点与边
进阶(理解优化)
- 学习 TVM 教程(TVM 文档中的 “Tensor Operations” 和 “Optimizing Operators” 章节)
- 阅读 XLA 概述文档 —— 了解 Google 的图编译优化 Pass
- 研究 TensorRT 的优化流程(层融合、精度校准、Kernel Auto-tuning)
深入(理解编译器)
- 研读 MLIR 概念论文 “MLIR: A Compiler Infrastructure for the End of Moore’s Law”(Chris Lattner et al.)
- 阅读 PyTorch 2.0 架构博客(dynamo → AOTAutograd → Inductor 的 pipeline)
- 研究陈天奇 TVM 论文 “TVM: An Automated End-to-End Optimizing Compiler for Deep Learning”
实践
- 将一个 PyTorch 模型导出为 ONNX,用 ONNX Runtime 对比优化前后的推理延迟
- 用
torch.compile编译一个 Transformer 模型,观察 compilation time vs inference speedup 的权衡 - 尝试在 Triton 中编写一个自定义融合算子,理解 kernel 编译层面的优化
一句话总结
静态图是深度学习从”能跑”到”跑得快”的技术基石——用户接口层面它已让位于动态图的灵活性,但在编译器底层,它作为全局优化的唯一载体,正成为 AI 基础设施中最关键的隐性竞争力。
延伸阅读与来源
| 资源 | 类型 | 说明 |
|---|---|---|
| TVM 论文:TVM: An Automated End-to-End Optimizing Compiler for Deep Learning | 学术论文 | AI 编译器领域的奠基性工作 |
| MLIR 论文:MLIR: Scaling Compiler Infrastructure for Domain Specific Computation | 学术论文 | 现代 AI 编译器 IR 基础设施 |
| PyTorch 2.0 官方博客 / Architecture Overview | 官方文档 | 理解 dynamo + Inductor 架构 |
| TensorFlow Graph 指南 | 官方文档 | 经典静态图系统的设计思路 |
| NVIDIA TensorRT Developer Guide | 官方文档 | 推理编译优化的工业实践 |
| ONNX 官方文档(onnx.ai) | 标准文档 | 静态图互操作标准 |
| Deep Learning Compilation (陈天奇 talks / TVM tutorials) | 教程/演讲 | 编译器技术的直觉建立 |
| Triton 文档(triton-lang.org) | 官方文档 | GPU kernel 编程新范式 |
注:本文技术描述基于深度学习编译领域的公开论文、框架文档与社区共识。具体框架版本的性能数据因硬件、模型、配置差异较大,建议以实际 benchmark 为准。市场数据方面,AI 编译器尚无独立市场研究,相关判断基于产业观察定性分析。