MODEL ARCHITECTURE · 2026-10-20

DeepSeek-V4-Pro 架构:
一个 token 的旅程

近处看细节,远处读压缩记忆;每层只叫醒少量专家。

61Transformer 层
1.6T总参数
49B每 token 激活参数

← → 逐步讲解 · 拖动进度条回看 · F 全屏

01 / 从文字到预测

文字先变向量,再一层层改写

token ID Embedding · 7168 4 路残差 Block × 61 合并 + 输出头 每个 Block:mHC → Norm → Attention → mHC → Norm → MoE → mHC 残差流的宽度是 4 × 7168;Attention / MoE 的输入仍是 7168 维。
查表token ID 找到一行 embedding。
加工Attention 汇总上下文,MoE 变换当前表示。
预测输出头为词表中的候选 token 打分。
工程细节

每个算子先对齐四个维度

B 是请求数,S 是本次处理的 token 数,d 是隐藏宽度。进入一个 Block 的残差多一条大小为 4 的轴。

位置完整形状单 token 的元素数
残差输入[B, S, 4, 7168]28,672
mHC 汇合后[B, S, 7168]7,168
Q / shared KV[B,S,128,512] / [B,S,512]65,536 / 512
专家中间态[被路由的 token 数, 3072]3,072

decode 时通常 S=1;prefill 的 S 可以很大。B×S 决定 GEMM 行数。Mi 表示 2²⁰:1 MiB=2²⁰ 字节,1 Mi 个参数=2²⁰ 个参数。

工程细节

低秩 Q:两次矩阵乘法接起来

X[B·S,7168] → Qr[B·S,1536] → Q[B·S,128·512]
qr = rms_norm(X @ Wq_a.T)
q = (qr @ Wq_b.T).reshape(B, S, H, 512)
q = q / sqrt(mean(q*q, axis=-1) + eps)
q[..., -64:] = RoPE(q[..., -64:], position)

两块权重共有 7168×1536 + 1536×65536 = 106.5 Mi 个参数。直接投影需要 448 Mi;低秩节省权重,但多出一次中间读写与归一化。

02 / 层的节奏

每层看多远,由层号决定

HCA L1 HCA L2 CSA L3 HCA L4 CSA L5 HCA L6 … 中间层 CSA L61 SWA:最近 128 token CSA:局部 + 压缩后选读 HCA:局部 + 高压缩全读
开头两层Pro 用 HCA,Flash 用纯 SWA。
从第 3 层开始CSA、HCA 交替,主干最后一层为 CSA。
一直保留局部窗口CSA 和 HCA 都同时看最近 128 个 token。
03 / 四路残差

四条信息通路,共用一个子层

残差流 1 新流 1 残差流 2 新流 2 残差流 3 新流 3 残差流 4 新流 4 Pre-mix Norm + 子层 Post-mix B:4 × 4 残差混合矩阵
Pre-mix把四路加权汇成一个 d 维输入。
子层照常计算Attention 和 MoE 各有一套 mHC 包裹。
Post + residual mix新结果分回四路;B 由 Sinkhorn 约束,行列和约为 1。
工程细节

mHC 真正混合的是什么

z = Σᵢ preᵢ · xᵢ  yⱼ = postⱼ · F(z) + Σᵢ Bᵢⱼ · xᵢ
张量形状如何得到
x / z[B,S,4,7168] / [B,S,7168]4 路残差加权成一个子层输入
pre / post / B4 / 4 / 4×424 个动态系数,经约束后参与混合
生成系数的权重[24, 28672]Attention 与 MoE 各有一套

B 做 20 轮 Sinkhorn 行列归一化,使行列和接近 1;pre 与 post 有自己的门控约束,不需要加和为 1。B 的两个轴分别对应旧流和新流。

逐步演算 · 教学数值

四路加权成 5,子层只运行一次

x₁ = 1权重 0.1 → 0.1x₂ = 3权重 0.2 → 0.6x₃ = 5权重 0.3 → 1.5x₄ = 7权重 0.4 → 2.8加权和0.00

取 F(z)=2z,得到 10。若 B=0.5I+0.125·11ᵀ,旧残差混成 [2.5,3.5,4.5,5.5];post=[.25,.5,.75,1],最终为 [5,8.5,12,15.5]。

04 / Shared-KV MQA

很多个问题,共用一本笔记

h ∈ R^7168 128 个 query 头 1 份 shared KV 各头分别读同一份 KV 512 维 = 448 内容 + 64 RoPE 输出投影 → d 维
Query不同头从不同角度询问上下文。
Shared KV同一个 512 维向量同时充当 K 和 V。
位置末尾 64 维用 RoPE 带上位置信息。
工程细节

局部和压缩记忆,共用一次归一化

aⱼ = q·kⱼ / √512  Z = exp(sink) + Σⱼ exp(aⱼ)
o = Σⱼ exp(aⱼ)·kvⱼ / Z

局部条目和选中的压缩条目组成同一个候选集合。每个头还有 learned sink:它增加分母,没有对应的 value 输出。

一维教学例:两个条目的分数为 log2、0,value 为 4、10,sink 分数为 0。

o = (2×4 + 1×10)/(2+1+1) = 4.5

如果删掉 sink,输出变为 6;如果先各自 softmax 再相加,权重也会改变。对齐参考实现时,这两处都要检查。

工程细节

输出投影也分组,并且降低中间维度

[128,512] → [16,4096] → [16,1024] → [7168]
o = inverse_RoPE(o)
o = o.reshape(B, S, groups, 4096)
r = einsum("bsgd,grd->bsgr", o, Wo_a)
y = r.flatten(-2) @ Wo_b.T

每组包含 8 个头。第一段共 64 Mi 参数,第二段 112 Mi,共 176 Mi。Pro 与 Flash 每组输入相同,组数翻倍;更宽的 d 让第二段又增长 3.5 倍。

05 / CSA 先压缩

把连续信息,整理成更少的条目

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 压缩条目 1 压缩条目 2 压缩条目 3 压缩条目 4 每新增 4 个 token 产出一条;CSA 的池化窗口还覆盖前一组,形成重叠。
学习怎么汇总用投影和门控加权池化生成条目。
每 4 个产出一条重叠池化照顾组间边界。
只用已到达的信息完整组才可见;未完成组留在压缩状态中。
工程细节

压缩是逐通道的 learned pooling

vₜ = Wkv xₜ  gₜ = Wgate xₜ + apeₜ
cⱼ = Σₜ softmaxₜ(gₜⱼ) · vₜⱼ

softmax 沿 token 轴做;每个通道可以重视不同 token。pooling 后做 RMSNorm,再对末尾 64 维施加 RoPE。

CSA 步长为 4。每个 token 投影成 2×512 维:上一组用前半,当前组用后半,合成最多 8 个 token 的重叠窗口。

HCA 每 128 个 token 一组,无重叠。压缩条目的 RoPE 位置取当前组起点:0、128、256……。

逐步演算 · 教学数值

一个通道,逐项算出压缩结果

v₁ = 1权重 0.4 → 0.4v₂ = 3权重 0.3 → 0.9v₃ = 7权重 0.2 → 1.4v₄ = 9权重 0.1 → 0.9加权和0.00

结果为 3.6。这里展示四个有效候选;第一组没有前一组,缺失位置的 gate 为 −∞、权重为 0。这只是归一化前的一个通道。

工程细节

压缩条目必须等整组完成后才可见

刚处理的位置 t(从 0 开始)CSA 已完成组数可见的新条目
2⌊3/4⌋ = 0无
3⌊4/4⌋ = 1第 0 组:token 0…3
6⌊7/4⌋ = 1仍只有第 0 组
7⌊8/4⌋ = 2第 1 组:前组+当前组重叠
visible = (t + 1) // ratio
valid = compressed_index < visible
if (t + 1) % ratio == 0:
    cache[t // ratio] = pool(completed_group)

prefill 可以并行算出整段的压缩条目,但每个 query 仍要加自己的因果 mask;否则前面的 token 会看到组内未来信息。

06 / CSA 再选读

先用小索引器挑,再做大注意力

当前 query Indexer 打分 c1 0.12 c2 0.83 c3 0.25 c4 0.91 c5 0.14 c6 0.38 c7 0.61 c8 0.08 c9 0.77 c10 0.17 c11 0.32 c12 0.2 Flash:最多 512 条 Pro:最多 1024 条
小计算扫一遍Indexer 看可见的压缩条目,产生相关性分数。
大计算少读一些Pro 的主注意力最多读 1024 个压缩条目。
局部细节另保留最近 128 token 一起进入注意力;图中仅示意选 3 / 12。
工程细节

少读 KV 之前,Indexer 仍要给历史打分

scoreⱼ = Σₕ wₕ · ReLU(qₕᵀ kⱼ) → top-k(score)

Indexer 使用 64 个 128 维头,共享一份 128 维压缩索引缓存。w = weights_proj(x) / √128 / √64,可正可负;它不是 softmax 概率。TP 时先 all-reduce 分数,再选条目。

上下文长度压缩候选 N/4Pro 主注意力压缩读数
32,7688,1921024
131,07232,7681024
1,048,576262,1441024

top-k 固定了主注意力读数,Indexer 的候选扫描仍随上下文增长。prefill 参考路径还会构建 query×候选分数,必须把这项计入临时显存。

07 / HCA 高压缩

把远处概括得更短,就能全部读

128 token 1 条压缩 KV 128 token 1 条压缩 KV 128 token 1 条压缩 KV 128 token 1 条压缩 KV 当前 query 读取所有已经完成的压缩组
128 → 1远处信息以更粗的粒度保留。
不再做 top-k 选择主注意力读全部可见的压缩条目。
粗细两条路远处用摘要,最近 128 token 保留细节。
工程细节

Pro 的 CSA 和 HCA,成本交点在哪里

CSA:128 + 1024 = 1152  HCA:128 + ⌊N/128⌋
上下文 NCSA 每头读数HCA 每头读数
32,7681,152384
131,0721,1521,152
1,048,5761,1528,320

只看注意力点积与 value 聚合,约需 4×头数×读数×512 FLOP。32K 时,Pro 的 CSA 单 query 约 302 MFLOP;HCA 约 101 MFLOP。

这份账本不含投影、Indexer、压缩器和 kernel 调度。交点只是读数相等,不代表完整 kernel 延迟相等。

08 / Mixture of Experts

384 个候选专家,每次选择 6 个

专家就是各自拥有权重的一小段前馈网络。图中只画出部分候选。

token 向量 Router E1 E2 E3 E4 E5 E6 E7 E8 E9 E10 E11 E12 共享专家:每 token 都算 加权和 → 输出
前 3 层token ID 查预定专家映射,仍然激活 6 个。
后续层Sqrt(Softplus) 评分,选择 6 个路由专家。
每层都有共享专家专家中间维度 3072;返回结果做加权合并。
工程细节

选谁和给多少权重,是两次计算

scores = sqrt(softplus(x @ Wgate.T))
if layer_id < 3:
    ids = tid2eid[token_id]        # 固定的 6 个专家 ID
else:
    ids = topk(scores + bias, k=6)
w = scores[ids] / scores[ids].sum()
w *= route_scale
y = sum(w[j] * expert[ids[j]](x) for j in range(6))
y += shared_expert(x)

专家选择可受 bias 影响,归一化权重取未加 bias 的 scores。Pro 的 route_scale=2.5,因此六个路由权重之和是 2.5,共享专家另外相加。

工程细节

一个专家,三块矩阵

gate = W₁x up = W₃x E(x)=W₂[SiLU(gate) ⊙ up]
项目计算参数量
一个专家3×7168×307263 Mi
61 层全部路由专家61×384×3dm1547.396 B
每 token 经过的专家参数61×(6+1)×3dm28.208 B

实际先把 up 限制在 [−10,10]、gate 上限设为 10,再做 SiLU 与逐元素乘法;路由权重融合在 W₂ 之前。表中未计 Attention、embedding、路由器、mHC 和 MTP。所有候选专家权重仍需存储。

09 / 词表与 MTP

把理解变成下一步的选择

最后一层:4 路残差 合并 + RMSNorm 词表 logits 采样下个 token MTP 深度 1:额外预测下一步 主干预测下一个 token;MTP 可用于草稿生成,再由主干验证。
主干输出词表中每个候选得到一个分数。
采样选出 token,追加到上下文,继续下一轮。
MTP 辅助多预测一步为投机解码提供草稿。
工程细节

同样是六个专家,为什么 Pro 更难喂满

教学观测:一次 decode 有 128 个 token,路由数固定为 6。Pro 每层 384 个专家,总计 768 次 token→expert 分配。

平均每专家 token 数 = 128×6/384 = 2

若负载均匀,每个专家 GEMM 只有约 2 行。中间维度 3072 再大,也不能保证 GPU 高利用率。

先看 tokens/expert 的直方图,再区分大量小 GEMM 和少数热点。可测更大 batch、grouped GEMM、专家复制和通信重叠。

Flash 同样 batch 的平均值为 3。Pro 的专家矩阵更大、专家更多,两者一起改变调度效率;只比较激活参数会漏掉这一层。

10 / 两种尺寸

同一套思路,不同的计算预算

配置 V4-Flash V4-Pro
主干层数 / 宽度 43 / 4096 61 / 7168
总参数 / 每 token 激活 284B / 13B 1.6T / 49B
开头两层 纯 SWA HCA + 局部窗口
Query 头 / 低秩维度 64 / 1024 128 / 1536
CSA top-k 512 1024
路由专家 / 中间维度 256 / 2048 384 / 3072
输出投影分组 8 16

共同配置:4 路残差、512 维 shared KV、128 token 局部窗口、4 / 128 压缩比、6 个路由专家 + 1 共享专家、MTP 深度 1。总参数决定常驻权重规模,激活参数描述每 token 使用的权重规模。

练习 1

为一个真实输入写出形状和字节数

B=2、S=16,Pro 的残差、Q、shared KV 均按 BF16。各有多少元素、占多少 KiB?只算这三个逻辑张量。
展开参考解答

残差:2×16×4×7168=917,504 元素,乘 2 B = 1792 KiB。Q:2×16×128×512=2,097,152 元素,占 4096 KiB。

shared KV:2×16×512=16,384 元素,占 32 KiB。头数改变 Q 的大小;shared KV 无须再乘 Q 头数,也没有额外一份 V。

先写出张量形状与单位,再代入数字。

练习 2

给选择加 bias,别给权重加 bias

教学路由器只有 4 个专家、选 2 个。scores=[1,2,3,4],bias=[4,0,0,0],route_scale=2.5。选哪些?最终权重多少?
展开参考解答

选择分数为 [5,2,3,4],所以选 E1 和 E4。归一化仍使用原始分数 [1,4],除以 5,再乘 2.5,得到 [0.5, 2]。

若误用 [5,4] 归一化,会得到 [1.3889, 1.1111],改变模型。共享专家没有参加这个 top-k,也不参加这次归一化。

先写出张量形状与单位,再代入数字。

练习 3

定位一个只在整组边界出现的错误

程序在 query 位置 t 使用 compressed_index ≤ ⌊(t+1)/4⌋。t=6、t=7 时分别会放行哪些索引?正确规则是什么?
展开参考解答

t=6 时错误规则放行 0、1,但只有第 0 组已完成。t=7 时放行 0、1、2,但只有前两组已完成。正确规则是严格小于完成组数:index < ⌊(t+1)/4⌋。

decode 中可能读到尚未写入的缓存;prefill 中则可能读到已经并行算出的未来条目。两条路径都错,却不一定以同一种症状出现。

先写出张量形状与单位,再代入数字。

动手实验

把推导变成可以检查的程序

用 NumPy 检查分组输出投影、Sinkhorn 行列和、路由 bias 与专家参数量。

python3 -m pip install numpy
python3 lab.py
grouped projection: equal
Sinkhorn max error < 1e-10
routing weights: [0.5, 2.0]
all checks passed

下载 lab.py

修改参数前先预测结果,再运行检查。实验使用小张量和解析预算,在 CPU 上执行。

11 / 参考与延伸阅读

继续沿着实现走

DeepSeek-V4-Pro 官方模型卡Preview 模型的总参数、激活参数与权重精度。
官方 config.json · 推理实现 model.py层数、维度、压缩周期、mHC、路由与 cache 更新。
DeepSeek-V4 技术报告§2 架构,§3.1 专家通信与计算重叠,§4.2 模型配置。
技术报告精读 · Pro 逐卡推理 · V4-Flash 架构

配置核对:2026-10-20。动画中的 token、专家选择、显存块大小是教学示例。