专栏DeepSeek-V4 模型结构·优化器与训练7 / 8
8 min学习

DeepSeek-V4 模型结构(6):优化器与稳定性,Muon

从「Adam 逐元素、Muon 逐矩阵」的动机出发,推出谱范数下最速下降的解是梯度的正交化,再看 Newton–Schulz 迭代怎么不做 SVD 地逼近它。V4 的混合迭代用两组系数:一组把小奇异值快速抬起来,一组把奇异值精确钉在 1 上,多项式的形状说明了为什么。再讲 RMS 匹配、哪些参数留给 AdamW、为什么 Q/KV 归一化让 QK-Clip 不再需要、Anticipatory Routing,以及 MTP。

目录9 节

对应论文 §2.4 "Muon Optimizer"(Algorithm 1,公式 (28))和 §4.2.3 "Mitigating Training Instability",顺带把 §2.1 的 MTP 收掉。这是 DeepSeek 第一次在旗舰模型上用 Muon,上游是 Keller Jordan 2024 年的原始实现和 Moonshot 2025 年的 Moonlight

文本 token复制成 4 份,进入 4 条残差流(mHC 的 hc_mult = 4)残差流 ×4每条 d 维重复 29 次CSA 与 HCA 交错第 2 – 59 层,偶数层 CSA、奇数层 HCA每层注意力后接一个 MoEmHC:每个子层一次读、一次写 + 混:sigmoid,4 条流压成 1 条:2·sigmoid,输出分给 4 条流:Sinkhorn 20 轮,双随机三者都由当前 4 条流的内容动态生成logits最后一次只读:4 条流压成 1 条4 条流的最终状态 + 下一个 token 的 embeddingmHC 读算子 A:对 4 条流做 sigmoid 加权求和,得到子层的 d 维输入读 AmHC 读算子 A:对 4 条流做 sigmoid 加权求和,得到子层的 d 维输入读 AmHC 读算子 A:对 4 条流做 sigmoid 加权求和,得到子层的 d 维输入读 AmHC 读算子 A:对 4 条流做 sigmoid 加权求和,得到子层的 d 维输入读 AmHC 读算子 A:对 4 条流做 sigmoid 加权求和,得到子层的 d 维输入读 AmHC 读算子 A:对 4 条流做 sigmoid 加权求和,得到子层的 d 维输入读 AmHC 读算子 A:对 4 条流做 sigmoid 加权求和,得到子层的 d 维输入读 AmHC 读算子 A:对 4 条流做 sigmoid 加权求和,得到子层的 d 维输入读 AmHC 读算子 A:对 4 条流做 sigmoid 加权求和,得到子层的 d 维输入读 AmHC 写算子 C 与混合矩阵 B:子层输出按 C 分到 4 条流,同时 4 条流按双随机矩阵 B 互相混合写 C · 混 BmHC 写算子 C 与混合矩阵 B:子层输出按 C 分到 4 条流,同时 4 条流按双随机矩阵 B 互相混合写 C · 混 BmHC 写算子 C 与混合矩阵 B:子层输出按 C 分到 4 条流,同时 4 条流按双随机矩阵 B 互相混合写 C · 混 BmHC 写算子 C 与混合矩阵 B:子层输出按 C 分到 4 条流,同时 4 条流按双随机矩阵 B 互相混合写 C · 混 BmHC 写算子 C 与混合矩阵 B:子层输出按 C 分到 4 条流,同时 4 条流按双随机矩阵 B 互相混合写 C · 混 BmHC 写算子 C 与混合矩阵 B:子层输出按 C 分到 4 条流,同时 4 条流按双随机矩阵 B 互相混合写 C · 混 BmHC 写算子 C 与混合矩阵 B:子层输出按 C 分到 4 条流,同时 4 条流按双随机矩阵 B 互相混合写 C · 混 BmHC 写算子 C 与混合矩阵 B:子层输出按 C 分到 4 条流,同时 4 条流按双随机矩阵 B 互相混合写 C · 混 B词表 129280Token Embedding129280 × 7168Heavily Compressed Attention:每 128 个 token 压成一个 KV 条目,不做稀疏选择HCA第 0、1 层 · m′ = 128前三层的 MoE 按 token id 查表决定 expert,权重仍由 router 打分Hash-MoE第 0–2 层的 FFN · 384 选 6Compressed Sparse Attention:每 4 个 token 压成一个条目,indexer 选 top-k 个条目,加 128 个滑窗条目CSA偶数层 · ×30 · m = 4sqrt(softplus) 打分,无辅助损失偏置路由,SwiGLU clamp,FP4 expertDeepSeekMoE384 选 6 + 1 shared每 128 个 token 压成一个条目,全部条目都看HCA奇数层 · ×29 · m′ = 128同上DeepSeekMoE384 选 6 + 1 shared最后一层是 CSACSA第 60 层 · 收尾同上DeepSeekMoE第 60 层最终归一化RMSNorm不与 embedding 共享权重LM Head→ 129280多 token 预测模块:一个完整的 decoder block,注意力只有滑窗分支,有自己的 4 流残差和输出头MTP 层 ×1滑窗注意力 + MoE · 自带 mHC
序列 · CSA序列 · HCA序列 · 滑窗深度 · mHC宽度 · DeepSeekMoE零件
这一篇不对应图上的某个模块,讲的是怎么更新图上所有的矩阵。底部的 MTP 层放在这一篇收尾。

为什么要一个逐矩阵的优化器

Adam 把每个参数当成独立的标量:一阶矩、二阶矩、逐元素地自适应步长。它不知道参数是排成矩阵的。但 Transformer 里几乎所有参数都是矩阵 WRn×mW \in \mathbb{R}^{n \times m},作用是 y=Wx\mathbf{y} = W\mathbf{x},梯度 G=WLG = \nabla_W \mathcal{L} 也是矩阵,并且经验上梯度矩阵的奇异值分布极不均匀:少数几个方向占了绝大部分能量,其余方向几乎不动。Adam 逐元素归一化并不会改变这一点,更新仍然集中在少数方向上,长尾方向学得慢。

Muon 的想法:把更新的所有奇异方向推同样的距离

推导。 把一步更新写成「在某个范数球内让损失下降最多」的最速下降:

ΔW=argminΔηG,Δ.\Delta W = \arg\min_{\|\Delta\| \le \eta} \langle G, \Delta \rangle .

范数取欧氏范数(Frobenius)时,解是 ηG/GF-\eta G / \|G\|_F,就是普通 SGD。Muon 换成谱范数,也就是限制 WW 作为线性算子的最大放大倍数。记 G=UΣVG = U\Sigma V^\top,令 Δ=ηUV\Delta = -\eta\, U V^\top

G,UV=tr(VΣUUV)=tr(Σ)=iσi,\langle G, UV^\top \rangle = \operatorname{tr}(V \Sigma U^\top U V^\top) = \operatorname{tr}(\Sigma) = \sum_i \sigma_i ,

而对任意谱范数不超过 1 的 Δ\DeltaG,ΔGΔ2iσi\langle G, \Delta\rangle \le \|G\|_* \|\Delta\|_2 \le \sum_i \sigma_i(核范数是谱范数的对偶)。所以 UVUV^\top 取到了上界,谱范数下的最速下降方向就是把梯度的奇异值全部置 1,只保留奇异方向。这个 UVUV^\top 就是「GG 的正交化」,也是离 GG 最近的半正交矩阵。

Muon 在正交化之前先做动量累积,再加 Nesterov:

Mt=μMt1+Gt,Ot=Orthogonalize(μMt+Gt).M_t = \mu M_{t-1} + G_t, \qquad O'_t = \operatorname{Orthogonalize}(\mu M_t + G_t) .

Newton–Schulz:不做 SVD 的正交化

每一步对每个矩阵做 SVD 太贵。Newton–Schulz 迭代用矩阵乘法逼近 UVUV^\top:先把 MM 除以 Frobenius 范数,保证所有奇异值不超过 1,然后反复做

Mk=aMk1+b(Mk1Mk1)Mk1+c(Mk1Mk1)2Mk1.M_k = a\, M_{k-1} + b\, (M_{k-1} M_{k-1}^\top)\, M_{k-1} + c\, (M_{k-1} M_{k-1}^\top)^2\, M_{k-1} .

关键观察:这个迭代不改变奇异方向,只改变奇异值。代入 M=UΣVM = U\Sigma V^\topMM=UΣ2UM M^\top = U \Sigma^2 U^\top,于是每一步是 Σp(Σ)\Sigma \mapsto p(\Sigma)

p(σ)=aσ+bσ3+cσ5,p(\sigma) = a\sigma + b\sigma^3 + c\sigma^5 ,

对每个奇异值独立地作用同一个奇多项式。目标是让 pp 迭代若干次后把 [0,1][0, 1] 上的所有 σ\sigma 都送到 1 附近。系数怎么选,就是在设计这个多项式的形状。

归一化后的奇异值 σ ∈ [0, 1]迭代后的奇异值
A 一步:B 一步:k 步复合(按所选调度)

Jordan 的系数 (3.4445,4.7750,2.0315)(3.4445, -4.7750, 2.0315) 看它在两端的行为:p(0)=3.4445p'(0) = 3.4445,原点附近斜率 3.4,一个很小的奇异值每步放大 3.4 倍,五步就是 500500 倍,这是为了让长尾方向尽快抬起来;但 p(1)=0.701p(1) = 0.701,它没有把 1 当成不动点,迭代到后面奇异值会在 [0.7,1.2][0.7, 1.2] 之间震荡。Jordan 的说法是训练不需要精确正交化,落在这个范围内就够。

V4 的第二组系数 (2,1.5,0.5)(2, -1.5, 0.5) 它满足 p(1)=21.5+0.5=1p(1) = 2 - 1.5 + 0.5 = 1p(1)=24.5+2.5=0p'(1) = 2 - 4.5 + 2.5 = 0。1 是它的不动点,而且导数为零意味着二次收敛:离 1 差 ϵ\epsilon,一步之后差 O(ϵ2)O(\epsilon^2)。代价是 p(0)=2p'(0) = 2,抬升小奇异值的速度慢于第一组。

混合。 前 8 步用第一组,把所有奇异值快速拉到 1 附近;后 2 步用第二组,把它们精确钉在 1 上。论文只说「第一阶段驱动快速收敛,第二阶段把奇异值精确稳定在 1」,上面对两个多项式的分析是从系数直接算出来的。为什么 V4 要精确正交化而 Jordan 不在乎,论文没说;一个合理的猜测是 1.6T 规模上更新的 RMS 要和 AdamW 严格对齐,震荡的奇异值会让每步的有效步长抖动。

RMS 匹配与 AdamW 的分工

RMS 匹配。 正交化之后 OO' 的每个奇异值都是 1,它的元素 RMS 是 min(n,m)/(nm)\sqrt{\min(n,m)/(nm)} 量级,随矩阵形状变化,和 Adam 更新的 RMS(约 0.2 到 0.4)不在一个尺度上。Moonlight 的做法是把更新缩放到固定的 RMS,Algorithm 1 第 7 行:

Ot=Otmax(n,m)γ,O_t = O'_t \cdot \sqrt{\max(n, m)} \cdot \gamma ,

γ=0.18\gamma = 0.18(config 之外的训练超参,论文 §4.2.2)。这样 Muon 参数可以直接复用 AdamW 的学习率和权重衰减,两种优化器混用时不需要分别调。

权重衰减。 第 8 行 Wt=Wt1(1ηλ)ηOtW_t = W_{t-1}(1 - \eta\lambda) - \eta O_tλ=0.1\lambda = 0.1。Moonlight 发现没有权重衰减时 Muon 训出来的权重范数会持续增长,长训练后期反而落后于 AdamW。

哪些参数不用 Muon。 正交化只对「矩阵」有意义:embedding 和 LM head 是查表和分类头,不是线性算子意义上的矩阵;RMSNorm 的增益是向量;mHC 的静态偏置 SS 和门 α\alpha 是向量和标量。这些用 AdamW,β1=0.9\beta_1 = 0.9β2=0.95\beta_2 = 0.95ϵ=1020\epsilon = 10^{-20},权重衰减 0.1。其余全部矩阵用 Muon,动量 0.95,权重衰减 0.1。

论文说正交化是对每个「逻辑上独立的权重」做的。分组输出投影的 16 个组、每个 expert 的三个矩阵,各自是独立矩阵。

为什么不需要 QK-Clip

Muon 有一个已知的副作用。Kimi K2 报告过:Muon 下注意力 logit 容易爆炸,因为正交化后的更新在所有方向上等距推进,WQW_QWKW_K 的谱范数增长得比 Adam 下快,qk\mathbf{q}^\top \mathbf{k} 随之增长。K2 的对策是 MuonClip:每步之后检查每个头的最大 logit,超过阈值就按比例缩小 WQW_QWKW_K

V4 不需要这一步,原因在结构上。第 3 篇讲过,query 展开成 128 头之后逐头做 RMSNorm,KV 那条 512 维向量也做 RMSNorm,都在计算 logit 之前。归一化之后 q\|\mathbf{q}\|k\|\mathbf{k}\| 的尺度被固定,logit 的上界由头维和 RMSNorm 的增益决定,和 WUQW^{UQ}WKVW^{KV} 的范数无关。WW 长多大都不会让 logit 爆炸。论文 §2.4 的原话:「V4 的注意力架构允许我们直接在 query 和 KV 上做 RMSNorm,有效防止 logit 爆炸,因此不采用 QK-Clip」。

能这么做的前提是 V4 的 KV 只有一条向量:MLA 的 latent 在展开成 128 个头的 K 之后才有 logit,对 latent 做归一化管不住展开后的尺度。K = V 的单头设计顺手解决了这个问题。

Anticipatory Routing

§4.2.3 的第二个稳定性技巧,和 MoE 相关。V4 训练中 loss spike 一直和 MoE 层的离群激活绑定,而且路由本身在放大它:某个 expert 出了离群值,路由把更多 token 送过去,离群值继续长。论文说完整的机理还不清楚,但找到了一个打断这个循环的办法。

多出的一次前向约 20% 额外时间,和 EP 通信重叠:多做一次前向预取步的数据,用算出路由索引缓存索引每个 token 选哪 6 个 expert:正常训练特征用算,路由按缓存的索引走检测到 loss spike短回滚,自动开启这个模式运行一段时间后自动关闭,回到标准训练
Anticipatory Routing。路由决定和特征计算被拆到两个时刻:路由索引来自 Δt 步之前的参数,特征来自当前参数。只在 spike 之后临时开启,所以整体开销可以忽略。

做法是把「算路由」和「算特征」在时间上拆开:第 tt 步的特征用当前参数 θt\theta_t,但路由索引用 Δt\Delta t 步之前的参数 θtΔt\theta_{t-\Delta t} 算。实现上不是保存两份参数,而是在第 tΔtt - \Delta t 步提前取到第 tt 步的数据,多跑一次前向把索引算出来缓存。多出来的一次前向经过流水线和 EP 通信重叠后约 20% 额外时间,但只在检测到 spike 之后才开启:自动回滚一小段、打开这个模式跑一阵、再切回正常训练。整体开销可以忽略,论文说不损性能。

和 SwiGLU 截断(第 5 篇)一起,这是 V4 训练稳定性的两个支柱:一个直接压离群值,一个打断路由的正反馈。

MTP

多 token 预测沿用 DeepSeek-V3:一个 MTP 模块,预测第 t+2t+2 个 token,损失权重 0.3,学习率衰减开始时降到 0.1。V4 里它的结构(官方代码 MTPBlock):

  • 是一个完整的 decoder block,含注意力、MoE 和自己的一套 mHC 参数,输入输出都是 4 条残差流。
  • 输入是主干最后一层的 4 条流经 RMSNorm 后过 h_proj,加上下一个 token 的 embedding 经 RMSNorm 后过 e_proj 广播到 4 条流。
  • 注意力只有滑窗分支compress_ratios 的最后一项是 0)。
  • 输出经它自己的 hc_head 压成 1 条,共用主干的最终 RMSNorm 和 LM head。

论文没有说 MTP 在部署时是否用于投机解码。

训练配方的数字

放在这里方便查,都来自 §4.2.2:

FlashPro
token 数32T33T
最大 batch75.5M token94.4M token
峰值学习率 → 末端2.7×1042.7 \times 10^{-4}2.7×1052.7 \times 10^{-5}2.0×1042.0 \times 10^{-4}2.0×1052.0 \times 10^{-5}
warmup2000 步同左
序列长度4K → 16K → 64K → 1M同左
稠密注意力阶段前 1T token更长
引入稀疏64K 阶段,先短暂热身 indexer同左
Muon RMS γ\gamma / 动量 / 衰减0.18 / 0.95 / 0.1同左
平衡偏置速度 / 序列级损失权重0.001 / 10410^{-4}同左
MTP 权重0.3 → 0.1同左

术语坑

  • Muon 里的「正交化」是半正交。 nmn \ne mUVUV^\top 只是一侧正交。
  • RMS 匹配的 0.18 不是学习率。 它是把 Muon 更新的元素 RMS 对齐到 AdamW 的量级,学习率另算。
  • QK-Clip 和 Q/KV 归一化不是二选一的技巧,是两种层面。 前者是优化器里的事后修正,后者是结构。
  • MTP 的 compress_ratios 项。 61 层的 config 有 62 项,Flash 43 层有 44 项,多的那项属于 MTP。

下一篇

最后一篇讲结构决定的系统:混合注意力的 KV cache 怎么布局,压缩窗口跨越上下文并行边界时怎么通信,磁盘上的前缀缓存怎么存,以及 mHC 的 6.7% 是怎么压出来的。