DeepSeek-V4_CSA-HCA与V4.1-CSA2详解
DeepSeek-V4 CSA/HCA 与 DeepSeek-V4.1 CSA2:从模型原理到推理基础设施
本文基于 DeepSeek-V4 与 DeepSeek-V4.1-Flash 官方技术报告和官方参考推理代码整理。重点解释 CSA2,包括 Compressor、Full/Reindex/Reuse、Hierarchical Sparse Indexer、CED Prefill/Decode、KV cache 布局、量化、分布式训练与推理实现。
预备知识假设:了解一点 MLA 和 DSA,但不要求熟悉 DeepSeek-V4 的具体实现。
目录
- 一句话结论
- 先建立 MLA、DSA、CSA 的坐标系
- DeepSeek-V4 的 CSA
- DeepSeek-V4 的 HCA
- 为什么 V4 要把 CSA 和 HCA 交替使用
- 从 CSA 到 CSA2:到底改了什么
- 重点:CSA2 的 Compressor 为什么叫“简化”
- 重点:Full、Reindex、Reuse 到底复用了什么
- V4.1 的精确层布局
- 重点:Decoder 中 ratio=1,没有压缩 token,收益在哪里
- Hierarchical Sparse Indexer
- CSA2 单层的完整张量流
- CED:为什么 Prefill 能跳过大部分 Decoder
- Decode 时的逐层数据流
- 对应官方代码的简化实现
- 为什么正好是 890 bytes/token
- KV Cache Manager 与持久化缓存
- SWA Bounded Replay
- 分布式训练与推理 Kernel
- 公开参考代码与生产系统的区别
- 复杂度与收益总结
- 常见误解与局限
- 参考资料
1. 一句话结论
DeepSeek-V4 的全局注意力由两种层交替构成:
- CSA:小倍率序列压缩 + 稀疏 Top-K 检索;
- HCA:大倍率序列压缩 + 对压缩结果做稠密 attention。
DeepSeek-V4.1 取消 HCA,改成纯 CSA2。CSA2 同时在三个维度压缩长期全局 KV:
- Entry 维度:64 个 Query head 共享一个 512 维 Main KV latent;
- Sequence 维度:Encoder 每 2 个 token 压成 1 个 Main KV entry;
- Layer 维度:38 个 CSA2 层实际只建立 4 份 global KV cache。
另外:
- 只有少数层重新运行 indexer;
- 大部分层复用上游层的 Top-K;
- Decoder 后续 indexer 只在最多 16,384 个候选位置中搜索;
- CED 让绝大多数 prompt token 只经过下半个模型;
- SWA state 不长期持久化,丢失时通过 Bounded Replay 近似恢复。
因此 CSA2 的重点绝不只是“每几个 token 压成一个 token”,而是:
把 global memory 的内容、索引结构、访问位置和局部状态拆开,并赋予它们不同的生成频率、共享范围、精度和生命周期。
2. 先建立 MLA、DSA、CSA 的坐标系
设上下文长度为 ,模型层数为 。
2.1 MLA 压缩的是每个位置的 KV 宽度
普通 MHA 对每个 token、每一层保存很多个 KV head:
MLA 将每个位置的 KV 压缩为一个较小的 latent:
所以 MLA 主要压缩的是:
但是位置数量没有变:
如果仍然对全部位置做 dense attention,那么每个 Decode token 仍需要扫描 个位置。
2.2 DSA 压缩的是实际参与主 Attention 的位置数
DSA 增加一个低成本 indexer:
- 用低维 Indexer Q/K 给历史位置打分;
- 从 个位置中选择 Top-;
- 真正昂贵的主 attention 只访问这 个位置。
但是 DSA 通常仍然需要:
- 保存每个历史位置的 Main KV;
- 保存每个历史位置的 Indexer K;
- 让 indexer 扫描很长的上下文。
所以 DSA 主要降低 core attention FLOPs,不会自动等比例降低 KV cache 与 indexer 扫描成本。
2.3 CSA 在 DSA 之前再做一次序列压缩
CSA 首先执行:
再从
因此可以把三者理解成:
| 方法 | 压缩的主要对象 |
|---|---|
| MLA | 每个 token 的 KV 宽度或 head 维度 |
| DSA | 真正参与主 attention 的历史位置数量 |
| CSA | 先压缩历史位置数量,再进行 DSA Top-K |
| CSA2 | 在 MLA/DSA/CSA 的基础上继续压缩 layer 维度,并复用索引 |
3. DeepSeek-V4 的 CSA
3.1 总体数据流
V4-Flash 中:
- CSA compression ratio:
; - attention Top-K:512;
- SWA window:
; - Main Query heads:64;
- Main head dimension:512;
- Indexer heads:64;
- Indexer head dimension:128。
V4-Pro 的 CSA 同样使用
3.2 V4 CSA 的 Compressor
输入为:
CSA 生成两套 KV 与两套 gate:
其中:
第
- 当前 block 的
个 ; - 前一个 block 的
个 。
权重来自:
这里需要注意三件事。
权重是逐 channel 的
每个
不同 KV channel 可以从 block 内不同 token 中提取信息。这比 mean pooling 或单标量 attention pooling 更有表达力。
每个输出覆盖 个 token,但输出 stride 是
一个原始 block 会通过:
进入当前 compressed entry; 进入下一个 compressed entry。
所以相邻 compressed entry 存在信息重叠,但最终仍只产生
Compressor 内有 block 位置 bias
3.3 Lightning Indexer
CSA 不直接使用 512 维 Main KV 扫描全部压缩位置,而是建立较小的 Indexer K:
V4 中,Indexer K 有一条独立 compressor 路径。对于 query token
Indexer 分数为:
其中每个 indexer head 的组合权重由当前 query hidden state 预测:
最后:
主 attention 只读取
3.4 Shared Key-Value MQA
一个 compressed latent 同时充当 Key 与 Value:
即:
64 个 Query head 共享同一份 512 维 KV latent。这样压缩了 KV cache,但 64 个 Query head 的输出拼接后宽度达到:
所以 V4 采用 Grouped Output Projection:先将 heads 分组、每组降维,再统一映射回模型 hidden dimension。
3.5 为什么还需要 SWA
Compressed entry 只有在整个 block 完成后才能安全地对 query 可见。
例如
因此每层额外保留最近
SWA 的作用包括:
- 覆盖当前未完成的 compression block;
- 保留最近 token 的高精度信息;
- 补偿压缩导致的局部细节损失;
- 维持严格 causal semantics。
4. DeepSeek-V4 的 HCA
HCA 是 Heavily Compressed Attention,不要和 mHC 混淆。
V4 中:
一百万 token 被压缩为大约:
个 HCA entry。
HCA 不使用 indexer,也不做 Top-K,而是让 query 稠密访问全部 HCA entry,计算复杂度为:
HCA compressor 是非重叠形式:
它同样是逐 channel learned pooling,但压缩率远大于 CSA。
5. 为什么 V4 要把 CSA 和 HCA 交替使用
| 机制 | 序列压缩率 | 全局访问方式 | 优点 | 缺点 |
|---|---|---|---|---|
| CSA | Indexer Top-K | 粒度较细,可以定位精确信息 | Indexer 仍要扫描长上下文,存在选择错误 | |
| HCA | Dense over compressed entries | 不依赖 Top-K,始终覆盖全部全局摘要 | 每个 entry 很粗糙 | |
| SWA | 不压缩 | 最近 128 token | 局部精确、因果安全 | 不能覆盖远距离历史 |
可以把 V4 理解成:
- CSA:稀疏但较精细的远程记忆;
- HCA:稠密但粗粒度的全局摘要;
- SWA:精确的近期记忆。
V4-Flash 前两层是纯 SWA,之后 CSA/HCA 交替;V4-Pro 前两层使用 HCA,后续继续交替。
6. 从 CSA 到 CSA2:到底改了什么
CSA2 不是简单地把 compression ratio 换成另一个数字。它主要包含四项变化。
6.1 Main Compressor 从双流重叠变成单流非重叠
V4 CSA:
- 两套 KV projection:
; - 两套 gate:
; - 每个输出覆盖
个 token; - 相邻输出共享一个原始 block;
- 有 block 内 absolute positional bias。
CSA2:
- 一套 KV projection;
- 一套 gate;
- 每个输出只覆盖自己的
-token block; - 相邻输出不重叠;
- 删除 compressor 内的 absolute positional bias。
6.2 Indexer K 从 Main KV 投影
V4 CSA:
CSA2:
即:
这消除了独立的 Indexer-K compression path。
6.3 Main KV 与 Indexer K 跨层共享
V4 基本上是每个 CSA/HCA 层保存自己的 global cache。CSA2 把多个层划成一组,只由 Full 层生成 global cache,后面的层共享它。
6.4 Top-K 也可以跨层共享
CSA2 将两个选择解耦:
- 要不要复用 KV;
- 要不要重新运行 indexer。
由此形成 Full、Reindex、Reuse 三种 mode。
7. 重点:CSA2 的 Compressor 为什么叫“简化”
7.1 用具体 token 看 V4 CSA
假设
V4 CSA 的输出关系大致是:
图示如下:
因此:
- 每个正常输出聚合
个 projected source; - 每个原始 block 通过两套参数进入相邻两个输出;
- Decode 时需要同时维护前一个 block 和当前未完成 block 的 state;
- gate 还要加入 block 内位置 bias。
它的优势是压缩边界更平滑,但实现和状态管理比较复杂。
7.2 CSA2 变成普通的非重叠 learned pooling
同样假设
其计算为:
仍需强调:这里不是普通平均池化。对于每个 channel
7.3 “简化”具体减少了什么
| 项目 | V4 CSA | CSA2 |
|---|---|---|
| Main KV projection | 两套 |
一套 |
| Gate projection | 两套 |
一套 |
| 单个输出源范围 | ||
| 相邻输出重叠 | 有 | 无 |
| Compressor 位置 bias | 有 | 无 |
| Indexer K | 从 hidden 走独立 compressor | 从 Main KV 投影 |
| Decode tail state | 前一块 + 当前块,状态复杂 | 只维护当前未完成块 |
7.4 删除位置 bias 不等于删除所有位置信息
CSA2 删除的是 Compressor 内部的 block-slot absolute bias,不是删除整个 attention 的 RoPE。
压缩完成后:
- Main KV latent 仍会施加 partial RoPE;
- Indexer K 也有自己的 partial RoPE;
- 一个 compressed latent 在官方代码中使用该 group 第一个 token 的位置;
- 最近 128 个 token 仍由未压缩 SWA 保留细粒度顺序。
因此删除的是复杂的“窗口内部位置参数”,不是让模型完全不知道位置。
7.5 ratio=1 时 Compressor 退化为什么
Decoder 使用
再计算 gate 没有意义,所以直接退化为:
官方代码也只在 compress_ratio > 1 时创建 wgate。
8. 重点:Full、Reindex、Reuse 到底复用了什么
8.1 三种 Mode 的组件级数据流
| 当前层的行为 | Full | Reindex | Reuse |
|---|---|---|---|
| 计算自己的 Main Q | ✓ | ✓ | ✓ |
| 计算自己的 SWA KV | ✓ | ✓ | ✓ |
| 生成新的 Main KV | ✓ | 复用 | 复用 |
| 生成新的 Indexer K | ✓ | 复用 | 复用 |
| 生成自己的 Indexer Q | ✓ | ✓ | 不生成 |
| 运行 indexer | ✓ | ✓ | 不运行 |
| 生成新的 Top-K | ✓ | ✓ | 复用 |
| 执行 core attention | ✓ | ✓ | ✓ |
| 生成新的 attention output | ✓ | ✓ | ✓ |
8.2 把共享对象看成三条“状态总线”
这三类状态的来源不同:
- Main KV / Indexer K:只能由 Full 层更新;
- Top-K:Full 或 Reindex 层都可以更新;
- SWA KV:从不跨层共享,每一层都有自己的 local state。
8.3 一个 Decoder group 的实际例子
以 layer 24–27 为例:
四层使用同一份历史 Main KV,但它们不是执行相同的 attention:
- layer 24 用自己的 hidden 生成 Query,并重新选 Top-K;
- layer 25–27 各自生成不同的 Query;
- 即使 Top-K 相同,attention logits 和 attention output 仍不同;
- 每层的 SWA KV、输出投影、MoE 和 residual/mHC 也不同。
可以把 shared Main KV 想象成一座共享图书馆:
- Full 决定图书馆里存什么书;
- Reindex 使用自己的问题重新制作借阅清单;
- Reuse 沿用上一份借阅清单;
- 但每一层都会用自己的 Query 阅读这些书,并形成自己的新 hidden state。
8.4 为什么层仍然不能并行
第
所以 Main KV 和 Top-K 的复用只减少 cache 与索引计算,不会消除 hidden-state data dependency。Transformer layers 仍需顺序执行。
9. V4.1 的精确层布局
V4.1-Flash 有 40 层:
- 20 层 causal encoder;
- 20 层 decoder;
- 前两层只有 SWA;
- 其余 38 层使用 CSA2。
官方配置为:
1 | kv_source_layers = [2, 8, 14, 20] |
完整映射:
| 层 | 区域 | ratio | Mode | 作用 |
|---|---|---|---|---|
| 0–1 | Encoder | — | SWA only | 只有局部注意力 |
| 2 | Encoder | 2 | Full | 创建第 1 份 Encoder global KV |
| 3–7 | Encoder | 2 | Reuse | 复用 layer 2 的 KV 和 Top-K |
| 8 | Encoder | 2 | Full | 创建第 2 份 Encoder global KV |
| 9–13 | Encoder | 2 | Reuse | 复用 layer 8 |
| 14 | Encoder | 2 | Full | 创建第 3 份 Encoder global KV |
| 15–19 | Encoder | 2 | Reuse | 复用 layer 14 |
| 20 | Decoder | 1 | Full | 创建唯一 Decoder global KV 与 candidate pool |
| 21–23 | Decoder | 1 | Reuse | 复用 layer 20 |
| 24 | Decoder | 1 | Reindex | 在候选池内重新选 Top-K |
| 25–27 | Decoder | 1 | Reuse | 复用 layer 24 的 Top-K |
| 28 | Decoder | 1 | Reindex | 重新选 Top-K |
| 29–31 | Decoder | 1 | Reuse | 复用 layer 28 |
| 32 | Decoder | 1 | Reindex | 重新选 Top-K |
| 33–35 | Decoder | 1 | Reuse | 复用 layer 32 |
| 36 | Decoder | 1 | Reindex | 重新选 Top-K |
| 37–39 | Decoder | 1 | Reuse | 复用 layer 36 |
总计:
- 4 个 KV source;
- 8 个 index source;
- 30 个 Reuse CSA2 层;
- 2 个 SWA-only 层。
10. 重点:Decoder 中 ratio=1,没有压缩 token,收益在哪里
这是理解 CSA2 最关键的问题之一。
10.1 先给直接答案
Decoder 的 sequence dimension 确实没有压缩:
但它在另外四个地方获得了主要收益:
- Layer dimension:20 个 Decoder 层只保存 1 份 global KV;
- Entry dimension:每个位置只有一个 512 维 shared-KV latent,并使用 FP4;
- Attention compute:每层主 attention 只读取 Top-512 + SWA-128;
- Indexer compute:20 层中只有 5 层产生 Top-K,后 4 个只在 16K candidate 中搜索;
- CED Prefill:绝大多数 prompt token 不经过 Decoder 主体。
10.2 从三维 KV 张量看收益
把普通 Decoder global KV 抽象成:
CSA2 Decoder 的变化可以写成:
虽然 position 维仍是
仅从结构上看,若每层都采用同样的 356-byte global entry,则逐层保存需要:
CSA2 Decoder 只需要:
也就是 Decoder global cache 的 layer 维理论上减少约 20 倍。
这不是说整个模型 KV 一定恰好减少 20 倍,因为还存在:
- Encoder 的三份 global cache;
- 每层 SWA state;
- 不同基线的量化格式;
- scale 与 metadata。
但它说明了 ratio=1 仍然能有巨大收益的原因。
10.3 Main KV 是共享的,但 Query 不是共享的
所有 Decoder 层可以读取同一份 global memory:
但每层仍生成自己的 Query:
所以同一份 Main KV 可以被不同抽象层次的 Query 以不同方式解释。共享的是 memory bank,不是 attention computation。
10.4 主 Attention 不会读取全部 个位置
ratio=1 只是表示 global memory 每个 token 一个 entry,并不表示 core attention 是 dense attention。
每层真正读取的数量大约为:
因此昂贵的 64-head、512-dim core attention 成本近似与
随
10.5 20 层并不都运行 Indexer
Decoder 中:
- 1 个 Full 层运行全局 indexer;
- 4 个 Reindex 层更新 Top-K;
- 15 个 Reuse 层完全不运行 indexer。
即使不考虑 hierarchical candidate,索引次数也从“每层一次”降到:
再加入 candidate pool 后,大致变成:
而不是:
10.6 CED 让历史 token 不必穿过整个 Decoder
Decoder global KV 从 Encoder final hidden 生成,而不是从每个 Decoder 层自己的历史 hidden 生成。因此对绝大多数 prompt token:
- 计算 Encoder final hidden;
- 建立共享 Decoder global KV;
- 不需要让这些 token 再经过 20 层 Decoder。
只有最后 128 个 token 需要经过 Decoder,以重建每层局部 SWA state 并得到最后位置 logits。
10.7 为什么不进一步把 Decoder 也设成
报告没有把它明确写成唯一因果解释,但从结构上可以得到一个合理判断:
- Decoder 已通过 20 层共享一份 cache,大幅压缩 layer dimension;
- Decoder 的 global memory 直接服务最终生成,更需要精细的逐 token 可寻址性;
- Hierarchical Indexer 已将 core attention 控制在 Top-512;
- FP4 又显著降低了每个 entry 的存储成本。
因此选择
11. Hierarchical Sparse Indexer
如果每个 Reindex 层仍扫描百万上下文,那么每次 indexer 仍是
第一层 Full indexer 的 block score 为:
选择 2048 个 block,每块 8 个位置,得到最大 16,384 个 candidate。之后每个 Reindex 层使用自己的 Query 和 head weights,在候选池中独立选择 Top-512。
11.1 为什么 Candidate Pool 比 Top-K 大很多
如果 layer 20 只把自己的 Top-512 传给所有深层,那么浅层遗漏的位置永远无法恢复。
16K candidate pool 是一个中间召回集合:
- Full 层自己的 attention 仍只读取 Top-512;
- 后续 Reindex 可以在较大的 16K 集合里改变选择;
- 这样在减少搜索范围的同时保留跨层多样性。
11.2 它仍然不是严格 Decode
仍然需要:
- Decoder layer 20 扫描全部
; - Encoder layer 2、8、14 各扫描大约
; - 只是这些扫描在较小的 128 维 FP4 Indexer K 上进行;
- 真正昂贵的 512 维、64-head core attention 始终只处理固定 Top-K。
所以报告所说的 Decode FLOPs “nearly constant”不是数学上完全没有线性项,而是线性项已经缩小到整体计算中的较小部分。
12. CSA2 单层的完整张量流
V4.1 的关键维度:
- hidden dimension:5120;
- Main Query heads:64;
- Main head dimension:512;
- Query latent rank:1280;
- Indexer heads:32;
- Indexer head dimension:128;
- Top-K:512;
- SWA window:128。
对 batch size
12.1 Partial RoPE 与 inverse RoPE
Main latent 同时充当 K 和 V。如果对其最后 64 维施加 RoPE,那么它作为 Value 被加权求和后,输出也携带绝对位置旋转。
因此对 attention output 再应用 query 位置的逆旋转:
来自位置
从而恢复相对位置信息。
13. CED:为什么 Prefill 能跳过大部分 Decoder
CED 中的 Encoder 仍然是 causal encoder,不是 BERT 式双向 Encoder。
下半 20 层对 prompt 的所有位置生成:
一般形式下,Decoder global KV 直接从
而不是从每个 Decoder 层自己的历史 hidden state 产生:
结合 V4.1 的 CSA2 schedule,实际只有 Decoder Full layer 20 创建 global cache,其余 19 层共享。
13.1 Prefill 数据流
普通 Decoder-only Transformer 的 Prefill 主体成本近似:
CED 的成本变为:
当
13.2 为什么早期 Prompt token 可以跳过 Decoder
未来 Decode 需要的 Decoder global KV 已经由 Encoder final hidden 产生。早期 prompt token 在 Decoder layer 21–39 的中间输出不会被保存为长期 global KV,也不会成为未来 token 的全局 Key/Value。
所以它们没有必要全部通过 Decoder。
但最近 token 的 Decoder hidden 仍然重要,因为每个 Decoder 层都有自己的 SWA KV。因此最后 128 个 token 必须顺序通过 Decoder,用来:
- 建立每层 Decoder SWA ring;
- 产生 prompt 最后位置的最终输出和 logits。
这意味着:
- Prefill 可以跳过绝大多数历史位置的 Decoder 计算;
- Decoder layers 之间仍然串行;
- 每个新 Decode token 仍需通过全部 40 层。
14. Decode 时的逐层数据流
具体过程:
- 新 token 经过全部 Causal Encoder layers;
- Encoder layer 2、8、14 是 ratio=2 的 Full source:
- 每两个 Decode step 产生一个 compressed entry;
- 尚未凑满两个 token 时保存在 compressor tail state;
- Encoder final hidden 到达 Decoder;
- layer 20 生成一个新的 ratio=1 Decoder Main KV 与 Indexer K;
- layer 20 扫描全部 Decoder Indexer K,产生 Top-512 与 candidate pool;
- layer 24/28/32/36 在 candidate pool 中重新选择;
- 每个 CSA2 层计算自己的 Main Q、SWA KV 和 attention output;
- token 顺序通过 40 层,因此 Decode 激活参数约为 16B/token。
15. 对应官方代码的简化实现
以下代码是为了突出控制流,不是可以直接加载官方 checkpoint 的完整实现。
15.1 CSA2 Compressor
1 | def compress(x, ratio, w_kv, w_gate=None): |
Decode 时
第二个 token 到达时才生成完整 latent,并追加到 global paged cache。
15.2 Indexer
1 | def run_indexer(query_x, query_latent, index_k, candidates=None): |
15.3 三种 Mode
1 | def csa2_layer(x, mode, shared): |
15.4 官方代码中的映射
官方 model.py 使用:
1 | self.is_kv_source = layer_id in kv_source_layers |
因此:
- 同时是 KV source 与 index source:Full;
- 不是 KV source、但是 index source:Reindex;
- 两者都不是:Reuse。
共享状态集中在:
1 | class SharedAttentionRuntime: |
物理 global cache 只在 KV source layer 分配;但每一层都拥有自己的:
1 | window_kv_cache # [batch, 128, 512] |
因此代码层面可以概括为:
Global cache 是 group-owned,SWA cache 是 layer-owned。
16. 为什么正好是 890 bytes/token
报告称 V4.1 的 global KV footprint 为:
这个数字可以从模型配置和 FP4 scale 格式推导出来。
16.1 一份 Main KV entry
Main KV dimension 为 512,FP4 payload:
Main KV 每 16 个值有一个 1-byte E4M3 scale:
因此:
16.2 一份 Indexer K
Indexer K dimension 为 128:
每 32 个值有一个 1-byte E8M0 scale:
因此:
一份 Main KV + Indexer K:
16.3 三个 Encoder source,ratio=2
Encoder KV source 为 layer 2、8、14:
16.4 一个 Decoder source,ratio=1
合计:
这里的 890 bytes 是随上下文长度线性增长的 global cache。每层 128-entry SWA ring 是固定大小
17. KV Cache Manager 与持久化缓存
17.1 V4 的异构 KV cache
V4 同时存在:
- CSA Main KV;
- CSA Indexer K;
- HCA KV;
- 每层 SWA KV;
- CSA/HCA 尚未凑满 block 的 tail state。
由于
个原始 token 的对齐关系。
V4 将缓存分为两类。
Classical/Paged KV cache
存放已经完成压缩的:
- CSA Main KV;
- CSA Indexer K;
- HCA KV。
State cache
为每个 active sequence 分配固定 state block,保存:
- 每层最近 128 个 SWA KV;
- 尚未完成压缩的 KV/gate tail state。
SWA 和 compressor tail 更像“当前位置决定的 sequence state”,不适合直接套用普通 append-only PagedAttention 管理方式。
17.2 V4.1 按复用时间尺度分层
V4.1 将状态进一步划分为:
长期 Global KV
- 可以被大量后续 turn 复用;
- active 部分驻留 HBM;
- persistent copy 放在 SSD/host memory;
- 报告中的典型长期保留时间至少约 72 小时。
短期 SWA state
- 主要在分钟级活跃 session 内有价值;
- 不再长期写入 persistent SSD cache;
- 使用每台机器约 10% host DRAM 组成短 TTL 分布式池。
可重建 state
当 SWA state 淘汰后,通过 Bounded Replay 恢复,而不是一直存储。
其原则是:
不同状态拥有不同的生命周期、存储介质、淘汰策略和恢复成本。
18. SWA Bounded Replay
18.1 为什么精确恢复需要
虽然一层 SWA 只读取最近
个 token-layer。
18.2 Encoder SWA Bounded Replay
当 global prefix cache 命中但 Encoder SWA 丢失时:
- 读取已经缓存的 global KV;
- 取命中 prefix 的最后
个 token; - 将它们与 uncached suffix 一起重放;
- replayed prefix 只重建 SWA,不覆盖原有 global KV;
- uncached suffix 同时建立新的 global KV 和 SWA。
由于 replay 起点截断了更早的 SWA 依赖,所以恢复结果是近似的,并且可能依赖 cache-hit position。
18.3 Decoder SWA Bounded Replay
每次 Prefill:
- 完整 prompt 通过 Causal Encoder;
- 从 Encoder outputs 建立 Decoder global KV;
- 只取最后 128 个 Encoder outputs;
- 让它们通过 Decoder;
- 生成所有 Decoder layers 接下来 Decode 所需的 SWA ring;
- 这些 Decoder SWA state 不进入长期 prefix cache。
这是 CED 能把 Prefill 主体从
19. 分布式训练与推理 Kernel
19.1 V4 的 Context Parallel Compressor 边界
Context Parallelism 按 sequence 维切分,每个 rank 保存连续 token。Compression block 可能跨 rank 边界,而且 packed samples 的尾部长度可能不足
V4 使用两阶段处理:
- rank
把末尾最多 个未压缩状态发送给 rank ; - 下游 rank 将边界状态与本地 token 一起压缩;
- 各 rank 产生固定上限长度、允许 padding 的 compressed entries;
- All-Gather 收集所有 compressed entries;
- fused select-and-pad 将有效 entry 重排,并把 padding 放到尾部。
V4.1 Encoder ratio=2 时仍有类似的 compression boundary 问题,只是窗口更小。
19.2 CSA2 跨 Pipeline Stage 共享
Full source 与 Reuse/Reindex consumer 可能被放到不同 Pipeline Parallel stage,因此训练系统需要:
Shadow Indexers
- 在参与执行的 stage 放置轻量可执行副本;
- 只有一个 logical owner 负责优化器和 checkpoint;
- 同步参数并聚合梯度。
Pipeline Payload Extensions
跨 stage 传输:
- 共享表示;
- sparse routing information;
- Top-K/candidate 等状态。
这些状态需要和 Context Parallelism 使用一致的分片方式。
Microbatch-Level Shared-State Manager
状态必须按照 microbatch 独立追踪,并跨越:
- forward;
- activation recomputation;
- backward。
直到最后一个 consumer 完成才能释放,避免并发 microbatch 相互覆盖。
19.3 Sparse Attention Kernel
官方参考 TileLang kernel 展示了:
- 按 int32 indices 直接 gather KV;
- 每轮处理 64 个 sparse positions;
- 256 threads;
- FlashAttention 风格 online softmax;
- 维护 running maximum 与 running sum;
- 融合 learnable attention sink;
- 不要求预先物化一份 Selected-KV cache。
生产报告还列出:
- FlashMLA:融合 RoPE–Attention–inverse RoPE–cast;
- DeepGEMM:Mega-Gate、Mega-mHC、Mega-MoE;
- TileKernels;
- DeepSelect TopK。
Reuse layer 因为没有 compressor 和 indexer,报告称只需:
- Prefill:15 个 kernels;
- Decode:11 个 kernels。
19.4 EPD Disaggregation
系统采用 Encoder–Prefill–Decode disaggregation:
- Encoder deployment stage 主要处理多模态 vision encoding;
- Prefill stage 面向长序列和高吞吐;
- Decode stage 面向单 token 与低延迟。
三类资源可以独立扩缩容并重叠执行。这里部署语境中的 Encoder 不应与模型内部 20-layer Causal Encoder 完全混为一谈。
20. 公开参考代码与生产系统的区别
官方 README 明确说明公开实现是 readable reference implementation,而不是 production serving engine。
20.1 Hierarchical Indexer 的参考实现没有真正减少 GEMM 范围
论文中的生产语义是:Reindex 只计算 candidate positions。
公开 Python 代码为了可读性,先执行:
1 | index_score = einsum(q, full_index_k) |
再做:
1 | index_score.masked_fill_(~candidates, -inf) |
这样数值语义正确,但并没有在参考实现中省掉完整 score GEMM。生产系统必须先 compact/gather candidates,再运行 indexer,才能得到固定候选成本。
20.2 FP4 主要是数值模拟,不是完整 Packed Cache Manager
参考代码使用 in-place quantize/dequantize 模拟 FP4 QAT 数值,而 sparse-attention 接口仍然接收 BF16 tensor。它没有完整展示生产系统中的:
- packed FP4 payload;
- scale layout;
- paged allocation;
- HBM/DRAM/SSD transfer;
- prefix cache metadata。
20.3 Top-K 与共享运行时
参考实现使用 torch.topk;生产系统使用更高性能的 DeepSelect TopK kernel。
参考实现还使用进程级 shared_attn singleton,适合一次顺序 forward。Continuous batching 中必须按以下粒度管理:
- request/sequence;
- microbatch;
- Pipeline stage;
- speculative branch;
- cache hit/replay 状态。
否则一个 batch 的 Main KV、Top-K 或 candidate pool 可能覆盖另一个 batch 的状态。
21. 复杂度与收益总结
21.1 各机制对比
| 机制 | 长期 Global KV | Core Attention | Indexer |
|---|---|---|---|
| Dense MLA | 无 | ||
| DSA | 通常仍约 |
多层扫描 |
|
| V4 CSA | 每层约 |
CSA 层扫描 |
|
| V4 HCA | 每层约 |
无 | |
| V4.1 CSA2 | 只在 4 个 KV source 保存 | 只在 8 个 source 执行;Decoder Reindex 使用 candidate pool |
21.2 一百万 token 的直观规模
当
Encoder 三个 source、ratio=2:
个 Main KV entry。
Decoder 一个 source、ratio=1:
个 Main KV entry。
合计为
同时每层真正昂贵的 core attention 只读取约 640 个位置。
21.3 V4 与 V4.1 汇总
| 维度 | V4 CSA/HCA | V4.1 CSA2 |
|---|---|---|
| KV entry | shared-KV latent | shared-KV latent + FP4 |
| Sequence compression | CSA 4:1、HCA 128:1 | Encoder 2:1、Decoder 1:1 |
| Layer compression | 基本逐层独立 | 38 个 CSA2 层只有 4 个 KV source |
| Index reuse | 无系统性跨层复用 | Full/Reindex/Reuse |
| Reindex 搜索 | 全部 compressed positions | Decoder 后续层最多 16K candidates |
| HCA | 有 | 取消,纯 CSA2 |
| SWA | 每层 128 | 每层 128 |
| Persistent SWA | 存储、checkpoint 或精确重算 | 不长期存,Bounded Replay |
| Prefill | Prompt 经过完整模型 | 全 Prompt 走 Encoder,Decoder 只 replay 尾部 |
| Global KV precision | RoPE BF16、其余 FP8 | FP4 |
| V4.1 runtime global KV | — | 890 bytes/token,约为 V4-Flash 的 1/4 |
| V4.1 persistent KV | — | 约为 V4-Flash 的 1/8 |
22. 常见误解与局限
22.1 常见误解
-
CSA compression 不是量化。 它是多个 token 到一个 latent 的 learned pooling;FP4/FP8 才是数值量化。
-
CSA2 不是单纯的 token pooling。 最主要的新增收益是 layer-level KV 与 index reuse。
-
Reuse layer 不是跳层。 它仍执行自己的 Query、SWA、core attention、输出投影、MoE 和 residual/mHC。
-
Decoder ratio=1 不代表没有压缩。 它仍有 entry compression、20-to-1 layer sharing、FP4 和 sparse Top-K。
-
共享 KV 不代表 layers 可以并行。 下一层 Query 仍依赖上一层 hidden output。
-
Candidate pool 不是新的 KV cache。 它是一组位置或 block routing state,Main KV 仍是原来的共享 cache。
-
Hierarchical Indexer 不是完全消除
。 第一层 Full indexer 仍扫描完整上下文。 -
Prefill 跳过 Decoder 不等于 Decode 也跳过 Decoder。 每个新生成 token 仍然经过完整 40 层。
-
删除 compressor absolute bias 不等于删除 RoPE。 Main KV、Indexer K、Query 和 output 仍有位置处理。
-
公开 Python 代码不是生产 Serving Engine。 它主要用于表达 checkpoint 结构、张量关系和数值语义。
22.2 主要局限
压缩损失
Encoder ratio=2 仍然是有损 pooling。虽然 SWA 保存局部精确信息,但远距离信息只能通过压缩 latent 被访问。
Index selection error
Top-K 可能漏掉真正相关的位置。Candidate pool 也可能在第一层 Full indexer 阶段漏掉某个区域,后续 Reindex 无法跳出候选集恢复它。
Reused Top-K 可能变旧
Reuse layers 的 hidden abstraction 在变化,但访问位置不变。V4.1 每四个 Decoder 层插入一次 Reindex,是精度与成本之间的折中。
Bounded Replay 是近似状态恢复
恢复结果可能依赖 prefix cache 命中位置,在极端输入或 cache-resumption boundary 上存在潜在鲁棒性风险。技术报告也明确把它列为未来需要继续压力测试的边界。
系统实现复杂
Layer sharing 会显著增加:
- Pipeline Parallel 调度复杂度;
- microbatch shared-state 生命周期管理;
- continuous batching 的状态隔离要求;
- prefix cache、replay 与 speculative decoding 的组合状态空间。
23. 参考资料
技术报告
官方参考实现
- 标题: DeepSeek-V4_CSA-HCA与V4.1-CSA2详解
- 作者: 鱿鱼圈
- 创建于 : 2026-09-12 23:52:00
- 更新于 : 2026-10-05 13:10:45
- 链接: https://yuyanqi.com/2026/09/12/DeepSeek-V4_CSA-HCA与V4.1-CSA2详解/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。