DeepSeek V3
DeepSeek V3 是 Decoder-only MoE 模型,Attention 延续 DeepSeek V2 的 Multi-Head Latent Attention(MLA)。MLA 不减少可访问的历史 token 数量,而是把每个 token 的 K/V 压缩为共享 Latent Vector,从而降低自回归推理的 KV Cache 与内存带宽。
Hidden State hₜ
├─ Query 低秩投影 → Q Heads ──────────────────────┐
└─ KV 下投影 → Latent KV cₜᴷⱽ → Cache │
├─ 上投影 → Content K Heads ├─→ Full Attention
└─ 上投影 → V Heads ────────┘
RoPE Key kₜᴿ → Cache ────────────────────┘Multi-Head Latent Attention
设第
计算 Attention 时,再从
这里的“恢复”是数学表达。高效推理实现可以把上投影权重吸收到 Query 与 Output Projection 中,直接在 Latent Space 完成主要计算,避免在 Decode 时显式展开完整 K/V Heads。
Decoupled RoPE
如果直接对压缩前的完整 Key 应用 RoPE,位置相关变换会阻碍低秩权重吸收。MLA 因此把每个 Key 分成内容部分与较小的 RoPE 部分:
所有 Attention Heads 共享
推理数据流
MLA 仍然执行对全部历史位置的 Softmax Attention,变化发生在 K/V 的表示方式:
- 新 token 到达时,计算并缓存
与 。 - Query 被拆成内容与 RoPE 两部分。
- 内容 Query 读取 Latent KV,位置 Query 读取 RoPE Key。
- 所有历史位置参与 Attention;输出再映射回 Hidden Size。
因此,MLA 将 KV Cache 从“每个 token、每个 KV Head 一组 K/V”压缩为“每个 token 一组共享 Latent KV”,但 Full Attention 的 Decode 读取长度仍然随
📄 Transformers:DeepSeek V3 MLA 投影
compressed_kv = self.kv_a_proj_with_mqa(hidden_states)
k_pass, k_rot = torch.split(
compressed_kv,
[self.kv_lora_rank, self.qk_rope_head_dim],
dim=-1,
)
k_pass = self.kv_b_proj(self.kv_a_layernorm(k_pass))
k_pass = k_pass.view(key_shape).transpose(1, 2)
k_pass, value_states = torch.split(
k_pass,
[self.qk_nope_head_dim, self.v_head_dim],
dim=-1,
)
# ... Query projection and RoPE ...
key_states = torch.cat((k_pass, k_rot), dim=-1)通用的 MHA、MQA 与 GQA 共享方式见 Attention。MLA 与它们的关键区别不是“共享几个 KV Heads”,而是“是否把每个 token 的 K/V 联合压缩到 Latent Space”。