专栏DeepSeek-V4 模型结构·总览1 / 8
9 min学习

DeepSeek-V4 模型结构(0):一张图看懂 DeepSeek-V4

连载开篇。用一张可点击的总架构图把 DeepSeek-V4 的 4 条残差流、交错的两种压缩注意力和 MoE 摆在一起,给出 Pro 与 Flash 的层排布和维度表、V3 → V3.2 → V4 的结构对照,并说明后面每一篇讲什么。

目录8 节

这个连载配合 DeepSeek-V4 技术报告的 §2 "Architecture" 一起读。论文这一节只有九页,但三个升级各自压着一篇独立论文,MoE 和训练稳定性上又散落着几处小改动。开篇先不进任何细节,只做三件事:把整个模型画成一张图,把层数和维度对上,告诉你后面每一篇在图上的哪个位置。

三句话版本

DeepSeek-V4 是两个模型:Pro 总参数 1.6T、每 token 激活 49B、61 层;Flash 总参数 284B、激活 13B、43 层。两者结构完全相同,只差尺寸,都在 32T 以上的 token 上预训练,上下文 1M

论文把结构上的改动归成三个升级,再加上 MoE 上的几处小调整:

维度混合的是什么模块来自哪篇论文
序列token 之间Compressed Sparse Attention(CSA)与 Heavily Compressed Attention(HCA)交错DeepSeek-V3.2 的 DSA(2512.02556)+ V4 自己的压缩
深度层之间Manifold-Constrained Hyper-Connections(mHC)mHC(2512.24880)
宽度通道之间DeepSeekMoE,打分函数、前三层路由、平衡损失、激活截断四处小改DeepSeekMoE、DeepSeek-V3
优化器Muon,混合 Newton–SchulzMoonlight(2502.16982)

论文给的效率数字:1M 上下文下,Pro 单 token 推理的 FLOPs 只有 DeepSeek-V3.2 的 27%,KV cache 只有 10%。

总图

下面这张图是论文 Figure 2 的中文可交互版。后面每一篇文章开头都会再放一次,只点亮当篇讲的模块。

文本 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零件
DeepSeek-V4-Pro 总架构。纵向是深度,每一行是一个子层:先经过一个读算子 A 把 4 条残差流压成一条,进子层,输出再由写算子 C 分回 4 条流,同时 4 条流按混合矩阵 B 互相交换。方块可点击跳到对应文章。

怎么读这张图:

  • 中间是 4 条残差流,不是 1 条。 这是 mHC 的做法:把残差流拓宽成 hc_mult = 4 份,每份 dd 维。词嵌入进来时复制 4 份。子层本身仍然只看 dd 维输入、输出 dd 维,所以注意力和 MoE 的内部设计不受影响。
  • 每个子层前后各有一个 mHC 算子。 前面的读算子 AlA_l 是 4 个非负权重,把 4 条流加权求和成子层输入;后面的写算子 ClC_l 把子层输出分回 4 条流,混合矩阵 BlB_l 让 4 条流在这一步互相交换。BlB_l 被约束成双随机矩阵,这个约束是 mHC 相对 HC 的全部改动。三者都由当前 4 条流的内容动态生成。
  • 子层只有四种。 CSA 和 HCA 是两种注意力,DeepSeekMoE 是 FFN,前三层的 FFN 是一个按 token id 查表路由的 hash-MoE。没有稠密层。
  • 虚线框里的四行交错重复。 偶数层是 CSA,奇数层是 HCA,每层注意力后面接一个 MoE。第 0、1 层是两层 HCA,最后一层是 CSA。
  • 底部是输出。 最后一次读算子把 4 条流压成 1 条,过 RMSNorm 和 LM head。预训练时还挂了一个 MTP 层,它是一个完整的 decoder block,带自己的 4 条流和输出头。

层怎么排

第 0 层:HCA(m′ = 128),FFN 是 hash-MoE第 1 层:HCA(m′ = 128),FFN 是 hash-MoE第 2 层:CSA(m = 4),FFN 是 hash-MoE第 3 层:HCA(m′ = 128),FFN 是 MoE第 4 层:CSA(m = 4),FFN 是 MoE第 5 层:HCA(m′ = 128),FFN 是 MoE第 6 层:CSA(m = 4),FFN 是 MoE第 7 层:HCA(m′ = 128),FFN 是 MoE第 8 层:CSA(m = 4),FFN 是 MoE第 9 层:HCA(m′ = 128),FFN 是 MoE第 10 层:CSA(m = 4),FFN 是 MoE第 11 层:HCA(m′ = 128),FFN 是 MoE第 12 层:CSA(m = 4),FFN 是 MoE第 13 层:HCA(m′ = 128),FFN 是 MoE第 14 层:CSA(m = 4),FFN 是 MoE第 15 层:HCA(m′ = 128),FFN 是 MoE第 16 层:CSA(m = 4),FFN 是 MoE第 17 层:HCA(m′ = 128),FFN 是 MoE第 18 层:CSA(m = 4),FFN 是 MoE第 19 层:HCA(m′ = 128),FFN 是 MoE第 20 层:CSA(m = 4),FFN 是 MoE第 21 层:HCA(m′ = 128),FFN 是 MoE第 22 层:CSA(m = 4),FFN 是 MoE第 23 层:HCA(m′ = 128),FFN 是 MoE第 24 层:CSA(m = 4),FFN 是 MoE第 25 层:HCA(m′ = 128),FFN 是 MoE第 26 层:CSA(m = 4),FFN 是 MoE第 27 层:HCA(m′ = 128),FFN 是 MoE第 28 层:CSA(m = 4),FFN 是 MoE第 29 层:HCA(m′ = 128),FFN 是 MoE第 30 层:CSA(m = 4),FFN 是 MoE第 31 层:HCA(m′ = 128),FFN 是 MoE第 32 层:CSA(m = 4),FFN 是 MoE第 33 层:HCA(m′ = 128),FFN 是 MoE第 34 层:CSA(m = 4),FFN 是 MoE第 35 层:HCA(m′ = 128),FFN 是 MoE第 36 层:CSA(m = 4),FFN 是 MoE第 37 层:HCA(m′ = 128),FFN 是 MoE第 38 层:CSA(m = 4),FFN 是 MoE第 39 层:HCA(m′ = 128),FFN 是 MoE第 40 层:CSA(m = 4),FFN 是 MoE第 41 层:HCA(m′ = 128),FFN 是 MoE第 42 层:CSA(m = 4),FFN 是 MoE第 43 层:HCA(m′ = 128),FFN 是 MoE第 44 层:CSA(m = 4),FFN 是 MoE第 45 层:HCA(m′ = 128),FFN 是 MoE第 46 层:CSA(m = 4),FFN 是 MoE第 47 层:HCA(m′ = 128),FFN 是 MoE第 48 层:CSA(m = 4),FFN 是 MoE第 49 层:HCA(m′ = 128),FFN 是 MoE第 50 层:CSA(m = 4),FFN 是 MoE第 51 层:HCA(m′ = 128),FFN 是 MoE第 52 层:CSA(m = 4),FFN 是 MoE第 53 层:HCA(m′ = 128),FFN 是 MoE第 54 层:CSA(m = 4),FFN 是 MoE第 55 层:HCA(m′ = 128),FFN 是 MoE第 56 层:CSA(m = 4),FFN 是 MoE第 57 层:HCA(m′ = 128),FFN 是 MoE第 58 层:CSA(m = 4),FFN 是 MoE第 59 层:HCA(m′ = 128),FFN 是 MoE第 60 层:CSA(m = 4),FFN 是 MoEMTP 层:纯滑窗注意力 + MoE02102030405060MTP第 0–2 层:hash-MoE■ CSA ×30(偶数层)■ HCA ×31(第 0、1 层 + 奇数层)■ MTP 层:纯滑窗注意力(config 里 compress_ratios 的最后一项)共 61 层,全部是 MoE;论文说的「前两层」是这里的第 0、1 层。第 60 层(最后一层)是 CSA。
Pro 的 61 层。层号按 config.json 和官方代码的 0-indexed 口径。
第 0 层:纯滑窗注意力,FFN 是 hash-MoE第 1 层:纯滑窗注意力,FFN 是 hash-MoE第 2 层:CSA(m = 4),FFN 是 hash-MoE第 3 层:HCA(m′ = 128),FFN 是 MoE第 4 层:CSA(m = 4),FFN 是 MoE第 5 层:HCA(m′ = 128),FFN 是 MoE第 6 层:CSA(m = 4),FFN 是 MoE第 7 层:HCA(m′ = 128),FFN 是 MoE第 8 层:CSA(m = 4),FFN 是 MoE第 9 层:HCA(m′ = 128),FFN 是 MoE第 10 层:CSA(m = 4),FFN 是 MoE第 11 层:HCA(m′ = 128),FFN 是 MoE第 12 层:CSA(m = 4),FFN 是 MoE第 13 层:HCA(m′ = 128),FFN 是 MoE第 14 层:CSA(m = 4),FFN 是 MoE第 15 层:HCA(m′ = 128),FFN 是 MoE第 16 层:CSA(m = 4),FFN 是 MoE第 17 层:HCA(m′ = 128),FFN 是 MoE第 18 层:CSA(m = 4),FFN 是 MoE第 19 层:HCA(m′ = 128),FFN 是 MoE第 20 层:CSA(m = 4),FFN 是 MoE第 21 层:HCA(m′ = 128),FFN 是 MoE第 22 层:CSA(m = 4),FFN 是 MoE第 23 层:HCA(m′ = 128),FFN 是 MoE第 24 层:CSA(m = 4),FFN 是 MoE第 25 层:HCA(m′ = 128),FFN 是 MoE第 26 层:CSA(m = 4),FFN 是 MoE第 27 层:HCA(m′ = 128),FFN 是 MoE第 28 层:CSA(m = 4),FFN 是 MoE第 29 层:HCA(m′ = 128),FFN 是 MoE第 30 层:CSA(m = 4),FFN 是 MoE第 31 层:HCA(m′ = 128),FFN 是 MoE第 32 层:CSA(m = 4),FFN 是 MoE第 33 层:HCA(m′ = 128),FFN 是 MoE第 34 层:CSA(m = 4),FFN 是 MoE第 35 层:HCA(m′ = 128),FFN 是 MoE第 36 层:CSA(m = 4),FFN 是 MoE第 37 层:HCA(m′ = 128),FFN 是 MoE第 38 层:CSA(m = 4),FFN 是 MoE第 39 层:HCA(m′ = 128),FFN 是 MoE第 40 层:CSA(m = 4),FFN 是 MoE第 41 层:HCA(m′ = 128),FFN 是 MoE第 42 层:CSA(m = 4),FFN 是 MoEMTP 层:纯滑窗注意力 + MoE021020304042MTP第 0–2 层:hash-MoE■ CSA ×21(偶数层)■ HCA ×20(奇数层)■ 纯滑窗 ×2(第 0、1 层)■ MTP 层:纯滑窗注意力(config 里 compress_ratios 的最后一项)共 43 层,全部是 MoE;论文说的「前两层」是这里的第 0、1 层。第 42 层(最后一层)是 CSA。
Flash 的 43 层。前两层是纯滑窗注意力,其余排法和 Pro 一样。

排布直接来自 config 里的 compress_ratios 数组,每一项是该层的压缩率:4 是 CSA,128 是 HCA,0 是只有滑窗分支的注意力。Pro 是

[HCA, HCA] + [CSA, HCA]×29 + [CSA],[\text{HCA},\ \text{HCA}]\ +\ [\text{CSA},\ \text{HCA}] \times 29\ +\ [\text{CSA}],

所以 CSA 有 30 层(全部偶数层),HCA 有 31 层(第 0、1 层加全部奇数层)。Flash 把开头两层换成纯滑窗注意力,中段重复 20 次,共 21 层 CSA、20 层 HCA、2 层滑窗。

两个 config 的数组都比层数多一项,最后一项是 0。官方推理代码里 MTP 块用的层号是 n_layers + 0,正好取到这一项:MTP 层的注意力只有滑窗分支。论文没有写这一点。

每一层的 FFN 都是 MoE。前三层用 hash routing(num_hash_layers = 3),DeepSeek-V3 里前三层的稠密 FFN 在 V4 里不存在了。

V3 → V3.2 → V4 对照表

DeepSeek-V3DeepSeek-V3.2DeepSeek-V4-ProDeepSeek-V4-Flash
层数61616143
隐藏维 dd7168716871684096
总参数671B671B1.6T284B
激活参数37B37B49B13B
注意力MLAMLA + DSACSA / HCA 交错同左,前两层滑窗
注意力头数 / 头维128 / 128 + 64同左128 / 51264 / 512
KV 每 token 每层576 数576 数CSA 每 4 token 一条 512,HCA 每 128 token 一条同左
稀疏选择top-2048 tokentop-1024 个压缩块top-512 个压缩块
残差连接普通普通mHC,4 条流mHC,4 条流
routed expert / 激活 / shared256 / 8 / 1同左384 / 6 / 1256 / 6 / 1
expert 中间维2048204830722048
路由打分sigmoidsigmoidsqrt(softplus)sqrt(softplus)
稠密层前 3 层前 3 层无,前 3 层 hash-MoE同左
优化器AdamWAdamWMuon + AdamWMuon + AdamW
词表129280129280129280129280
训练上下文128K128K1M1M
预训练 token14.8T续训33T32T
权重精度FP8FP8FP8,expert FP4FP8,expert FP4

config.json 里值得先记住的几个数,后面每一篇都会用到(Pro 的值,括号里是 Flash):

字段意思
hidden_size7168(4096)主干宽度 dd
num_attention_heads / head_dim128 / 512(64 / 512)query 头数与头维。头维 512 是 V3 的 4 倍
num_key_value_heads1只有一条 KV 向量,K 和 V 是同一个东西
q_lora_rank1536(1024)query 的低秩维 dcd_c,indexer 的 query 也从这里出来
qk_rope_head_dim64每个头最后 64 维带 RoPE
o_groups / o_lora_rank16 / 1024(8 / 1024)分组输出投影:16 组各投到 1024 维
sliding_window128滑窗分支的窗口 nwinn_{\text{win}}
compress_ratios4 / 128 / 0每层的压缩率,见上一节
index_n_heads / index_head_dim / index_topk64 / 128 / 1024(… / 512)lightning indexer 的头数、头维和选多少个块
compress_rope_theta / rope_theta160000 / 10000压缩层与滑窗层各用一套 RoPE 基数
rope_scalingYaRN,factor 16,原始 65536压缩层用 YaRN 从 64K 扩到 1M
hc_mult / hc_sinkhorn_iters4 / 20mHC 的流数和 Sinkhorn 轮数
n_routed_experts / num_experts_per_tok / n_shared_experts384 / 6 / 1(256 / 6 / 1)MoE 配置
moe_intermediate_size3072(2048)expert 中间维
scoring_func / routed_scaling_factorsqrtsoftplus / 2.5(1.5)路由打分函数与权重缩放
topk_methodnoaux_tc无辅助损失的偏置路由
num_hash_layers3前三层 MoE 用 hash routing
swiglu_limit10SwiGLU 截断
expert_dtypefp4routed expert 权重 FP4,其余 FP8
num_nextn_predict_layers1MTP 深度
max_position_embeddings10485761M 上下文

一个 token 的一次前向

把维度串起来走一遍,用 Pro 的数。进入第 ll 层时残差流是 4 个 7168 维向量。

读算子。 把 4 条流拉平成一个 28672 维向量,做无权重的 RMSNorm,乘一个 [24×28672][24 \times 28672] 的矩阵得到 24 个数。前 4 个过 sigmoid 是读权重 AlA_l,中间 4 个过 2σ()2\sigma(\cdot) 是写权重 ClC_l,后 16 个排成 4×44\times 4 过 Sinkhorn 是混合矩阵 BlB_l。子层输入是 4 条流按 AlA_l 的加权和,7168 维,再过普通的 RMSNorm。

CSA。 query 走低秩:7168 → 1536 → 128 头 × 512 维,逐头 RMSNorm,最后 64 维加 RoPE。KV 只有一条:7168 → 512,RMSNorm,最后 64 维加 RoPE,既当 K 也当 V。这条 512 维向量进两个地方:最近 128 个 token 的滑窗 cache;以及压缩算子,每 4 个 token 压成一个 512 维条目存进压缩 cache。lightning indexer 用自己的一套 128 维压缩键给每个压缩块打分,选出 1024 个块。核心注意力是 MQA:128 个 query 头对着 128 条滑窗加 1024 条压缩条目,每头一个可学习的 sink。输出的 64 维 rope 位做反旋转,然后分 16 组、每组 4096 → 1024,拼成 16384 → 7168。

HCA。 和 CSA 的差别只有两处:压缩率 128 且不重叠;没有 indexer,1M 上下文也只有 8192 个压缩条目,全部看。

DeepSeekMoE。 router 在 7168 维上给 384 个 expert 打分,打分函数是 softplus()\sqrt{\operatorname{softplus}(\cdot)},加偏置选 top-6,权重按原始分数归一化再乘 2.5。每个 expert 是 7168 → 3072 → 7168 的 SwiGLU,上支截到 [10,10][-10, 10]、门上限 10。一个同形的 shared expert 直接加上。前三层 expert 的选择不看分数,按 token id 查一张 [129280×6][129280 \times 6] 的表。

写算子。 子层输出乘 ClC_l 分到 4 条流,同时旧的 4 条流按 BlB_l 混合,两者相加就是下一个子层看到的残差流。

最后一层出来以后,一个只有读权重的 hc_head 把 4 条流压成 1 条,过 RMSNorm,LM head 把 7168 维映到 129280 个 logit。LM head 不和 embedding 共享权重。

参数账

按 config 手算,和论文的口径对得上:

部件ProFlash
routed expert:3 × dd × 中间维 × expert 数 × 层数3 × 7168 × 3072 × 384 × 61 = 1.57T3 × 4096 × 2048 × 256 × 43 = 277B
shared expert4.1B1.1B
注意力(含压缩算子和 indexer)19.8B5.2B
embedding + LM head1.85B1.06B
mHC 参数85M35M
合计≈ 1.60T≈ 291B
每 token 激活7 个 expert 28.7B + 注意力 19.8B + emb/head 1.85B ≈ 50B≈ 14B

routed expert 占了 98%。注意力这一项比 V3 大得多,因为头维从 128 涨到 512,128 个头的 query 展开矩阵一层就有 100M。

阅读地图

每一篇对应论文的一个小节,括号里是它在总图上点亮的部分。

讲什么对应论文
0本篇。总图、层排布、维度账§2 开头,§4.2.1,Figure 2
1序列维度(上):从 MLA 到压缩 KV。注意力的谱系,压缩算子怎么从平均池化推出来,重叠窗口,K = V 的 MQA,分组输出投影(CSA、HCA)§2.3 开头,§2.3.1 前半
2序列维度(中):lightning indexer 与在压缩块上做稀疏选择(CSA)§2.3.1 后半,V3.2 §2.1
3序列维度(下):HCA、混合排布、滑窗分支、部分 RoPE 与输出反旋转、attention sink、1M 上下文的账(HCA、滑窗)§2.3.2 – §2.3.4
4深度维度:mHC。为什么普通 HC 不稳,为什么双随机矩阵是对的约束,Sinkhorn,代码里的接线(mHC)§2.2,mHC 论文
5宽度维度:DeepSeekMoE 的四个改动。sqrt-softplus 打分,hash routing,序列级平衡损失,SwiGLU 截断(MoE)§2.1,§4.2.3
6优化器与稳定性:Muon 的混合 Newton–Schulz,为什么不需要 QK-Clip,Anticipatory Routing,MTP(零件)§2.4,§4.2.3
7结构决定系统:混合注意力的 KV cache 布局、上下文并行、磁盘缓存、mHC 的系统实现§3.4.2,§3.4.3,§3.5

明确一下本连载不讲:数据构建、post-training(SFT、RL、on-policy distillation)、评测结果、FP4 量化感知训练的细节、EP 通信重叠和 TileLang 内核。这些在论文 §3.1 – §3.3、§4.1、§4.3、§5 里。

资料