把 KV 缓存拆成「锚点+低秩+残差」,8GB 本地内存跑到 64k 上下文

2026-07-27

DKV 是一个 KV 缓存压缩运行时,把每个 256-token 块压成一个锚点、一个秩32低秩增量、再加若干精确残差,在 8.6GB 的 Apple M3 上把 Qwen2.5-1.5B 的上下文顶到 64k(默认 PyTorch 配置在 16k 就爆显存),代价是解码比稠密缓存慢。

这篇在解决什么

长上下文推理的瓶颈往往不是模型权重,而是 KV 缓存(key-value cache,Transformer 推理时为每个 token 缓存的键值对):它随序列长度线性增长,在消费级硬件上最先吃满内存。一个 1.5B 的 int4 模型权重只要约 1GB,但 KV 缓存可以轻松超过它。默认的 PyTorch 全 KV 配置在一台 8.6GB 的 Apple M3 上,到 16k 上下文就直接 OOM。

DKV 要解决的就是这个:在权重和精度都不动的前提下,把 KV 缓存从「线性增长的无底洞」变成「有上限的固定池」,让长上下文在本地小内存机器上跑得动。作者是 Newton School of Technology 的 Om Chimurkar,这是一份技术报告。

方法

核心思想是「把平滑的部分和离群点分开」。每 256 个 token 组成一个块,压成三部分:

解码时用一个 fused routed kernel:先用便宜的路由器选出 top-K 最相关的块,在低秩子空间里算注意力分数而不解压 K,残差和最近窗口(recency window,最新的 1024 个 token 原样保留)做精确注意力,最后用 flash 风格的 log-sum-exp 把两半合并。Prefill 用免训练的块稀疏注意力,成本随长度次二次增长。

结果

所有数字都在一台 8.6GB 的 Apple M3 上、Qwen2.5-1.5B(int4)实测得到。

指标(64k 上下文)DKV优化稠密默认 PyTorch 稠密
KV 缓存占用1.12GB1.88GBOOM
Prefill 时间477s821s(慢 1.72×)16k 即 OOM
解码吞吐21.4 tok/s20.2 tok/sOOM
针埋点是否精确召回/

几个关键数字:每个块的压缩比在 R=128 时是 1.44×、R=64 时 2.25×;从 4k 到 64k 的每个上下文长度,DKV 都精确召回了埋在文本里的密码;在 Llama-3.2-3B 上做了跨架构召回验证。Prefill 在 64k 比 weight-matched 的优化稠密快 1.72×。

为什么重要

KV 缓存压缩是本地长上下文推理能不能落地的关键。DKV 的价值定位很清楚:它是个「内存+prefill」工具,不是免费午餐。在稠密缓存还能塞下的区间(这台机器上到 32k),稠密解码更快,应该用稠密;DKV 的主场是缓存塞不下、否则根本跑不起来的区间——更大模型、更长上下文、更紧的内存、更多并发会话。在这个区间,稠密方案压根解码不了,慢一点的解码就是唯一能跑的选择。

作者把代价写得很诚实,没有藏。这种既报喜也报忧的报告在 KV 压缩这块很少见。

局限与存疑

诚实是这篇的特点,局限也都是作者自己列的。

解码慢是头号代价。sparse 表示每步都要重建和合并,per-token 算术量比一次 fused attention 大,E6 消融定位到这就是解码开销来源。最有效的修法是一个融合解码 kernel,而不是改表示。

CUDA/Triton 路径写了但没测。仓库里有 Triton 和 C++/GGML 解码 kernel,但评测机器没有 NVIDIA GPU,所以没有任何 GPU 数字,GPU 性能只是假设。两个已知的正确性 bug(元数据失配、Triton 残差对齐)在 CPU 上修了,GPU 验证还没做。

评测面窄。所有性能数字来自一个模型(Qwen2.5-1.5B int4)、一台机器;正确性只测了针召回和零困惑度漂移,没跑 RULER、LongBench 这类标准长上下文基准,也没和其他缓存压缩方法(量化、驱逐、其他低秩)对照。残差预算和路由参数是针对 Qwen2.5-1.5B 调的,换模型没验证。固定 256 块池把压缩容量卡在 65,536 token。

术语

原文与代码

社区讨论

全部论文解读