DeepSeek DSA FLOPs
一句话概括:DSA 先用一个低维但仍为二次复杂度的 Lightning Indexer 找到 Top- 个 token,再让 MLA 的核心注意力只处理这些 token,把主注意力从 降为 。
本文只推导两个部分:核心稀疏注意力和 Lightning Indexer。公式依据 DeepSeek-V3.2 Technical Report;具体张量维度和计算路径以 DeepSeek 官方的 V3.2-Exp 配置 与 Indexer 实现 为准。
Notation
沿用 MLA FLOPs 笔记的口径:一次 multiply-add 记作 FLOPs,并且只统计矩阵乘。暂时忽略 softmax、mask、normalization、RoPE、ReLU、逐元素乘法、Top- selection 和 cache 读写。
这里还需要明确计算边界:
- 核心注意力从已经形成的 absorbed content query 、RoPE query 和 MLA cache 开始计算,不重复统计 MLA 的 query/KV projection。
- Indexer 从 MLA 已有的 query latent 和输入 hidden states 开始计算。官方实现直接把 MLA 的 query latent 传给 Indexer,因此不再重复统计 。
- 不统计核心注意力之后的 latent value up-projection 和 output projection。
主要记号如下:
| Symbol | Meaning | DeepSeek-V3.2 |
|---|
| prefill / training sequence length | 最长 |
| decode 时的 KV-cache length | variable |
| 每个 query 选出的 token 数 | |
| hidden size | |
| 核心注意力的 query heads | |
| MLA KV latent / absorbed content dimension | |
| decoupled RoPE dimension | |
| MLA query latent dimension | |
| Indexer heads | |
| 每个 Indexer head 的维度 | |
核心注意力涉及的 tensor 可以写成:
Indexer 涉及的 tensor 是:
最容易误解的一点是: 在所有 个 Indexer heads 之间共享。因此 key projection 的 FLOPs 不乘 ;但每个 head 都要和这份 shared key 做点积,所以 pairwise scoring 的 FLOPs 仍然乘 。
Causal token-pair 数
Dense causal attention 实际可见的 query-key pair 数是:
DSA 中第 个 query 最多保留 个 key,因此核心稀疏注意力实际处理的 pair 数是:
第二项 是开头不足 个历史 token 的 causal 修正。长序列下才可以近似写成 。
Core Sparse Attention FLOPs
论文明确说明 DSA 的核心注意力采用 MLA 的 MQA mode:同一位置的 和 被所有 query heads 共享。对 query ,令 是 Indexer 选出的 token 集合,。
Attention score
content score 在 absorbed latent space 中计算:
RoPE score 单独走较小的 positional channel:
两部分相加后再做 softmax。相加和 softmax 不属于本文的矩阵乘 FLOPs。
Weighted latent value
softmax 得到每个 query head 各自的权重 。所有 heads 读取同一份 latent value cache,但因为各 head 的权重不同,weighted sum 仍然要按 head 计算:
因此,单个 query 的 core attention FLOPs 是:
其中两个 分别来自 content score 和 weighted latent value; 来自 RoPE score。
Prefill / training
对所有 causal query 求和:
当 时:
如果把 换成 ,就得到相同 MQA/absorbed 路径下的 dense MLA core attention FLOPs。也就是说,DSA 并没有改变每个保留 pair 的计算,而是把 pair 数从约 降到了约 。
Decode
decode 时只有一个当前 query。令 ,则:
当 cache 已经长于 时,core attention 对上下文长度不再线性增长,而是固定为:
代入 、、、:
- prefill 时,,core attention 约为 TFLOPs / layer。
- 当 时,每个 decode token 的 core attention 是 MFLOPs / layer。
Lightning Indexer FLOPs
论文给出的 index score 是:
是第 个 Indexer head 的 query, 是位置 的 shared key, 是当前 query 对各 Indexer heads 的组合权重。作者指出,选择 ReLU 是出于吞吐考虑;较少的 heads 和 FP8 实现使这个二次复杂度模块远轻于原始 dense attention。
Indexer projections
官方代码复用 MLA 的 query latent 来产生 Indexer queries:
shared Indexer key 直接从 hidden states 投影:
每个 query 还要产生 个 head weights:
所以 Indexer 的线性 projection part 是:
Full-prefix index scoring
每个 Indexer head 都要让所有 queries 与 shared keys 做点积:
如果只计算 causal lower triangle,所有 个 heads 的 FLOPs 是:
如果实现先形成完整的 score matrix 再 mask,则是:
ReLU、乘以 、跨 heads 求和以及 Top- 都不是这里统计的矩阵乘 FLOPs。特别要注意,Top- 不会让 Indexer 的打分也变成 :Indexer 必须先扫描整个 causal prefix,才能知道哪些位置属于 Top-,所以它仍然是 。
Prefill / training
采用 causal-aware 计数时,Indexer 总 FLOPs 是:
代入 、、、:
对于 :
- 三条 Indexer projection 共约 TFLOPs / layer;
- full-prefix causal scoring 约为 TFLOPs / layer;
- Indexer 合计约为 TFLOPs / layer,不包含 ReLU、reduction 和 Top-。
Decode
decode 时只生成当前 token 的 、 和 head weights,然后让当前 个 queries 扫描长度为 的 shared Indexer key cache:
前三项是当前 token 的 projections,最后一项是随 cache length 增长的 full-prefix scoring。代入 DeepSeek-V3.2 参数:
当 时,Indexer 约为 GFLOPs / token / layer,其中 GFLOPs 来自扫描历史 key cache。
当前范围内的总 FLOPs
只把本文讨论的 core attention 与 Indexer 相加:
在 上,前向计算约为 TFLOPs / layer;在 的单 token decode 中约为 GFLOPs / layer。这里的结论边界很明确:核心注意力已经从 变成 ,但 Lightning Indexer 仍保留 的全前缀打分。