架构演进 · 仅解码器

DeepSeek

DeepSeek-V3 · 潜在注意力与细粒度专家

对比
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

全部步骤

  1. GPT-2 vs DeepSeek-V3

    DeepSeek-V3 改动了 GPT-2 块的两半。注意力变成多头潜在注意力(MLA),为每个词元只缓存一个小的潜向量,而不是每个头的键和值。MLP 变成 DeepSeekMoE:一个共享专家加上 256 个小的路由专家,每个词元用其中 8 个。点击标签跳过去。

    61 层 · 共 671B · 每词元 37B

  2. 多头潜在注意力

    MLA 把每个词元的向量压缩成一个 512 维的潜向量 c(这里是 2 维),只缓存它。每个头的键和值都由 c 经升维投影重建。位置信息放进一个单独的 64 维 RoPE 键,所有头共享,它也被缓存。把鼠标停在格子上看看。

    c = h · WDKV · K = c · WUK · V = c · WUV

  3. 每词元的 KV 缓存

    每个词元、每一层,完整的多头注意力要缓存 2 × 128 个头 × 128 个数;MLA 只缓存 512 + 64 个。61 层下来,每个词元是 3.8 MiB 对 69 KiB,少了 57 倍,这正是 128K 词元的上下文负担得起的原因。

    (512 + 64) × 61 层 × 2 字节

  4. 共享专家与路由专家

    DeepSeekMoE 把专家拆成许多小专家:256 个路由专家,每个词元选 8 个,再加上一个每个词元都用的共享专家。分数是 sigmoid,在选中的 8 个上归一化。专家更多、更小,就有多得多的组合方式来专精。

    1 个共享 + 256 个路由中的前 8 个

  5. 用偏置保持均衡

    为了在不加额外损失项的情况下让专家被均匀使用,每个专家有一个偏置,只在选择专家时加到它的分数上。每一步之后,过载专家的偏置下调,空闲专家的偏置上调。这里用 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)

延伸阅读