Roofline 分析:算清楚一个 kernel 到底该多快
Roofline 分析:算清楚一个 kernel 到底该多快
前情说明:技术深度 D2。这是《读 JAX Scaling Book》系列第 1 篇。JAX Scaling Book 是 Google DeepMind 团队写的一本非常硬的教程,讲清楚 Transformer 训练/推理在大规模硬件上到底怎么跑到理论最优。这本书的第一章 Roofline 是所有后续章节的地基——你不理解 roofline,就无法回答"这个 kernel 为什么慢"、"我该切哪个维度"、"batch 应该开多大"这类问题。 我这一篇是中文深度重构:保留原书的公式和推导(讲得极清楚,我不重复造轮子),加上 GPU 侧数字(原书主要用 TPU,你博客读者主要用 GPU)、推理场景 roofline(decode 阶段的 memory-bound 天堂)、量化对临界点的影响、以及面试锚点。
建议阅读姿态:先读 JAX 原书 Ch1 看图和公式(15 分钟),再回来看我这篇的中文重构和补充(20 分钟)。两篇加起来对 roofline 应该有 90% 的直觉。
一、一个 50ms 的 kernel 到底在忙什么
先问一个极其简单的问题:为什么一个 kernel 跑 50ms 而不是 50s 或 5ms?
任何 kernel 的时间开销归根到底就三件事:
一个 kernel 的时间构成
┌──────────────────────────────────────────────────────┐
│ │
│ Computation(计算) │
│ ├─ 做 matmul 需要多少 FLOPs │
│ ├─ 加速器峰值 FLOPs/s 是多少 │
│ └─ T_math = FLOPs / (Peak FLOPs/s) │
│ │
│ ───────────────────────────────────────────────── │
│ │
│ Communication within chip(片内通信 / HBM ↔ 计算单元) │
│ ├─ 从 HBM 读多少 bytes 到 SRAM │
│ ├─ HBM 带宽是多少 │
│ └─ T_hbm = Bytes / (HBM Bandwidth) │
│ │
│ ───────────────────────────────────────────────── │
│ │
│ Communication between chips(片间通信 / NVLink/IB) │
│ ├─ 传多少 bytes 到别的卡 │
│ ├─ NVLink / IB 带宽是多少 │
│ └─ T_net = Bytes / (Network Bandwidth) │
│ │
└──────────────────────────────────────────────────────┘
核心洞察:这三件事可以并行——计算的同时可以从 HBM 拿数据、同时可以跨卡传数据。所以 kernel 的最短时间是三者的 max,不是 sum:
T_lower = max(T_math, T_hbm, T_net) ← 完全 overlap 时
T_upper = T_math + T_hbm + T_net ← 完全串行时
实际时间在这两者之间。工程优化的目标就是尽量让 T_lower 成立——通过 kernel fusion、异步传输、CUDA stream overlap 等手段把三件事并行起来。
一旦达到 overlap,那件耗时最长的成为瓶颈——其他两件"免费",因为它们藏在这一件的时间里。所以性能分析的第一步永远是:这三个数谁最大?
二、Arithmetic Intensity:判断谁是瓶颈的关键指标
三个时间比大小有个巧妙的等价写法。以 T_math vs T_hbm 为例:
T_math > T_hbm
⇔ FLOPs / (Peak FLOPs/s) > Bytes / (HBM BW)
⇔ FLOPs / Bytes > (Peak FLOPs/s) / (HBM BW)
───────────── ──────────────
算法的强度 硬件的强度
左边只和算法有关(这个 kernel 做多少运算、传多少字节)。右边只和硬件有关(卡的峰值算力除以带宽)。
这就是 Arithmetic Intensity(算术强度) 的核心定义:
Arithmetic Intensity = FLOPs / Bytes 单位: FLOPs/byte
"这个 kernel 每传 1 字节数据,能做多少次浮点运算?"
判断规则(背下来):
算法 Intensity > 硬件 Intensity → compute-bound(算得慢,理论上榨干 FLOPs)
算法 Intensity < 硬件 Intensity → memory-bound(带宽慢,FLOPs 有富余)
算法 Intensity = 硬件 Intensity → 完美平衡(罕见)
硬件的 Intensity 就是临界点——低于这个值就 memory-bound,高于就 compute-bound。这个临界点在书里叫 Critical Intensity 或 Ridge Point。
2.1 主流硬件的 Critical Intensity
| 硬件 | Peak FLOPs/s (bf16) | HBM BW | Critical Intensity |
|---|---|---|---|
| H100 SXM5 | 989 TFLOPs/s | 3.35 TB/s | ~295 FLOPs/byte |
| H200 | 989 TFLOPs/s | 4.8 TB/s | ~206 |
| B200 | 2250 TFLOPs/s | 8.0 TB/s | ~281 |
| TPU v5e | 197 TFLOPs/s | 0.82 TB/s | 240 |
| TPU v6e (Trillium) | 910 TFLOPs/s | 1.6 TB/s | ~570 |
| A100 80GB | 312 TFLOPs/s | 2.0 TB/s | ~156 |
几个关键观察:
- 临界点普遍在 200-300 FLOPs/byte 范围——这是"一次矩阵乘想吃满硬件"的最低门槛
- B200 / TPU v6e 临界点更高——算力涨得比带宽快,硬件越新对 arithmetic intensity 的要求越苛刻
- H200 比 H100 好——涨了带宽没涨算力,临界点降到 206,更容易 compute-bound
- 注意 FP8/FP4 会翻倍/四倍算力——临界点也随之升高
面试锚点:H100 的 critical intensity 是 ~295 FLOPs/byte(不带稀疏的真实值)。低于这个,你的 kernel 就在浪费 FLOPs 等数据。
三、Matmul 的黄金定律:Batch > 240 才 compute-bound
现在把 roofline 应用到最重要的 kernel:矩阵乘。
3.1 从形状到 Intensity
考虑一个标准的 X · Y = Z matmul:
X ∈ bf16[B, D] B: batch × seq (总 token 数)
Y ∈ bf16[D, F] D: hidden dim (~4096-8192)
Z ∈ bf16[B, F] F: FFN dim (~11000-28000)
FLOPs = 2 * B * D * F (BDF 次乘法 + BDF 次加法)
Bytes = 2*(BD + DF + BF) (读 X + 读 Y + 写 Z, bf16 每个数 2 字节)
Intensity = 2BDF / 2(BD + DF + BF)
= BDF / (BD + DF + BF)
分母有三项,看谁 dominant:
Transformer 典型场景:
B ~ 数百到几千 tokens
D ~ 4096-8192
F ~ 11000-28000
当 B << D, F 时:
BD, BF 都很小 → 分母 ≈ DF
Intensity ≈ BDF / DF = B ← 就是 B!
当 B ~ D, F 时:
三项都不能忽略 → Intensity 复杂但仍是 O(B)
关键结论:Matmul 的算术强度 ≈ B(token 数)。
3.2 240 tokens 定律
拿 TPU v5e 举例(critical = 240):
Intensity(matmul) > Intensity(TPU v5e)
⇔ B > 240
只要每卡的 token 数超过 240,matmul 就是 compute-bound!
这就是 JAX Scaling Book 反复强调的黄金定律:
┌──────────────────────────────────────────────────────┐
│ Matmul 想 compute-bound? │
│ │
│ per-chip batch (in tokens) > ~240 │
│ │
│ TPU v5e: 240 | TPU v6e: ~570 | H100: ~295 │
└──────────────────────────────────────────────────────┘
注意"per-chip"这个词——如果你做 TP=8 把权重切了,每卡还是要过 240 tokens 才 compute-bound。
注意"token"这个词——不是 "sequence"。如果 batch=512 seq × 4096 tokens/seq = 2M tokens,TP=8 每卡有 256K tokens,远超 240,稳稳 compute-bound。但decode 阶段每步只有 batch × 1 token——如果 batch=16,每卡 2 tokens,永远 memory-bound。
3.3 推理 decode 为什么必然 memory-bound
这是 JAX 原书没深入讲的地方,我补一下——因为这对推理工程师至关重要。
Decode 阶段每步的 matmul:
Prefill 阶段: X ∈ bf16[B*S, D] → 长向量,S=8192 时 tokens 很多
Decode 阶段: X ∈ bf16[B*1, D] → 每步只有 batch 个 token
以 B=16 为例:
Prefill: 每卡 16*8192 = 131K tokens → intensity 131K → compute-bound
Decode: 每卡 16*1 = 16 tokens → intensity 16 → memory-bound!
Decode intensity 只有 16 vs 硬件临界 295,也就是只用了 5% 的 FLOPs!
Decode 时的浪费
┌────────────────────────────────┐
│ │
FLOPs │ █████████████████████████████ │ 可用峰值
│ █ │
│ █ 实际用到 │
│ █ │
│ █ 剩下的 95% 都在等 HBM 读权重! │
│ █ │
└────────────────────────────────┘
5% 剩下 95%
算力用到 浪费掉
瓶颈: 每次 forward 都要把 70B 参数(140 GB bf16)从 HBM 拉一遍
H100 HBM 3.35 TB/s → 140/3.35 = 42ms
这就是每 token 42ms 的物理下界(decode TPOT)
这就是为什么推理侧的所有优化几乎都在"降低 memory 压力":
- PagedAttention 省 KV Cache 显存 → 允许更大 batch → 更高 intensity
- Continuous Batching 把不同请求的 decode 拼一起 → batch 变大 → 更接近 compute-bound
- Speculative Decoding 让每步预测多个 token → 有效 batch 放大
- 量化(INT4/FP8) → HBM 带宽压力减半到 1/4
理解 roofline 后,所有推理优化的动机瞬间清晰:它们都在把 decode 从 memory-bound 拽向 compute-bound。
3.4 一张图记住 Roofline
Roofline Plot (log-log)
FLOPs/s
(吞吐)
▲
│ ┌────────────────
│ ╱ compute-bound
│ ╱ (用满 FLOPs)
│ peak ────────────────
│ ╱ ↑
│ ╱ 完全 compute-bound
│ memory ╱ (绿区)
│ bound ↗ ╱
│ (红区) ╱ ╱ ← ridge point / critical intensity
│ ╱ ╱
│ ╱ ╱
│ ╱ ╱
│ ╱╱
│ ╱╱
│ ╱
└────────────────────────────────────►
Arithmetic Intensity (FLOPs/byte)
↑ ↑
decode 在这里 prefill 在这里
(intensity ~10-50) (intensity 数千+)
远远 memory-bound 稳稳 compute-bound
红区(左边):你的算法 intensity 太低,被带宽拖着。加更多算力也没用,只能加带宽或提高 intensity(比如提升 batch)。
绿区(右边):你已经用满 FLOPs 了。加带宽也没用,只能等硬件下一代更强的算力。
Ridge Point(拐点):硬件的 critical intensity,就是 240 / 295 那个数字。
四、量化如何改变临界点
原书简单提了 int8,我系统展开——这是面试超高频问题。
4.1 全量化(权重 + 激活都低精度)
bf16 matmul: Intensity ≈ B, critical = Peak_bf16 / HBM_BW = 295
int8 matmul: Intensity ≈ B, critical = Peak_int8 / HBM_BW = 590? NO!
为什么不是简单翻倍:
int8 权重占字节数少一半 (bytes 减半)
int8 FLOPs 峰值翻倍 (H100 fp8 是 bf16 的 2x)
Intensity = FLOPs / Bytes
= (2*B*D*F) / (BD + DF + BF) # FLOPs 不变
Bytes 从 2*(BD+DF+BF) 变成 (BD+DF+BF) # 减半
所以真实 Intensity 变成 2B (加倍!)
Critical = 2 * Peak_bf16 / HBM_BW = 590
条件 2B > 590 ⇔ B > 295 (和 bf16 一样!)
关键洞察:全量化(同精度权重+激活+计算)不改变临界 batch size。因为算力和带宽压力同比例下降。
好处在哪:同样 batch 下每步跑得快 2 倍(因为 T_math 和 T_hbm 都减半)。
4.2 混合量化(权重 int8,激活 bf16)
这是实际部署最常见的方案(INT8/INT4 weight-only quantization)。
权重 int8: 1 byte/param
激活/计算 bf16: 2 bytes/activation, bf16 FLOPs
X ∈ bf16[B, D] → 需要 2BD bytes
Y ∈ int8[D, F] → 需要 DF bytes (关键: 权重减半!)
Z ∈ bf16[B, F] → 输出 2BF bytes
FLOPs = 2BDF (bf16 峰值)
假设 B << D,F:
Intensity ≈ 2BDF / DF = 2B ← 加倍了!
Critical: 2B > 295 ⇔ B > 148
临界 batch 从 240 掉到 120 附近!
这就是 INT4/INT8 weight-only 量化的核心价值——推理 decode 阶段本来 batch 小 memory-bound 严重,量化后临界点砍半,同样 batch 能利用更多算力。
4.3 各种量化方案对比
量化对 Roofline 的影响 (H100)
┌──────────────────────────────────────────────────────┐
│ 方案 │ Bytes/param │ Peak FLOPs │ Critical B │
├──────────────────┼──────────────┼────────────┼────────────┤
│ bf16 全精度 │ 2 │ 989 T │ 295 │
│ int8 weight-only │ 1 │ 989 T │ ~150 │
│ int4 weight-only │ 0.5 │ 989 T │ ~75 │
│ int8 全量化 │ 1 │ 1979 T │ 295 │
│ fp8 全精度 │ 1 │ 1979 T │ 295 │
│ fp4 全精度 │ 0.5 │ 3958 T │ 295 │
└──────────────────────────────────────────────────────┘
── Weight-only 量化 ──
→ 带宽压力小, FLOPs 峰值不变 → Critical B ↓ (对小 batch 好)
→ 适合 decode 场景
── 全精度量化 ──
→ 带宽/算力同比例下降 → Critical B 不变
→ 适合 prefill 场景(本来就 compute-bound)
面试锚点:为什么 INT4 weight-only 在 decode 阶段收益特别大?因为它把权重带宽压力砍到 1/4,同时算力峰值不变——decode 本来 memory-bound,砍带宽压力直接砍延迟;而算力峰值不变意味着 batch 稍微一大就 compute-bound。这是 llama.cpp 单卡推理经常用 INT4 的原因。
五、Case Study:Attention Decode 为什么必然 memory-bound
这是理解推理性能最重要的一个 case。用 roofline 分析清楚。
5.1 场景设定
一个 request,正在 decode 第 4097 个 token(KV cache 已有 4096 tokens):
Batch = 1
Head 数 (KV) = 8 (GQA)
Head dim = 128
KV Cache 大小 = 2 (K,V) × 8 (heads) × 4096 (S) × 128 (D_head) × 2 (bf16)
= 16 MB per layer
Q 大小 = 1 (token) × 64 (Q heads) × 128 × 2 = 16 KB
5.2 Attention FLOPs 和 Bytes
1. QK^T: Q · K^T
Q shape: [64, 128] → 但 GQA 8 KV heads → 每 KV head 对应 8 Q heads
K shape: [8, 4096, 128]
实际是 batch=64, matmul([1, 128] × [128, 4096]) 每次
总 FLOPs = 64 × 2 × 1 × 128 × 4096 = 67 M FLOPs
2. softmax:
忽略 (相对很小)
3. attn · V:
总 FLOPs = 64 × 2 × 1 × 4096 × 128 = 67 M FLOPs
4. 合计:
Total FLOPs ≈ 134 M FLOPs
Bytes:
加载 Q : 16 KB
加载 K,V : 16 MB
输出 : 16 KB (小)
Total Bytes ≈ 16 MB
5.3 Roofline 判断
Intensity = 134M / 16M ≈ 8 FLOPs/byte
H100 critical: 295 FLOPs/byte
8 << 295 → 严重 memory-bound!
T_hbm = 16 MB / 3.35 TB/s = 4.8 μs (一层)
T_math = 134 M / 989 T = 0.14 μs
T_hbm / T_math = 35x ← 计算单元 97% 时间在等 HBM!
80 层 decoder = 80 × 4.8 μs ≈ 380 μs / token / layer
加上 MLP 部分 ≈ 15-25 ms/token TPOT
核心洞察:每 decode 一个 token 都要把整个 KV Cache 从 HBM 拉一遍。KV Cache 越大(长上下文),memory 压力越大,TPOT 越差。
5.4 优化方向
理解 roofline 后,优化方向都变清晰:
Attention Decode 优化路径
瓶颈:Intensity 太低(~8)
原因:每 token 要 load 全部 KV Cache
────────────────────────────────────────────
优化 1: 提高 batch
Batch=1 时 intensity ~8
Batch=32 时 intensity ~250 → 接近 compute-bound!
→ Continuous batching 的核心价值
优化 2: 降低 KV Cache 精度
bf16 → fp8: KV Cache 减半 → intensity 翻倍
→ SGLang / vLLM 的 fp8 KV Cache 支持
优化 3: 减小 KV Cache 尺寸
MHA → GQA → MQA: KV heads 从 64 → 8 → 1
→ Llama 3, GPT-4 全部用 GQA
优化 4: FlashAttention
减少 HBM 访问次数(tiling)
→ 减少 Bytes,不减 FLOPs → intensity 提升
优化 5: Speculative Decoding
每步预测 k 个 token → batch 有效放大 k 倍
→ intensity 涨 k 倍
所有推理优化本质都在做同一件事:把 attention decode 从 memory-bound 拉向 compute-bound。
六、网络通信 Roofline:多卡时 D 才是关键
原书讲多卡 matmul 通信 roofline 时给了一个反直觉的结论——多卡场景临界条件不再是 B,而是 D。这个必须讲清楚。
6.1 场景:D 维度切分的两卡 matmul
X ∈ bf16[B, D] D 维度切分到 2 张卡
Y ∈ bf16[D, F] D 维度切分到 2 张卡
GPU 0: X[:, :D/2] · Y[:D/2, :] = Z_0 (partial sum, [B, F])
GPU 1: X[:, D/2:] · Y[D/2:, :] = Z_1 (partial sum, [B, F])
然后互换 partial sum + 相加:
最终 Z = Z_0 + Z_1
T_math (each chip) = BDF / Peak_FLOPs = BDF / 989 TFLOPs
T_net = 2BF (bf16) / NVLink_BW
= 2BF / 900 GB/s (H100 NVLink Gen4)
compute-bound 条件:
T_math > T_net
⇔ BDF/989T > 2BF/900G
⇔ D > 2 * 989T / 900G = 2197
⇔ D > ~2200
关键结论:网络通信 roofline 的临界条件是 D,不是 B!
6.2 直觉解释
为什么单卡是 B,多卡是 D?
单卡: Intensity = FLOPs / HBM_Bytes
计算量 ∝ BDF
内存量 ≈ DF (权重, 支配)
比值 ≈ B ← 所以 B 是关键
多卡: Intensity = FLOPs / Network_Bytes
计算量 ∝ BDF (每卡 BDF/N)
通信量 ≈ BF (partial sum 交换)
比值 ≈ D ← 所以 D 是关键!
直觉:多卡通信传的是 activation(大小 BF),不是 weight(大小 DF)。所以 batch 大时通信压力也大,反而是 D 越大越"值得通信"。
6.3 什么时候能承受 TP=8
用同样方法算 TP=8 的临界条件(Ring AllReduce 每卡收发 2BF):
H100 NVLink Gen4: 900 GB/s
每层 4 次 AllReduce(fwd 2 + bwd 2)
Llama 70B: D=8192, F=28672
BF 单次通信: 1 * 8192 * 2 = 16 KB (小 batch)
128 * 8192 * 2 = 2 MB (batch 128)
T_net per AllReduce = 2BF / 900G
matmul BDF FLOPs / Peak = BDF / 989T
compute-bound: BDF/989T > 2BF/900G ⇔ D > 2200
Llama 70B D=8192 >> 2200 ✓
→ 稳稳 compute-bound
面试锚点:D=8192 时 TP=8 内 matmul 完全 compute-bound。这就是为什么 TP 在 Transformer 内工作良好——D 天然大。但如果 D 只有几百(小模型),TP 就会 network-bound——这就是为什么小模型不用 TP。
七、面试锚点
Q1: 什么是 arithmetic intensity?为什么它决定了 compute-bound vs memory-bound?
A: Arithmetic intensity = FLOPs / Bytes,单位 FLOPs/byte,衡量"每传 1 字节数据能做多少浮点运算"。当算法的 intensity 高于硬件的 critical intensity(H100 ≈ 295)时,compute-bound——算力吃满,带宽有富余;低于则 memory-bound——算力浪费在等数据。这决定了优化方向:memory-bound 要么增大 batch 要么砍带宽压力(量化、fusion),compute-bound 要么等下一代硬件要么改精度。
Q2: H100 的 critical arithmetic intensity 是多少?怎么算出来的?
A: ~295 FLOPs/byte。用 Peak bf16 FLOPs/s (989 TFLOPs/s,不含 sparsity 的真实值) 除以 HBM 带宽 (3.35 TB/s) = 295。注意 NVIDIA spec sheet 上写的 1979 TFLOPs 是"带 sparsity"的营销数字,真实值是 989。
Q3: Matmul 什么时候是 compute-bound?
A: 当 per-chip batch size (in tokens) > critical intensity 时。TPU v5e 需要 > 240,H100 需要 > 295。注意是 tokens 数不是 sequence 数——batch=16 seq × 8192 tokens/seq = 128K tokens,远超临界。注意是 per-chip——TP=8 时每卡还是要过 295。
Q4: 为什么推理 decode 阶段几乎必然 memory-bound?
A: Decode 每步只算 1 token/sequence 的 forward。batch=16 时每卡只有 16 tokens,intensity ≈ 16,远低于 H100 的 295。GPU 时间几乎全在等 HBM 把 70B 参数拉一遍。这是 KV Cache、Continuous Batching、Speculative Decoding、量化等一系列推理优化的动机——都在把 decode 从 memory-bound 拉向 compute-bound。
Q5: INT4 weight-only 量化为什么能显著加速 decode?
A: Decode 是 memory-bound,瓶颈在 HBM 读权重。INT4 每个参数 0.5 byte,比 bf16 少 4 倍,HBM 压力砍到 1/4,同时 FLOPs 用 bf16 计算峰值不变。结果是 critical batch 从 295 降到 ~75,同时每步 T_hbm 降 4 倍。llama.cpp 单卡推理常用 INT4 就是这个道理。注意 prefill 收益小——prefill 本来 compute-bound,量化不改临界。
Q6: 为什么多卡通信 roofline 的临界条件是 D 而不是 B?
A: 单卡 roofline: intensity = FLOPs / HBM_Bytes ≈ BDF/DF = B,B 是关键。多卡通信传的是 activation(BF)不是 weight(DF),intensity = FLOPs / Network_Bytes ≈ BDF/BF = D。所以 D 越大越"值得通信",D 小的场景(小模型)不适合 TP。Llama 70B D=8192 完全承受 TP=8,但 D=1024 的小模型就会 network-bound。
Q7(进阶): 你怎么判断一个 kernel 该往哪个方向优化?
A: 三步走: (1) 算出算法 intensity = FLOPs/Bytes; (2) 和硬件 critical intensity 比较; (3) memory-bound 就减 bytes(fusion / 量化 / 更大 batch / KV Cache 优化),compute-bound 就减 FLOPs(更好算法、更低精度、稀疏化)。用 profiler(Nsight/JAX profiler)看 SM occupancy 和 memory throughput 交叉验证——SM 高 memory 低 = compute-bound,反之亦然。
Q8(进阶): FlashAttention 提升 attention 性能,是提高了 intensity 还是别的?
A: 提高了 intensity。标准 attention 需要把 [N, N] 的中间矩阵完整写回 HBM 再读回来,bytes 巨大。FlashAttention 用 tiling + online softmax 让整个 attention 在 SRAM 里 fused 完成,FLOPs 不变,bytes 大幅下降,intensity 从"远低于 critical"提升到"接近 critical"。这就是 FlashAttention 又快又省显存的根本原因——不是新算法,是 IO-aware 的实现。
Q9(进阶): Roofline 分析什么时候会失效?
A: 几个常见场景: (1) 计算和通信 overlap 不完美——理论 T_lower = max,实际接近 T_upper = sum; (2) Kernel launch overhead 主导——小 kernel(比如 element-wise op)真实时间被 CUDA API 开销吃了,roofline 完全不适用; (3) 算法不规则——有 branching / dynamic shape / sparse pattern,实际 FLOPs 难精确算; (4) VMEM/L2 缓存效应——tile 大小合适时会有额外加速,roofline 无法捕捉。Roofline 是下界估计,永远比实际好——用它做 sanity check 和优化方向,不用它做绝对预测。
一句话记住这一篇
Roofline 分析的本质:算算法的 FLOPs/Bytes,和硬件的 Peak_FLOPs/BW 比大小——低于就 memory-bound(推理 decode 常态),高于就 compute-bound(训练常态)。Matmul 有个黄金法则:per-chip batch > 240(TPU v5e)/ 295(H100)就 compute-bound。所有推理优化都是把 memory-bound 拉向 compute-bound——大 batch、量化、KV Cache 优化、Speculative Decoding,本质都在提高 intensity 或降低 bytes。
系列下一篇预告:《Sharded Matmul: 分片矩阵乘的通用记号》——JAX Scaling Book 独门武器 [BX, DY] 记号,把 6 种并行统一到"哪个维度切给哪个 mesh axis"这一件事上。理解了这一套记号,分布式 Transformer 的所有变体都变成"填空题"。
配套阅读: JAX Scaling Book Ch1 是原书章节,极硬,推荐先读英文原文再看这篇中文重构。相关文章: 分布式 Transformer 深度解析、FlashAttention 三代演进、MoE 推理完整机制。

Written by
Zoe
AI Infra Engineer · LLM Serving · GPU/RDMA · 造工具的偏执狂