Browse this library

Chinese source article

02 · DeepSeek-V2: 用 MLA 压推理显存, 用 MoE 压训练算力

DeepSeek-V2 总参 236B, 每个 token 激活 21B, 上下文 128K, 在 8.1T token 上预训练, 再经 1.5M 条 SFT 和两阶段 GRPO 得到 Chat 版.

View original Markdown ↗

来源: 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 在每层要缓存 2×8×128=20482\times 8\times 128=2048 个 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 每层缓存 2nhdh2n_hd_h 个元素. 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 先联合压成一个低维潜向量 ctKV=WDKVht\mathbf{c}_t^{KV}=W^{DKV}\mathbf{h}_t(式 9), 再用 WUKW^{UK}, WUVW^{UV} 上投影回每个头的 K 和 V(式 10–11). 推理时只缓存 ctKV\mathbf{c}_t^{KV}, 每层 dcd_c 个元素. V2 取 dc=512d_c=512, 而 MHA 在同样 128 头, 每头 128 维下要存 32,768 个. 更关键的是矩阵吸收: 注意力分数 qTk=hTWQ TWUKc\mathbf{q}^T\mathbf{k}=\mathbf{h}^TW^{Q,T}W^{UK}\mathbf{c}, 中间两个矩阵可以预先乘成一个, 推理时 query 直接和缓存的潜向量做内积, 不用把每个历史 token 的 K 展开出来; WUVW^{UV} 同理吸进输出投影 WOW^O. 中文技术社区的实现笔记指出, 吸收后 128 个头共享同一份 cKV\mathbf{c}^{KV}, 计算形态接近 MQA, 算术强度正比于头数, 这对显存带宽受限的解码阶段很有利.

矩阵吸收也有代价. 吸收之后, 每个头的 query 要先映射到 512 维的潜空间, 再和每个历史 token 的潜向量做内积, 单头单 token 的点积长度从 128 变成 512 加 64. 解码阶段每步只有一个新 token, 瓶颈是读缓存的显存带宽, 多算一点不要紧; 预填充阶段一次处理整段 prompt, 算力才是瓶颈, 这时把 K, V 显式展开反而更省. 所以公开的推理实现通常在预填充时展开, 解码时吸收. 报告附录 C 只说「推理时可以吸收」, 没有区分这两个阶段.

Query 也做了低秩压缩, dc′=1536d_c'=1536(式 12–13), 但目的只是省训练期的激活显存, 与 KV cache 无关. 低秩压缩会改变层输出的尺度, 所以报告在压缩潜向量之后加了 RMSNorm, 并在宽度瓶颈处(潜向量和路由专家的中间态)乘额外的缩放系数来稳住训练. 缩放系数取多少, 报告没有给. 机制推导见 MLA: 低秩潜变量与矩阵吸收, GQA 的折中思路见 GQA: 在性能与缓存之间折中.

1.3. 解耦 RoPE, 以及 93.3% 是怎么算出来的

RoPE 和矩阵吸收不兼容. 如果对上投影后的 ktC\mathbf{k}t^C 施加 RoPE, 与当前位置相关的旋转矩阵就会夹在 WQW^Q 和 WUKW^{UK} 中间, 矩阵乘法不满足交换律, 两者不能预先合并, 推理时又得为所有前缀 token 重算 K. 报告的办法是把位置信息单独拿出来: 另开每头 dhRd_h^R 维的 qt,iR\mathbf{q}{t,i}^R 和一个所有头共享的 ktR\mathbf{k}_t^R 专门承载 RoPE(式 14–15), 内容部分 qC\mathbf{q}^C, kC\mathbf{k}^C 不加位置编码, 继续走吸收路径; 两部分拼接后算注意力, 分母改成 dh+dhR\sqrt{d_h+d_h^R}(式 18). 共享的 ktR\mathbf{k}_t^R 直接从 ht\mathbf{h}_t 投影, 不经过潜向量, 也要进缓存. 社区里常把 kR\mathbf{k}^R 描述成「MQA 版的 RoPE」: 位置这一路只有一个头, 内容这一路有 128 个头.

V2 取 dhR=64d_h^R=64, 每层缓存 512+64=576512+64=576 个元素, 等于 4.5dh4.5d_h. Table 1 说这相当于「只有 2.25 组的 GQA」, 就是由 2ngdh=4.5dh2n_gd_h=4.5d_h 解出来的. 这个数可以和附录交叉验证: 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, 34,560×6 / (194,560×16)≈6.7%34{,}560\times 6,/,(194{,}560\times 16)\approx 6.7%, 缩减正好是 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 的输出是

ht′=ut+∑i=1NsFFNi(s)(ut)+∑i=1Nrgi,t FFNi(r)(ut),si,t=Softmaxi(ut⊤ei),\mathbf{h}_t'=\mathbf{u}_t+\sum_{i=1}^{N_s}\mathrm{FFN}_i^{(s)}(\mathbf{u}_t)+\sum_{i=1}^{N_r}g_{i,t}\,\mathrm{FFN}_i^{(r)}(\mathbf{u}_t),\qquad s_{i,t}=\mathrm{Softmax}_i(\mathbf{u}_t^\top\mathbf{e}_i),

gi,t=si,tg_{i,t}=s_{i,t} 当 si,ts_{i,t} 在 NrN_r 个亲和度的 Top-KrK_r 内, 否则为 0. 第一项是残差; 第二项 Ns=2N_s=2 个共享专家不经门控, 权重恒为 1, 每个 token 都走; 第三项 Nr=160N_r=160 个路由专家里只有 Kr=6K_r=6 个非零. ei\mathbf{e}_i 是专家 ii 的中心向量, 亲和度就是 token 和它的内积. Softmax 是在全部 160 个专家上做的, 取 Top-6 之后不再归一化, 所以 6 个门控之和小于 1, 路由越分散, 路由专家这一路的输出就越小, 共享专家那一路的相对分量越大. 这套结构的机制讨论见 DeepSeek-MoE.

细粒度带来一个副作用: 激活专家多, 如果它们散在很多张卡上, 专家并行的 all-to-all 通信就会变贵. 每层 160 个路由专家均匀铺在 8 张卡上(D=8D=8), 每卡 20 个, 不加限制时一个 token 的 6 个专家最多可能落在 6 张卡上. 设备受限路由(device-limited routing)先按每张卡上最高的亲和度挑出 MM 张卡, 再只在这些卡的专家里做 Top-6. V2 取 M=3M=3, 报告称 M≥3M\ge 3 时效果与不受限的 Top-K 大致持平, 但没有附表, 也没有给出 M=1M=1 或 M=2M=2 的数字.

用配置可以反推 236B 和 21B 是怎么构成的. 一个 SwiGLU 专家有三个 5120×1536 的矩阵, 约 23.6M 参数; 每层 162 个专家约 3.8B, 59 个 MoE 层合计约 225B. 每 token 激活 2 个共享加 6 个路由, 共 8 个专家, 59 层约 11.1B. 注意力一层的投影矩阵加起来约 149M(其中输出投影 WOW^O 就有 128×128×5120, 约 84M), 60 层约 9B. 再加约 1B 的输入输出词嵌入和第一层的 Dense FFN, 激活参数约 21B, 总参约 235B, 与报告的 21B 和 236B 对得上. 这笔推算说明, V2 激活的 21B 里注意力占了四成以上, 专家只占一半左右; MLA 省的是缓存, 不是参数.

这个限制还给了发送端一个硬上界: 每张卡最多向外发送 MTMT 个隐状态, TT 是序列 token 数. 共享专家不需要跨卡, 所以 V2 把共享专家的计算和专家并行的 all-to-all 通信重叠起来, 让等通信的时间也在算东西. 这一步是训练效率的关键之一, 但重叠带来的具体提速比例, 报告没有给.

2.2. 三级均衡损失和 token-dropping

路由不均衡有两个后果: 一部分专家训不到, 出现路由塌缩; 专家并行时, 忙的卡拖慢整层. V2 叠了三级辅助损失. 专家级一项写全是

LExpBal=α1∑i=1NrfiPi,fi=NrKrT∑t=1T1(token t 选中专家 i),Pi=1T∑t=1Tsi,t,\mathcal{L}_{\mathrm{ExpBal}}=\alpha_1\sum_{i=1}^{N_r}f_iP_i,\qquad f_i=\frac{N_r}{K_rT}\sum_{t=1}^{T}\mathbb{1}(\text{token }t\text{ 选中专家 }i),\qquad P_i=\frac{1}{T}\sum_{t=1}^{T}s_{i,t},

α1=0.003\alpha_1=0.003. 一个序列 TT 个 token 各选 KrK_r 个专家, 共 KrTK_rT 次选择, 均匀时每个专家分到 KrT/NrK_rT/N_r 次, 前面的系数 Nr/(KrT)N_r/(K_rT) 就是把这个值归一到 fi=1f_i=1. PiP_i 是专家 ii 在这段序列上的平均 Softmax 亲和度, ∑iPi=1\sum_iP_i=1. 均匀路由时 ∑ifiPi=Nr⋅1⋅1Nr=1\sum_if_iP_i=N_r\cdot1\cdot\frac{1}{N_r}=1. fif_i 来自 Top-K 的指示函数, 不可导, 梯度只经 PiP_i 流回路由器, 而 PiP_i 前面的权重正是 fif_i: 被选得越多的专家, 它的亲和度被往下压得越重, 冷门专家几乎不受压. 这就是乘积形式的作用, 用不可导的计数给可导的概率加权. 设备级 LDevBal\mathcal{L}{\mathrm{DevBal}}(式 26–28)把同卡专家的 ff 取平均, PP 求和, α2=0.05\alpha_2=0.05. 通信级 LCommBal\mathcal{L}{\mathrm{CommBal}}(式 29–31)的 f′′f'' 统计的是 token 被发往某卡的频率, 用 D/(MT)D/(MT) 归一化, α3=0.02\alpha_3=0.02; 归一化的道理和专家级相同: 每个 token 最多发往 MM 张卡, 共 MTMT 次发送, 均匀时每卡 MT/DMT/D 次, 归一后 fi′′=1f''_i=1; 设备受限路由限住了发送端, 这一项鼓励每张卡接收的量也在 MTMT 左右.

读公式时会发现, 设备级和通信级两项的 PP 完全相同(都是同卡专家亲和度之和), 区别只在 ff: 一个是同卡专家被选频率的均值, 一个是「被发送到该卡」的频率. 仓库的 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, β1=0.9\beta_1=0.9, β2=0.95\beta_2=0.95, weight decay 0.1, 梯度裁剪 1.0. 学习率前 2K 步线性升到峰值 2.4e-4, 训到约 60% 和 90% token 时各乘 0.316, 这个系数约为 1/101/\sqrt{10}, 两次之后学习率是峰值的 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 里只有解耦的 ktR\mathbf{k}_t^R 和 qR\mathbf{q}^R 带 RoPE, 所以 YaRN 只作用在这 64 维上. 参数: 扩展倍数 s=40s=40, α=1\alpha=1, β=32\beta=32, 目标上限 160K(4K 乘 40), 期望 128K 可用. YaRN 原版用一个随 ss 变化的注意力温度调节 softmax 的熵, 原式是 1/t=0.1ln⁡s+1\sqrt{1/t}=0.1\ln s+1; V2 把系数改成 0.0707, 报告写作 t=0.0707ln⁡s+1\sqrt{t}=0.0707\ln s+1, 目标是让困惑度最低. 频率插值的机制见 长度外推: 从 PI 到 YaRN 的频率扩展.

这里有一个实现层面的细节. 原版 YaRN 通常把温度乘到 RoPE 的 cos/sin 上, 让 q 和 k 各自放大 1/t\sqrt{1/t}, 点积就放大 1/t1/t. 这个做法要求整个 q, k 向量都经过 RoPE; MLA 里只有 64 维带 RoPE, 另外 128 维不带, 乘在 cos/sin 上只会放大一部分. llama.cpp 社区在移植时讨论过这个问题, 公开推理代码的做法是把温度移到 softmax 的缩放系数上. 按 s=40s=40 算, V2 的系数约 1.26, 原版约 1.37. 另外社区指出报告里的 t\sqrt{t} 应为 1/t\sqrt{1/t}, 属于笔误.

长上下文训练只有 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 维, dc=512d_c=512, 解耦 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. 专家全放在同一张卡上, 所以只保留很小的专家级损失(α1=0.001\alpha_1=0.001), 设备级, 通信级损失和设备受限路由都不需要. 之后扩到 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. 矩阵吸收的代数条件

线性、固定与位置无关: 矩阵吸收成立需要三个条件. 第一, 被合并的两步必须是线性映射. WUKcW^{UK}c 与 query 做双线性内积, 可以利用结合律重排; 若两者之间插入逐元素激活、归一化或依赖 token 的门控, 就无法用一个固定矩阵替代. 例如键若写成 SiLU⁡(WUKc)\operatorname{SiLU}(W^{UK}c), 一般不存在矩阵 AA 使 qTSiLU⁡(WUKc)=(Aq)Tcq^{\mathsf T}\operatorname{SiLU}(W^{UK}c)=(Aq)^{\mathsf T}c 对所有 q,cq,c 成立.

第二, 上投影参数在处理整段缓存时固定. 常规推理满足这一点. 若使用根据输入动态生成权重的超网络, 每个历史 token 的 WsUKW_s^{UK} 不同, query 端无法预先吸收成同一个矩阵. 量化不会必然破坏吸收, 但「先量化两矩阵再相乘」与「先相乘再量化」会产生不同舍入误差, 部署时必须明确使用哪条路径.

第三, 上投影不能夹带无法移到 query 侧的位置操作. RoPE 正是违反这条条件的因素. 旋转矩阵依赖历史位置 ss, 合成结果也依赖 ss. 解耦之后, 内容路恢复位置无关, 位置路则直接缓存已经旋转的共享键. ALiBi 一类把位置偏置直接加在 logit 上的方法不会夹在 K 上投影中, 理论上更容易与吸收共存; 代价与长程性质属于另一问题.

6.1. 多头输出吸收的索引展开

设第 ii 个头值上投影为 UiV∈Rdh×dcU_i^V\in\mathbb R^{d_h\times d_c}, 输出投影按头分块为 Oi∈Rd×dhO_i\in\mathbb R^{d\times d_h}. 层输出为

yt=∑iOi∑sat,s,iUiVcs=∑i∑sat,s,i(OiUiV)cs.y_t=\sum_i O_i\sum_s a_{t,s,i}U_i^Vc_s =\sum_i\sum_s a_{t,s,i}(O_iU_i^V)c_s.

预计算 Bi=OiUiV∈Rd×dcB_i=O_iU_i^V\in\mathbb R^{d\times d_c} 后, 历史值无需展开. 但权重 at,s,ia_{t,s,i} 仍按头不同, 所以不能把所有 BiB_i 简单加成一个矩阵后只做一次加权和. 正确顺序是每头先依据自己的注意力权重汇聚潜向量, 再乘相应的 BiB_i, 或使用等价的融合核.

这条限制给出了计算账. 每头先形成 ut,i=∑sat,s,ics∈Rdcu_{t,i}=\sum_s a_{t,s,i}c_s\in\mathbb R^{d_c}, 需要约 SdcS d_c 次乘加; 再做 Biut,iB_i u_{t,i}, 需要 ddcd d_c 量级计算. 标准注意力的值汇聚为 SdhS d_h, 随后所有头拼接后做 d×dd\times d 输出投影. 两种路径谁更省取决于 SS、batch、内核和张量并行. MLA 的核心保证是少读缓存, 并未保证每个阶段 FLOPs 都更少.

训练时为何仍可用展开形式: 训练和长 prompt 预填充同时拥有许多 query. 若完全采用吸收形式, 每个 query 头与 512 维潜键相乘; 展开形式先生成 128 维键, 再使用成熟的矩阵乘法和 FlashAttention. 展开 K/V 会产生临时张量, 但它们只活在当前计算块中, 无需像解码缓存那样跨步保存. 因此训练时可选择计算更友好的形式, 解码时选择带宽更友好的形式, 两者在精确算术下表示同一函数.

这种等价性也提供了实现校验: 对同一批输入分别运行展开与吸收路径, 在 FP32 下输出应只差浮点误差; BF16、量化和融合核会扩大差异, 仍应落在预设容差内. 如果差异随序列长度系统增长, 常见原因包括 RoPE 路处理错误、softmax 缩放维度不一致, 或量化尺度在合并前后使用了不同轴.

解耦 RoPE 的缓存账与反例: V2 每层每 token 缓存 cKVc^{KV} 的 512 个元素和 kRk^R 的 64 个元素. 60 层合计 34560 个元素. BF16 为 69120 字节, 约 67.5 KiB; 128K token 按 131072131072 计算得到 8.44 GiB. 若把 64 维位置键也按 128 个头分别缓存, 每层会新增 128×64=8192128\times64=8192 个元素, 总缓存变成每层 8704, 单条 128K 请求约 127.5 GiB. 「位置键跨头共享」本身就贡献了约 15 倍差距.

若取消位置路, 每层只剩 512 个元素, 单条 128K 缓存约 7.5 GiB, 比正式方案只少约 0.94 GiB. 这笔账说明 64 维位置键占 MLA 缓存的 64/576=11.1%64/576=11.1%, 用约一成缓存换取显式相对位置信息. 它的成本远低于按头保存 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 的主效应:

ΔMLADense=S(MLA,Dense)−S(MHA,Dense),\Delta_{MLA}^{Dense}=S(MLA,Dense)-S(MHA,Dense),
ΔMLAMoE=S(MLA,MoE)−S(MHA,MoE).\Delta_{MLA}^{MoE}=S(MLA,MoE)-S(MHA,MoE).

若两者接近, MLA 质量影响与 FFN 类型基本独立; 若差异很大, 说明低秩注意力与专家容量存在交互. MoE 的主效应也可同理计算. 交互项为

I=S(MLA,MoE)−S(MHA,MoE)−S(MLA,Dense)+S(MHA,Dense).I=S(MLA,MoE)-S(MHA,MoE)-S(MLA,Dense)+S(MHA,Dense).

I>0I>0 表示组合收益超过两项简单相加, I<0I<0 表示两者一起使用出现额外损失. V2 附录比较 MLA 与 MHA 时使用 MoE 模型, 能估计 ΔMLAMoE\Delta_{MLA}^{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 数为

9216×4096=37,748,736.9216\times4096=37{,}748{,}736.

如果 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 吞吐:

1012172800×3600≈1607 token/s/GPU.\frac{10^{12}}{172800\times3600}\approx1607\ \text{token/s/GPU}.

67B 对应

1012300600×3600≈924 token/s/GPU.\frac{10^{12}}{300600\times3600}\approx924\ \text{token/s/GPU}.

二者比值约 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 使用 2302^{30} 字节作一 GiB. 若云服务页面按十进制 GB 展示, 同一缓存是 9.06 GB. 两个数字描述相同对象. 再加入 batch、张量并行与缓存量化时尤其容易因单位混乱得出看似矛盾的结果.

6 bit KV 若紧密打包, 理论上单条 128K 缓存为 8.44×6/16≈3.178.44\times6/16\approx3.17 GiB. 实现通常还需要分组尺度、零点、对齐与元数据, 实占会稍高. 若简单用 8 bit 容器存每个 6 bit 值而不打包, 则为约 4.22 GiB. 摘要的 93.3% 缩减更像理论有效位宽口径, 复现实测显存时应把量化元数据算进去.

对 67B GQA 的 BF16 基线, 95 层、8 个 KV 头、头宽 128, 每 token 为 95×2×8×128=19456095\times2\times8\times128=194560 个元素. 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 走完整条路径: 把前面的部件串起来看一遍. 第 tt 个 token 进入某层后, 隐状态先经 RMSNorm. 查询下投影生成 1536 维潜表示, 再上投影为各头的内容查询与位置查询; KV 下投影生成 512 维 ctKVc_t^{KV}, 另一路生成 64 维位置键. 当前 token 的这 576 个元素加入缓存. 内容查询在吸收后的潜空间里与所有历史 csKVc_s^{KV} 点积, 位置查询与旋转后的位置键点积, 两项相加并缩放, 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