稀疏注意力省了什么,没省什么?
本课一问:稀疏注意力省了什么,没省什么?
这一课先不碰:服务端怎么给成百上千个请求分配 KV(C13 的 PagedAttention);FP4 这类格式本身怎么编码(C9 岔路);「窗口 1M」是不是「有效 1M」(C2 第 5 课)。
从已有出发
上一课把锚点 3/4 的层换成了不存 KV 的固定状态;剩下 1/4 的全注意力层,每个 query 仍要和前面所有 token 打分,KV 仍按长度一条条存。C3 第 10 课的 KV 阶梯停在 DeepSeek-V3 的 70,272 字节,末尾留了一张 890 字节的虚线卡——这一课把中间的每一级补上。
这一课换个例子,原因是:稀疏注意力的意思是「每个 query 只读 k 个 key」,只有前文远多于 k 时才有意义;贯穿例句 5 个 token,全部读完也不贵。下面用 64 个 key 的教学构造演示选择过程,真实规模用官方 config 在长度轴上算。
一个框架先摆在前面(旧版课程 M8 的三分法):要让「KV 随长度增长」不再成立,数学上只有三种可能——不增长(固定状态,上一课)、增长得慢(把几个 token 压成一条)、照常增长但少读(全存、只挑 top-k 读)。这一课讲后两种。
先自己设计:每个 query 读全部前文
- ① 朴素方案
- ② 它在哪失败
- ③ 改进方案
每生成一个 token,它的 query 要和缓存里全部 L 条 KV 打分、加权。计算随 L 线性增长,整段序列就是 L²;KV 也要一条不落地存着。
试三件事(在改进一侧):① top-k = 8:读的 key 从 64 个变成 8 个,看选中的这些占了多少注意力权重、输出误差多大;② 勾「理想索引器」:直接按真实分数挑,是这一步的上限——真实的索引器维度低、是另外训练出来的,差的就是这一截;③ 换几个 query:有的 query 注意力很集中(少数 key 就占大头),有的很分散,稀疏对后者伤得多。不管哪种,64 个 key 都还在缓存里,索引器也给 64 个都打了分。
改进一:DSA——便宜的索引器挑 top-k
DeepSeek-V3.2(2025-09)的 DeepSeek Sparse Attention:在每个 MLA 层前面加一个 lightning indexer,给前文每个 token 打一个分,只把分数最高的 2,048 个送进真正的注意力。打分式逐项看(旧版课程 M8 的五项解释全部保留):
| 维度 | 含义 | 真实规模 | 小规模 |
|---|---|---|---|
| L | 上下文长度(这里取 128K) | 131,072 | 64 |
| dI | 索引器 key 维(index_head_dim) | 128 | 4 |
| k | 每个 query 读几条(index_topk) | 2048 | 8 |
| dc | MLA 每条缓存的维数(kv_lora_rank + qk_rope_head_dim) | 576 | 16 |
新的失败有两个。第一,KV 一条不少:V3.2 每层每个 token 存 656 字节(FP8 潜向量 + scale + BF16 的 RoPE 部分)加索引器 key 约 132 字节,61 层合计 48,068 字节——比 V3 的 70,272 字节小,是因为换成了 FP8,不是因为稀疏。第二,索引器本身仍是 O(L²):每个 query 仍要给全部 L 个前文打分,只是每一次打分便宜。1M 上下文时,V3.2 每个 query 每层给 1,048,576 个条目打分,是它读进核心注意力的 512 倍。
改进二:少算几次索引器
两个办法:
- 跨层复用:相邻层挑出来的 top-k 高度相似(IndexCache 论文的观察),那就几层共用一次。GLM-5.2 起的 IndexShare:78 层里 21 层自己算索引、57 层直接用前一个的结果 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条IndexShare 是 GLM 的贡献;DSA 本身是 DeepSeek 的,GLM-5 报告原文是「we adopt DSA」。 出处IndexCache · Z.ai 与清华 2026(需联网) ↗需联网 。它一点注意力都没省,省的只有索引器(旧版 IndexShareDemo 的结论)。可在「线性 + 全局」的混合架构里,全局层之间隔着 3 层线性层,层间的 top-k 不再相似:Qwen 的消融显示跨层共享索引效果差,GLM-5.3-Flash 也改用 IndexPool(4 条索引 key 池化成 1 条)、不再跨层共享(R2 核对 config 与报告)。
- 分层粗筛:先按块挑候选,再在候选里逐 token 挑。V4.1 的第 20 层给出 2,048 块 × 8 个位置 = 16,384 个候选,之后的索引器只在这里面打分——后续层的索引成本与上下文长度无关(思路出自 HISA)。
试三件事:① L = 4,096:V3.2 的核心注意力读 2,048 条,只省了一半;稀疏是为长序列设计的;② L 拖到 1M:核心注意力那张图里,四种稀疏做法都早早「躺平」在几百到几千条;差别几乎全在索引器那张图——V3.2 每层要给一百万条打分;③ 对照 GLM-5.3 与 V4.1:一个靠「少算几层」,一个靠「先压缩再粗筛」,斜率不同。这张表只比条目数、不比 FLOPs(索引器一条比核心注意力一条便宜得多),替代了旧版课程那组示意常数。
改进三:把序列压短(DeepSeek-V4 的 CSA 与 HCA)
要省存储,就得让存下来的条目变少。DeepSeek-V4(2026-04)把每 m 个 token 的 KV 压成 1 条:
V4-Flash 的 43 层:前 2 层纯滑动窗口,之后 21 层 CSA(每 4 个 token 一条,再用索引器挑 top-512)与 20 层 HCA(每 128 个 token 一条、不挑、全读)交错;每一层另有 128 个 token 的滑动窗口,因为压缩对近处伤害最大。V4 报告的 1M 口径:V4-Flash 的 KV 是 V3.2 的 7%,单 token FLOPs 是 10%;激活参数更多的 V4-Pro 分别是 10% 与 27% 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条官方自报;FLOPs 是整模型单 token 口径(大头是 MoE),不是只算注意力。 出处DeepSeek-V4 §1(本地 PDF) ↗ 。
改进四:几层共用一份、再压精度(DeepSeek-V4.1)
V4.1-Flash(2026-09)接着砍另外两个维度:
- 层:CSA2 把层分成三种模式——Full(自己算 KV 与索引)、Reindex(复用 KV、自己重挑)、Reuse(连挑选结果都复用)。40 层里只有第 2、8、14、20 层真正持有全局 KV。再加上 CED:下面 20 层是 causal encoder,上面 20 层 decoder 的全局 KV 由第 20 层的输出投影得到,prefill 可以在 encoder 结束(所以 prefill 每 token 激活 8B、decode 16B)。
- 精度:全局 KV 存成 FP4(每条 512 个 E2M1 + 每 16 个一个 E4M3 缩放 = 288 字节)。
逐字节的账:
代价写在官方报告里:CED 下 decoder 的滑动窗口缓存要靠 Bounded Replay 近似重建,报告原话是「数学上并不等价」,只说内部测试影响可忽略,并把「边界情况下的鲁棒性」列为局限 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条官方自报;对照:YOCO(2024)的提前退出是精确的,CED 用近似换成本。 出处DeepSeek-V4.1 报告 §2.2、§6(需联网) ↗需联网 。官方还报告,上下文从 4K 扩到 1M(256 倍),V4.1 的单 token decode FLOPs 只多了 1/4。
2026 年各家把「省 KV」的刀下在不同维度上(R3 §3.2 的框架):
| 维度 | 手段 | 谁在用 |
|---|---|---|
| 条目大小 | GQA 减头;MLA 存潜向量;K = V 共享 | Qwen3.8(4 个 KV 头);K3、GLM-5.3(MLA 512);DeepSeek V4 / V4.1 |
| 序列长度 | 固定状态(不增长);几个 token 压成一条 | Qwen3.8、K3、GLM-5.3-Flash(上一课);DeepSeek CSA / HCA |
| 层数 | 几层共用一份 KV 或索引 | V4.1 CSA2 与 CED;GLM-5.3 IndexShare |
| 精度 | FP8 / FP4 缓存 | V3.2(FP8);V4.1(FP4 全局 KV) |
| 只读一部分(不省存储) | 索引器 top-k;块级选择 | DSA(V3.2、GLM-5.3);Qwen3.8-Flash-Next 的 QSA(索引 key 每 4 个 token 一条,预算 2,048 个 token) |
常见误解一:「稀疏注意力省显存。」 按内容挑 top-k 只省计算;KV 一条不少(V3.2 每 token 48,068 字节)。GLM-5.3 这类「MLA + DSA」的 1M 上下文,KV 加索引 key 约 93 GiB(frontier-models.json 的核对值)。
常见误解二:「索引器很便宜,可以忽略。」 单次打分便宜,可它要给全部前文打分:1M 时每个 query 每层是核心注意力读取量的 512 倍条目。这正是 IndexShare、分层索引、索引 key 压缩出现的原因。
常见误解三:「每 token KV 字节可以直接横比。」 要先对齐:什么精度(BF16 / FP8 / FP4)、含不含索引器 key、滑动窗口和固定状态(与长度无关)有没有另计。本课所有阶梯只算随长度增长的全局部分。
常见误解四:「DSA 是 GLM 提出的。」 DSA 出自 DeepSeek-V3.2;GLM-5 报告原文是「we adopt DSA」,GLM 自己的贡献是 IndexShare。
① 更多参数,不要更多算力(MoE)
- 解决了结构最简单:所有参数对每个 token 都生效。卡在锚点 Qwen3.8-27B 每 token 前向约 51.2 GFLOPs;同家族 2.4T 规模若是 dense,约 4.84 TFLOPs(94 倍)。
- 解决了每个 token 只算 top-k 个专家:Qwen3.8-2.4T-A95B 每 token 约 186.5 GFLOPs,是同参数 dense 的 26 分之一。卡在路由会自我强化地偏心:8 个专家全挤到 1 个时,Switch 负载损失从 0.01 升到 0.08;所有专家的权重仍要常驻显存。
- 解决了把「均衡」写进 loss,路由器被梯度推向均匀。卡在α 难调:太小拉不平,太大干扰主 loss(Switch 在 10⁻¹ 到 10⁻⁵ 之间扫;Wang 2024 的出发点)。
- 解决了偏置只改「选谁」,不进门控、不产生干扰梯度;DeepSeek-V3 前 14.3T token 用 γ = 0.001,最后 500B 设为 0。卡在固定步长在近千个专家时太慢或来回震荡(Kimi K3 报告)→ Quantile Balancing;而且统计范围(整批 vs 单条序列)比「有没有 loss」更要紧。
- 解决了同参数同计算,16 选 2 的 120 种组合变成 64 选 8 的 4,426,165,368 种;共享专家装公共知识。卡在显存账不减:Qwen3.8-2.4T 路由专家占主干参数 97.98%,BF16 权重 4.89 TB。
- 解决了Qwen3.8-2.4T 512 选 10 + 1 共享;K3 896 选 16 + LatentMoE + Quantile Balancing;V4.1 图文两套偏置。卡在共享专家 0、1、2 个都有人用(Qwen3 一个不设),稀疏度从 32 到 64 都有(GLM-5.3 与 V3 为 32、GLM-5.3-Flash 36、K2 48、Qwen3.8 51、K3 56、V4.1-Flash 64)——都是实验选择。
② 长文本:KV 与计算不再随长度等比例涨
- 解决了每个 token 都能精确回看任意一个前文 token。卡在KV ∝ 长度:锚点若 64 层全是全注意力,262,144 token 时 64 GiB。
- 解决了去掉 softmax,求和提前累加成一个固定大小的状态,与长度无关。卡在只加不减:同一个键写两次,读回的是两个值之和;状态最多装 d 对互不干扰的键值(C0 岔路)。
- 解决了写前先擦(delta)、每步衰减(门):锚点 48 层状态共 144 MiB(FP32)、与长度无关;KV 降到四分之一(262,144 时 16 GiB 对 64 GiB)。卡在剩下四分之一的全注意力层仍按长度涨;容量有限,3:1 是实验选出来的。
- 解决了每通道一个衰减;g_min = −5 让 16 token 块内累积不低于 −80,e⁸⁰ ≈ 5.5 × 10³⁴ 在 BF16 范围内(上限约 3.4 × 10³⁸),慢路径删除。卡在MiniMax M1 用线性混合、M2 又退回全注意力:大规模下多跳推理缺陷、训练受访存限制、低精度与缓存难题(官方博客)。
- 解决了lightning indexer 每个 query 只挑 top-2048 条做核心注意力。卡在省计算不省内存:KV 一条不少,每 token 48,068 B;indexer 本身仍要扫全部前文。
- 解决了V3.2 每 token 48,068 B → V4-Flash 3,514 B → V4.1-Flash 890 B(1M 时 0.87 GiB)。卡在是近似:V4.1 自陈 Bounded Replay「数学上不等价」、选择误差可能在未测过的边界情况退化。
③ 训练 4K,使用 128K
- 解决了训练与使用同一个长度,不需要任何折算。卡在注意力项随长度涨:Qwen3-32B(64 层全注意力)在 131,072 时注意力项是 6N 的 215%;早期长序列还带来梯度方差极端值(Li 2021)。
- 解决了DeepSeek-V3 的 14.8T token 全在 4K,之后两段各 1,000 步扩到 32K、128K,只占全部训练 token 的 0.84%;Llama 3 405B 六段、约 800B token。卡在长序列阶段的数据要专门配(长度上采样、领域均衡、合成跨全文任务)。
- 解决了K3:8K → 64K → 256K → 1M(NoPE 也照走课程);V4.1 注意力从头就是压缩稀疏的,直接从 64K 起训。卡在各家配方大多只公开阶段、不公开每段 token 数,无法横向比较成本。
- 解决了每个位置多学一个更远的目标;推理时当草稿,接受率 α 时每步期望产出 1 + α 个 token。卡在DeepSeek-V3 第 2 个 token 接受率 85%–90%,实测 1.8 倍 TPS;V4.1 预训练干脆去掉 MTP,没有公开消融。
证据三问
| 问 | 本课的回答 |
|---|---|
| ① 它解决什么问题? | 让长上下文里的每个 query 不必读全部前文(省计算);再通过压序列、压层、压精度省存储 |
| ② 数学上为什么可能有效? | 字节与条目数的记账 证据等级 · 数学可证明 在写明的前提下可以严格推导出来,不依赖实验。只要前提成立,换数据、换规模仍然成立。 本条V4.1 的 890 字节由 config 与 FlashMLA 格式逐字节复算,与官方一致。 出处待补 ;注意力权重通常集中在少数位置,只读 top-k 损失可控是理论动机 证据等级 · 有理论动机 有数学或机制上的理由说明它可能有效,但没有证明它一定更好。最后是否采用,仍然要看实验。 本条不同 query 的集中程度差别很大(上面的实验台);有损压缩的误差没有通用上界。 出处待补 |
| ③ 实验上为什么最后选了它? | V4-Flash 1M 下 KV 为 V3.2 的 7%;V4.1 4K → 1M decode FLOPs 只多 1/4;Qwen QSA 的 RULER、MRCR 提升 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条全部官方自报;近似带来的风险由官方自陈。 出处DeepSeek-V4 / V4.1;Qwen3.8-Flash-Next 报告 ↗ |
一句话
按内容挑 top-k 省的是计算,不是 KV;要省内存得压序列、压层、压精度——DeepSeek 三刀一起砍到 890 字节。
先停在这里:「只读一部分 ≠ 少存一部分」,记住这一句就够进下一课。
再深一层:对着 FlashMLA 的 README,自己把 V3.2 的 656 字节和 V4.1 的 288 字节算一遍;再读 V4.1 报告的 §2.3。
下一个缺口
推理时的计算和显存都压下来了——那训练要不要一开始就用长序列? → 第 6 课:训练 4K,使用 128K?
你可能会问
- 「为什么每层还要留一个滑动窗口?」 压缩和稀疏挑选都容易伤到最近的几个 token,而近处往往最重要;128 个 token 的窗口是与长度无关的常数(V4.1 FP8 约 2.7 MB/序列,frontier 核对值)。
- 「稀疏注意力能从头训吗?」 V4 先用稠密注意力训 1T token、到 64K 才切换;V4.1 从头就用;Qwen 的 QSA 在 256K 的继续预训练阶段才引入,先让索引器单独对齐主注意力。下一课的长度课程里有这几段。
- 「有效上下文会不会因此变差?」 可能。「窗口 1M」和「1M 处还找得到东西」是两回事,只能靠 NIAH、MRCR、RULER 去测(C2 第 5 课)。