DeepSeek V3.2
DeepSeek V3.2 保留逐 token 的 Multi-Head Latent Attention(MLA)缓存,并增加 DeepSeek Sparse Attention(DSA)。MLA 负责压缩每个 token 的 K/V 表示,DSA 负责从长上下文中动态选择少量位置;两者分别解决“每个位置存多少”和“每次读取多少”。
text
历史 token
├─ MLA Latent KV ────────────────────────────────┐
└─ Index Key ─→ Lightning Indexer ─→ Top-k Index │
↓
Query ─────────────────────────────→ Gather Latent KV → Sparse MLA → OutputMLA Cache
DeepSeek V3.2 沿用 DeepSeek V3 的 MLA:每个历史 token 保存共享的 Latent KV 与 RoPE Key,而不是保存完整的多 Head K/V。设上下文长度为
DSA 不改变这份缓存的表示形式。它改变的是 Query 在一次 Attention 中读取哪些条目。
DeepSeek Sparse Attention
DSA 增加一个轻量的 Lightning Indexer。Indexer 在独立的低维空间中计算当前 Query 与历史位置的相关性:
主 MLA 随后只读取这些位置:
Indexer 的作用是低成本决定“读哪里”,主 Attention 才负责在选中的高维 Latent KV 上计算精确权重。
复杂度与实现边界
当每个 Query 最多读取
- MLA Cache:仍为每个历史 token 保存 Latent KV,存储规模是
。 - Lightning Indexer:仍需为可见历史计算检索分数,但投影维度和数值精度更低。
- Sparse Attention Kernel:必须按 Top-k Index 真正 Gather K/V 并跳过未选位置,才能兑现计算收益。
如果先计算完整的主 Attention Matrix,再用稀疏 Mask 清除大部分位置,只能得到稀疏语义,不能减少核心矩阵计算。
📄 Transformers:Lightning Indexer 与 Top-k
python
scores = torch.matmul(
q.float(),
k.transpose(-1, -2).float().unsqueeze(1),
) * self.softmax_scale
scores = F.relu(scores)
weights = self.weights_proj(hidden_states).float() * (self.n_heads**-0.5)
index_scores = torch.matmul(weights.unsqueeze(-2), scores).squeeze(-2)
topk = min(self.index_topk, index_scores.shape[-1])
topk_indices = index_scores.topk(topk, dim=-1).indices
# Sparse Backend 直接消费 topk_indices;
# Eager/SDPA 仅能把它转换为语义等价的 Sparse Mask。DeepSeek V3.2 的演进关系可以概括为:
text
DeepSeek V3 :MLA 压缩 KV 表示 + Full Access
DeepSeek V3.2 :MLA 压缩 KV 表示 + DSA Dynamic Top-k Access
DeepSeek V4 :进一步压缩序列维度 + CSA/HCA Hybrid Attention