架构演进 · 仅解码器
- 对比
- DeepSeek-V3 vs GPT-2 small
- 层
- 61 GPT-2 12
- dmodel
- 7,168 GPT-2 768
- 注意力
- MLA · 128 个头 GPT-2 MHA · 12
- 专家
- 1 个共享 + 256 选 8 GPT-2 1 个稠密 MLP
- 参数
- 671B · 激活 37B GPT-2 124M
- 上下文
- 128K GPT-2 1,024
全部步骤
GPT-2 vs DeepSeek-V3
DeepSeek-V3 改动了 GPT-2 块的两半。注意力变成多头潜在注意力(MLA),为每个词元只缓存一个小的潜向量,而不是每个头的键和值。MLP 变成 DeepSeekMoE:一个共享专家加上 256 个小的路由专家,每个词元用其中 8 个。点击标签跳过去。
61 层 · 共 671B · 每词元 37B多头潜在注意力
MLA 把每个词元的向量压缩成一个 512 维的潜向量 c(这里是 2 维),只缓存它。每个头的键和值都由 c 经升维投影重建。位置信息放进一个单独的 64 维 RoPE 键,所有头共享,它也被缓存。把鼠标停在格子上看看。
c = h · WDKV · K = c · WUK · V = c · WUV每词元的 KV 缓存
每个词元、每一层,完整的多头注意力要缓存 2 × 128 个头 × 128 个数;MLA 只缓存 512 + 64 个。61 层下来,每个词元是 3.8 MiB 对 69 KiB,少了 57 倍,这正是 128K 词元的上下文负担得起的原因。
(512 + 64) × 61 层 × 2 字节共享专家与路由专家
DeepSeekMoE 把专家拆成许多小专家:256 个路由专家,每个词元选 8 个,再加上一个每个词元都用的共享专家。分数是 sigmoid,在选中的 8 个上归一化。专家更多、更小,就有多得多的组合方式来专精。
1 个共享 + 256 个路由中的前 8 个用偏置保持均衡
为了在不加额外损失项的情况下让专家被均匀使用,每个专家有一个偏置,只在选择专家时加到它的分数上。每一步之后,过载专家的偏置下调,空闲专家的偏置上调。这里用 16 个玩具专家和 64 个词元演示。
按 si + bi 选择 · 按 si 加权
代码
# MLA: cache one small latent per token instead of every head's K and V
c_kv = kv_a_proj(h) # (tokens, 512) cached
k_rope = rope(k_rope_proj(h)) # (tokens, 64) cached, shared by all heads
k_nope, v = kv_b_proj(c_kv).split(...) # each head's keys and values, rebuilt
k = torch.cat([k_nope, k_rope.expand(heads)], dim=-1)
# DeepSeekMoE: one shared expert plus the top 8 of 256 routed experts
s = torch.sigmoid(gate(x)) # (tokens, 256) affinities
idx = torch.topk(s + bias, 8).indices # the bias only affects the choice
w = s.gather(-1, idx); w = w / w.sum(-1, keepdim=True)
y = shared_expert(x) + sum(w[..., j] * experts[idx[..., j]](x) for j in range(8))
# after each step: nudge each expert's bias toward an even load
bias += gamma * torch.sign(load.mean() - load)