2 注意力演化史 / 8 年间砍 KV 的 7 刀

V4 的 CSA/HCA 不是横空出世。注意力机制过去八年,每一代都在回答上一代留下的问题—— 每一刀都砍向同一个目标:KV cache

2.1 一个被 99% 教程模糊掉的关键差别:训练 vs 推理

教科书里画的注意力图,永远是一个 N×N 的方阵——每个 Q 和每个 K 互相点积。 但这只对训练阶段(和推理 prefill 阶段)成立。推理 decode 时根本不长这样。

训练 / Prefill

        K_1  K_2  ...  K_N
Q_1     ✓    ✓         ✓
Q_2     ✓    ✓         ✓
...
Q_N     ✓    ✓         ✓

形状: N × N
所有 Q 全部参与

推理 Decode(生成第 N+1 个 token)

        K_1  K_2  ...  K_N
Q_N     ✓    ✓         ✓   ← 只有这一行



形状: 1 × N
只有最末位 Q 在工作
K_1..K_N 全部要存(KV cache)
核心洞察:推理 decode 时 N 个 K/V 全要用,但只用 1 个 Q。所以——

2.2 七代演化时间线(每代配一张 SVG 图示)

MHA — Multi-Head Attention 2017 · Vaswani et al. 原版

每个 head 自己的 W_q / W_k / W_v,128 个 head 各存自己的 K/V。表达力强但 KV cache 巨大。

MHA:每个 Q head 对应自己独立的 K/V head(图示 8 个 head,实际 128 个) Q heads K heads V heads 8 / 8 8 / 8 ✕ 8 / 8 ✕

紫=Q 头,蓝=K 头,绿=V 头。三行一一对齐,每个 token 每层要存 8×2=16 个 head 向量(实际 256 个)。

↓ 留下:存得太多
MQA — Multi-Query Attention 2019 · Google 激进

Q 还是多头,但 K 和 V 全模型只保留一套。128 个 head 共用同一份 K/V。

MQA:8 个 Q 头共享同一份 K/V(全模型只 1 份) Q heads K (1) V (1) 8 / 8 1 / 8 ✓ 1 / 8 ✓

KV cache 砍到 1/128——但表达力下降,几个基准明显掉点。

↓ 留下:表达力损失太大
GQA — Grouped-Query Attention 2023 · Google 折中

把 Q heads 分若干组,每组共享一套 K/V。LLaMA-3、Qwen、Gemma 这一代主流都在用。

GQA:8 个 Q 头分 4 组,每组共享 1 份 K/V(图示 8 头 4 组,可调) Q heads K (4) V (4) 8 / 8 4 / 8 ⚖ 4 / 8 ⚖

在 MHA 和 MQA 之间给了一个旋钮:组数越少越省,越多越接近 MHA。

↓ 留下:还是只能砍头数维度,不够
MLA — Multi-head Latent Attention 2024 · DeepSeek V2 🔥 DeepSeek 原创

不砍头数。从另一个维度下刀:砍每条 KV 的"维度"

把所有 head 的 K/V 压成一份 512 维的 latent,存的时候只存这个 latent。 "还原 K"和"还原 V"的投影矩阵在训练时被吸收进 Q 投影和输出投影里——推理时 latent 直接参与运算,从头到尾不需要还原成 K 和 V。

MLA:128 个 Q 头 + 共享 1 份 512 维 latent(不是 K 也不是 V,是压缩态) Q heads Latent latent · 512 维 维度 512 (MLA) ↑ MHA 标准 K+V 合计 = 14336 维 128 1 latent

128 个 Q 头都从这一份 latent "投影"出自己的 K/V——但投影矩阵在训练时被合并进 Q' 和 W_o',推理时永远不显式还原。

查看:MLA 的数学技巧(吸收投影)
原始:   score = Q × Kᵀ / √d
        output = softmax(score) × V

代入 K = latent × W_uk:
  Q × Kᵀ = Q × W_ukᵀ × latentᵀ
         = Q' × latentᵀ      ← Q' = Q × W_ukᵀ 提前合并

代入 V = latent × W_uv:
  output = softmax(score) × latent × W_uv × W_o
         = softmax(score) × latent × W_o'   ← W_o' = W_uv × W_o

✅ K 和 V 从来没被显式算出来。"还原"操作被合并进固定权重。

配置:head_dim=512,num_key_value_heads=1,num_attention_heads=128。50K 上下文 KV cache 从 81.5 GiB → 2.9 GB。

↓ 留下:每条 KV 变小了,但条数还是和上下文长度一一对应
DSA — DeepSeek Sparse Attention 2025 · DeepSeek V3.2 🔥 DeepSeek 原创

KV cache 全存,但注意力计算时只看 top-k。装一个轻量 Indexer 打分,挑最相关的 2048 条来做 attention。

50000 → 2048,计算量直接砍到 4%。

DSA:50 条 KV 全存,但 Indexer 只挑亮色的几条做 attention(图示 50 条选 12) KV cache (全存) Indexer 打分 实际 attend

蓝色=被 Indexer 选中、参与 attention 的 KV;灰色=存了但不看的 KV。存储没省,只省了计算。

但 DSA 有两个限制: ① 只省计算不省存储——KV cache 还是要全存(不存怎么选); ② 推理阶段才启用——训练时模型用的还是完整注意力。本质是"不改脑子,换副眼镜"
↓ 留下:训推不一致 + 存储没省
NSA — Native Sparse Attention 2025-02 · DeepSeek 论文 arXiv 2502.11089 理论铺路

梁文锋署名。两个关键词: Hardware-Aligned(块结构对齐 GPU 内存访问)+ Natively Trainable(从训练第一步就用稀疏,不是套眼镜)。

每层并行三个分支:压缩全看(粗概览)+ 选块精读(top-16 块)+ 滑动窗口(最近 512)+ 门控加权合并。

NSA:每层三分支并行,门控加权(图示 64 tokens 上下文) ① 压缩全看 32:1 ② 选块精读 top-k 块 ③ 滑动窗口 最近 16 门控合并 α·① + β·② + γ·③

三分支独立计算,最后门控加权求和。训练时就用稀疏——稀疏成了模型的归纳偏置。

实测:27B 模型在 9 项基准上平均 0.456 vs Full Attn 0.443,稀疏甚至比全注意力强。 AIME 24 数学竞赛 +7.5 分。原因:稀疏在训练时变成了 inductive bias。

↓ 留下:27B 实验室原型,1.6T 工程化要重做
CSA + HCA 2026 · DeepSeek V4 🚀 V4 落地

NSA 的工程实践:从"层内三分支并行"改成"层间交替分工":

  • HCA 层(128:1 重压缩 + 全看):扫一遍全局大意
  • CSA 层(4:1 重叠压缩 + Lightning Indexer 选 top-1024):精选细节
  • 滑动窗口(最近 128):兜底最近上下文

每过两层 = 1 全局粗扫 + 1 精选细节。50K KV cache 从 MLA 的 2.9 GB → 228 MB。

V4:相邻两层做不同的事——HCA 看全局轮廓,CSA 选细节,滑窗兜底(图示 128 tokens) HCA 层 128:1 全看 ≈1 块 ↓ 下一层 CSA 层 4:1 压缩 32 块 + Indexer 选 top-k 滑窗 (128) 兜底

橙=HCA 压缩块蓝=CSA 选中块灰=CSA 未选中块绿=滑窗。 相邻两层组合,既扫了全局又选了细节。

2.3 NSA → V4 的三大工程改造

NSA 论文(2025-02)V4 CSA/HCA(2026)
三分支怎么放每层并行跑三个,门控加权求和奇偶层交替:CSA / HCA 错开
压缩块大小统一 32(步长 16,重叠)CSA 4(重叠)/ HCA 128(不重叠)
选 top-k复用压缩分支分数(可微分)独立 Lightning Indexer(FP4 全程)
滑窗大小512128(= max(块大小))
训练阶段就用是(继承 NSA)

2.4 一图看完:50K 上下文 KV cache 怎么从 81.5 GiB 砍到 228 MB

每代注意力的 KV cache 总量(对数刻度,50K token × 61 层)
阶段核心想法50K KV cachevs 上一代
MHA(标准)每头独立 K/V81.5 GiB基线
GQA (8 组)分组共享 K/V5.1 GB↓ 16×
MQA全模型 1 组 K/V0.64 GB↓ 8×
MLA (V2)维度压缩到 latent 5122.9 GB基线 ↓ 28×
DSA (V3.2)序列稀疏(只省计算)2.9 GB— 存储不省
CSA/HCA (V4)序列压缩 + Indexer228 MB↓ 13×

从 MHA 到 V4,总共压了 99.7%。注意 DSA → CSA 这一步:从"不改脑子换眼镜" 进化到 "眼镜从一开始就长在脑子里"

2.5 多想一步:为什么 KV cache 能被压掉 99.7%?

大模型权重存的是"知识"——世界的地图。KV cache 存的不是地图,是当前这段上下文在地图上走过的路径

路径能被压到 0.3% 而效果不掉,是因为自然语言的有效路径本来就是低维的。 7168 维的隐藏空间里,大部分维度是 MLP 临时展开的"计算脚手架",真正的语义坐标集中在几百维子空间里 (Intrinsic Dimension 实测约占隐藏空间个位数百分比)。

V4 所有压缩——MLA 砍维度、Compressor 砍条数、Indexer 选 top-k——都在压路径,没人动地图。 这不是算法的胜利,是语言本身的低维性质。