KV 稀疏化¶
算法维度(横向)之二:在已经训练好的模型上,推理时丢掉一部分 KV,以降低显存占用和读带宽压力。
与 Attention 变体 的区别:那里改的是模型本身的结构,本章讨论的是给定模型不变,在推理阶段动态决定哪些 K/V 可以扔掉。
1. 为什么可以丢¶
经验观察:attention 分布是高度稀疏的——大部分 query 对大部分 key 的 attention 权重接近 0。如果能识别出"对未来 decode 几乎不影响"的 K/V,丢掉它们对最终输出影响有限。
剪枝粒度可以分四类:
| 粒度 | 操作 | 代表方法 |
|---|---|---|
| Token 级 | 丢掉序列中某些 token 的 K/V | StreamingLLM、H2O、SnapKV、Scissorhands |
| Head 级 | 不同 head 重要性不同,丢掉次要 head 的 K/V | Ada-KV、MoA |
| Layer 级 | 跨层共享 K/V 或跳过部分层的缓存 | YOCO、CLA |
| 基于 query 的动态稀疏 | 每个 decode 步只读一小部分相关 K/V | Quest、Loki、RetrievalAttention |
2. Token 级稀疏¶
Attention sink + 滑动窗口(StreamingLLM)¶
观察:模型在前 \(k\) 个 token("attention sink")上集中了大量 attention 概率,简单丢弃会让分布塌陷。
策略:永久保留前 \(k\) 个 token + 滑动窗口最近 \(w\) 个 token,中间的全部丢掉。 代价:长程依赖可能丢失,适合"短期局部依赖为主"的对话场景。
重要性评分驱动(H2O / Heavy-Hitter Oracle)¶
观察:少数 token("heavy hitters")在 attention 中被频繁高分关注,它们的 K/V 不能丢。
策略:用累积 attention 分数为每个 token 打分,保留 top-K 个高分 token,其余驱逐。 工程难点:
- 评分需要在线维护,不能太重
- 与 paged 内存管理的整合:被剪掉的 K/V 释放后,块复用策略要重新设计
- 长序列下评分窗口的滑动逻辑
代表论文:H2O (2023)。
提示驱动(SnapKV)¶
观察:在 prefill 完成时,可以从最后几个 prefill token 的 attention 模式预测整个 prompt 中哪些 token 会被 decode 频繁关注。
策略:prefill 结束时一次性筛掉不重要的 K/V,进入 decode 时 KV 已是"瘦身版"。 优点:实现简单,与 paged attention 兼容性好。 代价:依赖 prefill 末尾的 attention 是否真能反映 decode 期间的需求——RAG / Coding 等场景可能不准。
代表论文:SnapKV (2024)。
3. Head 级稀疏¶
观察:同一层不同 attention head 的"信息容量"差异巨大,部分 head 高度重复或承担"分发"角色。
策略:
- 离线:用校准集评估每个 head 的重要性,对低重要性的 head 进行更激进的压缩或丢弃
- 在线:保留 head 数量随上下文长度自适应变化
代价:与 GQA / MLA 的"绑定"——head 已经被压缩过的模型上,进一步 head 级剪枝空间有限。
代表论文:Ada-KV (2024)。
4. Layer 级稀疏¶
YOCO(You Only Cache Once)¶
策略:只在少数几层真正缓存 K/V,其余层共享或重计算。 效果:KVCache 体积可下降一个数量级。 代价:需要从训练阶段就考虑这一架构(属于"半改架构、半改运行时")。
代表论文:YOCO (2024)、CLA (Cross-Layer Attention)。
5. 基于 query 的动态稀疏¶
前面几类是与 query 无关的剪枝——一次决定哪些 K/V 留下。Query-aware 的方法每个 decode 步都重新选 K/V:
Quest¶
每个 decode 步:
- 把 KV 划成块,为每块计算一个紧凑的"摘要"(min/max/平均向量)
- 用 query 与摘要做粗筛,选出 top-\(k\) 个块
- 只对选中的块做完整 attention
效果:每步只读 \(k\) 个块的 K/V,HBM 带宽压力大幅下降。 难点:摘要质量、top-\(k\) 阈值、块大小选择。
代表论文:Quest (2024)、Loki、RetrievalAttention。
6. 稀疏化在系统层面的代价¶
理论上稀疏可以让 KV 变小,但工程上有几个常见陷阱:
| 陷阱 | 描述 |
|---|---|
| 与 paged 内存管理的不兼容 | 被剪掉的 K/V 在块内位置不连续,要么留空(碎片)要么压实(额外搬运) |
| prefix cache 的语义破坏 | 跨请求 prefix 相同但稀疏决策不同 → 物理 KV 不一致,无法复用 |
| kernel 改写成本 | 稀疏 attention 需要 indirection,kernel 复杂度上升、效率下降 |
| 质量回归不易评估 | 短任务上看不出差异,长任务、多轮、reasoning 上才暴露问题 |
工业落地里 SWA + attention sink 是最稳的,token 级重要性剪枝在特定场景部署,layer/head 级和 query-aware 还多停留在论文阶段。
7. HiSparse:稀疏注意力后的内存系统¶
HiSparse 的关键判断是:top-k sparse attention 只减少"每步计算哪些 KV",没有自动减少"哪些 KV 必须常驻 HBM"。在 GLM-5.1-FP8、32K input + 8K output、8xH200、256 并发场景中,baseline sparse attention 很快被 HBM 容量卡住;HiSparse 通过 hot device buffer + host inactive KV + swap-in kernel,使高并发长上下文吞吐超过 baseline 3 倍,部分配置最高约 5 倍。
| 组件 | 作用 | 调优边界 |
|---|---|---|
| hot device buffer | HBM 中保留当前 top-k 更可能访问的 KV | buffer 越小 miss 越多,buffer 越大容量收益越小 |
| host inactive KV | 把非活跃 KV 下沉到 CPU memory | 依赖 CPU-GPU 带宽与 sparse locality |
| swap-in kernel | 在 decode 路径中识别 miss、更新 page table、搬回 KV | miss 频繁时会直接落在 decode critical path |
HiSparse 适合高并发、长上下文、sparse pattern 有局部性的 decode 侧;低并发或短上下文下,主动 offload 只会增加 I/O。它和 Offload 的差别在于:offload 的对象由 sparse attention 当前访问集合驱动,而不是由会话空闲或 LRU 单独决定。
来源:主站 reading HiSparse:稀疏注意力真正缺的那层内存系统
8. 推理型负载:逐出不是压缩的同义词¶
reasoning / CoT 负载暴露了永久逐出的硬边界:DeepSeek-R1-Distill-Qwen-7B 在 GSM8K 上把 50% KV 永久逐出时,准确率可从 71% 崩到 2.5% 或 0%。语义感知内存层级的实验显示,准确率主要由永久逐出比例决定,而不是由 HBM 中保留比例决定;把低重要性 token 全精度 offload 到 DDR 再预取回来,可以在释放约一半 HBM 的同时保留 91.5% 的 baseline 准确率。
这意味着 reasoning 场景里应区分三种动作:
| 动作 | 信息是否保留 | 适合场景 |
|---|---|---|
| Evict | 否 | 只适合确定不再需要的 token,比例必须极低 |
| Offload | 是,全精度搬家 | CoT / reasoning token 的默认安全路线 |
| Quantize | 是,低精度 | 需要 reasoning-aware 校准,8-bit 也可能不稳 |
来源:主站 reading 推理的 KV 逐出是一场灾难
关联章节¶
- 与 Attention 变体 的关系:算法维度的"减条目" vs "改形状"
- 与 Paged KV 的兼容性问题在 维度交叉 §3.1 详细讨论
- 与不同工作负载的匹配度:工作负载维度 中讨论各场景适合哪类稀疏
- reasoning 场景的 offload 边界:Reasoning / Long CoT
版本历史¶
| 版本 | 日期 | 说明 |
|---|---|---|
| v0.2 | 2026-06-02 | 新增 HiSparse 分层稀疏内存系统与 reasoning 负载中逐出/搬家/量化的边界 |
| v0.1 | 2026-05-14 | 框架搭建 |