来源: DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model (arXiv: 2405.04434v5, 2024-06-19). 仓库: https://github.com/deepseek-ai/DeepSeek-V2
DeepSeek-V2 总参 236B, 每个 token 激活 21B, 上下文 128K, 在 8.1T token 上预训练, 再经 1.5M 条 SFT 和两阶段 GRPO 得到 Chat 版. 摘要里的三组数字最常被引用: 相对 DeepSeek 67B 训练成本省 42.5%, KV cache 减 93.3%, 最大生成吞吐 5.76 倍. 这三组数字分别来自不同的环节: 42.5% 主要来自 MoE 的稀疏计算, 93.3% 是 MLA 和部署期 KV 量化叠在一起的结果, 5.76 倍则是显存省下来以后 batch 能开大的连锁效应. 读这份报告, 要把架构, 数据, 训练日程, 对齐和评测放在一起看, 才能分清哪一部分收益来自哪一步.
1. 起点与注意力: MLA
1.1. 起点: 67B 卡在哪里
前一代 DeepSeek LLM 67B 是 Dense 模型, 95 层, 隐宽 8192, 64 个 query 头, 8 组 KV 的 GQA, 在 2T token 上训练. 它有两个瓶颈. 训练侧, 每个 token 都要走完全部 67B 参数, 算力随参数线性涨. 推理侧, 每个 token 在每层要缓存 个 KV 元素, 95 层合计 194,560 个(按 67B 配置推算), BF16 下约 380 KB; 128K 上下文单条请求就要约 47 GB, 一张 80 GB 的卡放不下几条长请求.
V2 同时处理这两个瓶颈. 注意力换成 Multi-head Latent Attention(MLA), 解决推理缓存; FFN 换成 DeepSeekMoE, 解决训练算力. 其余小设定(RMSNorm, SwiGLU 激活, 分词器)沿用 67B, 数据流水线也沿用 67B 的阶段划分. 这意味着 V2 相对 67B 的提升混合了架构, 数据量和数据配比三个因素, 报告没有做「只换架构, 数据不变」的对照, 这一点在看后面的 Base 分数时要记着.
1.2. MLA: 把 K, V 压进一个共享的低维向量
标准 MHA 每个 token 每层缓存 个元素. GQA 和 MQA 让多个 query 头共用一组 K, V 来减缓存, 代价是表达能力. 附录 D.1 的对照说明了这个代价: 三个约 7B 的 Dense 模型同训 1.33T token, 只改注意力并调层数对齐参数, MHA 的 MMLU 45.2, GQA(8 组) 41.2, MQA 37.9; C-Eval 分别是 42.9, 37.7, 30.0. 在这个规模上, 省缓存的老办法要付出 4 到 13 个点.
MLA 换了一个思路: 不减头数, 而是把 K 和 V 先联合压成一个低维潜向量 (式 9), 再用 , 上投影回每个头的 K 和 V(式 10–11). 推理时只缓存 , 每层 个元素. V2 取 , 而 MHA 在同样 128 头, 每头 128 维下要存 32,768 个. 更关键的是矩阵吸收: 注意力分数 , 中间两个矩阵可以预先乘成一个, 推理时 query 直接和缓存的潜向量做内积, 不用把每个历史 token 的 K 展开出来; 同理吸进输出投影 . 中文技术社区的实现笔记指出, 吸收后 128 个头共享同一份 , 计算形态接近 MQA, 算术强度正比于头数, 这对显存带宽受限的解码阶段很有利.
矩阵吸收也有代价. 吸收之后, 每个头的 query 要先映射到 512 维的潜空间, 再和每个历史 token 的潜向量做内积, 单头单 token 的点积长度从 128 变成 512 加 64. 解码阶段每步只有一个新 token, 瓶颈是读缓存的显存带宽, 多算一点不要紧; 预填充阶段一次处理整段 prompt, 算力才是瓶颈, 这时把 K, V 显式展开反而更省. 所以公开的推理实现通常在预填充时展开, 解码时吸收. 报告附录 C 只说「推理时可以吸收」, 没有区分这两个阶段.
Query 也做了低秩压缩, (式 12–13), 但目的只是省训练期的激活显存, 与 KV cache 无关. 低秩压缩会改变层输出的尺度, 所以报告在压缩潜向量之后加了 RMSNorm, 并在宽度瓶颈处(潜向量和路由专家的中间态)乘额外的缩放系数来稳住训练. 缩放系数取多少, 报告没有给. 机制推导见 MLA: 低秩潜变量与矩阵吸收, GQA 的折中思路见 GQA: 在性能与缓存之间折中.
1.3. 解耦 RoPE, 以及 93.3% 是怎么算出来的
RoPE 和矩阵吸收不兼容. 如果对上投影后的 施加 RoPE, 与当前位置相关的旋转矩阵就会夹在 和 中间, 矩阵乘法不满足交换律, 两者不能预先合并, 推理时又得为所有前缀 token 重算 K. 报告的办法是把位置信息单独拿出来: 另开每头 维的 和一个所有头共享的 专门承载 RoPE(式 14–15), 内容部分 , 不加位置编码, 继续走吸收路径; 两部分拼接后算注意力, 分母改成 (式 18). 共享的 直接从 投影, 不经过潜向量, 也要进缓存. 社区里常把 描述成「MQA 版的 RoPE」: 位置这一路只有一个头, 内容这一路有 128 个头.
V2 取 , 每层缓存 个元素, 等于 . Table 1 说这相当于「只有 2.25 组的 GQA」, 就是由 解出来的. 这个数可以和附录交叉验证: 60 层乘 576 是 34,560, 正好是表 9 里大号 MoE 带 MLA 那一行的 34.6K; Lite 的 27 层乘 576 是 15,552, 对上表 9 小号 MoE 带 MLA 的 15.6K. 相对同配置 MHA 的 32,768, 缩到约 1/57.
再算相对 67B 的缩减. 67B 每 token 194,560 个元素, V2 是 34,560 个, 只按元素数算, 缩减为 82.2%. 报告在 §3.2.3 还写了部署时把 KV 平均量化到 6 bit; 如果拿 V2 的 6 bit 对比 67B 的 16 bit, , 缩减正好是 93.3%. 摘要里的 93.3% 很可能合并计算了 MLA 与 KV 量化, 而 Table 1 的脚注又明确说缓存量「按元素数计, 不论存储精度」. 两处口径不一致, 报告没有说明. 按元素数归因时, MLA 对应 82.2% 的缩减, 其余差距来自量化精度.
换成实际显存更直观. V2 每 token 34,560 个元素, BF16 下约 67.5 KB, 128K 上下文单条请求约 8.4 GB; 67B 同长度约 47 GB. 同一台 8×H800 能并发的长请求数因此多出好几倍, 这就是 5.76 倍生成吞吐的主要来源. 吞吐测试用的 prompt 和生成长度分布取自线上 67B 服务的真实流量, 并且叠加了 FP8 权重和 6 bit KV 量化, 所以 5.76 倍衡量的是整套部署方案, 不是 MLA 单独的贡献. 生成吞吐超过 50K token/s, prompt 吞吐超过 100K token/s, 这两个数都是单节点 8 卡的结果.
1.4. 注意力消融能证明多少
附录 D.2 用两档 MoE 比较 MLA 和 MHA. 小档总参约 16B, 训 1.33T token: MHA 激活 2.5B, 缓存 110.6K; MLA 激活 2.4B, 缓存 15.6K, 约为前者的 14%; 四项硬基准里 MLA 赢三项(BBH 39.0 对 37.9, MMLU 50.0 对 48.7, CMMLU 53.4 对 52.3), C-Eval 输 0.7(50.9 对 51.6). 大档总参约 250B, 只训 420B token: MHA 激活 25.0B, 缓存 860.2K; MLA 激活 21.5B, 缓存 34.6K, 约为 4%; 四项全赢, BBH 50.7 对 46.6, MMLU 59.0 对 57.5, C-Eval 59.2 对 57.9, CMMLU 62.5 对 60.7.
这组结果支持「MLA 不比 MHA 差」, 证据仍有三项限制. 其一, 大档只训练了 420B token, 约为正式训练量的 5%, 早期优势能否保持到 8.1T 尚无数据. 其二, 从缓存量反推, 小档 MHA 每层 4,096 个元素, 即 16 头乘 128 维, 与 Lite 一致; 大档 MHA 每层约 14,336 个元素, 若每头 128 维则只有 56 个头, 而 MLA 设定使用 128 头. 报告称两者「除注意力外架构相同」, 却未列出 MHA 的头数和维度, 因此一部分差异可能来自头数. 其三, 每档每个设置只训练一次且没有误差条, 1 个点以内的差距缺少统计稳定性证据.
表 8 和表 9 合起来看, 报告想说明的是一条链: GQA, MQA 比 MHA 差, MLA 又不比 MHA 差, 所以 MLA 同时拿到了省缓存和保质量. 前半条链在 7B Dense 上测, 后半条在 MoE 上测, 两者不在同一个模型族里. 表 8 为了对齐参数量调整了层数, MQA 版本 7.1B, 另外两个 6.9B, MQA 省下的 KV 投影参数被换成了更多的层, 所以它和 MHA 的差距不是「同样深度下少了 KV 头」那么单纯. MLA 和 GQA 的直接对比, 报告没有给.
2. DeepSeekMoE
2.1. DeepSeekMoE: 细专家, 共享专家和设备受限路由
FFN 侧沿用 DeepSeekMoE 的两个做法(式 20–22). 一是把专家切细: 在总专家参数不变时, 专家越小, 数量越多, 激活组合就越多, 每个专家更容易学到专门的知识. 二是隔离共享专家: 每个 token 都经过的共享专家负责通用知识, 减少路由专家之间的重复. V2 除第一层外全部换成 MoE, 每层 2 个共享专家加 160 个路由专家, 专家中间宽 1536, 每 token 激活 6 个路由专家. 一层 MoE 的输出是
当 在 个亲和度的 Top- 内, 否则为 0. 第一项是残差; 第二项 个共享专家不经门控, 权重恒为 1, 每个 token 都走; 第三项 个路由专家里只有 个非零. 是专家 的中心向量, 亲和度就是 token 和它的内积. Softmax 是在全部 160 个专家上做的, 取 Top-6 之后不再归一化, 所以 6 个门控之和小于 1, 路由越分散, 路由专家这一路的输出就越小, 共享专家那一路的相对分量越大. 这套结构的机制讨论见 DeepSeek-MoE.
细粒度带来一个副作用: 激活专家多, 如果它们散在很多张卡上, 专家并行的 all-to-all 通信就会变贵. 每层 160 个路由专家均匀铺在 8 张卡上(), 每卡 20 个, 不加限制时一个 token 的 6 个专家最多可能落在 6 张卡上. 设备受限路由(device-limited routing)先按每张卡上最高的亲和度挑出 张卡, 再只在这些卡的专家里做 Top-6. V2 取 , 报告称 时效果与不受限的 Top-K 大致持平, 但没有附表, 也没有给出 或 的数字.
用配置可以反推 236B 和 21B 是怎么构成的. 一个 SwiGLU 专家有三个 5120×1536 的矩阵, 约 23.6M 参数; 每层 162 个专家约 3.8B, 59 个 MoE 层合计约 225B. 每 token 激活 2 个共享加 6 个路由, 共 8 个专家, 59 层约 11.1B. 注意力一层的投影矩阵加起来约 149M(其中输出投影 就有 128×128×5120, 约 84M), 60 层约 9B. 再加约 1B 的输入输出词嵌入和第一层的 Dense FFN, 激活参数约 21B, 总参约 235B, 与报告的 21B 和 236B 对得上. 这笔推算说明, V2 激活的 21B 里注意力占了四成以上, 专家只占一半左右; MLA 省的是缓存, 不是参数.
这个限制还给了发送端一个硬上界: 每张卡最多向外发送 个隐状态, 是序列 token 数. 共享专家不需要跨卡, 所以 V2 把共享专家的计算和专家并行的 all-to-all 通信重叠起来, 让等通信的时间也在算东西. 这一步是训练效率的关键之一, 但重叠带来的具体提速比例, 报告没有给.
2.2. 三级均衡损失和 token-dropping
路由不均衡有两个后果: 一部分专家训不到, 出现路由塌缩; 专家并行时, 忙的卡拖慢整层. V2 叠了三级辅助损失. 专家级一项写全是
. 一个序列 个 token 各选 个专家, 共 次选择, 均匀时每个专家分到 次, 前面的系数 就是把这个值归一到 . 是专家 在这段序列上的平均 Softmax 亲和度, . 均匀路由时 . 来自 Top-K 的指示函数, 不可导, 梯度只经 流回路由器, 而 前面的权重正是 : 被选得越多的专家, 它的亲和度被往下压得越重, 冷门专家几乎不受压. 这就是乘积形式的作用, 用不可导的计数给可导的概率加权. 设备级 (式 26–28)把同卡专家的 取平均, 求和, . 通信级 (式 29–31)的 统计的是 token 被发往某卡的频率, 用 归一化, ; 归一化的道理和专家级相同: 每个 token 最多发往 张卡, 共 次发送, 均匀时每卡 次, 归一后 ; 设备受限路由限住了发送端, 这一项鼓励每张卡接收的量也在 左右.
读公式时会发现, 设备级和通信级两项的 完全相同(都是同卡专家亲和度之和), 区别只在 : 一个是同卡专家被选频率的均值, 一个是「被发送到该卡」的频率. 仓库的 GitHub issue 里有人提过这两项几乎等价, 讨论者后来认为差别在于「发送」只计跨卡的 token. 报告正文没有这个解释, 也没有三级损失各自的消融. 三个系数里设备级最大, 专家级最小, 说明作者更在意卡间的均衡, 对专家间的轻微不均更宽容, 这和细粒度专家本来就希望专业化分工的设计一致.
辅助损失保证不了严格均衡, 所以训练时还加了设备级 token-dropping: 每卡的算力预算按平均值算(容量因子 1.0), 超出预算时丢掉该卡上亲和度最低的 token, 被丢的 token 在这一层只走残差. 约 10% 的训练序列永远不丢, 这样推理时可以按效率需要选择丢或不丢, 训练里两种情况都见过. 评测时一个 token 都不丢. 这个设计把「训练吞吐」和「评测分数」分开, 但也意味着训练时约 90% 的序列里有一部分 token 在某些层没有经过专家; 报告没有给出实际丢弃率.
3. 预训练
3.1. 数据与训练日程
67B 的数据流水线分去重, 过滤, 再混合三步, 去重跨 91 个 Common Crawl dump 一起做. V2 沿用这三步, 但做了四处改动: 改进清洗流程, 找回大量此前被误删的网页数据; 显著增加中文; 改进基于质量的过滤算法, 并补充多来源的高质量数据; 过滤争议内容, 减少特定地域文化带来的偏见. 分词器仍是 67B 的 100K 词表 BBPE. 8.1T token 里中文比英文多约 12%. 如果只算中英两种, 英文最多约 3.8T, 这和 §3.2.2 里「英文 token 不到 LLaMA3 70B 的四分之一」的说法一致. 代码, 数学的占比和各来源配比, 报告没有给.
训练超参: 60 层, 隐宽 5120, 128 头, 每头 128 维, 参数初始化标准差 0.006. AdamW, , , weight decay 0.1, 梯度裁剪 1.0. 学习率前 2K 步线性升到峰值 2.4e-4, 训到约 60% 和 90% token 时各乘 0.316, 这个系数约为 , 两次之后学习率是峰值的 1/10. Batch 在前 225B token 内从 2304 条增到 9216 条, 之后固定. 序列长 4K, 所以稳定期每步约 37.7M token, 剩余约 7.9T token 大约对应 21 万步. 和 67B 比, 峰值学习率从 3.2e-4 降到 2.4e-4, batch 从固定 4608 条变成最终 9216 条. 67B 报告里拟合过超参的 Scaling 规律: 算力预算越大, 最优 batch 越大, 最优学习率越小. V2 的训练算力比 67B 大, 两个超参的调整方向与这条规律一致, 但报告没有说是否按那套公式算出来的. Batch 先小后大, 让早期 loss 下降快的阶段多走几步更新, 等梯度噪声变大再换大 batch, 这是 batch size warmup 的常见理由, 报告只写了做法, 没写理由. 这套分段下降的日程来自 67B 的 Scaling 实验, 好处是可以从中间 checkpoint 续训, 后来 Coder-V2 就是从 V2 的中间 checkpoint 出发继续训练的.
训练框架是自研 HAI-LLM: 16 路 zero-bubble 流水线并行, 8 路专家并行, ZeRO-1 数据并行. 激活参数少, 再对部分算子做重算节省激活显存, 所以完全不用张量并行. 通信, 路由和跨专家的融合线性层都写了专门的 CUDA kernel, MLA 基于改进版 FlashAttention-2. 集群是 H800, 节点内 NVLink/NVSwitch, 节点间 InfiniBand. 实测每训 1T token, 67B 要 300.6K GPU 小时, V2 要 172.8K, 这就是 42.5% 的来源. 按此推算, V2 预训练约 140 万 GPU 小时, 67B 的 2T 约 60 万. 如果只看激活参数, V2 每 token 的 FFN 计算量约是 67B 的 31%, 实际成本却是 57.5%, 说明 MoE 的通信和负载不均吃掉了接近一半的理论收益(未计注意力计算量差异). 报告只说「MFU 相对较高」, 没有给具体数值.
预训练阶段没有混入 SFT 数据. 报告以 MiniCPM 在预训练中加入 SFT 数据的做法作对照, 并声明 Table 2 的 Base 分数未受指令数据影响. 这是报告给出的数据口径, 公开材料没有提供独立核查方法.
3.2. YaRN 把 4K 扩到 128K
预训练结束后用 YaRN 把窗口从 4K 扩到 128K. 在 MLA 里只有解耦的 和 带 RoPE, 所以 YaRN 只作用在这 64 维上. 参数: 扩展倍数 , , , 目标上限 160K(4K 乘 40), 期望 128K 可用. YaRN 原版用一个随 变化的注意力温度调节 softmax 的熵, 原式是 ; V2 把系数改成 0.0707, 报告写作 , 目标是让困惑度最低. 频率插值的机制见 长度外推: 从 PI 到 YaRN 的频率扩展.
这里有一个实现层面的细节. 原版 YaRN 通常把温度乘到 RoPE 的 cos/sin 上, 让 q 和 k 各自放大 , 点积就放大 . 这个做法要求整个 q, k 向量都经过 RoPE; MLA 里只有 64 维带 RoPE, 另外 128 维不带, 乘在 cos/sin 上只会放大一部分. llama.cpp 社区在移植时讨论过这个问题, 公开推理代码的做法是把温度移到 softmax 的缩放系数上. 按 算, V2 的系数约 1.26, 原版约 1.37. 另外社区指出报告里的 应为 , 属于笔误.
长上下文训练只有 1000 步, 序列 32K, batch 576 条, 合计约 18.9B token, 不到预训练量的 0.3%. 训练只在 32K 上做, 评测却到 128K, Figure 4 的 Needle-In-A-Haystack 在全部长度和深度上都表现良好. 但大海捞针只测「能不能找到一句插入的…1478 tokens truncated…据来自编译器反馈, 数学偏好数据来自标准答案. 注意这里的编译器和标准答案只用来造奖励模型的训练数据, RL 时打分的仍是神经网络奖励模型. 到 R1 才把规则判分直接当奖励. 工程上有三项: 训练和推理用不同并行策略的混合引擎, 大 batch 的 vLLM 做采样, 以及模型在 CPU 和 GPU 之间卸载, 回载的调度. 讨论节还说在线 RL 在偏好对齐里明显好于离线, 所以专门搭了在线框架, 但同时说明这个结论可能随场景变化.
4.2. Chat 评测与对齐税
Table 3 里, RL 相对 SFT 的变化分成两类. 代码和数学继续涨: HumanEval 76.8 到 81.1, LiveCodeBench 28.7 到 32.5, MBPP 70.4 到 72.0, GSM8K 90.8 到 92.2, MATH 52.7 到 53.9. 知识和推理类选择题回落: BBH 81.3 到 79.7, MMLU 78.4 到 77.8, C-Eval 80.9 到 78.0, AGIEval 63.2 到 61.4, IFEval 64.1 到 63.8. 报告把 BBH 的下降称作 alignment tax, 说通过数据处理和训练策略把代价压到可接受的程度; 实际上 C-Eval 掉了 2.9 个点, 比 BBH 的 1.6 还多, 正文没有提. LiveCodeBench 取的是 2023-09-01 到 2024-04-01 的题, 用时间窗口降低污染风险.
横向比较有两处口径问题. 67B Chat 的数字直接引自前作, 没有在本次框架里重跑, 和其它列的设定不完全一致. 表注还说 LLaMA3 70B Instruct 这类模型不一定遵守 few-shot 格式, TriviaQA, NaturalQuestions 可能被低估, LLaMA3 Instruct 的 TriviaQA 只有 69.1 就是例子. IFEval 上 LLaMA3 Instruct 79.7, 远高于 V2 的 63.8, 这是 V2 Chat 最明显的短板.
开放生成上, Table 4 的 MT-Bench 从 SFT 的 8.62 升到 RL 的 8.97, AlpacaEval 2.0 长度控制胜率从 30.0 升到 38.9, 分别与 LLaMA3 70B Instruct (8.95) 持平和领先 (34.4). RL 对开放生成的提升明显大于标准基准, 与偏好奖励模型的训练目标一致. Table 5 的 AlignBench 总分为 RL 7.91、SFT 7.74、GPT-4-0613 7.53;该评测同时使用 GPT-4-0613 作为评分模型, 报告没有分析自评与评估其他模型时是否存在系统差异. 分项中, RL 的中文理解为 8.28, 高于 GPT-4-1106-Preview 的 7.33;逻辑推理为 7.14, 低于后者的 7.66, 也低于 SFT 版的 7.26;数学计算则从 7.34 升到 7.77. 因而中文推理分项呈现一升一降, 总分不足以代表所有能力同时改善.
5. Lite, 附录和谱系位置
附录 B 放出 DeepSeek-V2-Lite: 27 层, 隐宽 2048, MLA 16 头, 每头 128 维, , 解耦 RoPE 64 维, 不压缩 query; MoE 为 2 共享加 64 路由, 专家中间宽 1408, 每 token 激活 6 个; 总参 15.7B, 激活 2.4B. 同一份语料从头训 5.7T token, 恒定 batch 4608, 峰值学习率 4.2e-4, 在 80% 和 90% token 处各乘 0.316. 专家全放在同一张卡上, 所以只保留很小的专家级损失(), 设备级, 通信级损失和设备受限路由都不需要. 之后扩到 32K 上下文并做 SFT. Table 6 里 Lite 的 MMLU 58.3, 对 DeepSeekMoE 16B 的 45.0; GSM8K 41.1 对 18.8; MATH 17.1 对 4.3. 但 Lite 训了 5.7T, 对手只训了 2T, 语料也换成了 V2 的新版本, 这些差距不能全记在 MLA 头上.
附录 E 解释了 MMLU Humanity-Moral 子集上的落后: 三名标注员独立标注 420 个道德情景, 与标准答案的一致率只有 66.7%, 59.8% 和 42.1%, 标注员之间也只有 57.9% 到 69.0%. 作者据此认为这个子集的答案本身带有地域文化倾向, V2 在这里掉分是预训练去偏的结果. 附录 F 的 SC-Math6 上, V2 Chat(RL) 总准确率 84.54, 与 Ernie-bot 4.0 的 84.38 接近, 低于 GPT-4-1106-Preview 的 89.77.
谱系上, V2 把三条已有的线接到一起: 67B 的数据流水线, 分词器和分段学习率日程, DeepSeekMoE 的专家结构, DeepSeekMath 的 GRPO. MLA 是它自己的新东西, 致谢里点名 Huazuo Gao 和 Wangding Zeng 做出了 MLA 的关键设计, 并感谢苏剑林在位置编码上的讨论. 往后看, V3 保留了 MLA 和细粒度加共享专家的结构, 把规模推到 671B 总参, 37B 激活; 三级辅助损失换成了不靠损失项的偏置调节(auxiliary-loss-free), 设备受限路由改成节点受限, token-dropping 取消, 另加 MTP 和 FP8 训练. V2 里推理 RL 用神经奖励模型, 到 R1 换成规则判分, 并把「推理能力可以随训练步数持续提升」这条观察发展成了主线. 回头看, V2 在 MLA 上的设计后来几乎没有大改, 在负载均衡上的设计则被整套替换.
6. 矩阵吸收的代数条件
线性、固定与位置无关: 矩阵吸收成立需要三个条件. 第一, 被合并的两步必须是线性映射. 与 query 做双线性内积, 可以利用结合律重排; 若两者之间插入逐元素激活、归一化或依赖 token 的门控, 就无法用一个固定矩阵替代. 例如键若写成 , 一般不存在矩阵 使 对所有 成立.
第二, 上投影参数在处理整段缓存时固定. 常规推理满足这一点. 若使用根据输入动态生成权重的超网络, 每个历史 token 的 不同, query 端无法预先吸收成同一个矩阵. 量化不会必然破坏吸收, 但「先量化两矩阵再相乘」与「先相乘再量化」会产生不同舍入误差, 部署时必须明确使用哪条路径.
第三, 上投影不能夹带无法移到 query 侧的位置操作. RoPE 正是违反这条条件的因素. 旋转矩阵依赖历史位置 , 合成结果也依赖 . 解耦之后, 内容路恢复位置无关, 位置路则直接缓存已经旋转的共享键. ALiBi 一类把位置偏置直接加在 logit 上的方法不会夹在 K 上投影中, 理论上更容易与吸收共存; 代价与长程性质属于另一问题.
6.1. 多头输出吸收的索引展开
设第 个头值上投影为 , 输出投影按头分块为 . 层输出为
预计算 后, 历史值无需展开. 但权重 仍按头不同, 所以不能把所有 简单加成一个矩阵后只做一次加权和. 正确顺序是每头先依据自己的注意力权重汇聚潜向量, 再乘相应的 , 或使用等价的融合核.
这条限制给出了计算账. 每头先形成 , 需要约 次乘加; 再做 , 需要 量级计算. 标准注意力的值汇聚为 , 随后所有头拼接后做 输出投影. 两种路径谁更省取决于 、batch、内核和张量并行. MLA 的核心保证是少读缓存, 并未保证每个阶段 FLOPs 都更少.
训练时为何仍可用展开形式: 训练和长 prompt 预填充同时拥有许多 query. 若完全采用吸收形式, 每个 query 头与 512 维潜键相乘; 展开形式先生成 128 维键, 再使用成熟的矩阵乘法和 FlashAttention. 展开 K/V 会产生临时张量, 但它们只活在当前计算块中, 无需像解码缓存那样跨步保存. 因此训练时可选择计算更友好的形式, 解码时选择带宽更友好的形式, 两者在精确算术下表示同一函数.
这种等价性也提供了实现校验: 对同一批输入分别运行展开与吸收路径, 在 FP32 下输出应只差浮点误差; BF16、量化和融合核会扩大差异, 仍应落在预设容差内. 如果差异随序列长度系统增长, 常见原因包括 RoPE 路处理错误、softmax 缩放维度不一致, 或量化尺度在合并前后使用了不同轴.
解耦 RoPE 的缓存账与反例: V2 每层每 token 缓存 的 512 个元素和 的 64 个元素. 60 层合计 34560 个元素. BF16 为 69120 字节, 约 67.5 KiB; 128K token 按 计算得到 8.44 GiB. 若把 64 维位置键也按 128 个头分别缓存, 每层会新增 个元素, 总缓存变成每层 8704, 单条 128K 请求约 127.5 GiB. 「位置键跨头共享」本身就贡献了约 15 倍差距.
若取消位置路, 每层只剩 512 个元素, 单条 128K 缓存约 7.5 GiB, 比正式方案只少约 0.94 GiB. 这笔账说明 64 维位置键占 MLA 缓存的 , 用约一成缓存换取显式相对位置信息. 它的成本远低于按头保存 RoPE 键.
若把位置维度从 64 加到 128, 每层缓存为 640 个元素, 128K 单条约 9.38 GiB; 降到 32 维则为 544 个元素, 约 7.97 GiB. 在 32、64、128 间移动只改变一 GiB 左右, 所以维度选择更可能由质量决定, 而非容量发生数量级变化. 真正昂贵的是是否跨头复制.
再看一个位置混淆反例. 输入为「甲给乙一本书……甲又给丙一本书」, 末尾问「最近一次甲把书给了谁」. 两个事件的内容键都含有甲、给、书, 区别主要在位置和受事. 内容路能够通过「乙/丙」区分, 但 query 在问最近一次, 需要相对位置偏好. 若训练数据总把答案放在最近位置, 无位置路的模型也可能借残差状态中的间接位置信息猜测; 把两个事件替换为高度对称、受事随机的合成样本, 才能更纯粹地检验 RoPE 路.
另一个反例来自绝对位置无关任务. 将同一组事实随机打乱, 问其中某个实体的属性. 正确答案不应随顺序变化. 如果位置分数过强, 模型可能偏向开头或结尾. 所以位置路既要能表达距离, 又要允许 query 把其权重压低. 拼接后相加的两路分数提供了这种自由: 内容项可主导无序检索, 位置项可主导顺序任务.
MLA 与 MoE 必须联合观察: 四格消融: 最直接的联合实验是四个模型: MHA+Dense、MLA+Dense、MHA+MoE、MLA+MoE. 固定训练 FLOPs很难, 因为 MoE 改变激活计算, MLA 又改变注意力计算; 更可行的是同时报告固定 token、固定 GPU 小时两套结果. 固定 token 比较同样数据摄入后的质量和成本, 固定 GPU 小时比较现实预算下谁能学到更多数据.
从四格可计算 MLA 的主效应:
若两者接近, MLA 质量影响与 FFN 类型基本独立; 若差异很大, 说明低秩注意力与专家容量存在交互. MoE 的主效应也可同理计算. 交互项为
表示组合收益超过两项简单相加, 表示两者一起使用出现额外损失. V2 附录比较 MLA 与 MHA 时使用 MoE 模型, 能估计 , 但缺少 Dense 对应项, 无法计算交互.
6.2. 为什么可能产生交互
MLA 压缩注意力可长期保存的信息, MoE 扩大 FFN 的条件容量. 一种可能是互补: 注意力负责从上下文找出少量相关信息, 专家再按 token 类型做复杂变换; FFN 容量更大可以弥补注意力压缩造成的细节损失. 另一种可能是冲突: 路由器依据被 MLA 改写后的隐藏状态选择专家, 小的表示误差若让 token 跨过路由边界, 后续会进入完全不同的专家, 误差被离散选择放大.
可以记录同一批样本在 MHA 与 MLA 模型中的专家选择一致率. 若注意力输出很接近而专家选择频繁翻转, 说明路由边界敏感; 若翻转主要发生在分数接近的专家间且最终输出稳定, 则多个专家功能可能冗余. 还可固定路由选择, 单独替换注意力输出, 将路由放大效应与专家函数差异拆开.
联合系统上也有互补. MLA 减少张量并行中的缓存压力, MoE 增加专家并行通信. 省下的显存可以扩大 micro-batch, 更大的 token 批量提高 all-to-all 消息尺寸, 往往更容易利用网络带宽; 同时并发增大也可能加剧专家负载波动. 最终 GPU 小时包含这两种方向相反的作用. 仅凭参数量无法推导墙钟收益.
固定什么才算公平: 固定总参数会让 MoE 的激活参数远小于 Dense; 固定激活参数则 MoE 总容量更大; 固定训练 FLOPs又会使各模型见到的 token 数不同. 公平口径取决于所问的问题. 比较「同请求成本的准确率」可固定激活 FLOPs和数据; 比较「同存储容量的准确率」可固定总参数; 比较「同预算最终能力」则固定 GPU 小时. 报告中的正式模型比较偏向第三种现实问题, 附录消融更接近固定数据和规模.
训练与成本数字的复算表: 预训练 token 与步数: 最终 batch 为 9216 条, 序列长 4096, 每步 token 数为
如果 8.1T token 全部按最终 batch 训练, 约需 214578 步. 实际前 225B token 使用较小且逐渐增加的 batch, 所以总步数会更多. 最小 batch 2304 时每步 9437184 token; 前 225B token 的步数因此位于 5961 到 23842 之间. 剩余 7.875T token 按最终 batch 约 208617 步. 总步数可限定在约 214578 到 232459 之间, 精确值取决于 batch 增长曲线.
2000 步学习率 warmup 至少覆盖约 18.9B token, 至多约 75.5B token, 同样取决于当时 batch. 它明显短于 225B token 的 batch warmup. 学习率已到峰值时, batch 可能仍在增长. 两种 warmup 调节的是不同噪声来源, 时间范围不必一致.
GPU 小时与平均吞吐: 论文给出每 1T token 172.8K H800 GPU 小时. 换算为单 GPU 平均 token 吞吐:
67B 对应
二者比值约 1.74, 与 GPU 小时比值的倒数一致. 这是把整个集群工作量平均到每张 GPU 的统计吞吐, 包含流水线气泡与通信, 不能当作单卡独立运行 236B 模型的速度.
8.1T 乘 172.8K 得 1.39968M GPU 小时. 若集群有效使用 2048 张 GPU 且持续满载, 墙钟约 683 小时, 即 28.5 天; 4096 张则约 14.2 天. 论文数字可用来做这种量级换算, 实际卡数、维护中断与利用率会改变日历时间. GPU 小时也没有包含数据处理、失败重跑、消融和后训练的全部项目成本.
KV cache 的十进制与二进制单位: 前文 8.44 GiB 使用 字节作一 GiB. 若云服务页面按十进制 GB 展示, 同一缓存是 9.06 GB. 两个数字描述相同对象. 再加入 batch、张量并行与缓存量化时尤其容易因单位混乱得出看似矛盾的结果.
6 bit KV 若紧密打包, 理论上单条 128K 缓存为 GiB. 实现通常还需要分组尺度、零点、对齐与元数据, 实占会稍高. 若简单用 8 bit 容器存每个 6 bit 值而不打包, 则为约 4.22 GiB. 摘要的 93.3% 缩减更像理论有效位宽口径, 复现实测显存时应把量化元数据算进去.
对 67B GQA 的 BF16 基线, 95 层、8 个 KV 头、头宽 128, 每 token 为 个元素. 128K 时约 47.5 GiB. V2 的 6 bit 理论缓存约 3.17 GiB, 比值约 6.67%, 即减少 93.33%. 这次复算把层数、头数、精度与长度全部列出, 也验证了摘要数字为何不能只归给 MLA 结构.
6.3. 结论的强弱分层
可以由公式直接确认的结论有三条: V2 的缓存元素数是每层每 token 576; 不含位置操作的线性 K/V 上投影可以吸收到 query 和输出投影; MoE 每 token 只激活 2 个共享与 6 个路由专家. 这些结论不依赖基准波动.
由一次公开实验支持的结论包括: 附录规模下 MLA 相对 MHA 没有表现出质量损失; 正式训练中 V2 每 1T token 的 GPU 小时低于 67B; 给定部署方案下最大生成吞吐达到对照的 5.76 倍. 它们成立于报告的模型、数据和系统配置, 外推到其他规模需要继续测量.
仍属于待验证解释的部分包括: 共享潜变量主要滤掉了头间冗余; 共享专家确实承接通用知识; 三层均衡损失各自改善了哪种瓶颈; 128K 检索能力能否转化为复杂长程推理. 这些解释与结果相容, 论文提供的消融不足以逐条确认.
把三层分开有一个实际好处: 后续模型即使改掉路由损失, 也不会推翻 MLA 的代数节省; 某个新长上下文基准表现不佳, 也不会改变缓存确实缩小的事实. 相反, 若吸收与展开路径在高精度下无法给出一致输出, 就直接触及实现正确性; 若同配置复现实测缓存远超公式, 则应检查额外张量、量化元数据与并行副本. 结论越贴近可计算对象, 复核路径就越短, 争议也越少.
从一枚 token 走完整条路径: 把前面的部件串起来看一遍. 第 个 token 进入某层后, 隐状态先经 RMSNorm. 查询下投影生成 1536 维潜表示, 再上投影为各头的内容查询与位置查询; KV 下投影生成 512 维 , 另一路生成 64 维位置键. 当前 token 的这 576 个元素加入缓存. 内容查询在吸收后的潜空间里与所有历史 点积, 位置查询与旋转后的位置键点积, 两项相加并缩放, softmax 得到每头的历史权重. 各头用该权重汇聚潜值, 经过吸收后的值输出矩阵回到隐藏宽度.
注意力结果加回残差后进入 MoE. 路由器为 160 个路由专家打分, 设备限制先保留至多三张卡的候选, 再选 6 个专家; 两个共享专家始终参与. 八路输出加权汇总并走下一次残差. 训练时, 主语言建模损失更新全部被选路径, 三类均衡损失额外更新路由概率; 超过设备容量的低分分派可能被丢弃. 解码时不再保留这一 token 的完整 K 与 V, 下一步只读取刚写入的潜向量和位置键.
这条路径说明两个稀疏发生在不同坐标上. MLA 对历史状态做表示压缩, 每个历史 token 仍参加注意力; MoE 对参数执行做条件选择, 每个当前 token 只访问部分专家. 一个没有丢掉历史位置, 一个没有删掉未激活专家的参数. 把二者都简称为「稀疏」会掩盖它们各自的误差来源: MLA 的风险是低秩信息损失, MoE 的风险是路由错误与负载拥塞.
也可以据此定位故障. 长文中找不到近处的精确事实, 先查位置路、缓存量化和 MLA 容量; 某类 token 表现突然变差且伴随专家热点, 先查路由与丢弃; 所有领域随上下文增长一起退化, 再查 YaRN 外推和训练长度. 这些现象会互相影响, 但从 token 的数据流出发, 至少能把检查顺序排清.
还有一项容易漏掉的检查: 同一 token 在预填充路径和逐 token 解码路径中, 层输出应在数值容差内一致. 前者可能展开 K/V, 后者使用吸收矩阵; 两条路径若在短序列上已经分叉, 长上下文评测就失去解释基础. 先用 FP32 排除代数和索引问题, 再依次加入 BF16、权重量化与 KV 量化, 可以判断误差从哪一步进入. 对 RoPE 路还应分别测试位置 0、训练长度边缘与外推区间, 因为旋转频率错误往往在短输入上不明显, 到远距离才迅速积累. 这种逐层对照比只看最终生成文本更敏感, 也更容易复现.
参考资料: - DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model