CSA2 = 会跨层复用的 CSA + 两级稀疏检索。

它把长上下文成本沿三个相乘的维度一起压:

  1. entry size:一条 KV 有多宽(GQA / MLA 已经做过);
  2. sequence:隔多少个 token 记一条 KV(V4 的 CSA / HCA 已经做过);
  3. layer:哪些层可以有自己独立的一份(CSA2 新增)。

并且把第三维上的两件事解耦:

解耦之后就有了三种静态模式:Full / Reindex / Reuse。

为什么要往层维度压

三个维度的关系是乘法而不是加法:总 KV 成本大致是

\[ \text{cost} \;\propto\; \underbrace{(\text{entry size})}_{\text{每条 KV 多大}} \times \underbrace{\frac{N}{m}}_{\text{序列方向条目数}} \times \underbrace{\#\text{layers keeping their own}}_{\text{层方向份数}} \times \text{bits} \]

前两个维度 V4 已经压过了,第三维是剩下的空间。论文列举的前人工作在层维度上各有缺口:

工作 做法 缺口
IndexCache 跨层复用 Top-K 索引 省的是 indexer 计算,省不了 main KV 存储
YOIO 一次算完 sparse routing,全层共享 全网共享一份 routing,限制性能
HySparse sparse 层复用 dense 层 KV 仍保留全量 attention 层

论文的结论很直接:index reuse alone saves no main KV storage, network-wide routing sharing limits performance, and hybrid designs still retain full attention layers——没有一种方法同时覆盖三个维度。

CSA2 的答案是把三个维度乘起来用,同时把 cache 共享与索引复用拆开——拆开之后,“共享了 cache 但想让每层选出不同的 KV”这种中间形态(Reindex)才存在。

相比 V4 的 CSA,改了什么

维度 CSA(DeepSeek-V4) CSA2(DeepSeek-V4.1)
压缩窗口 一条压缩条目由 \(2m\) 个原始 entry 产生,相邻条目重叠 去掉 overlap,一条由 \(m\) 个 entry 产生
位置编码 压缩时用 absolute positional embedding 标注这 \(2m\) 个位置 去掉
indexer K 的来源 从 hidden state 走独立的压缩路径 由 main KV 投影得到
全局分支结构 CSA + HCA 混合 纯 CSA2(HCA 取消),\(m=1\) 作为不压缩特例
与其它层的关系 每层各自持有自己的 cache 与索引 Full / Reindex / Reuse 三模式跨层复用
深层 indexer 的打分域 每层都在全量可见范围打分 Hierarchical Sparse Indexer:只在前层给出的候选池内打分(仅 decoder)

前三行都是减法,论文给的理由是 simplify the implementation and increase the training efficiency。从结构上看:

三种模式

三个模式共享的部分:每层都自己计算 main Q 和 SWA KV,都用「选中的 main KV 条目 + 本层 SWA KV」拼接后做 core attention。模式之间的差别只在三件事上:main KV、indexer K、Top-K 索引从哪来。

模式 main KV indexer K indexer Q Top-K 索引
Full 本层算 由本层 main KV 投影 本层算 本层全量打分后选出
Reindex 复用最近可用的 随 main KV 一起复用 本层算 本层在候选池内重新选出
Reuse 复用最近可用的 随 main KV 一起复用 不算 直接复用(针对同一份 main KV 的最近一次选择)
Full    :  本层 hidden ──► main KV ──► indexer K ──┐
                                                     ├─► indexer Q ──► 全量打分 ──► Top-K
Reindex :  main KV ◄──复用── (前层) ──► indexer K ──┘   └─► 本层 indexer Q ──► 池内打分 ──► Top-K

Reuse   :  main KV ◄──复用── (前层),Top-K ◄──复用── (前层),不算 indexer Q、不打分

两点值得单独说:

与 CED 结合时:decoder 里被分配为 Full 模式的层,它的 global KV 不是从本层 hidden state 算出来的,而是从第 \(L/2\) 层——也就是 causal encoder 最后一层——的 hidden state 投影出来的:

\[ C_l = H_{L/2}\,W^{KV}_l, \qquad Z_l = H_{L/2}\,W^{Z}_l, \qquad l > \frac{L}{2} \]

其中 \(C, Z\) 分别是 KV 条目及其压缩权重,\(W^{KV}_l, W^{Z}_l\) 是逐层不同的投影矩阵。Reindex 与 Reuse 模式不受这条改动影响——它们本来就只负责”复用”。

成本上的意义:论文给了一个很具体的数字——一个处于 Reuse 模式的 CSA2 层,prefill 只需要 15 个 kernel、decode 只需要 11 个。层层都算 indexer 的开销被摊薄了。

Hierarchical Sparse Indexer

问题:跨层复用减少了 indexer 被执行的次数,但每次执行时它仍然要打整段因果可见 context 的分。在百万级 context 下,剩下的那几次全量打分本身就成了瓶颈。

做法分成两级:

  1. 第一个 Full 模式层做全量检索:对所有因果可见的 main KV 位置打分、选出自己的 Top-K;同时做一次块级选择——每个 block 取块内最大 index score 作为该块的分数,选出分数最高的若干 block,把这些 block 覆盖的位置收集成一个候选池。报告给的例子是选 2,048 个 block、每块 8 个位置,得到 16,384 个候选位置;
  2. 后续 Reindex 层只做池内精排:只在候选池里打分,并在这个池内选自己的 Top-K;Reuse 层则完全不再索引。

候选池在索引层之间共享,但每层最终的 Top-K 可以不同。

复杂度上的关键结论:候选池大小固定之后,每个后续 indexer 每 query 需要打分的位置数与 context 长度无关;只有第一个 Full 层仍然扫描全量可见范围。也就是说层次化索引把”每一次都是 \(O(N)\)“变成了”一次 \(O(N)\) + 若干次 \(O(1)\)”。

训练一致性:这个机制是 training-aware 的,在 post-training 阶段引入,训练与推理使用完全相同的候选域。否则深层 indexer 会在训练时见过全量位置、推理时只看得到池子,产生明显的 domain shift。

V4.1-Flash 的实际配置

项 取值
总层数 / 结构 40 层 = 20 层 causal encoder + 20 层 decoder,\(d = 5120\)
encoder 前 2 层 纯 SWA(无 global attention)
encoder 其余 18 层 CSA2,压缩率 \(m = 2\);分 3 组、每组 6 层:1 Full + 5 Reuse
decoder 20 层 CSA2,压缩率 \(m = 1\);分 5 组、每组 4 层:第 1 组 1 Full + 3 Reuse,其余 4 组 1 Reindex + 3 Reuse
indexer 32 个 indexer query head,head dim 128,attention top-k = 512
main attention 64 个 query head,head dim 512,query 压缩维度 1280
Hierarchical Indexer 最多 2,048 个 block × 8 个位置 = 最多 16,384 个候选位置
输出投影 8 组,每组中间维度 1024
SWA 窗口 \(n_{\text{win}} = 128\)
MoE / mHC 1 shared + 384 routed experts,每 token 激活 6 个;mHC 扩展因子 4、Sinkhorn 20 次迭代

这张表里有两件事值得单独指出来。

decoder 的压缩率是 1,也就是不压缩。 换言之 CSA2 在 decoder 里其实只做”跨层复用 + Top-K 稀疏”,序列方向上的压缩(\(m=2\))只发生在 encoder。真正让 decoder 变便宜的是:top-k 固定为 512(decode 时每 token 只读 512 个 main KV 条目)加上大部分层复用前层的 cache 与索引。这也解释了为什么 CSA2 要费力气做层次化 indexer——在 \(m=1\) 的 decoder 里,“候选数”没有被压缩稀释过,indexer 的打分成本必须靠搜索域约束来降。

模式分配的比例很激进:encoder 是 1:5、decoder 是 1:3。按层数算,40 层里只有 4 层(1 个 decoder Full + 3 个 encoder Full)产出全局 cache 和候选池,4 层做 Reindex,其余 30 层都是 Reuse。

收益与代价

收益(报告给出的数字):

指标 结果
global KV cache(常驻 HBM) 890 bytes / token,约为 V4-Flash 的 \(1/4\);相对 V1 是 437 倍
persistent KV cache(SSD / host memory) 约为 V4-Flash 的 \(1/8\)
单 token decode FLOPs context 从 4K 扩到 1M(256 倍)只增加约 \(1/4\)(论文用词是 “nearly constant”)

\(1/8\) 是两件事相乘的结果:

\[ \underbrace{\frac{1}{2}}_{\text{不再持久化 SWA KV}} \;\times\; \underbrace{\frac{1}{4}}_{\text{global KV 架构 + 精度优化}} \;=\; \frac{1}{8} \]

代价:

训练侧怎么支撑 CSA2

共享组件的层可能被切在不同的 pipeline stage 上,这让”直接复用模块对象”在传统的 stage-local 执行模型下不成立。报告给了三个设计:

再加上 optimizer、checkpointing、warm-up、计算图追踪的适配,CSA2 才能在原有分布式训练接口和 pipeline 调度下”透明”运行。

笔者的分析与开放问题

以下不属于报告的结论:

与 CSA/HCA 的关系

V4 的 CSA / HCA V4.1 的 CSA2
压缩的轴 序列轴(每 \(m\) 个 token 一条) 层轴(跨层复用)+ 序列轴(\(m=1\) 或 \(2\))
核心算子 逐通道 softmax 门控的凸组合(软池化) 没变,压缩器本身被简化(去 overlap、去 APE)
稀疏选择 Lightning Indexer + TopK TopK 保留,新增层次化候选池把后续 indexer 的打分域压到 \(O(1)\)
省的是 KV cache 条目数 KV cache 的份数(层维度)与 indexer 计算

一句话:CSA2 没有换掉压缩算子,而是改变了”谁来压缩、压缩结果给谁用”。压缩器本身仍然是那套逐通道 softmax 加权平均(见《压缩数学原理》),变化发生在算子的复用拓扑上——这才是 CSA2 这个名字里那个 “2” 实际指的东西。