KeepKV:用「选举票」机制和零扰动合并实现无损 KV 缓存压缩

笔记日期: 2026-06-10 笔记作者: Zhongzhu Zhou 论文标题: KeepKV: Achieving Periodic Lossless KV Cache Compression for Efficient LLM Inference 作者: Yuxuan Tian, Zihan Wang, Yebo Peng, Aomufei Yuan, Zhiming Wang, Bairen Yi, Xin Liu, Yong Cui, Tong Yang arXiv: 2504.09936 状态 / Venue: arXiv 预印本,2025 年 4 月(v2 2025 年 11 月)

一句话总结

KeepKV 是一种新型 KV 缓存合并压缩方法,通过「选举票」(Electoral Votes)机制和「零推理扰动合并」(ZIP-Merging)在单步上实现了可证明的无损压缩,彻底解决了此前所有合并方法都存在的「注意力衰落」缺陷,并在只保留 10% KV 缓存的情况下实现了超过 2 倍推理吞吐提升。

前置知识:理解这篇论文需要什么背景

KV 缓存是什么?

基于 Transformer 的大语言模型(LLM)在生成每个新 token 时,需要将当前 query 与所有历史 token 的 key 做内积、再对 value 加权求和,这就是 自注意力机制。如果每步都从头重新计算所有历史 key 和 value,计算量随序列长度平方增长。

为了解决这个问题,LLM 推理时会把每个历史 token 的 key 和 value 向量存起来——这就是 KV 缓存。新 token 只需一次前向传播,利用缓存的 K、V 直接计算注意力,避免重复计算。

但 KV 缓存的内存代价极高。 以 LLaMA-3-70B 为例,batch size=128、上下文长度 8K 时,KV 缓存需要高达 320 GB 显存,远超单卡甚至多卡的承受上限。这就是本文要解决的核心问题。

KV 缓存压缩的三个思路

现有方法大致分三类:

  1. 量化(Quantization):把 KV 张量存储成低精度格式(4-bit、8-bit)。例子:KVQuant、MiKV、GEAR。与 KeepKV 正交,可以结合使用。

  2. 驱逐(Eviction):只保留「重要」的 KV 对,其余永久丢弃。重要性通常用注意力分数衡量。例子:H2O(历史注意力分数)、SnapKV(观察窗口内的注意力)、StreamingLLM(开头 + 最近 token)、PyramidKV(底层分配更多 cache)、AdaKV / HeadKV / DuoAttention(按注意力头分配预算)。

  3. 合并(Merging):不丢弃 KV 对,而是把不重要的 KV 合并进旁边的 KV,保留所有 token 的信息(压缩形式)。例子:CaM(只合并 value)、D2O(按余弦相似度加权合并)、KVMerger(聚类 + 高斯核权重合并)。

KeepKV 的核心发现:现有所有合并方法都存在一个可以数学证明的缺陷——「注意力衰落」(Attention Sag),而 KeepKV 推导出了唯一能消除这一缺陷的合并公式。

注意力计算的基本公式

在理解论文的推导之前,先把注意力计算写清楚。对于单头注意力,解码阶段第 tt 步的输出为:

ot=i=1tAitvi=i=1tsitvii=1tsit(1)o_t = \sum_{i=1}^{t} A_i^t v_i = \frac{\sum_{i=1}^{t} s_i^t v_i}{\sum_{i=1}^{t} s_i^t} \tag{1}

其中 sit=eqtki/ds_i^t = e^{q_t k_i / \sqrt{d}}非归一化注意力分数(标量),Ait=sit/jsjtA_i^t = s_i^t / \sum_j s_j^t 是归一化权重。输出是 value 向量的加权平均,权重就是注意力分数。

图1:KV 缓存压缩方法全景

graph TD
    A[KV 缓存内存瓶颈] --> B[量化 Quantization]
    A --> C[驱逐 Eviction]
    A --> D[合并 Merging]

    B --> B1["降低存储位宽(4-bit, 8-bit)
示例:KVQuant, MiKV
优点:与其他方法正交可叠加
缺点:低位精度下有质量损失"]

    C --> C1["只保留重要 KV,其余永久丢弃
示例:H2O, SnapKV, StreamingLLM
优点:简单快速
缺点:不可逆信息丢失
         被驱逐的 token 后续可能变重要"]

    D --> D1["把不重要的 KV 合并进其他 KV
示例:CaM, D2O, KVMerger
优点:无永久信息损失
缺点:注意力衰落 → 仍有输出扰动"]

    D --> D2["KeepKV:选举票 + ZIP-Merging
单步可证明无损(定理 3)
多步有上界(定理 4)"]

    style D2 fill:#d4edda,stroke:#28a745
    style C1 fill:#fff3cd,stroke:#856404
    style D1 fill:#fff3cd,stroke:#856404

核心问题:为什么现有方法都有扰动?

驱逐方法的不可避免误差

设驱逐了 KV 对 (ke,ve)(k_e, v_e),剩余 t1t-1 对产生的新输出为:

ot=i=1,ietsitvii=1,ietsit(2)o_t' = \frac{\sum_{i=1, i \neq e}^{t} s_i^t v_i}{\sum_{i=1, i \neq e}^{t} s_i^t} \tag{2}

将其用原始输出 oto_t 表示,整理得:

ot=11Aet(otAetve)(3)o_t' = \frac{1}{1 - A_e^t} \left( o_t - A_e^t v_e \right) \tag{3}

扰动量 otot\|o_t' - o_t\| 等于零,当且仅当 Aet=0A_e^t = 0 也就是说,只有被驱逐的 token 注意力权重恰好为零时,驱逐才是无损的——这在实践中几乎不可能。PyramidKV 等方法再聪明,也只能减小 AetA_e^t,无法将其归零。

更糟糕的是,论文图 2(b) 表明,在解码过程中,原本被判定为「不重要」的 token 会在后续步骤变得非常重要。驱逐是不可逆的,一旦丢弃就无法找回。

合并方法的「注意力衰落」

合并方法更聪明——把 (ke,ve)(k_e, v_e) 合并进 (kc,vc)(k_c, v_c),形成新的 (kr,vr)(k_r, v_r)。现有方法普遍用凸组合

kr=weke+wckc,vr=weve+wcvc(4)k_r = w_e k_e + w_c k_c, \quad v_r = w_e v_e + w_c v_c \tag{4}

其中 we+wc=1w_e + w_c = 1(D2O 用余弦相似度计算权重,KVMerger 用高斯核)。

定理 2(注意力衰落): 对于任意满足 we+wc=1,we,wc>0w_e + w_c = 1, w_e, w_c > 0 的凸组合,合并后新 KV 对的注意力分数必然满足:

srt=eqtkr/d<set+sct(5)s_r^t = e^{q_t k_r / \sqrt{d}} < s_e^t + s_c^t \tag{5}

从而 Art<Aet+ActA_r'^t < A_e^t + A_c^t,输出扰动 otot>0\|o_t' - o_t\| > 0

直觉证明(Jensen 不等式): 指数函数是凸函数,因此:

eqt(weke+wckc)/dweeqtke/d+wceqtkc/d=weset+wcscte^{q_t(w_e k_e + w_c k_c)/\sqrt{d}} \leq w_e e^{q_t k_e/\sqrt{d}} + w_c e^{q_t k_c/\sqrt{d}} = w_e s_e^t + w_c s_c^t

且当 kekck_e \neq k_c 时不等号严格成立。两个原始 KV 合并成一个向量后,分数「缩水」了——被合并的那两个 token 本来合起来有 se+scs_e + s_c 的影响力,现在只剩下 sr<se+scs_r < s_e + s_c。这就是「注意力衰落」,是凸组合合并的数学必然,不是参数选择不当的问题。

图2:注意力衰落的几何直觉

graph LR
    subgraph 合并前
        E["token e: k_e → 分数 s_e"]
        C["token c: k_c → 分数 s_c"]
        SUM["合起来的注意力贡献 ∝ s_e + s_c"]
    end

    subgraph 凸组合合并后
        R["merged: k_r = w_e k_e + w_c k_c"]
        SCORE["s_r = exp(q·k_r/√d)"]
        LOSS["根据 Jensen 不等式:
s_r < w_e·s_e + w_c·s_c ≤ s_e + s_c
→ 注意力衰落!"]
    end

    E --> R
    C --> R
    R --> SCORE
    SCORE --> LOSS

    style LOSS fill:#f8d7da,stroke:#842029
    style SUM fill:#d4edda,stroke:#28a745

根本原因:将两个向量线性插值后再取指数,结果比先取指数再加权求和要小。单个合并后的 KV 向量,永远无法「顶替」两个原始 KV 向量合起来的注意力贡献。

KeepKV 的解法:选举票 + ZIP-Merging

思路一:选举票机制——修改注意力计算规则

既然无法用一个向量同时满足分子和分母的约束,KeepKV 就修改注意力计算规则,让每个 KV 对携带一个整数**「票数」** pip_i(初始化为 1)。新的输出公式变为:

ot=i=1tpisitvii=1tpisit(6)o_t = \frac{\sum_{i=1}^{t} p_i s_i^t v_i}{\sum_{i=1}^{t} p_i s_i^t} \tag{6}

当把 (ke,ve)(k_e, v_e) 合并进 (kc,vc)(k_c, v_c) 时,新 KV 的票数设为:

pr=pe+pc(7)p_r = p_e + p_c \tag{7}

类比美国选举人制度:票数多的「选举人」代表更多选民。一个票数为 3 的 KV 对,在注意力计算中相当于有 3 个独立的相同 KV 对参与——这就补偿了分数缩水带来的影响力损失。

思路二:ZIP-Merging——唯一正确的合并公式

有了选举票机制,我们可以推导出让输出 精确 不变的合并公式。设合并后 ot=oto_t' = o_t,要求分子和分母分别相等:

分母条件(保证归一化):

prsrt=peset+pcsct(8)p_r s_r^t = p_e s_e^t + p_c s_c^t \tag{8}

we=pesetw_e = p_e s_e^twc=pcsctw_c = p_c s_c^t,则 srt=we+wcprs_r^t = \frac{w_e + w_c}{p_r}

分子条件(保证加权求和):

prsrtvr=pesetve+pcsctvc=weve+wcvc(9)p_r s_r^t v_r = p_e s_e^t v_e + p_c s_c^t v_c = w_e v_e + w_c v_c \tag{9}

代入 prsrt=we+wcp_r s_r^t = w_e + w_c,得:

vr=weve+wcvcwe+wc(10)v_r = \frac{w_e v_e + w_c v_c}{w_e + w_c} \tag{10}

这就是 value 合并公式——以当前注意力分数为权重,对两个 value 向量做加权平均,直觉非常自然。

key 合并公式的推导:srt=eqtkr/d=we+wcprs_r^t = e^{q_t k_r / \sqrt{d}} = \frac{w_e + w_c}{p_r},可得:

qtkr=dlnwe+wcpr(11)q_t k_r = \sqrt{d} \cdot \ln\frac{w_e + w_c}{p_r} \tag{11}

我们不知道未来的 qtq_t,但知道 qtke=dlnsetq_t k_e = \sqrt{d} \ln s_e^tqtkc=dlnsctq_t k_c = \sqrt{d} \ln s_c^t。利用这两个约束,用 kek_ekck_c 的线性组合表示 krk_r,使得等式(11)在点积意义下成立:

kr=(weke+wckc)lnwe+wcpe+pcwelnset+wclnsct(12)k_r = \frac{(w_e k_e + w_c k_c) \ln\frac{w_e + w_c}{p_e + p_c}}{w_e \ln s_e^t + w_c \ln s_c^t} \tag{12}

定理 3(单步无损): 使用公式(10)和(12)合并,并按公式(6)计算注意力,则:

otot=0(13)\|o_t' - o_t\| = 0 \tag{13}

这是论文最核心的贡献——从数学上严格证明了单步合并的无损性。

图3:选举票 + ZIP-Merging 操作序列

sequenceDiagram
    participant Cache as KV 缓存
    participant EV as 选举票 p_i
    participant ZIP as ZIP-Merging

    Note over Cache: 合并前:(k_e,v_e,p_e=1) 和 (k_c,v_c,p_c=2)
    Cache->>ZIP: 按 cosim(k_e, k_c) 选取合并候选对
    ZIP->>ZIP: 计算权重:w_e = p_e·s_e^t = 1·s_e, w_c = p_c·s_c^t = 2·s_c
    ZIP->>ZIP: v_r = (w_e·v_e + w_c·v_c) / (w_e + w_c)
    ZIP->>ZIP: k_r = (w_e·k_e + w_c·k_c) · ln((w_e+w_c)/(p_e+p_c))
                              / (w_e·ln(s_e) + w_c·ln(s_c))
    ZIP->>EV: p_r = p_e + p_c = 3
    ZIP->>Cache: 用 (k_r, v_r, p_r=3) 替换原来两个 KV 对
    Note over Cache: 新注意力输出:o_t = Σ p_i·s_i·v_i / Σ p_i·s_i
    Note over Cache: 定理3 保证:||o_t' - o_t|| = 0 ✓

扩展到多步生成:EMA 注意力分数预测

ZIP-Merging 公式(12)需要当前步的注意力分数 sets_e^tscts_c^t。预填充(prefill)阶段这是可以精确获得的。但实际推理中,我们在 prefill 结束时压缩一次缓存,然后跑很多步解码——在后续步骤 t>tt' > t,新 query qtq_{t'}qtq_t 不同,之前的合并是基于旧分数的,会引入误差。

为了减小这个误差,KeepKV 利用了一个关键的经验观察:注意力分数具有很强的局部性——相邻步骤之间,某个 token 的注意力分数变化平滑(图 2d)。基于此,KeepKV 用指数移动平均(EMA) 预测分数:

s^t=11αtSt(14)\hat{s}^t = \frac{1}{1 - \alpha^t} S^t \tag{14} St={k=twt(1α)αtkskt=L(prefill ends)αSt1+(1α)stt>L(15)S^t = \begin{cases} \displaystyle\sum_{k=t-w}^{t} (1-\alpha) \alpha^{t-k} s^k & t = L \text{(prefill ends)} \\ \alpha S^{t-1} + (1-\alpha) s^t & t > L \end{cases} \tag{15}

其中 ww 是初始化窗口大小,α(0,1)\alpha \in (0,1) 是衰减系数,1/(1αt)1/(1-\alpha^t) 是偏差修正项(防止早期估计偏小)。

定理 4(多步误差上界): 解码步骤 tt' 的输出扰动满足:

ototCδt1(ipisit)2(16)\|o_{t'}' - o_{t'}\| \leq \frac{C \cdot \|\delta^{t'}\|_1}{(\sum_i p_i s_i^{t'})^2} \tag{16}

其中 δit=s^itsit\delta_i^{t'} = |\hat{s}_i^{t'} - s_i^{t'}| 是 EMA 预测误差,CC 与 value 向量范数有关。只要注意力分数演化平滑,δt1\|\delta^{t'}\|_1 就小,误差也就有界。

图4:多步解码流水线

flowchart TD
    A["输入序列(长度 L)
    运行 prefill → 计算所有 K, V"] --> B

    B["将完整 KV 存入外部存储
    (CPU 内存 / NVMe)"] --> C

    C["将 GPU 缓存压缩到预算 B
    应用 ZIP-Merging + 选举票
    (在步骤 L 时单步无损)"] --> D

    D["解码步骤 t+1:新 query q_{t+1}
    用压缩缓存计算注意力
    (多步:有界误差)"] --> E

    E["EMA 更新:
    S^t = α·S^{t-1} + (1-α)·s^t
    为下次合并预测分数"] --> F

    F{"预算超出?"}
    F -- "是:再次压缩" --> G
    F -- "否" --> D

    G["定期从外部 KV 刷新
    重新加载完整缓存,重新压缩
    (将累积误差重置为 0)"] --> D

    style B fill:#cce5ff,stroke:#004085
    style G fill:#d4edda,stroke:#28a745

定期刷新是实现「周期性无损」的关键:将完整 KV 存在外部,每隔 TT 步重新加载并重新压缩,可以将多步累积误差清零。刷新周期 TT 是吞吐量与质量的权衡参数。

合并候选选择:为什么用余弦相似度?

KeepKV 用两个 key 向量间的余弦相似度来选择合并对。论文为此提供了理论依据:从多步误差上界的 Taylor 展开来看,主导项与 kekc22\|k_e - k_c\|_2^2 成正比。余弦相似度高的两个 key 在向量空间中更接近,合并后引入的 key 空间误差更小。这为 D2O 中「余弦相似度选候选」这一此前只是启发式的做法给出了理论解释。

实现中,选择候选时排除最近的 RR 个 token(最近 token 的时序局部重要性高,不宜过早合并)。

完整算法流程

算法 1:KeepKV 推理
输入:提示词 token x_1,...,x_L;预算 B;EMA 衰减 α;窗口 w;刷新周期 T
输出:生成的 token

=== Prefill 阶段 ===
1. 计算完整 KV 缓存:K_L = X_L W_k,V_L = X_L W_v
2. 初始化所有票数:p_i = 1(i=1,...,L)
3. 将 (K_L, V_L, p_i) 存入外部存储(CPU)
4. 初始化 EMA:S^L = Σ_{k=L-w}^{L} (1-α)α^{L-k} s^k
5. 当 |缓存| > B 时循环:
   a. 计算所有候选对的 cosim(k_i, k_j)
   b. 选取 (e,c) = argmax cosim(k_e, k_c)(排除最近 R 个 token)
   c. 计算权重:w_e = p_e·s_e^L,w_c = p_c·s_c^L
   d. 合并 value:v_r = (w_e·v_e + w_c·v_c) / (w_e + w_c)
   e. 合并 key:k_r = (w_e·k_e + w_c·k_c) · ln((w_e+w_c)/(p_e+p_c))
                           / (w_e·ln(s_e^L) + w_c·ln(s_c^L))
   f. 票数累加:p_r = p_e + p_c
   g. 从缓存删除 (k_e,v_e,p_e) 和 (k_c,v_c,p_c),添加 (k_r,v_r,p_r)

=== 解码阶段 ===
6. 对每个生成步骤 t = L+1, L+2, ...:
   a. 计算新 KV:k_t = x_t W_k,v_t = x_t W_v
   b. 添加 (k_t, v_t, p_t=1) 到缓存
   c. 计算 query:q_t = x_t W_q
   d. 计算注意力输出:o_t = Σ p_i·s_i^t·v_i / Σ p_i·s_i^t
   e. 生成 token;更新 EMA:S^t = α·S^{t-1} + (1-α)·s^t
   f. 若 |缓存| > B:用 EMA 预测分数再次压缩(ZIP-Merging)
   g. 若 (t-L) mod T == 0:[定期刷新]
      - 从外部存储加载 (K_L, V_L)
      - 用当前 EMA 分数重新执行 ZIP-Merging
7. 返回生成的 token

关键细节:prefill 阶段(步骤 5c)使用精确注意力分数(定理 3 严格成立);解码阶段(步骤 6f)使用 EMA 预测分数(引入有界误差)。定期刷新(步骤 6g)将累积误差清零。

图5:KeepKV 与现有方法对比

graph LR
    subgraph 驱逐方法
        EV_M["H2O / SnapKV / PyramidKV
不可逆信息丢失
无理论保证
实现简单"]
    end

    subgraph 现有合并方法
        MG_M["CaM / D2O / KVMerger
无永久信息丢失 ✓
仍有注意力衰落 ✗
无理论误差界"]
    end

    subgraph KeepKV
        KK["选举票 + ZIP-Merging
无永久信息丢失 ✓
单步无损(定理3)✓
多步有界(定理4)✓
外部存储支持定期刷新 ✓"]
    end

    style KK fill:#d4edda,stroke:#28a745
    style EV_M fill:#f8d7da,stroke:#842029
    style MG_M fill:#fff3cd,stroke:#856404

实验结果

实验设置

模型: LLaMA-3-8B-Instruct、LLaMA-3-70B-Instruct、Mistral-7B-Instruct-v0.2

基准测试:

  • LongBench(14 个长上下文任务):多文档问答(HotpotQA、2WikiMQA、MuSiQue)、单文档问答(NarrativeQA、Qasper、MultiFieldQA)、摘要(GovReport、QMSum、MultiNews)、少样本学习、合成任务(段落检索)、代码补全(LCC、RepoBench-P)
  • RULER(最长 128K 的长度泛化压力测试)

对比基线: Full KV(上界)、StreamingLLM、H2O、SnapKV、PyramidKV、CaM、D2O、KVMerger

KV 预算比例: 10%、20%、50%

主要结果

LongBench 结果(20% 预算,LLaMA-3-8B):

方法问答摘要代码平均
Full KV47.127.366.245.8
StreamingLLM28.418.648.330.4
H2O35.222.153.736.4
SnapKV40.624.859.440.7
PyramidKV41.325.360.141.5
CaM39.824.258.239.8
D2O41.725.060.841.9
KVMerger42.125.461.042.3
KeepKV44.826.563.744.3

在 20% 预算下,KeepKV 填补了最优基线(KVMerger)与 Full KV 之间约 70% 的性能差距。

关键发现:

  1. 极端压缩(10% 预算): KeepKV 仍能保持可用的生成质量,而所有驱逐方法的质量显著崩塌。选举票机制保留了所有 token 的信息(压缩形式),即使在极低预算下也没有 token 被完全遗忘。

  2. RULER 长上下文: 在 128K 上下文下,KeepKV 的退化幅度明显小于其他方法,因为 EMA 分数追踪对长范围依赖维持了更准确的重要性估计。

  3. 吞吐量: 在 10% 预算下,LLaMA-3-70B 的推理吞吐量比 Full KV 提升超过 2.1 倍(以 token/s 计算)——KV 大小减少直接转化为每次注意力计算的内存访问减少。

  4. 消融实验(LLaMA-3-8B,20% 预算):

变体LongBench 均分
无压缩(Full KV)45.8
仅 D2O 合并41.9
仅选举票(无 ZIP)42.6
仅 ZIP(无选举票)43.1
选举票 + ZIP(KeepKV)44.3

两个组件各有贡献:单独的选举票部分弥补了注意力衰落;单独的 ZIP 公式在没有票数追踪的情况下无法完整应用;两者结合才实现了无损保证。

图6:不同 KV 预算下的 LongBench 性能

xychart-beta
    title "LongBench 平均分 vs KV 预算比例(LLaMA-3-8B)"
    x-axis ["10%", "20%", "50%", "100%"]
    y-axis "分数" 25 --> 50
    line [28.8, 36.4, 41.8, 45.8]
    line [32.5, 41.9, 43.5, 45.8]
    line [36.7, 44.3, 45.1, 45.8]

(近似值:蓝=H2O,橙=D2O,绿=KeepKV;KeepKV 的优势在低预算时最显著)

理论深入:ZIP-Merging Key 公式的推导

这里我更详细地梳理公式(12)的推导逻辑。

目标: 找到 krk_r,使得 preqtkr/d=we+wcp_r \cdot e^{q_t k_r / \sqrt{d}} = w_e + w_c(即 srt=(we+wc)/prs_r^t = (w_e+w_c)/p_r)。

这等价于:

qtkrd=lnwe+wcpr(17)\frac{q_t k_r}{\sqrt{d}} = \ln\frac{w_e + w_c}{p_r} \tag{17}

约束: 我们不知道未来的 query qtq_t,但有两个已知的点积关系:

qtked=lnset,qtkcd=lnsct(18)\frac{q_t k_e}{\sqrt{d}} = \ln s_e^t, \quad \frac{q_t k_c}{\sqrt{d}} = \ln s_c^t \tag{18}

构造:kr=λeke+λckck_r = \lambda_e k_e + \lambda_c k_ckrk_rkek_ekck_c 的线性组合),则:

qtkrd=λelnset+λclnsct=lnwe+wcpr(19)\frac{q_t k_r}{\sqrt{d}} = \lambda_e \ln s_e^t + \lambda_c \ln s_c^t = \ln\frac{w_e + w_c}{p_r} \tag{19}

一个自然的选择是令 λewe\lambda_e \propto w_eλcwc\lambda_c \propto w_c,归一化使等式成立:

λe=welnwe+wcprwelnset+wclnsct,λc=wclnwe+wcprwelnset+wclnsct(20)\lambda_e = \frac{w_e \cdot \ln\frac{w_e+w_c}{p_r}}{w_e \ln s_e^t + w_c \ln s_c^t}, \quad \lambda_c = \frac{w_c \cdot \ln\frac{w_e+w_c}{p_r}}{w_e \ln s_e^t + w_c \ln s_c^t} \tag{20}

代回得 Eq.12:

kr=(λeke+λckc)=(weke+wckc)lnwe+wcprwelnset+wclnsct(21)k_r = (\lambda_e k_e + \lambda_c k_c) = \frac{(w_e k_e + w_c k_c) \ln\frac{w_e+w_c}{p_r}}{w_e \ln s_e^t + w_c \ln s_c^t} \tag{21}

这个推导的关键假设是:qtkr=λe(qtke)+λc(qtkc)q_t k_r = \lambda_e (q_t k_e) + \lambda_c (q_t k_c),即内积的线性性(这对任意 qtq_t 都精确成立,不是近似)。精确成立!唯一的「近似」在于多步生成时 qtq_t 会变化,此时用的是 EMA 预测的 s^e,s^c\hat{s}_e, \hat{s}_c

注意事项:分母为零的边界情况

公式(21)在 welnset+wclnsct=0w_e \ln s_e^t + w_c \ln s_c^t = 0 时分母为零。这等价于 λelnset+λclnsct=0\lambda_e \ln s_e^t + \lambda_c \ln s_c^t = 0,即两个分数的对数加权平均为零,也就是 qtq_t 与两个 key 都正交(set=sct=1s_e^t = s_c^t = 1,即点积为零)。这是一个极端边界情况,实现时需要加保护(例如加入 epsilon)。

局限性与边界条件

  1. 多步误差有界但不为零。 单步无损性需要精确的当前步注意力分数;在多步解码中,KeepKV 依赖 EMA 预测,引入有界误差。对于需要极精确远程依赖的任务(如「大海捞针」—— 段落中随机插入的事实检索),仍可能退化。

  2. 外部 KV 存储的内存代价。 定期无损压缩需要把完整 KV 存到 CPU 内存中。对于 LLaMA-3-70B 在 128K 上下文下,这可能是几十 GB。论文没有量化定期刷新的时延开销。

  3. GQA / MLA 兼容性未评估。 现代架构如 LLaMA-3 用了分组查询注意力(GQA),多个 query head 共享同一 KV head。KeepKV 的理论基于标准 MHA;论文没有明确讨论 EV 和 ZIP-Merging 对 GQA 共享 KV 结构的泛化性。

  4. 注意力局部性假设。 ZIP-Merging 的 key 公式假设未来 query 方向与当前相似。对于有突然话题切换的任务,或一段长上下文中有截然不同段落的情况,这个假设可能失效。

  5. 未测试批量推理场景。 实验均为单序列推理。在生产中常见的批量服务(如 vLLM 的 continuous batching)下,不同序列有不同的上下文长度和注意力分布,票数和 EMA 状态需要按序列、按 head、按层维护,元数据开销值得关注。

批判性分析:不足与可改进之处

不好的地方和方法层面的缺陷

(a) 吞吐量声称掩盖了真实时延开销。 论文报告的 2× 吞吐量提升只测量注意力计算部分,并未将定期刷新(从 CPU 加载完整 KV 并重新压缩)的 I/O 时延计入。在 NUMA 架构或 NVLink 带宽受限的系统中,这段 I/O 可能非常显著。表现为吞吐量高但端到端时延不降。

(b) 10% 预算实验的上下文窗口较短。 论文 LongBench 实验的上下文在 4K–32K 范围,10% 预算对应 400–3200 个 token,这已经是相当宽裕的缓存了。真正困难的场景是 128K 上下文 + 10% 预算(约 800 个 token),在这种情况下 EMA 局部性假设的成立更难保证。RULER 实验虽然测了 128K,但粒度较粗。

(c) 基线对比不完整。 论文对比了 CaM、D2O、KVMerger,但没有对比 KIVI(量化方案)、GemFilter、或 InfiniGen(利用部分注意力处理长上下文),而论文声称超越「所有现有 KV 缓存压缩方法」,这个说法因遗漏上述方法而显得过于宽泛。

(d) 消融实验粒度不足。 消融只对比了「有/无选举票」和「有/无 ZIP」,但对以下最关键的超参数没有敏感性分析:EMA 衰减系数 α\alpha、EMA 窗口大小 ww、刷新周期 TT,以及排除最近 RR 个 token 的参数 RR。这些参数直接影响方法质量,却缺乏系统研究。

(e) 定理 3 的适用范围在正文中表述不够清晰。 论文有时暗示「KeepKV 是无损的」,但严格来说,只有在精确当前分数可用时(prefill 阶段)单步才是无损的。在解码阶段再次压缩(缓存超出预算时),用的是 EMA 预测分数,定理 3 不严格成立。这一区分在正文中不够突出,容易让读者误解「所有步骤都无损」。

作者淡化或回避的局限

(a) 外部存储方案对系统的要求被低估。 论文提到「存入 CPU 内存」,但没有量化对不同规模模型和上下文长度的内存需求,也没有讨论当 CPU 内存也受限时的降级策略。对于实际部署来说,额外几十 GB 的 CPU 内存占用是一个显著的系统约束。

(b) 方法不完全是「训练自由的」。 EMA 衰减 α\alpha 和窗口 ww 的最优值因模型架构而异。论文报告了固定值,但实际部署不同模型时可能需要重新调参,这带来了额外的开发和维护成本。

(c) 与量化方法的联合评估缺失。 论文宣称与量化正交可以结合,但没有给出实验数据。「KeepKV + 4-bit 量化」能达到什么质量水平?这对于实际部署价值最高,却被完全留白。

具体改进建议

  1. 提供完整时延分解。 在不同刷新周期 TT 下报告端到端时延(不仅是吞吐量),并在评测中包含刷新 I/O 时间,使实验结论与生产环境的预期更一致。

  2. 在更长上下文(64K–128K)下系统评测 10% 预算场景。 这才是真正考验 EMA 局部性假设的关键场景。

  3. 超参数敏感性分析。α{0.8,0.9,0.95,0.99}\alpha \in \{0.8, 0.9, 0.95, 0.99\}T{16,64,256,}T \in \{16, 64, 256, \infty\} 进行系统扫描,给出调参建议,降低实际使用门槛。

  4. 联合量化实验。 给出 KeepKV + 4-bit KVQuant 的组合基准,量化两者结合的收益,这对于极致效率场景(模型部署)非常有价值。

  5. GQA/MLA 的理论扩展和实验验证。 明确推导 GQA 下选举票机制的正确性,并在 LLaMA-3(实际使用 GQA)上做针对性验证,因为这是目前最主流的开源模型架构。

  6. 批量推理实验。 在 vLLM 框架下的 continuous batching 场景中测量元数据开销,并与单序列场景对比,为系统集成提供数据支撑。

可复现性说明

  • 代码: 写作时(v2,2025 年 11 月)尚未公开,但论文对算法的描述足以复现。
  • 模型: LLaMA-3-8B/70B-Instruct(Meta)、Mistral-7B-Instruct(Mistral AI),均公开可用。
  • 基准: LongBench(Hugging Face)、RULER(github.com/hsiehjackson/RULER)。
  • 需要调的超参数: 预算比例 B/LB/L、EMA 衰减 α\alpha、EMA 窗口 ww、刷新周期 TT、排除最近 token 数 RR
  • 实现陷阱: ZIP-Merging key 公式(12)中分母 welnset+wclnsctw_e \ln s_e^t + w_c \ln s_c^t 理论上可能为零(当两个分数均为 1,即 qtki=0q_t k_i = 0 时)——需要加保护 epsilon;另外 lnsit\ln s_i^tsit>0s_i^t > 0 恒成立(指数函数恒正),所以对数本身不会有未定义问题。

总结与我的看法

KeepKV 对一个经典的工程问题做出了扎实的理论贡献。识别出「注意力衰落」是所有现有合并方法的共同缺陷,并用 Jensen 不等式给出严格证明——这是一个真正的洞见,而不是实验上的改进。选举票 + ZIP-Merging 的组合设计也很优雅:不是修补原有的合并公式,而是改变注意力计算规则本身,从根本上绕过了 Jensen 不等式的限制。

多步扩展不如单步那么干净——它依赖 EMA 预测的局部性假设,只能提供有界误差而非零误差——但通过定期刷新将问题分解为若干个「有保证的单步」,是一个实用且有吸引力的工程选择。

对于实际从业者,三点带走:

  1. 如果你现在在用 H2O/SnapKV 等驱逐方法,切换到 KeepKV 风格的合并理论上应该有明显的质量提升,且没有额外吞吐代价。
  2. 定期刷新需要 CPU 内存缓冲完整 KV;对于 CPU 内存也紧张的边缘设备,可以使用无刷新变体(有界误差但不需外部存储)。
  3. 方法与量化正交——KeepKV + 4-bit 量化是一个值得尝试的组合,论文未覆盖但应该有协同效应。

未来方向: 将理论扩展到 GQA/MLA(DeepSeek-V2 的 MLA 特别有趣);集成到 vLLM/SGLang 的连续批处理中;自适应选择刷新周期(根据实时 EMA 误差动态调整 TT)。

深度思考:KeepKV 与信息论的联系

从更高层次来思考 KeepKV 为何有效。KV 缓存压缩的根本问题是:保留什么信息,以何种形式保留?

驱逐方法的回答: 保留那些移除后对当前输出影响最小的 KV 对。这是贪心的、短视的——忽略了 token 的重要性会随时间变化。

朴素合并方法的回答: 把不重要的 KV 混合在一起,以免信息丢失。这在原则上更好,但具体的混合公式(凸组合)系统性地低估了合并后 KV 对的贡献(注意力衰落)。

KeepKV 的回答: 改变信息的表示方式。不试图用一个向量近似两个不同的向量,而是追踪已被融合的向量个数(选举票),再推导出唯一正确的 key 向量,使得这个 key 向量加上票数后,产生与原来两个向量完全相同的注意力输出。

类比无损压缩: 这类似于信息论中的无损压缩——无法在减少符号的同时保留每一个可能的输出,但可以改变表示方式,使得解码器(这里是注意力计算)用更少的存储项产生相同的结果,前提是解码器也相应地更新(这里是使用加权注意力公式)。

为什么现有合并方法调参也救不了

自然的问题:CaM、D2O、KVMerger 能不能通过选择更好的权重来避免注意力衰落?答案是不能,定理 2 是证明。

注意力衰落与在凸组合内如何选择 wew_ewcw_c 无关——它是两个向量的任意凸组合所产生的单个向量,对任意 query 的指数内积,都严格小于各自指数内积之和(由指数函数的严格凸性决定)。无论如何调整 wew_ewcw_c,都无法逃脱 Jensen 不等式。

唯一的出路是改变下游计算的方式——这正是选举票机制所做的事。

选举票的空间开销

选举票机制对每个 KV 条目增加一个整数 pip_i。对于有 BB 个活跃条目的缓存,就是 BB 个整数。与 KV 张量本身相比:每个条目是 dd 维 float16 向量(key + value),即 2d2d 个 float16 = 2d×22d \times 2 字节。对于 LLaMA-3 的头维度 d=128d=128,每个条目 512 字节,而一个 int32 票数 4 字节。额外开销 4/512=0.78%4/512 = 0.78\%——完全可以忽略。

ZIP-Merging 本身的计算量增加也很小(主要是 log 运算),在 GPU 内存带宽瓶颈面前可以忽略不计。

与 SnapKV、H2O 的深度对比

SnapKV 和 H2O 是目前部署最广泛的驱逐方法,值得深入比较 KeepKV 在哪些地方超越了它们。

H2O(重击者预言机): 驱逐历史累积注意力分数最低的 token。核心弱点:用历史注意力分数预测未来重要性,但如图 2(b) 所示,很多被驱逐的 token 后来会变成高注意力的「重击者」。KeepKV 从不驱逐,只压缩,所以历史信息永远不会消失。

SnapKV: 在提示词末尾的观察窗口内用注意力分数决定驱逐哪些 token。这比 H2O 更适合提示词密集型长上下文任务,但仍然永久丢弃 token,且窗口外的重要 token 仍可能被错误丢弃。

KeepKV 在 10% 预算下碾压两者的原因: 在极端压缩(丢弃 90% token)时,驱逐方法只保留分数最高的 10% token,其余 90% 上下文信息永久消失。KeepKV 保留的是所有 token 的压缩表示,没有任何上下文被真正丢弃,只是编码得更紧凑。在 10% 预算下,KeepKV 的 LongBench 分数比 SnapKV 高约 8 分,正是因为合并表示保留了那些本会被驱逐的信息。

与训练方法的对比:DMC 和 Compressive Transformer

Compressive Transformer(Rae 等,2020): 使用学习到的压缩函数将过去的激活值压缩成固定大小的记忆。KeepKV 的定期刷新在概念上与之相关——两者都维护完整上下文的外部记忆。但 Compressive Transformer 需要训练压缩函数,而 KeepKV 是无训练的,使用理论推导的合并公式。

动态记忆压缩(DMC,Nawrot 等,2024): 训练模型决定何时以及如何合并 token。DMC 在某些场景下压缩率更高,但需要重新训练,无法直接用于已有预训练模型。KeepKV 是后训练方法——不需要修改模型,可以直接应用于任何现成的 LLM。

KeepKV 相对于训练方法的核心实践优势:可以立即应用于任何模型,无需微调,在标准基准上表现有竞争力或更优。

图7:与相关工作的全面对比

graph LR
    subgraph 无训练方法
        E1["StreamingLLM
Initial + recent tokens
最简单,质量最差"]
        E2["H2O
历史注意力分数驱逐
快,但历史重要性≠未来重要性"]
        E3["SnapKV
观察窗口内驱逐
对提示词重任务更好"]
        E4["D2O / KVMerger
余弦相似度 / 高斯核合并
保留信息但有注意力衰落"]
        E5["KeepKV
选举票 + ZIP-Merging
单步无损 + 多步有界"]
    end

    subgraph 需要训练的方法
        T1["DMC
训练模型做合并决策
压缩率高但依赖微调"]
        T2["Compressive Transformer
学习压缩函数
需要从头训练"]
    end

    E1 -.->|"更好"| E2
    E2 -.->|"更好"| E3
    E3 -.->|"更好"| E4
    E4 -.->|"理论突破"| E5

    style E5 fill:#d4edda,stroke:#28a745
    style T1 fill:#cce5ff,stroke:#004085
    style T2 fill:#cce5ff,stroke:#004085

实际部署考量

与推理框架的集成

KeepKV 可以集成到任何暴露 KV 缓存的 LLM 推理框架中。关键改动:

  1. KV 缓存数据结构:在每个 (key, value) 条目旁增加整数 votes 字段。
  2. 注意力计算:修改注意力核,在 softmax 前将每个 token 的注意力 logit 加上 lnpi\ln p_i(等价于将非归一化分数乘以 pip_i)。
  3. 压缩步骤:实现 ZIP-Merging 算法(按余弦相似度选候选,计算合并 key/value/votes,更新缓存)。
  4. EMA 状态:为每个激活的缓存条目维护 EMA 状态 SiS_i(按层、按头存储)。

候选选择的余弦相似度计算是 O(B2)O(B^2),对大预算可用 LSH 或 FAISS 近邻搜索近似。

数值稳定性

ZIP-Merging key 公式的几个数值陷阱:

  1. 分数的对数: lnset=qtke/d\ln s_e^t = q_t k_e / \sqrt{d} 就是 softmax 前的原始 logit,直接读取即可,无需先 exp\expln\ln

  2. 分母趋近于零: welnset+wclnsctw_e \ln s_e^t + w_c \ln s_c^t 在两个 logit 均接近零时趋近于零。修复方法:若 welnset+wclnsct<ϵ|w_e \ln s_e^t + w_c \ln s_c^t| < \epsilon,回退到简单等权平均 kr=(ke+kc)/2k_r = (k_e + k_c)/2

  3. 票数增长: 在级联合并下,票数最大值约为 L/BL/B(原始长度除以预算)。对 32K 上下文、10% 预算,最大约 10——用 int8 完全足够。

对注意力机制的更宽视角

KeepKV 的贡献从另一个角度来看,是对注意力机制本身做了一个自然的推广。标准注意力可以写成:

ot=i1sitvii1sit(22)o_t = \frac{\sum_{i} 1 \cdot s_i^t \cdot v_i}{\sum_{i} 1 \cdot s_i^t} \tag{22}

这里的「1」是每个 KV 对的隐式权重——每个 KV 对在注意力中地位平等(都用 sits_i^t 参与)。KeepKV 将这个「1」推广为 pip_i

ot=ipisitviipisit(23)o_t = \frac{\sum_{i} p_i \cdot s_i^t \cdot v_i}{\sum_{i} p_i \cdot s_i^t} \tag{23}

这实际上是一种加权注意力,权重不是人为设置的,而是由合并历史自动维护的。这个推广形式保留了标准注意力的所有性质(正则化、可微等),同时赋予了注意力机制「记忆合并历史」的能力。

从这个角度来说,KeepKV 不仅仅是一种压缩技巧,而是对注意力计算语义的一个有趣扩展:KV 对不再只代表自身对应的 token,而是代表一组被压缩进来的 token 的「代表」,票数就是代表的数量。

结论

KeepKV 是 KV 缓存压缩领域一个扎实的理论贡献。识别出「注意力衰落」是所有现有合并方法的共同缺陷,并用严格的 Jensen 不等式证明——这是真正的洞见,不是实验上的小改进。选举票 + ZIP-Merging 的组合很优雅:不是修补原来的合并公式,而是修改注意力计算规则本身,从根本上绕开了 Jensen 不等式的限制。

多步扩展不如单步干净,但定期刷新将问题分解为若干「有保证的单步」,是工程上实用且有吸引力的设计。

这篇论文对我的主要启示:在优化系统时,有时不应该只在现有约束下做近似,而应该重新审视约束本身是否可以合理放宽。KeepKV 发现的关键点是:注意力机制要求每个 KV 对地位平等(权重都是 1),这个限制是不必要的——只要下游的注意力公式也做相应修改,就可以给不同 KV 对赋予不同的「代表权重」,而这完全不破坏注意力的数学性质。这种「修改游戏规则」的思路值得在其他场景下借鉴。

延伸分析:EMA 衰减参数 α\alpha 的行为

EMA 衰减系数 α\alpha 是 KeepKV 多步扩展中最重要的超参数。理解它的行为有助于判断方法在什么场景下有效、在什么场景下会遇到困难。

α\alpha(如 0.99): EMA 追踪注意力分数的长期平均,变化缓慢。适合注意力模式在长上下文中比较稳定的任务(如摘要任务,文档中的多处内容在整个解码过程中都相关)。不适合注意力快速转移的场景(如在长文档末尾回答一个具体问题,此时只有问题相关的 token 重要)。

α\alpha(如 0.8): EMA 快速响应近期变化,适应哪些 token 重要的突然转变。适合动态上下文,但容易受单步异常值干扰。

偏差修正项 1/(1αt)1/(1-\alpha^t) 确保解码初期(EMA 尚未「预热」前)估计不偏小。没有修正项时,t=1t=1 步的 EMA 是 (1α)s1(1-\alpha) s^1,对 α=0.99\alpha = 0.99 来说只有 0.01s10.01 \cdot s^1——远低于实际。有修正项则 t=1t=1 时 EMA 等于 s1s^1,之后逐渐收敛到指数加权平均。

实用调参建议: 论文报告 α=0.9\alpha = 0.9、窗口 w=32w = 32 效果不错。一个合理的启发式规则:令有效记忆长度 1/(1α)1/(1-\alpha) 大约为上下文长度的 10-20%。对 32K 上下文,α=0.9\alpha = 0.9 对应记忆长度 10\approx 10,可能过短;α=0.999\alpha = 0.999(记忆 1000\approx 1000)可能更合适。

局部性假设为何在经验上成立

KeepKV 多步扩展的核心理论假设是注意力分数在相邻解码步之间平滑变化。这一「局部性」既有直觉支撑,也有实验验证。

直觉: token ii 在第 tt 步的注意力分数反映了模型当前隐状态 qtq_t 对该 token 的「关注程度」。随着生成推进,qtq_t 在连续变化(每次只处理一个新 token),因此点积 qtkiq_t \cdot k_i 也连续变化——注意力分数平滑演化,而不是突然跳变。

实验支持: 论文图 2(c) 显示,某个 token 的注意力分数在相邻步的方差(蓝色点)远大于在滑动窗口内的方差(橙色点)。这说明基于窗口内预测(即 EMA 所用的)比跨窗口预测准确得多——正是 KeepKV 所依赖的局部性。

失效场景: 以下情况局部性可能不成立:

  • 文档开头和结尾注意力模式截然不同的超长上下文。
  • 多轮对话中话题突然切换。
  • 投机解码(speculative decoding)场景,草稿模型和目标模型的 query 差异较大。

这些情况下,需要更短的 EMA 窗口或更频繁的定期刷新。

内存和计算开销分析

内存开销:

组件每层/头大小说明
票数 pip_iB×4B \times 4 字节 (int32)约占 KV 大小的 0.78%
EMA 状态 SiS_iB×d×2B \times d \times 2 字节 (fp16)与 K 缓存大小相同
外部完整 KVL×d×2×2L \times d \times 2 \times 2 字节存放于 CPU 内存

以 LLaMA-3-8B(32 层,32 头,d=128d=128)、L=32768L=32768B=3277B=3277(10% 预算)为例:

  • 票数:32×32×3277×4=1332 \times 32 \times 3277 \times 4 = 13 MB(可忽略)
  • EMA 状态:与 K 缓存相同 = 32×32×3277×128×286032 \times 32 \times 3277 \times 128 \times 2 \approx 860 MB
  • 外部完整 KV:32×32×32768×128×2×21732 \times 32 \times 32768 \times 128 \times 2 \times 2 \approx 17 GB(CPU 内存)

对于 LLaMA-3-70B(80 层,64 头)在 128K 上下文下,外部 KV 约需 280 GB CPU 内存——需要配置充足的服务器。

计算开销:

主要开销来自候选选择(余弦相似度计算),朴素实现是 O(B2)O(B^2)。在 B=3277B=3277 时约 1070 万次相似度计算。每 10 步触发一次压缩,每步摊下来约 107 万次——对 GPU 来说可以接受,但对大预算需要考虑 LSH 近似。

未解问题与未来方向

1. 自适应刷新调度。 当前设计使用固定刷新周期 TT。一个更合理的方案是实时监控 EMA 预测误差,当误差超过阈值时触发刷新——注意力模式稳定时省去不必要的 I/O,不稳定时更频繁刷新。

2. 层间协同合并。 不同层的注意力模式差异很大。协调跨层的合并决策(如只在多层都认为某 token 不重要时才合并)可能进一步提升质量,但会显著增加复杂度。

3. 与前缀缓存的结合。 现代推理框架(vLLM、SGLang)对系统提示词的 KV 做前缀缓存,跨请求复用。KeepKV 的外部 KV 存储与前缀缓存兼容——系统提示词的完整 KV 可以存一份共享,每个请求只需对动态部分维护自己的压缩 KV。

4. 与 GQA/MLA 的理论整合。 LLaMA-3 用了 GQA(多个 query head 共享一个 KV head),DeepSeek-V2/V3 用了 MLA(低秩 KV 压缩)。KeepKV 的理论基于标准 MHA,如何将选举票和 ZIP-Merging 推广到这些共享/低秩 KV 结构,是重要的开放问题。

5. 学习型合并调度策略。 ZIP-Merging 公式在给定当前 query 时是理论最优的,但何时触发合并(哪一步压缩)和选择哪对候选(余弦相似度是否最优)仍有改进空间。一个轻量级学习策略,基于历史合并质量来决策,值得探索。