24 · 实战与挑战项目
⏱ 项目 1–2 天 / 挑战 4–7 天 | ⭐ 这个领域不动手等于没学
🎯 一句话
这一章的项目和别的教程不同:产出不是模型,是一张"我把它从 X 优化到 Y"的表格。 每个任务都有一个可以量化的、二元的成功判据 —— 数字动了还是没动。
💡 为什么这对 ADHD 友好:不像调模型那样"好像好了一点", 这里每一步都有明确的数字反馈。多巴胺来得快。
🧰 开工前:三条纪律
① 每次只改一件事,改完立刻测 (第 23 章)
② 每个数字记进表格,带上配置 (不记的话两小时后你会忘)
③ 先建立基线,再优化 (没基线就只有"感觉变快了")
⭐ 还有一件 30 分钟的热身,做了下面几个项目会顺很多: 附录 A 的「🧮 十道计算题」——显存、KV Cache、最大 batch、算术强度、Roofline、MFU、吞吐上限、量化后的账,各一道,全部只用本板块给过的公式。 为什么值得先做:下面每个项目的第一步都是「测出基线」,而基线要不要信,取决于你能不能先手算出它大概该是多少。 ⚠️ 不会估的人最典型的两种翻车:基线 MFU 只有 8% 却以为正常(其实是数据管线卡着,不是模型的问题)、 OOM 了就无脑减 batch(其实是 KV Cache 按 max_len 预分配吃掉的,减 batch 治标不治本)。 算过一遍之后,你会先知道数字该落在哪个区间,再去跑——这就是项目二、三里"数字动没动"能不能被判读的前提。
没有 GPU 怎么办:
| 资源 | 说明 |
|---|---|
| Colab / Kaggle | 免费 T4 或 P100,够做项目一、二的大部分 |
| 云上按需 A100 | 约 $1-2/小时,做完挑战项目花不了多少 |
| 本地消费级卡 | 3060/4090 都能做,只是模型要小一号 |
🥉 项目一:把一个模型的 MFU 从 15% 提到 40%+(1 天)
练什么:第 3、4、6、7、9、22 章。
任务清单
- [ ] T1 (45min) 搭一个故意没优化的训练脚本
(FP32、
num_workers=0、没有torch.compile、朴素 attention) 测出基线 MFU ⭐ - [ ] T2 (30min) 换 BF16 混合精度 → 记录 MFU 变化
- [ ] T3 (30min) 修数据管线(
num_workers、pin_memory、persistent_workers) → 先做第 22 章那个"换随机张量"的诊断实验 - [ ] T4 (30min) 换成
F.scaled_dot_product_attention(走 FlashAttention 后端) - [ ] T5 (30min) 加
torch.compile,用TORCH_LOGS="graph_breaks"确认没断图 - [ ] T6 (30min) 调 batch size,找到 MFU 的甜点
- [ ] T7 (30min) 画一张"每一步的 MFU 演进"表
🎯 该看到的数字
基线(FP32 + 朴素) ~12-18%
+ BF16 ~25-30% ⭐ 最大的一跳
+ 修数据管线 ~30-35%
+ FlashAttention ~35-40%
+ torch.compile ~40-48%
+ 调 batch ~45-52% ✅ 通关
✅ 通关标准
- MFU 翻 3 倍以上
- 能说出每一步的收益来自哪个物理原因(Tensor Core?带宽?kernel 启动?)
- 有一步的收益低于预期,且你能解释为什么 ⭐
⚠️ 三个常见卡点(卡住了再点)
- BF16 没提升 → 矩阵维度不是 8 的倍数(第 6 章),把 hidden 改成 4096 这类整数
torch.compile没提升 → 有 graph break,TORCH_LOGS="graph_breaks"查;训练循环里有.item()或print- MFU 算出来 >100% → 公式错了。检查是不是把 6N 写成了 2N,或者峰值算力用错了精度那一列
🥈 项目二:推理服务的完整调优(1–2 天)
练什么:第 15–20 章。
任务清单
- [ ] T1 (45min) 用 HuggingFace
model.generate()起一个服务,压测出基线吞吐 - [ ] T2 (45min) 换成 vLLM,同样压测 → 感受第一跳有多大 ⭐
- [ ] T3 (45min) 画出延迟-吞吐曲线(第 20 章) —— 并发从 1 扫到 256,记录吞吐和 TPOT P95
- [ ] T4 (45min) 开 前缀缓存,用带长系统提示词的请求测收益
- [ ] T5 (60min) 上 AWQ 或 FP8 量化,对比:吞吐、显存、以及质量
- [ ] T6 (45min) 开 KV Cache 量化,看最大并发数变化
- [ ] T7 (30min) 算出每百万 token 成本,对比基线
🎯 该看到的数字(7B 模型,单卡 A100 量级)
HF generate()(无批处理) ~100-200 tok/s
vLLM 默认 ~2000-3500 tok/s ⭐ 10-20 倍
+ 前缀缓存(长系统提示词) TTFT 降 50%+
+ INT4/FP8 量化 ~5000-7000 tok/s
+ KV Cache 量化 最大并发翻倍
✅ 通关标准
- 吞吐提升 10 倍以上
- 有一张完整的延迟-吞吐曲线,并据此定出了
max_num_seqs - 量化做了质量评估(第 18 章:不能只看 PPL,要测业务能力)⭐
- 能算出每百万 token 成本
⭐ T5 是这个项目最有价值的一步: 大多数人量化完只看速度,不看质量。 你要做的是拿 200 条真实样本,对比量化前后的输出 —— 尤其测数学和代码,那是量化伤害最大的地方。
🥇 挑战项目 A:手写一个 mini 推理引擎(4–5 天)
难度 ★★★★☆ | 把第 16、17 章真正变成你的
目标:从零实现一个支持【连续批处理】和【分页 KV Cache】的推理引擎
—— 不追求快,追求【正确且你完全理解】
阶段一:能跑(Day 1)
- [ ] 加载一个小模型(如 TinyLlama-1.1B),实现朴素的自回归生成
- [ ] 加 KV Cache,对比有无缓存的速度 → 验证 O(n²) → O(n) ⭐
- [ ] 测出单请求的 tokens/秒,和"带宽÷模型大小"的理论上限对比(第 4 章)
阶段二:批处理(Day 2)
- [ ] 实现静态批处理,测吞吐
- [ ] 实现连续批处理:每步检查完成/加入新请求
- [ ] 用长度方差很大的请求集对比两者 ⭐ → 方差越大,连续批处理赢得越多
阶段三:分页(Day 3–4)
- [ ] 实现块管理器:固定大小的块池 + 每请求一张块表
- [ ] 实现分页版的 attention(可以先用朴素实现,正确优先)
- [ ] 测量 KV Cache 利用率:分页前 vs 分页后 ⭐
- [ ] 实现前缀共享(引用计数 + 写时复制)
阶段四:验证(Day 5)
- [ ] 和 HuggingFace 的输出逐 token 对比(贪心解码下应完全一致)⭐
- [ ] 和 vLLM 对比吞吐,分析差距来自哪里
- [ ] 写报告
✅ 通关标准
- 贪心解码下输出和 HF 完全一致(这是正确性的硬标准)⭐
- 连续批处理相比静态批处理,在高方差请求集上吞吐提升 ≥ 3 倍
- 分页把 KV Cache 利用率从 <50% 提到 >85%
- 报告里说清楚你和 vLLM 的差距来自哪几个具体的地方
🥇 挑战项目 B:多卡并行策略的实测扫描(3–4 天)
难度 ★★★★★ | 需要至少 4 张卡(云上按小时租)
目标:亲手验证[第 14 章]的黄金法则,并找出你的硬件上的最优配置
阶段一:摸清你的硬件(Day 1)
- [ ]
nvidia-smi topo -m画出拓扑图 - [ ] 用
all_reduce_perf实测各种规模下的卡间带宽 - [ ] 对比实测和标称值,差距在哪 ⭐
阶段二:单维度实验(Day 2)
- [ ] 纯 DDP:扫 1/2/4/8 卡,画扩展效率曲线
- [ ] 纯 FSDP:对比 ZeRO-2 和 ZeRO-3 的显存和速度
- [ ] 纯 TP:扫 TP=2/4/8,验证"通信量和 TP 度无关" ⭐
- [ ] 纯 PP:扫 micro-batch 数,验证气泡公式 (P−1)/(M+P−1) ⭐⭐
阶段三:组合扫描(Day 3)
- [ ] 固定总卡数,扫所有可行的 (TP, PP, DP) 组合
- [ ] 每组记录:MFU、单步时间、峰值显存
- [ ] 画出热力图,找到最优配置
- [ ] 验证黄金法则:TP 跨机 vs TP 机内,差多少?⭐
阶段四:分析(Day 4)
- [ ] 用第 5 章的通信量公式,预测每种配置的通信时间
- [ ] 和实测对比 —— 预测准吗?不准的地方为什么? ⭐
- [ ] 写报告
✅ 通关标准
- 气泡公式的预测和实测吻合(误差 < 20%)
- 找到的最优配置比朴素配置(纯 DDP 或纯 TP)快 30% 以上
- 验证了"TP 不能跨机" —— 给出具体的性能数字
- 报告里有一段"我原本以为 ,实际上 " ⭐
🏆 加分
- 测出你的硬件上 TP 的实际甜点(是不是真的是 8?)
- 对比
HYBRID_SHARD和FULL_SHARD在多机下的差距 - 加上序列并行,看长序列下的收益
📝 报告模板
# 优化目标:____
## 基线
| 指标 | 值 | 配置 |
## 优化步骤
| 步骤 | 改了什么 | MFU/吞吐 | 变化 | 物理原因 |
|------|---------|---------|------|---------|
| 1 | BF16 | 15%→28% | +87% | 用上了 Tensor Core |
## 遇到的瓶颈和排查过程
## 我原本以为 ___,实际上 ___ ← 最有价值的一节 ⭐
## 还剩多少空间(用 Roofline 论证)
💡 "我原本以为"那一节别省。 这个领域的直觉极容易出错(第 1 章那三个错误直觉), 记录下你的直觉在哪被推翻,比记录结论有用十倍。
🔗 这一章连到哪里
| 做完这里的项目,接着去 | 为什么 |
|---|---|
| 《Kaggle竞赛方法论》04 超参数调优与工程实践 实验记录与结果管理 | 项目一那张"每一步的 MFU"表,那边有可以直接抄的实验记录模板 ⭐ |
| 《大模型全景导论》06 推理优化 | 挑战 A 要手写的两个机制(分页、连续批处理),动手前先看那一页纸的对照版 |
| 《模型上线之后》20 实战与挑战项目 | 项目二调出来的是"跑得快";那边的项目教你怎么发现它上线后悄悄变差了 ⭐ |
| 《强化学习基础》12 RLHF 全流程 阶段 3 的工程现实 | 挑战 B 的配置扫描,放到"四个模型同时在显存里"的 RLHF 上是最难的一档 |
✅ 检查点
- 这一章的项目产出是什么?为什么说它对 ADHD 友好?
- 开工前的三条纪律是什么?
- 项目一里,哪一步的收益通常最大?为什么?
- "BF16 没提升"最可能是什么原因?
- 项目二 T5 最有价值的地方在哪?
- 挑战 A 的正确性硬标准是什么?
- 挑战 B 要验证的两个公式/法则是什么?
- 报告模板里最有价值的是哪一节?为什么?
👀 答案
- 产出是"我把它从 X 优化到 Y"的表格,不是模型。友好是因为每个任务都有可量化的、二元的成功判据——数字动了还是没动,反馈清晰。
- ①每次只改一件事,改完立刻测 ②每个数字记进表格带上配置 ③先建立基线再优化(没基线就只有"感觉变快了")。
- 换 BF16(~12-18% → ~25-30%)。因为半精度才能用上 Tensor Core(第 2、6 章),算力差 16 倍。
- 矩阵维度不是 8 的倍数,没走上 Tensor Core。把 hidden 改成 4096 这类整数。
- 因为大多数人量化完只看速度不看质量。要拿 200 条真实样本对比量化前后,尤其测数学和代码——那是量化伤害最大的地方。
- 贪心解码下输出和 HuggingFace 逐 token 完全一致。
- ①气泡公式 (P−1)/(M+P−1) ②黄金法则"TP 不能跨机"(还有"通信量和 TP 度无关")。
- "我原本以为 ,实际上 "。因为这个领域的直觉极容易出错,记录直觉在哪被推翻比记录结论有用十倍。
🛑 可以停在这里
⚡ 走神救援
⭐产出不是模型,是"我把它从 X 优化到 Y"的表格——每步都有可量化的二元判据(数字动了没有),ADHD 友好。三条纪律:每次只改一件事、每个数字记进表、⭐先建基线(没基线就只有"感觉变快了")。项目一:把 MFU 从 15% 提到 40%+——路径是 基线12-18% → ⭐+BF16 到 25-30%(最大的一跳,因为半精度才能用 Tensor Core) → +修数据管线 → +FlashAttention → +torch.compile → +调 batch 到 45-52%;卡点:BF16 没提升是维度不是 8 的倍数、compile 没提升是 graph break、MFU>100% 是公式写错(6N 写成 2N)。项目二:推理调优——HF generate ~100-200 tok/s → vLLM ~2000-3500(10-20 倍第一跳) → 前缀缓存 → 量化 → KV 量化;⭐T5 最有价值:大多数人量化完只看速度不看质量,要拿 200 条真实样本对比,尤其测数学和代码(量化伤害最大的地方)。挑战 A:手写 mini 推理引擎(KV Cache 验证 O(n²)→O(n)、连续批处理、分页 + 块表 + 前缀共享);⭐正确性硬标准是贪心解码下和 HF 逐 token 完全一致;目标:连续批处理在高方差请求集上吞吐 ≥3 倍、分页把利用率从 <50% 提到 >85%。挑战 B:并行策略实测扫描——摸拓扑 → 单维度实验(⭐验证气泡公式 (P−1)/(M+P−1) 和"通信量和 TP 度无关")→ 组合扫描画热力图 → ⭐验证"TP 不能跨机"给出具体数字;还要用第 5 章的公式预测通信时间再和实测对比。⭐报告里"我原本以为实际上"这节最有价值——这个领域直觉极容易出错,记录直觉在哪被推翻比记录结论有用十倍。
下一节 👉 附录A-速查.md