对应 Maps to:Stanford CS349E / EE339 Efficient ML Inference at Scale(Autumn 2026),原课第 9 次课(10/20 · Project Pitches)和第 18–19 次课(12/1、12/3 · Project Presentations)。这三次课是学生的项目提案和展示,没有讲授内容;原课评分里项目占 40%。 依据说明:本讲是我写的总结:§1 把前 15 讲串起来,§2 用前面各讲的模块搭了一个端到端的部署规划器,§3 讲做项目的方法(借用了第 14 讲、本仓库 CS349D 第 17 讲的评测方法),§4 列开放问题。原课的第 13 次课(客座讲座)没有公开内容,不覆盖。不代表课堂上实际讲了什么。 配套代码 Code:
code/lecture16/(numpy;一个模块 + 4 个脚本,最长的约 25 秒) 先修:全部前 15 讲。规划器直接用到 第 1 讲(账本)、第 3 讲(精度)、第 4 讲(张量并行)、第 5 讲(服务模拟器)、第 6 讲(投机解码)、第 12 讲(内核个数)。 预计阅读时间:2–2.5 小时(含运行代码)
0. 本讲导航 · How to read this lecture
0.1 学习目标 Learning goals
学完这一讲,你应该能够:
- 把一个 token 的生成拆成”读权重 / 读 KV / 计算 / 通信 / 内核启动 / 排队”几项,说出每一项归哪一讲管、对策是什么。
- 解释”优化阶梯”上每一级的收益从哪里来,区分哪些技术改善单个用户的延迟、哪些改善吞吐和成本。
- 给定模型、负载、SLO 和价格,用”解析模型筛选 + 模拟验证”选出部署方案(GPU、精度、张量并行度、共置还是解耦、几块 GPU),并说出解析模型会在哪里出错。
- 设计一个推理系统的课程项目:选题、基线、测量方法、模型与实测的关系、消融、写报告。
- 说出这个领域在 2026 年的几个开放问题。
0.2 本讲地图 Map
§1 全栈复盘:一个 token 的账与优化阶梯 ← 代码 01
§2 端到端的部署规划器 ← 代码 02、03、04
§3 怎样做一个推理系统项目
§4 开放问题
§5–9 小结、常见误区、练习(含答案)、延伸阅读、结语
0.3 本讲的代码
planner.py 有三部分:
- A. 一个 token 的全栈账:
tp_step把张量并行下一次前向的时间拆成读权重、读 KV、计算、all-reduce、内核启动(用第 1、4 讲的账本,P5 的 α–β 公式,第 12 讲graph_lab数出来的每层内核数);ladder_point算优化阶梯上的一级(含第 6 讲的投机解码)。 - B. 部署规划:
Scenario(模型、提示 / 输出长度、TTFT / TPOT 的 P90 SLO、流量);decode_capacity、prefill_capacity、colocated_capacity(解析模型);plan枚举 {H100, H200, B200} × {BF16, FP8} × 张量并行 {1, 2, 4, 8} × {共置, 解耦},按每百万输出 token 的成本排序。 - C. 验证:
simulate用第 5 讲的离散事件模拟器跑一个方案;repair不达标就加实例;verified_best把两步串起来。
0.4 记号 Notation
| 符号 | 含义 |
|---|---|
| TTFT、TPOT | 第一个 token 的时间、之后每个 token 的间隔;SLO 都按 P90 |
| 共置 colocated | prefill 和 decode 在同一组 GPU 上,用分块 prefill 混在一起跑(第 5 讲) |
| 解耦 disaggregated | prefill 实例和 decode 实例分开,KV 通过网络搬(第 5 讲) |
| TP | 一个实例用 块 GPU 做张量并行(第 4 讲) |
| “按整数台”的成本 | 实际要租的 GPU 数 × 价格 / 产出的 token |
| “按效率”的成本 | 如果 GPU 能按小数台租:每块 GPU 的吞吐决定的成本 |
1. 全栈复盘:一个 token 的账 · The full-stack ledger
1.1 五条主线,最后一次
整门课一直在重复五句话(SYLLABUS §0.3):
- 能量和带宽,而不是算力,是推理的主要约束。45 nm 下读 8 字节 DRAM 是一次 32 位浮点乘法的 351–703 倍(第 1 讲);性能 = 能效 × 功率。
- roofline 是贯穿全课的尺子:H100 BF16 的屋脊点约 295 FLOP/字节;decode 注意力的强度就是 GQA 的组大小(第 1、2 讲),永远到不了屋脊点。
- LLM 推理的两种”性格”:prefill 吃算力,decode 吃带宽和容量;KV cache 是批处理摊不薄的部分。
- 同一个瓶颈可以在任何一层去攻:模型(GQA、MoE)、精度(FP8、NVFP4)、服务系统(批处理、分页、解耦)、硬件(HBM、SRAM、Tensor Core)、内核(分块、FlashAttention、megakernel)、编译器(融合、调度、自动调优)——代价各不相同。
- 异构与解耦:一个请求的不同阶段适合不同的硬件和并行方式(第 5 讲;本讲 §2.4 会在一个极端的 SLO 下再看到它)。
1.2 一个 token 的账
Llama-3.1-70B 在 8 块 H100 上(张量并行 8、上下文 4096)decode 一步(01 演示 1):
| 配置 | 读权重 | 读 KV | 计算 | 通信 | 内核启动 | 一步 |
|---|---|---|---|---|---|---|
| 批 1,eager | 6.48 ms | 0.06 ms | 0.03 ms | 0.98 ms | 8.64 ms | 16.16 ms |
| 批 1,融合 + CUDA Graphs | 6.48 | 0.06 | 0.03 | 0.98 | 0.96 | 8.48 |
| 批 64,融合 + CUDA Graphs | 6.48 | 4.01 | 2.02 | 2.08 | 0.96 | 13.53 |
每一项归哪一讲管:
| 项 | 由什么决定 | 对策(讲次) |
|---|---|---|
| 读权重 | 参数量 × 每个数的字节 / 带宽 | 低精度(3)、批处理摊薄(1、6)、更大带宽的硬件(8) |
| 读 KV | 批 × 上下文 × 每 token 的 KV | GQA / MLA(2)、KV 量化(3)、分页与前缀缓存(7) |
| 计算 | FLOPs / 峰值 | Tensor Core(8、10)、FlashAttention(11)、低精度的算力(3) |
| 通信 | 每层 2 次 all-reduce 的 α–β | 切分方式(4、P5)、计算和通信重叠 |
| 内核启动 | 层数 × 每层内核数 × 每个的开销 | 融合(12)、CUDA Graphs / megakernel(11) |
| 排队与干扰 | 到达过程、prefill / decode 混跑 | 连续批处理(6)、分块 prefill / 解耦(5)、KV 调度(7、15) |
三个容易忽略的事实:
- 批 1 的 eager 里,内核启动比读权重还多:80 层 × 27 个内核 × 4 µs = 8.64 ms(每层的内核数是第 12 讲的
graph_lab数出来的:eager 27 个、融合 12 个)。这就是 megakernel(第 11 讲)、融合和 CUDA Graphs(第 12 讲)要解决的问题。 - 张量并行的通信每步约 1–2 ms:批 1 时消息很小,几乎全是每次 all-reduce 的延迟 α × 160 次;批大了带宽项才上来(第 4 讲)。
- prefill 是另一副面孔(演示 3):一次 2,048 个 token 的 prefill,计算 61.13 ms 远大于读权重 6.48 ms(计算受限),通信也涨到 25.36 ms。
1.3 优化阶梯
从”最朴素的部署”出发,逐个加上各讲的技术(演示 2;每块 H100 按 2 美元 / 小时、700 W 算):
| 部署 | 每个用户 token/s | 每块 GPU token/s | 美元 / 百万 token | 焦耳 / token |
|---|---|---|---|---|
| 0. 朴素:批 1、BF16、eager | 62 | 8 | 71.84 | 90.5 |
| 1. + CUDA Graphs(11、12) | 103 | 13 | 43.04 | 54.2 |
| 2. + 融合(12) | 118 | 15 | 37.70 | 47.5 |
| 3. + 连续批处理到批 64(6、7) | 74 | 591 | 0.94 | 1.18 |
| 4. + FP8 权重和 KV(3) | 121 | 966 | 0.58 | 0.72 |
| 5. + 投机解码 γ = 4、α = 0.8(6) | 158 | 1,261 | 0.44 | 0.56 |
| (对照)批 1 + FP8 + 投机解码 | 342 | 43 | 12.98 | 16.4 |
- 从第 0 级到第 5 级,每块 GPU 的吞吐提高 163 倍。最大的一步是批处理:decode 受限于读权重,64 个用户分摊同一次读取——第 1 讲 roofline 的直接推论。
- 前两级(CUDA Graphs、融合)主要改善单个用户的延迟;批处理提高吞吐,但每个用户的速度反而下降(每步多读 KV)——延迟和吞吐的取舍。
- FP8 同时减少读权重和读 KV 的字节,把单用户速度补回来;投机解码在批 64 时仍有收益,但远不如批 1 时(对照行):批越大,验证 γ+1 个 token 越接近计算受限(第 6 讲 §5)。
- 这条阶梯上的每一级都只用了前面某一讲的模型。真实系统里它们会相互影响(显存共享、投机解码和批处理争算力),所以最后一步总要端到端地测,或至少端到端地模拟(§2.3)。
2. 端到端的部署规划器 · An end-to-end deployment planner
代码:
02_deployment_planner.py、03_verify_with_simulation.py、04_what_if.py
2.1 问题
一个推理服务上线前要回答:**用哪种 GPU、BF16 还是 FP8、张量并行几路、prefill 和 decode 放在一起还是分开、要几块 GPU?**目标是在满足 SLO 的前提下让每百万输出 token 的成本最低。四个场景:
| 场景 | 模型 | 提示 / 输出(平均,对数正态) | SLO(P90) | 流量 |
|---|---|---|---|---|
| 聊天 | Llama-3.1-70B | 1000 / 250 | TTFT ≤ 1 s、TPOT ≤ 50 ms | 20 请求/s |
| 写代码的智能体 | Llama-3.1-70B | 8000 / 400 | TTFT ≤ 3 s、TPOT ≤ 50 ms | 4 请求/s |
| 离线批处理 | Llama-3.1-70B | 2000 / 300 | TTFT ≤ 60 s、TPOT ≤ 0.5 s | 20 请求/s |
| 低延迟(小模型) | Llama-3.1-8B | 500 / 100 | TTFT ≤ 0.2 s、TPOT ≤ 15 ms | 40 请求/s |
搜索空间:{H100, H200, B200} × {BF16, FP8} × 张量并行 {1, 2, 4, 8} × {共置(分块 prefill), 解耦}。GPU 价格是假设值(H100 2.0、H200 2.6、B200 4.0 美元 / 小时),只用来比较。
2.2 解析模型
每步时间都来自第 5 讲的 StepModel(roofline + 60% 算力、80% 带宽的折扣 + 每步 1 ms 的固定开销 + 张量并行的 all-reduce)。
- decode 实例:KV 按”提示 + 全部输出”预留,批大小 ≤ 显存容量 / (P + O);在这之下找最大的批 ,使一步的时间 ≤ 0.85 × TPOT(留 15% 给长短不一和 P90 的尾巴)。吞吐 = / (一步 × 平均输出长度)。
- prefill 实例:M/D/1 排队(第 5 讲 §4):平均等待 ;用 近似尾部(2.3 ≈ ln 10),解出满足 TTFT 的最大利用率。
- 共置实例:稳态下每一步 = 个 decode + 一块 个 prefill token;要求一步 ≤ 0.85 × TPOT、 步 ≤ TTFT / 2;吞吐 = / 一步。在 和 上搜索。
- 解耦:和 DistServe 的算法 1 一样,prefill、decode 各自挑”每块 GPU 吞吐最高”的张量并行度,再各自复制到满足流量。
02 演示 1 的结果(解析模型):聊天最便宜的是 2 块 B200(FP8、共置、各自单卡),0.444 美元 / 百万输出 token,4 块 H100(FP8、共置、TP2 × 2)一样便宜;写代码的智能体约贵 3 倍(1.389,提示长 8 倍:每个输出 token 分摊的 prefill 多、KV 大、批小);离线批处理 0.556;低延迟的 8B 一块 H100 就够(0.139)。
按”每块 GPU 的效率”比较(演示 3,美元 / 百万输出 token,共置 / 解耦):
| 场景 | H100 BF16 | H100 FP8 | H200 BF16 | H200 FP8 | B200 BF16 | B200 FP8 |
|---|---|---|---|---|---|---|
| 聊天 | 0.85 / 1.10 | 0.39 / 0.52 | 0.93 / 1.14 | 0.44 / 0.54 | 0.55 / 0.79 | 0.27 / 0.35 |
| 写代码的智能体 | 3.61 / 6.61 | 1.67 / 4.83 | 4.70 / 8.60 | 2.17 / 4.48 | 2.73 / 5.18 | 1.21 / 2.70 |
| 离线批处理 | 1.23 / 1.72 | 0.58 / 0.82 | 1.42 / 1.79 | 0.67 / 0.85 | 0.84 / 1.40 | 0.41 / 0.65 |
| 低延迟 | 0.10 / 0.24 | 0.05 / 0.08 | 0.13 / 0.21 | 0.06 / 0.10 | 0.08 / 0.13 | 0.04 / 0.07 |
- FP8 每一格都更便宜(字节减半,批更大,第 3 讲)——前提是质量允许。
- B200 的效率最高:带宽 2.4 倍、显存 2.4 倍、算力 2.5 倍,价格只贵 1 倍。H200 在这四个场景里都比 H100 略贵:它贵 30%,多出来的带宽和显存只帮了 decode,prefill 的算力一样。
- 共置几乎总是比解耦便宜:分块 prefill 已经控制住了干扰,解耦还要付 KV 传输和两边各自取整的代价。
演示 2 还说明了整数台的影响:按效率 B200 是 0.274 美元 / 百万,可 20 请求/s 时要 2 块 B200、容量是需要的 1.6 倍——多出来的是闲置。流量小的时候,“凑整”的浪费可能比方案之间效率的差别还大;办法是挑容量合适的配置、多个模型 / 租户共享 GPU(CS349D 第 12 讲)或弹性伸缩。
2.3 用模拟器检验:解析模型哪里会错
03 脚本用第 5 讲的离散事件模拟器检验这些方案(SLO 达成率按中间 60% 的请求统计,目标 90%)。
教训一:SLO 是 P90,就要用 P90 的长度去检查。写代码的智能体的提示长度是长尾的(平均 8,000,P90 16,195)。按平均长度筛选出的前三个方案在模拟器里都不达标(达成率 70%、76%、44%,TTFT 的 P90 是 4.3、4.6、10 秒);其中 H200 单卡的方案加多少实例都救不回来——单卡、每步 256 个 token 的分块 prefill,把一个一万多 token 的提示 prefill 完就要好几秒,这不是排队的问题,加机器不能让单个请求变快。改成按 P90 的提示长度检查 TTFT,这类不可行的方案就被去掉了。
**教训二:解析模型的排队近似对长短悬殊的请求偏乐观。**按 P90 筛选之后,写代码的智能体的前 6 个方案里仍有 3 个要加实例:最便宜的从 2 块 B200 变成 3 块(1.389 → 2.083 美元 / 百万,达成率 97%)。其他三个场景的方案直接通过。
**教训三:模拟要跑到稳态。**用二分查找量一个方案能承受的最大流量时,离线批处理(TTFT 限制 60 秒)的结果随模拟长度变化:
| 模拟的长度 | 量到的最大流量(请求 / 秒,解析值 27.0) |
|---|---|
| 固定 1,500 个请求 | ≥ 107.9 |
| 至少 120 秒的到达 | 45.6 |
| 至少 300 秒的到达 | 33.3 |
| 至少 600 秒的到达 | 30.0 |
过载的系统要过一段时间队列才会长到违反 SLO;只模拟十几秒的到达,会把一个不稳定的系统误判成”满足 SLO”(CS349D 第 17 讲 §5.2 讲过同一件事)。模拟够长之后(600 秒),解析容量和模拟的比值:聊天 0.91、离线批处理 1.11、写代码的智能体(单个实例)0.69——同一个解析模型,在不同的负载上偏差的方向都可能不同。
所以规划器的正确用法是**“解析模型筛选 + 模拟(或真机)验证”**:解析模型便宜,可以扫几百个组合;模拟器慢,但看得见排队和长尾。解析模型给出的成本只是一个估计,最后的数以验证后的为准。DistServe 的放置算法也是这样设计的。
2.4 假设一变,答案就变
04 脚本(每个结果都经过模拟检验和修复):
- TPOT 收紧(聊天):从 100 ms 到 15 ms 成本都是 0.444 美元 / 百万(整数台留下的余量吸收了收紧的 SLO;15 ms 时换成张量并行 2)。收紧到 10 ms,最便宜的方案变成 H200、FP8、解耦(3 个单卡 prefill + 1 个 TP4 的 decode),1.011 美元 / 百万——这是本讲所有实验里解耦唯一一次胜出:decode 要用大的张量并行才够快,prefill 用小的更省,共置只能用同一种并行方式,两头顾不上(DistServe 的论点)。
- 不许用 FP8:聊天和写代码的智能体都贵 2.00 倍。如果 FP8 的质量损失可以接受(第 3 讲用 KL、困惑度、下游任务来衡量),这部分钱就能省下来。规划器把质量当作约束,评估质量要另外做。
- 硬件与价格:默认价格下 2 块 B200 和 4 块 H100 恰好一样贵(2 × 4.0 = 4 × 2.0);B200 涨到 6 美元后 H100 胜出;H200 降到 2.2 美元仍然不够。规划器的输出永远是”在这组价格、这个流量下”的答案。
- 模型大小:同样的聊天 SLO,8B 0.111、70B 0.444、405B 3.556 美元 / 百万(405B 要 16 块 B200,TP4 × 4)。“用多大的模型”本身就是推理效率里最重要的决定之一。
- 流量:5 请求/s 时按整数台的成本 0.578、按效率 0.440;500 请求/s 时 0.276 vs 0.274——流量大了,整数台的浪费消失,选择也更接近效率最高的配置。
2.5 这个规划器没有做的
为了诚实:它不考虑前缀缓存(智能体的长提示大部分可复用,第 7、15 讲)、投机解码(只在 01 的阶梯里)、流水线并行、MoE、多模型共享、弹性伸缩、故障;质量只是一个”允许 / 不允许 FP8”的开关;每步时间是 roofline 模型而不是实测;价格是假设的。把其中任何一项加进去,都是一个合格的课程项目(§3.7)。
3. 怎样做一个推理系统项目 · How to do a project
3.1 选题
好的推理系统项目通常从下面几种问题之一出发:
- 一个瓶颈:用 roofline(第 1 讲)或 profiler 找到时间花在哪里,然后去攻它(§1.2 的那张表就是一个瓶颈清单)。
- 一种负载:长上下文、智能体(多轮、工具暂停)、多模态、批处理——新负载往往让旧的假设失效(第 15 讲的 KV 保留就是例子)。
- 一种硬件变化:FP4 / NVFP4、更大的 HBM、SRAM 芯片、新的互连——旧的取舍点会移动。
- 一个评测问题:现有的基准测的对不对(第 14 讲 §3、§4)?
把题目缩小到能在一个学期里得出清楚结论的大小:一个问题、一个指标、一个有说服力的实验。
3.2 基线
- 强、调好:和最好的已有方法比(vLLM / SGLang 的默认设置往往不是最好的设置);给基线调参的力气不能比给自己的方法少。
- 可比:同样的硬件、同样的精度(第 14 讲 §4.5 的 TF32 教训)、同样的负载、同样的 SLO。
- 问自己:**谁会对这个结果感到惊讶?**如果领域里的专家看了说”当然”,要么结果太弱,要么基线太弱。
3.3 测量
第 14 讲 §4 和 CS349D 第 17 讲 §5 的清单:
- 写明测量条件:硬件、软件版本、cache 冷热、同步方式、预热、重复次数。
- 交替测量对比的两方(A B A B),报告中位数和置信区间;不要只报一次的数字。
- 用一组测量挑候选,用另一组独立的测量报告它(挑赢家的偏差)。
- 问题要足够大(固定开销不要主导),实验要跑到稳态(§2.3 的教训三)。
- 服务系统要分清开环(按到达率发请求)和闭环(固定并发),报告 SLO 达成率和分布,而不只是平均值。
- 每个”变快了”的结果都要附上”还是对的”的证据(第 14 讲 §2–§3)。
3.4 模型与实测
这门课大量使用模型:roofline、解析的容量估计、离散事件模拟器。它们的价值在于便宜地探索和解释为什么;它们的风险在于把假设当成结论。好的做法:
- 用少数几个真实的测量点校准模型(例如测一下实际的每步时间,替换
StepModel的效率折扣); - 报告模型和实测的差距(本仓库每一讲的 README 都有一节”关于实验结果”,记录写作时和预想不一致的地方——这是一个值得模仿的习惯);
- 用模型筛选、用更真实的方法确认(§2.3)。
3.5 消融与敏感性
一次只改一处(第 14 讲 §6.5 的消融);把关键假设(SLO、负载、价格、硬件)扫一遍,看结论在哪里翻转(§2.4)。种子之间的波动要和效果的大小一起报告——5 个种子的中位数差 0.02 说明不了什么。
3.6 写报告
- 每一个主张对应一个实验;每一张图回答一个问题。
- 写清楚局限:哪些是模型、哪些是实测;在什么范围内成立。
- 写下没成功的尝试和意外:它们常常是最有价值的部分。
3.7 项目点子(从本仓库的代码出发)
| 点子 | 起点 |
|---|---|
| 给规划器加上前缀缓存(智能体的长提示可复用),看最优方案怎样变 | 本讲 planner.py + 第 7 讲 kv_store.py |
| 给规划器加上投机解码和 MoE | planner.py + 第 6 讲 decode_lab.py、第 3 讲 quant_lab.py |
用真机测量校准 StepModel,比较模型和实测的差距 | 第 5 讲 serving_sim.py |
| 实现 InferCept 的”最小浪费”策略或 Continuum 的 TTL 预测,接到智能体服务模拟里 | 第 15 讲 agent_lab.py |
| 程序级调度(Autellix)+ KV 保留的联合设计 | 第 15 讲 + CS349D 第 13 讲 |
| 给 KernelBench 式的评估器再加几道防线,找一个新的作弊方式 | 第 14 讲 kbench.py |
| 用真正的 LLM 替换模拟的提议器,进化分块启发式 | 第 14 讲 evolve.py |
| FP4 / NVFP4 的质量 vs 吞吐前沿 | 第 3 讲、P3 numfmt.py |
| decode 的 megakernel 时间线:哪些开销能真正消掉 | 第 11 讲 flash_lab.py |
| 动态形状和 CUDA Graphs 的取舍(按桶补齐 vs 重新编译) | 第 12 讲 graph_lab.py |
| 稀疏注意力 / 长上下文下的 KV 压缩,对 roofline 的影响 | 第 2、3、11 讲 |
| 能量账:每个 token 多少焦耳,哪一层最费电 | 第 1 讲 hw_specs.py + 本讲阶梯 |
4. 开放问题 · Open problems(2026)
- 内存墙:算力每代翻倍,HBM 的带宽和容量增长慢得多,价格和供应也受限。decode 和长上下文直接撞在这堵墙上;近存计算、SRAM 芯片、分层的 KV 存储(第 7、8 讲)是不同的绕法。
- 长上下文:KV 随上下文线性增长,注意力的计算随上下文增长;稀疏 / 混合注意力、KV 压缩、外存上的 KV 都在发展,但质量和效率的取舍还没有定论。
- 智能体负载:多轮、输入远多于输出、频繁暂停、跨请求的前缀共享(第 15 讲)——推理引擎的调度、缓存、KV 保留都要为它重新设计。
- 异构与解耦走到底:prefill / decode、注意力 / FFN、草稿 / 验证,放在不同的芯片上;代价是数据搬运和协调(第 5 讲)。什么样的拆分在什么规模下划算?
- 低精度的边界:FP8 已经普及,FP4 / NVFP4 的质量代价随模型和任务而变;训练和推理的精度怎样协同(第 3 讲、P3)?
- 内核与编译器追不上新硬件:每代硬件都要新内核;编译器(第 12、13 讲)和 AI 智能体(第 14 讲)都在尝试自动化,但评估它们本身就是一个难题。
- 评测的可信度:从内核基准(第 14 讲)到服务基准(CS349D 第 17 讲),每一次加固评估,报告的数字都下降一截。可复现、难作弊的评测方法本身就是研究课题。
- 能耗与成本的完整账:每个 token 的焦耳、每瓦的 token 数、数据中心的电力约束(第 1 讲)——效率最终要落到这几个数上。
5. 小结 · Summary
- 一个 token 的时间可以拆成读权重、读 KV、计算、通信、内核启动和排队;每一项都有对应的讲次和对策。批 1 的 eager decode 里,内核启动可以比读权重还多。
- 优化阶梯:批处理是最大的一步(每块 GPU 的吞吐 ×40),低精度和投机解码再往上推;有的技术改善延迟、有的改善吞吐,两者常常互相拉扯。
- 部署规划 = 在 {硬件, 精度, 并行度, 共置 / 解耦, 数量} 里找满足 SLO 的最便宜方案。解析模型筛选、模拟器验证;SLO 是 P90 就要用 P90 的长度检查;模拟要跑到稳态;整数台在流量小时很重要;价格一变,答案就变。
- 做项目:从瓶颈、负载、硬件变化或评测问题出发;强而可比的基线;严谨的测量(交替、置信区间、独立报告、稳态、正确性);模型和实测互相校准;消融和敏感性;诚实地写局限和意外。
- 开放问题:内存墙、长上下文、智能体负载、异构解耦、低精度、内核与编译器、评测、能耗。
6. 常见误区 · Common pitfalls
- “把每一讲的加速比乘起来,就是端到端的加速比。” 各层共享显存、算力和带宽,收益会互相抵消(批处理让投机解码的收益变小);要端到端地测或模拟。
- “解析模型说够了,就够了。” 它对长尾和排队常常偏乐观(写代码的智能体:解析容量是模拟的 1/0.69 倍),也可能偏保守(离线批处理)。
- “用平均长度检查 P90 的 SLO。” P90 由长请求决定;用平均值会把根本不可行的方案选出来。
- “模拟了 1,500 个请求,结果很稳定。” 稳定可能只是因为队列还没长起来;过载要很久才看得出来。
- “最快的 GPU 一定最省钱。” 取决于价格和流量;流量小时整数台的粒度可以抹平效率的差别。
- “FP8 总是可以用。” 那是质量问题,规划器只把它当作约束;要在你的任务上量。
- “解耦总是更好 / 总是更差。” 本讲里它只在 TPOT ≤ 10 ms 时胜出;第 5 讲里它在 TTFT 很紧时胜出。答案取决于 SLO 和负载。
- “项目的价值在于新方法。” 一个严谨的测量、一个推翻常识的发现、一个更可信的评测,同样是好项目。
7. 练习 · Exercises
练习 1(批处理为什么没有 64 倍) 从第 2 级(批 1,每块 GPU 15 token/s)到第 3 级(批 64,591 token/s)只提高了约 40 倍,不是 64 倍。为什么?
答案:一步的时间从 8.48 ms 涨到 13.53 ms:读 KV 从 0.06 涨到 4.01 ms(64 个序列 × 4096 个 token),计算从 0.03 涨到 2.02 ms,通信从 0.98 涨到 2.08 ms。吞吐 ∝ 批 / 一步 = 64 × 8.48 / 13.53 ≈ 40 倍。
练习 2(成本公式) 2 块 GPU、每块 4 美元 / 小时,服务 20 请求 / 秒、每个请求平均 250 个输出 token。每百万输出 token 多少钱?
答案: 美元(和 02 演示 1 一致)。
练习 3(TPOT 的下界) Llama-3.1-70B FP8(矩阵乘法参数约 69.5 B,每个 1 字节),H100 有效带宽按 3.35 TB/s × 0.8 算。单卡 decode 一步至少要多久?TPOT ≤ 10 ms 至少要几路张量并行?
答案: ms,单卡不可能;TP4 时约 6.5 ms(还要加 KV、通信、固定开销),TP4 起才有可能——这正是 04 演示 1 里 decode 用 TP4 的原因。
练习 4(prefill 的利用率) 单个请求的 prefill s,平均每个请求占 s,TTFT ≤ 1 s,尾部系数 2.3。按 planner 的公式最大利用率是多少?
答案:;(02 演示 1 里 H100 单卡 prefill 实例的 0.85–0.87)。
练习 5(P90 的长度) 提示长度对数正态、平均 8000、σ = 0.8。P90 是多少?
答案:;P90 。
练习 6(整数台) 每个实例能承受 16.2 请求 / 秒,目标 20 请求 / 秒。要几个实例?平均利用率多少?
答案: 个,利用率 。
练习 7(为什么模拟要长) 一个系统的到达率比容量高 10%。粗略地说,队列里的等待时间每过 1 秒增长多少?TTFT 限制 60 秒时,大约要模拟多久才能发现它不稳定?
答案:到达率 λ = 1.1μ,积压每秒增加 λ − μ = 0.1μ 个请求;按 μ 的速度处理,等待时间每秒增加约 0.1 s,约 600 秒后等待才超过 60 秒。只模拟十几秒(1,500 个请求)根本看不出来——§2.3 的表正是这样。
练习 8(解耦什么时候赢) 为什么 TPOT ≤ 10 ms 时解耦胜出,而 50 ms 时共置更便宜?
答案:10 ms 时 decode 要 TP4 才够快(练习 3);共置只能用一种并行方式,prefill 也只好跑在 TP4 上,多出来的 GPU 和通信是浪费;解耦让 prefill 用单卡、decode 用 TP4,各取所需。50 ms 时单卡(或 TP2)就能满足 TPOT,共置的分块 prefill 已经控制住了干扰,解耦反而要多付 KV 传输和两边取整的代价。
练习 9(投机解码的账) α = 0.8、γ = 4,一轮平均产出几个 token?
答案:(第 6 讲的式 1)。
练习 10(能量) 8 块 H100(每块 700 W)、每块 GPU 每秒 1,261 个 token。每个 token 多少焦耳?
答案: J(01 演示 2 的第 5 级)。
练习 11(设计一个测量) 你要比较两个 decode 内核 A、B 的速度,怎样设计实验,才不会被噪声、cache 和挑赢家骗?
答案(要点):固定输入大小(足够大)和 cache 状态(例如每次前清 L2);预热;A B 交替测 30 次以上,报告中位数和 bootstrap 置信区间;如果是从很多候选里挑出来的,用一组新的测量重新报告;检查两者输出一致(容差、多种输入分布);写明硬件、驱动、编译器版本。
练习 12(选一个项目) 从 §3.7 里挑一个点子,写出:要回答的问题、基线、指标、最关键的一个实验、你预期的结果和”如果预期错了说明什么”。
答案:开放题。检查标准:问题是否具体到一个学期能回答;基线是否强且可比;指标是否和问题直接对应(例如”同样 SLO 下每百万 token 的成本”);实验是否能区分”你的解释”和”别的解释”。
8. 延伸阅读 · Further reading
回到起点
- J. Austin et al., How to Scale Your Model(Google DeepMind,2025):第 0–3、7 章是第 1、4 讲的主线。
- M. Horowitz, Computing’s Energy Problem (and what we can do about it), ISSCC 2014:第 1 讲的能量表。
部署与评测
- Y. Zhong et al., DistServe, OSDI 2024(第 5 讲):解析筛选 + 模拟验证的放置算法。
- R. Pope et al., Efficiently Scaling Transformer Inference, MLSys 2023(第 4 讲):延迟、吞吐与成本的前沿。
- CS349D 第 17 讲:一个迷你推理引擎的端到端评测,以及怎样评测一个推理系统(稳态、开环与闭环、公共随机数、调好基线)。
本仓库
- 每一讲代码目录的 README 都有”关于实验结果(写作过程中和预想不一致的地方)“一节——它们是这门课里最接近”做研究”的部分。
- SYLLABUS:全部讲次的大纲、和原课的对应、写作约定。
9. 结语 · Closing
这门课从”读 8 个字节比算一次乘法贵几百倍”出发,一路往下走:模型的账本、精度、切分、服务系统、KV 管理、硬件、内核、编译器,最后到”让 AI 来写内核”和”为智能体做推理”。每一层看到的都是同一个问题的不同侧面——把数据搬到算力旁边的代价——和同一种思维方式:先算账(roofline、能量、成本),再动手,最后诚实地测。希望你带走的不是某一个技巧,而是这种思维方式。