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 章。
任务清单
参考用时 · 45 分钟
搭一个故意没优化的训练脚本 (FP32、num_workers=0、没有torch.compile、朴素 attention) 测出基线 MFU ⭐参考用时 · 30 分钟
换 BF16 混合精度 → 记录 MFU 变化参考用时 · 30 分钟
参考用时 · 30 分钟
换成F.scaled_dot_product_attention(走 FlashAttention 后端)参考用时 · 30 分钟
加torch.compile,用TORCH_LOGS="graph_breaks"确认没断图参考用时 · 30 分钟
调 batch size,找到 MFU 的甜点参考用时 · 30 分钟
画一张"每一步的 MFU 演进"表
🎯 该看到的数字
下表保留本练习的参考数字,帮助你组织记录;它们不是所有硬件与模型都能达到的性能保证。请把自己的测量值填进实验表。
| 累积改动 | 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 章。
任务清单
参考用时 · 45 分钟
用 HuggingFacemodel.generate()起一个服务,压测出基线吞吐参考用时 · 45 分钟
换成 vLLM,同样压测 → 感受第一跳有多大 ⭐参考用时 · 45 分钟
画出延迟-吞吐曲线(第 20 章) —— 并发从 1 扫到 256,记录吞吐和 TPOT P95参考用时 · 45 分钟
开 前缀缓存,用带长系统提示词的请求测收益参考用时 · 60 分钟
上 AWQ 或 FP8 量化,对比:吞吐、显存、以及质量参考用时 · 45 分钟
开 KV Cache 量化,看最大并发数变化参考用时 · 30 分钟
算出每百万 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(可以先用朴素实现,正确优先)
- :分页前 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 度无关")。
- "我原本以为 ,实际上 "。因为这个领域的直觉极容易出错,记录直觉在哪被推翻比记录结论有用十倍。
🛑 可以停在这里
⚡ 走神救援
先记住这几件事
- 先建基线,再优化;每次只改一件事,把速度、资源用量和质量变化记进同一张表。
- 训练项目检查计算、数据管线和编译;推理项目同时看吞吐、延迟与输出质量。
- mini 推理引擎先验证输出正确,再测试缓存、批处理与分页带来的收益。
- 并行策略先单独测,再组合比较;用实测解释哪些直觉被推翻了。
下一节 👉 附录A-速查.md