Appearance
第20章 · DeepSeek 模型专题(MLA / MoE / GRPO / R1 / MTP / FP8)
所有架构数字以论文与官方开源 config 为准,toy 实现只复现"记账规则与更新规则",不等于工业训练或推理系统。
先修:第9章(MQA/GQA/KV Cache/量化)与第10章(normalized advantage fixture、DPO toy)。
本章目标
- 沿 MHA → MQA → GQA → MLA 的演进线,手算四种注意力在相同模型 shape 下的 KV 缓存字节数(治"定量分析"弱项)。
- 讲清 MoE 的 router/top-k/负载坍缩问题,区分 Switch 式 aux loss 与 DeepSeek-V3 的 auxiliary-loss-free bias 调整。
- 把第10章的 group normalized advantage fixture 迈半步到 GRPO:命名、公式、KL 项、vs PPO-clip 的对照。
- 概念级讲透 R1-Zero → 冷启动 → 多阶段流程,以及 MTP/FP8 的动机,能把 V3 架构图完整画出并讲"为什么"。
1. MLA:从 GQA 到低秩压缩(接第9章)
1.1 KV cache 演进线
第9章已经手写过 MQA/GQA:每个 token 每层要缓存的元素数是 KV 体积的全部来源。MLA(multi-head latent attention,DeepSeek-V2 提出)是这条线的下一步:
| 变体 | 每 token 每层缓存元素数 | 直觉 |
|---|---|---|
| MHA | 每个头各存一份 K、V | |
| MQA | 所有头共享一份 K、V | |
| GQA | 头分组共享, | |
| MLA | 存低秩 latent |
MLA 的核心恒等式只有一行:
解耦 RoPE 的取舍:RoPE 的位置旋转作用在 Q/K 上,如果 K 是从低秩
1.2 定量算账(本课核心纪律:先算公式,再上数字)
以 DeepSeek-V3 公开 config 的注意力 shape 为例(61 层、128 头、head_dim 128、kv_lora_rank 512、qk_rope_head_dim 64;bf16 = 2 字节/元素)。MHA/GQA 两列是同头数的假设基线——真实 V3 只实现 MLA:
| 变体 | 每 token 每层元素 | 每 token 全模型 | seq=4096 总缓存 | seq=128K 总缓存 |
|---|---|---|---|---|
| MHA(假设) | 2×128×128 = 32768 | 3.81 MiB | 15.25 GiB | 488.0 GiB |
| GQA-8(假设) | 2×8×128 = 2048 | 0.238 MiB | 0.95 GiB | 30.5 GiB |
| MLA(真实 V3) | 512+64 = 576 | 0.067 MiB | 274.5 MiB | 8.58 GiB |
手算验证(以 MLA 为例):kv_cache_bytes_mla 输出逐字节一致。比值:MLA/MHA ≈ 1.76%(约 56.9 倍压缩),MLA/GQA-8 ≈ 28.1%(再压 3.6 倍)。论文口径:DeepSeek-V2 摘要报告 KV cache 相比 DeepSeek 67B 减少 93.3%、最大生成吞吐提升至 5.76 倍(arXiv:2405.04434)。
复述口径(面试用):KV 缓存 = 2(K+V) × 层数 × KV 头数 × head_dim × 序列长 × 批大小 × 每元素字节;MLA 把"KV 头数 × head_dim"这一项整体换成常数 576。
1.3 代价与边界
- 低秩展开不是免费的:推理时要多做矩阵乘(或用矩阵吸收技巧预计算),工程复杂度高于 GQA。
- MLA 省的是 KV cache 显存与带宽,不是 FLOPs 的大头;attention 计算量本身仍随序列长增长。
- 本课只复现字节数记账,不实现 MLA 的前向 kernel。
2. MoE 与路由
2.1 DeepSeekMoE:细粒度专家 + 共享专家
把 FFN 换成
| DeepSeek-V2 | DeepSeek-V3 | |
|---|---|---|
| 总参 / 激活 | 236B / 21B | 671B / 37B |
| routed experts | 160,top-6 | 256,top-8 |
| shared experts | 2 | 1 |
| dense 前置层 | 1 | 3 |
(来源:V2/V3 论文与官方开源 config。)
2.2 负载坍缩与两种解法
无约束的 top-k 路由会自我强化:早期略占优的专家拿到更多 token → 训练更充分 → 更易被选中,最终坍缩到少数专家(其余专家参数浪费、容量白买)。两种解法:
- Auxiliary loss(Switch 式):
, 是路由到专家 的 token 比例, 是 router 概率质量。它度量的是"负载与 gate 偏好的相关性"——负载压在 gate 本来偏爱的专家上时 > 1。代价:辅助梯度直接干扰主任务梯度,权重难调。 - Auxiliary-loss-free(V3):给每个专家加一个只参与选择、不参与加权的 bias
:选谁用 ,算权重仍用原始 score。每步按 调整——超载就降、欠载就升。没有任何辅助梯度碰模型权重,负载均衡与任务损失完全解耦。
2.3 动手:toy router 观察坍缩与纠偏
python/llm_core/deepseek_toys.py 的 router_balance_experiment 用 2048 个 token、16 个专家、top-2,并给分数加了几何衰减的"专家热度"先验。实测(seed=13,200 步 bias 纠偏):
| 指标 | 无约束 | bias 纠偏后 |
|---|---|---|
| 单专家最大负载占比 | 0.500 | 0.0964 |
| 被激活专家数 | 3 / 16 | 16 / 16 |
| 负载占比 std | 0.1644 | 0.0229 |
| Switch aux loss | 2.8345 | 0.8920 |
注意最后一行:纠偏后 aux loss 低于 1。这不是 bug——bias 纠偏故意把负载推向 gate 不偏好的专家,负载与 gate 质量被去相关,而 aux loss 度量的正是这个相关性。教训:均衡程度要看负载分布本身(max/std),aux loss 只是训练时的一个代理。
3. GRPO:从第10章 advantage fixture 迈半步
3.1 命名与公式
第10章的 fixture 已经做过这件事:对一组样例算 baseline = mean(rewards)、centered advantage、normalized advantage(chosen/rejected = ±1.2247)。GRPO(Group Relative Policy Optimization,DeepSeekMath, arXiv:2402.03300)就是把这个记账法命名并放进 RL 目标:
其中组
3.2 GRPO vs PPO-clip 对照表
| 维度 | PPO | GRPO |
|---|---|---|
| baseline 来源 | 学到的 value model | 同 prompt 组内 reward 均值 |
| advantage 估计 | GAE(critic 递推) | 组内归一化 |
| KL 位置 | 通常折算进 reward | 显式项 |
| 组件数 | actor + critic + reward + ref | actor + reward(可 rule-based)+ ref |
| 显存/训练成本 | 高(多一个同规模 critic) | 省一档 |
| 适用 reward | 任意(reward model 打分) | 天然适配 rule-based / 可验证 reward |
rule-based reward 是 GRPO 在推理训练里的天然搭档:数学题答案对不对、代码过不过测试、输出格式合不合规,都能用确定性规则打分,不需要 reward model——这也正是 R1 用的方案。
3.3 动手:toy GRPO 更新
grpo_policy_update 在一个 prompt 的 4 个回答上跑 50 步 GRPO 式更新(rewards = [1,0,1,0],模拟"答对/答错"的 rule-based 打分)。实测:
- 组内 advantage = (1, -1, 1, -1),零均值、单位标准差(第10章 fixture 的同款性质)。
- 期望 reward:0.500 → 0.6397;最优与最差回答的 logit margin:0 → 0.5741(chosen/rejected 方向与第10章 DPO 观察一致)。
- KL 对照(6 回答、单赢家、100 步):
时 KL=0.0926、margin=0.9654; 时 KL=0.0810、margin=0.9100——KL 项确实把策略拴在 ref 附近,代价是更新更慢。
边界:这是单 prompt 的 toy 更新,没有 rollout 采样器、没有多 prompt batch、没有真实语言模型——它只证明"组归一化 advantage + clip + KL"这条更新规则的方向性。
4. R1 推理训练(概念级 + 口述题)
4.1 R1-Zero:纯 RL 能走通
DeepSeek-R1-Zero(arXiv:2501.12948)回答了一个人人关心的问题:不做任何 SFT,直接在 base model 上跑 RL 行不行? 行——在 DeepSeek-V3-Base 上用 GRPO + 纯 rule-based reward(答案准确性 + 格式),AIME 2024 pass@1 从 15.6% 涨到 71.0%(maj@64 达 86.7%),并涌现出自我反思、验证、思考长度自发增长("aha moment")。为什么能成:base model 经大规模预训练已潜伏推理能力,可验证 reward 提供了无噪声的梯度信号,组内相对 advantage 又不需要 critic。
但 R1-Zero 有硬伤:可读性差、语言混杂(中英夹杂),所以有了 R1 的多阶段流程。
4.2 R1 四阶段流程
图:DeepSeek-R1 四阶段训练 pipeline — 从 V3 Base(671B MoE 预训练)出发,先经冷启动 SFT 解决 RL 早期的输出可读性问题,再进入 GRPO 推理导向 RL,然后用拒绝采样生成 ~800k 合成数据做第二阶段 SFT,最后用 rule-based + reward model 混合信号做全场景 RL 收敛到 R1。中间的拒绝采样步骤是"数据飞轮"的关键:RL 发现的推理轨迹反过来生成更多训练数据。蒸馏分支把 R1 的 800k 数据教给小模型(Qwen/Llama),无需完整 RL 即可获得部分推理能力。
- 冷启动:数千条高质量长 CoT 微调,解决 RL 早期不稳定与输出可读性。
- 语言一致性奖励:按目标语言的词元占比给分,治 R1-Zero 的语言混杂(论文承认这会让 benchmark 分数略降,是可读性与能力的取舍)。
- 与 V3 的关系:V3 是 base(架构:MLA + MoE + MTP),R1 是在其上的后训练(RL-for-reasoning);R1 的 800k 数据又能蒸回小模型。
4.3 诚实声明
本课没有 RL 环境实操:没有跑过 rollout、没有接 verifiable reward 环境、没有复现任何 R1 曲线。本节所有数字(15.6%→71.0%、600k/200k)引自论文;对应技能缺口(RL 实操)应在后续用小型开源 RL 框架补,而不是在本课伪造。
5. MTP 与 FP8
5.1 MTP:多 token 预测
V3 的训练目标不只预测下一个 token,还用额外 MTP 模块预测更远的 token(开源 config:num_nextn_predict_layers: 1,即多预测一个)。两个作用:
- 训练侧:每个位置提供多个监督信号,信号密度更高,数据利用更充分。
- 推理侧:MTP 头可当投机解码(speculative decoding)的草稿模型——自己给自己打草稿,主模型一次校验多个 token,加速解码(self-speculative,无需额外小模型)。
5.2 FP8 混合精度训练
V3 是首个公开验证 FP8 混合精度训练可在此规模稳定收敛的模型之一:权重/激活用 FP8(e4m3),配合细粒度 scaling(按 tile/block 而非全张量),累加与敏感算子保持高精度。成果:全训练仅用 2.788M H800 GPU 小时,且全程无不可恢复的 loss spike(V3 摘要原文)。精度风险是真实的:FP8 只有 4 位指数/3 位尾数,溢出与下溢范围窄,必须靠细粒度 scale 与高精度累加兜底——这不是"免费的 2 倍吞吐"。
5.3 与第9章 int8 推理量化的对比
| 维度 | 第9章 int8 量化(推理侧) | V3 FP8(训练侧) |
|---|---|---|
| 目的 | 省显存、省带宽,部署更小 | 提训练吞吐、降训练成本 |
| 量化时机 | 训练后(PTQ) | 训练全程(量化感知) |
| 格式 | int8 + per-tensor/per-channel scale | FP8 e4m3 + tile/block 级 scale |
| 主要风险 | 权重误差 → 输出漂移(第9章已实测) | 梯度/累加下溢 → 训练不稳 |
| 反向传播 | 无 | 必须在低精度下保证梯度可用 |
6. V3 架构总装
把前五节拼成一张图,每块都能指回去:
口述主线:输入进 embedding;前 3 层 dense 打底;其余 58 层每层是 MLA 注意力(KV cache 压到每 token 每层 576 元素)+ MoE FFN(256 选 8 + 1 共享,bias 调负载不用辅助梯度);LM head 之外挂 MTP 头(训练加信号密度、推理做投机解码);整个预训练在 FP8 混合精度下用 2.788M H800 小时跑完。每个设计回答同一个问题:同等能力下,把训练/推理成本再砍一刀。
数学桥接:第2章 → 第20章
本章的 MLA、MoE、GRPO、R1、MTP 和 FP8 全部是第2章基础函数的规模化变体:
MLA 与 dot_product:第2章 §4 的 dot_product(a, b) = Σ a[i]·b[i] 不关心向量是从哪里来的。MHA 的 K/V 直接缓存,MLA 的 K/V 从低秩 latent
MoE Router 与 softmax:第2章 §5 的 softmax 把任意向量归一化为概率分布。MoE 的 router 对每个 token 输出 gate 概率
GRPO 与 kl_divergence:第2章 §6 的 kl_divergence(p, q) = Σ p(x)·log₂(p(x)/q(x)) 衡量两个分布的"距离"。GRPO(Group Relative Policy Optimization)在 DPO 的 KL penalty 基础上加入 group-wise baseline:同一组内的 advantage 标准化后更新 policy。与 PPO 的区别在于不需要 critic 网络——用组内 reward 统计量做 baseline,天然适配 rule-based reward(如数学正确性)。
MTP 与 cross_entropy:第2章 §6 的 cross_entropy(p_dist, q_dist) 可以堆叠。MTP(Multi-Token Prediction)在 main head 之外挂额外的预测头,每个头预测未来的第 2、3…N 个 token:
训练时 cross_entropy 的单 token 版本是同一公式的扩展。
FP8 与 entropy:第2章 §6 的 entropy(probs) = -Σ p(x)·log₂(p(x)) 衡量信息量。FP8 量化把 bf16 权重(16 bit)压缩到 8 bit——每个权重的自信息从 16 位降到 8 位,丢失的信息量 = 原始熵 - 量化后熵。e4m3 的动态范围(±448)适合权重激活值分布较集中的场景,超出范围的数值会被 clip——clip 就是截断高概率尾部,等效于信息的有损压缩。
前端类比:MLA = CSS content-visibility: auto——浏览器只渲染视口内的内容,视口外的用低分辨率占位;用户滚动到视口时才加载完整内容。MoE = React lazy loading + Suspense——只加载当前需要的组件(top-k experts),其余按需加载。FP8 = CSS image-rendering: pixelated + 调色板——减少颜色深度,保留结构但损失渐变细节。
7. 动手任务与验收(从零实践)
7.1 必做(核心)
- KV 算账对拍:用
compare_kv_cache复算上表,并把 V3-like config 换成自己设定的 shape(如第9章的 24 层/16 头小模型)再算一遍,手算与程序输出逐字节一致。 - Router 实验:跑
router_balance_experiment(),复现坍缩 → 纠偏对照表;把bias_speed调大 10 倍观察震荡(负载在目标附近来回跳过),写一句为什么 V3 用小步长。 - GRPO toy:跑
grpo_policy_update,确认期望 reward 上升、margin 扩大;把 rewards 全部改成相等值,确认 advantage 全零、策略不动(零方差组无梯度——这就是 GRPO 要求组内有区分度的原因)。
7.2 必做(验证)
bash
cd <仓库根>
PYTHONPATH=python .venv/bin/python -m pytest python/tests/test_deepseek_toys.py -qtext
.................... [100% ]
20 passed in 0.32s
判定信号:
KV 字节数与手算逐字节一致(MHA/GQA/MLA 三式)
MLA 缓存与头数无关;GQA 满 KV 头时退化为 MHA
bias 只影响专家选择、不影响 gate 权重
无约束路由坍缩(3/16 专家),bias 纠偏后 16/16 且 std 下降
GRPO advantage 组内零均值、单位方差;零方差组全零
toy 更新后期望 reward 上升、KL 随 beta 增大而减小实测快照见 evidence/20-deepseek-v1.json:20 测试全绿;V3-like shape 下 seq=4096 的 KV 缓存 MHA 15.25 GiB / GQA-8 0.95 GiB / MLA 274.5 MiB;router 无约束最大负载 0.500(3/16 专家)→ bias 纠偏后 0.0964(16/16);GRPO toy 期望 reward 0.500 → 0.6397。这些数字只覆盖本仓库 toy fixture 与论文引用,不描述任何真实 DeepSeek 模型的训练或推理。
8. 故障注入与预期信号
| 注入 | 预期失败信号 | 修复后证据 |
|---|---|---|
| MHA/GQA 公式漏乘 2(忘了 K 和 V 两份) | 字节数恰为手算值一半 | 手算对拍测试通过 |
| MLA 缓存乘了头数 | test_mla_cache_does_not_scale_with_head_count 失败 | 缓存只含 rank+rope 维 |
| router 权重用 biased score 计算 | bias 同时扭曲选择和加权 | test_router_bias_steers_selection_not_weights 通过 |
| bias 更新方向写反(超载加 bias) | 负载加速坍缩,max_load_fraction 上升 | 纠偏实验 std 下降断言通过 |
| GRPO advantage 忘减组均值 | 组内零均值断言失败、所有回答同向更新 | 零均值/单位方差测试通过 |
| 零方差组直接除 std | NaN 或 inf | 全零 advantage 断言通过 |
| KL 项符号写反(减成加) | beta 越大 KL 反而越大 | KL 正则对照测试通过 |
| 把论文数字(93.3%、2.788M 小时)当本地实测写进 evidence | 违反"证据先于勾选"纪律 | evidence 只记本地 toy 运行值,论文数字注明来源 |
9. 论文与延伸
- DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model(DeepSeek-AI,2024)——MLA 与 DeepSeekMoE 出处
- DeepSeek-V3 Technical Report(DeepSeek-AI,2024)——aux-loss-free、MTP、FP8、671B/37B
- DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning(DeepSeek-AI,2025)——R1-Zero 与多阶段流程
- DeepSeekMath: Pushing the Limits of Mathematical Reasoning(Shao 等,2024)——GRPO 出处
- DeepSeekMoE: Towards Ultimate Expert Specialization(DeepSeek-AI,2024)——细粒度 + 共享专家
- Switch Transformers(Fedus 等,2021)——aux loss 负载均衡的经典出处
完整索引见 参考 / 必读论文;L1 动机级词条见 术语表(MLA / MoE / GRPO / MTP / PPO)。
10. 前端/Agent 迁移
- MLA ≈ 状态压缩存储:像把冗长 state 压成序列化索引再按需还原——存压缩表示,用时展开;前提是你清楚还原成本。
- MoE router ≈ 微前端按路由懒加载:全量代码很大,单次渲染只挂载命中的子应用;负载均衡就是不让所有流量挤进同一个子应用。
- GRPO 组内相对打分 ≈ 组内排名而非绝对分数线:同一任务多次 rollout 形成相对反馈——这正是 Agent Harness 里 Eval 设计的直接灵感。
- rule-based reward ≈ 确定性测试:数学答案、代码测试、格式校验都是 verifier;Harness 的价值在于把真实任务做成可执行、可观测、可回放的反馈环境。
11. 口述与自测(不看资料,5–10 分钟)
- MLA 定量推导:给定 d_model/n_heads/层数/序列长,现场写出 MHA、GQA、MLA 的 KV 缓存公式并算出字节数;说清 93.3% 是 V2 对 DeepSeek 67B 的口径,而你手算的是同 shape 假设基线。
- MoE 负载均衡为什么 aux-loss-free:讲负载坍缩的自我强化机制;aux loss 的梯度干扰问题;bias 只影响选择、不影响加权,为什么不引入辅助梯度。
- GRPO vs PPO:画两者的组件图(critic 有无)、baseline 来源、KL 位置;说清 GRPO 为什么天然适配 rule-based reward。
- R1-Zero 为什么能纯 RL:base model 的潜伏能力 + 可验证 reward + 组内 advantage 无 critic;它有什么硬伤,R1 用哪四阶段修。
- MTP 的训练/推理双作用:信号密度 + 投机解码草稿头。
- FP8 的精度风险:e4m3 的动态范围问题、tile/block 级 scale 与高精度累加;对比第9章 int8 推理量化的误差路径。
- 统一防守句(弱项卡纪律):"我没有亲手训练这些模型;我的理解来自公开论文和本课 toy 复现,数字以论文为准。toy 实现证明的是记账和更新规则,不是工业系统。"
- 用第2章
dot_product解释 MLA 的 attention score 为什么和 MHA 同构:KV 从低秩 latent 展开后的点积公式不变,MLA 省的是缓存带宽(576 vs 32768 元素),不是点积计算量。 - 用第2章
kl_divergence对比 GRPO 和 DPO 的 KL penalty:两者都在 policy 和 reference 之间加散度约束;GRPO 额外用 group-wise advantage 替代 critic,KL 项位置相同但 baseline 来源不同。 - 用第2章
entropy解释 FP8 量化的信息损失:bf16 → FP8 把每个权重的自信息从 16 bit 降到 8 bit,丢失的信息量 = 原始熵 - 量化后熵;e4m3 的 clip 就是截断高概率尾部。
12. 资源 / 成本 / 隐私
全部 toy 实验为本地 NumPy 计算,gross cost 为 0;不下载模型权重、不调用任何 API。论文数字只引用公开摘要与官方开源 config,面试资料(careers 仓库)为本地只读输入,内容不入库。
13. 诚实边界声明
- toy ≠ 工业训练:本章所有代码只复现三类规则——KV 字节数记账、router bias 更新、GRPO 组归一化 advantage 更新。没有训练、服务或 benchmark 任何真实模型。
- 无 RL 环境:本课没有 rollout 采样器、verifiable reward 环境或 RL 训练循环;§4 的全部 R1 数字引自论文。RL 实操是学习者已知缺口,需另找机会补齐,本课不伪造。
- 数字以论文为准:236B/21B、671B/37B、93.3% KV 压缩、5.76× 吞吐、2.788M H800 小时、15.6%→71.0%、600k/200k 均来自论文摘要/正文与官方开源 config;本地实测的只有 toy fixture 输出。
- 假设基线已标注:§1 的 MHA/GQA 列是同头数假设,真实 V3 只有 MLA;router toy 用 softmax gate,V3 实为 sigmoid + 分组 top-k;toy 只复现 bias 更新规则。
- 范围外:V3.1/V3.2(DSA 稀疏注意力)、V4 Preview、DualPipe、3FS 等更新/ infra 主题不在本章范围;蒸馏、YaRN 长上下文只作延伸提及。
Evidence
仓库当前机器证据(只读快照)
evidence/20-deepseek-v1.json 是当前 checkout 的脱敏机器运行记录,只覆盖该 JSON 记录的命令、指标、产物和已知失败;它不是学习者提交,也不能推出学习者已完成本章。模块已登记进 evidence/module-manifest-v1.json。
学习者提交模板(待填写,不是当前机器证据)
复制下面模板并填写自己的真实运行结果。所有 <...> 都是未填写状态;actual 和 artifacts 尤其不能被当作已运行或已通过。artifacts 必须替换为本次提交中真实存在的仓库相对路径。
yaml
schema: learn-llm.evidence.v1
module: 20-deepseek
commit: <learner-commit-sha>
verified_at: <iso-date>
environment: <sanitized-python-device>
seed: 13
commands:
- PYTHONPATH=python .venv/bin/python -m pytest python/tests/test_deepseek_toys.py -q
metrics:
- name: kv_mla_bytes_v3like_seq4096_bf16
expected: 287834112
actual: <recorded-value>
- name: kv_mla_vs_mha_ratio_v3like
expected: "≈0.0176"
actual: <recorded-value>
- name: router_unconstrained_max_load_fraction
expected: 0.5
actual: <recorded-value>
- name: router_corrected_active_experts
expected: 16
actual: <recorded-value>
- name: grpo4_final_expected_reward
expected: ">0.5"
actual: <recorded-value>
- name: grpo6_kl_beta_stronger_is_smaller
expected: true
actual: <recorded-value>
artifacts:
- <learner-repo-relative-artifact-path>
cost:
gross_usd: 0
credit_usd: 0
licenses:
- source: <source>
version: <version>
license: <license>
attribution: <attribution>
redistribution: <redistribution>
known_failures:
- <sanitized-failure-or-none>若没有 KV 对拍、router 纠偏对照和 GRPO 性质断言的真实运行值,本章只能标记为 gate;论文引用数字不替代本地运行证据。