CacheGen: KV Cache Compression and Streaming for Fast Large Language Model Serving

framework 2310.0724
kv-cachecompressioncontext-reuseadaptive-streamingttft

CacheGen — KV Cache Compression and Streaming #

1. TL;DR #

当被复用的长上下文 KV cache 存在远端存储、需经普通云网络(单位数 Gbps)取回时,取回延迟可与重算 prefill 相当甚至更久。CacheGen 用改造过的视频编码流水线把 KV cache 编码成紧凑比特流(size 降 3.5–4.3×,TTFT 降 3.2–3.7×),并按带宽逐块自适应流式传输以守住 SLO。

2. Q1 / Q2 / Q3 #

Q1 — 痛点:被复用 KV cache 的"传输时延"是被忽略的瓶颈 #

复用上下文的 KV cache 可以省掉超线性增长的 prefill 计算,这一点已被 vLLM / SGLang / Prompt Cache 等系统利用。但这些系统隐含假设 KV cache 已在本地 GPU 显存,或经 NVLink(数百 Gbps)在 GPU 间共享。现实中 KV cache 体量巨大——Llama-34B 处理 Amazon 2023 年报(约 8 万 token)产生 19 GB KV cache,与模型本身相当——GPU 显存装不下这么多复用上下文,复用请求间隔可能长达数小时且不一定命中同一 GPU,因此 KV cache 通常被卸载到专用存储服务器。当它需要经普通云服务器间链路(单位数 Gbps)取回时,网络延迟可达数百毫秒到 10 秒以上,与不复用直接 prefill 相当。已有的 KV 压缩工作(丢 token、量化)都是为了缩小运行时显存占用、必须保留张量形状,没有针对传输时体积

Q2 — 方法:把 KV cache 当视频来编码 + 按带宽自适应流式 #

CacheGen 提出 "KV cache streamer" 抽象,承担三个角色:离线把 KV cache 编码成紧凑比特流、在变化的网络吞吐下流式传输、在接收端 GPU 解码回 KV cache。编码器建立在三个关于 KV cache 数值分布的经验洞察之上(§5.1),流水线与视频编码同构(group-of-pictures → delta → 量化 → 算术编码),但参数针对 KV 数据重新推导。流式层把上下文切成块(默认 1.5K token),每块离线编码成多个可独立解码的质量等级,运行时按上一块测得的吞吐挑选满足 SLO 且损失最小的配置,带宽过低时回退到发文本让 LLM 重算。

核心技术壁垒(THE 最难复现的洞察):放弃 KV cache 的张量形状约束,从而能像视频一样做"delta + 层级差异化量化 + 按 channel-layer 分组的算术编码"三重压缩。所有竞品(H2O、LLMLingua、smart quantization)都被"必须保留张量形状供 LLM 直接消费"这一约束绑死,只能丢 token 或均匀量化;CacheGen 把 KV 目标从"运行时可用"改为"传输后再解码可用",解锁了完全不同的压缩空间——这也是为何它能叠加在 H2O/LLMLingua 之上再降 3.3–4.2×。真正难复现的不是任一单步,而是"发现 KV cache 具备 channel-layer 熵集中 + token 局部性 + 浅层敏感三重结构"并把它们同时映射到一条编解码流水线。

Q3 — 结果 #

3 Gbps 下,相较文本上下文 TTFT 降 3.1–4.7×,相较均匀量化基线降 3.2–3.7×;即便对比近乎无损的 8-bit 量化,仍降 1.67–1.81×(意味着高精度量化后仍存在大量可压缩冗余)。同质量下 KV cache 体积较均匀量化小 3.5–4.3×,质量退化不超过 2% accuracy / <0.1% F1 / <0.1 perplexity。自适应流式在 SLO=1s 下把违约率从 81% 降到 8%。离线编码延迟约 200 ms,存储成本与量化基线相当。

3. 架构 / 方法图 #

CacheGen 的请求生命周期分离线(编码入库)与在线(取回解码)两条路径。整体系统对照如下——基线传全尺寸 KV 张量慢,CacheGen 传压缩比特流:

Figure 1: CacheGen compresses KV cache before transmission

Paper's Figure 1(caption: "When the context is reused, CacheGen speeds up the sharing of its KV cache by compressing (encoding) the KV cache."). (a) 基线跨网络传"整块 KV cache 张量"很慢;(b) CacheGen 传"压缩后的 KV cache"。这张图钉死了 CacheGen 在系统中的位置:它是一个介于存储服务器与推理服务器之间的上下文加载模块,不改动 LLM 本体。

三种加载方式的延迟构成对比揭示了设计取舍:

Figure 2: three ways of loading context and their delay breakdown

Paper's Figure 2(caption: "How different ways of loading context affect the network delay ... and the computation delay ..."). (a) 传文本:数据少但计算延迟高(要重算 prefill);(b) 传 KV cache:计算延迟低但数据量大;(c) CacheGen:传压缩 KV(或文本),网络与计算延迟同时省。关键读点是 (b) 中 "transfer KV" 那条网络时间条可长过 (a) 的 "process context" 计算条——这正是"隐藏瓶颈"的可视化。

编码流水线(change-based encoding,group-of-tokens):每 10 个连续 token 组成一组,组内第一个 token(anchor)独立压缩,其余 token 只记录相对 anchor 的 delta 张量:

Figure 6: anchor-token + delta tensor encoding within a token group

Paper's Figure 6(caption: "Within a token group, CacheGen computes delta tensors between KV tensors of the anchor token and those of remaining tokens."). 注意它不像视频那样逐帧做前后 delta,而是全组共用同一个 anchor,使组内所有 token 可并行编解码——这是为解码吞吐做的关键工程取舍(牺牲一点压缩率换并行)。

请求 / 任务生命周期(arrival → schedule → dispatch → output)与调度决策可概括为:

sequenceDiagram participant Q as User Query participant IS as Inference Server (streamer) participant SS as Storage Server participant LLM as LLM (GPU) Q->>IS: query + context_id IS->>IS: 测上一块吞吐, 估 remaining_time = SLO - elapsed loop 每个 chunk (1.5K tokens) alt time_recompute <= remaining_time IS->>SS: 放弃 KV, 取文本块 SS-->>IS: text chunk IS->>LLM: 交 LLM 重算该块 KV else 带宽够 IS->>SS: get_kv(chunk_id, level=最大且满足SLO) SS-->>IS: 该等级的 KV 比特流 IS->>LLM: GPU 算术解码 (与下一块传输 pipeline) end end LLM->>Q: generate_with_kv → 首 token

调度纪律说明:streamer 的"调度器"以 chunk 为粒度做逐块配置决策(FCFS 顺序发送,无抢占——每块一旦发出即完成),准入/过载策略是在带宽过低时降级到文本重算(相当于用计算换带宽的软降级,而非丢弃请求)。"内存管理器"侧的分配单元是 1.5K-token 的 chunk;每个 chunk 离线预编码成多质量等级存于存储服务器的 {chunk_id: encoded_KV} 字典,无碎片问题,复用即按 chunk_id 直接命中。跨节点通信路径是普通云链路(单位数 Gbps TCP,非 NVLink/IB),传输的是编码后比特流而非张量。

4. 作者证明 #

无形式化作者证明 — 仅实证。

本文没有吞吐/延迟的解析模型或定理,全部结论由跨 3 模型 × 4 数据集的实测支撑;最接近"形式化"的是 App. C.1 的 Algorithm 1(自适应流式伪代码),它是一个贪心的逐块配置选择规则而非可分析的性能模型。为满足 framework 类别对成本模型的期待,此处补记:一个显式的性能模型本可澄清的问题(论文当前留白)——

核心技术壁垒(承接 §2 Q2):最难复现处在于把三条经验洞察(token 局部性 → delta;浅层敏感 → 分层量化;channel-layer 熵集中 → 分组 AC)同时成立并映射到一条负担得起解码开销的流水线;缺任一洞察,压缩率或质量就会崩。

5. 实验与数据 #

头号结果——TTFT 降低(跨 3 模型 4 数据集):

Figure 8: Time-to-first-token across models and datasets

Paper's Figure 8(caption: "Time-to-first-token (TTFT): Across different models and different datasets, CacheGen reduces TTFT with little negative impacts on quality ..."). 每个子图横轴 TTFT、纵轴质量(accuracy/F1/perplexity),"Better" 指向左上。读点:CacheGen(绿)点几乎总在 Quantization / Text 左侧同一质量水平——即同质量更快,3 Gbps 下相对文本快 3.1–4.7×、相对量化快 3.2–3.7×。

同质量下体积降低

Figure 9: KV cache size reduction with little quality loss

Paper's Figure 9(caption: "Reducing KV cache size: Across various models, CacheGen reduces size of KV cache with little accuracy decrease on various datasets."). 证实 3.5–4.3× 的体积下降不是以质量为代价换来的(退化 ≤2% acc)。

互补性——叠加在上下文压缩之上

Figure 10: CacheGen further compresses H2O / LLMLingua KV caches

Paper's Figure 10(caption: "Reducing KV cache size on top of H2O [153] and LLMlingu [72] ..."). CacheGen 在 H2O 上再降 3.5–4×、在 LLMLingua 上再降 3.3–4.2×,说明这些方法产出的浮点 KV cache 仍保有 CacheGen 所利用的统计特性——CacheGen 与它们正交互补。

自适应流式的价值隔离

Figure 13: SLO violation rate with and without adaptation

Paper's Figure 13(caption: "CacheGen reduces SLO violation rate over CacheGen without adaptation and the quantization baseline."). SLO=1s 下违约率 81%→8%,SLO=0.5s 下违约率低 60%——单独把"无自适应"版本剥出来对比,证明逐块降级/回退逻辑本身贡献显著,而非仅靠编码器。

开销与消融

Figure 15: ablation of the three encoder ideas

Paper's Figure 15(caption: "Contributions of individual ideas behind KV encoder: change-based encoding, layer-wise quantization, and AC based on channel-layer grouping."). 从均匀量化基线逐步叠加 channel-layer AC → change-based encoding → 分层量化,熵-精度曲线逐级右移,AC 与 change-based encoding 贡献最大。配合 Fig 14(此处未内嵌)显示离线编码 ~200 ms、存储与量化基线持平、解码经 GPU + pipeline 后对端到端延迟影响极小。

§6 Workload characterization — 赢/输的具体区间(据 §7.3 Fig 11/12、App. D Fig 19):

Workload regimeCacheGenBaseline (best of quant/text)Why
短上下文 (<1K token)自动回退到传文本文本 prefill 更快压缩+解码开销 > 省下的传输,短文本 KV 本就不大
长上下文 + 低带宽 (单位数 Gbps)大幅领先传全尺寸 KV 或重算都慢传输时体积降 3.5–4.3× 直接砍传输条
高带宽 (>20 Gbps)领先收窄趋近持平量化基线传 KV 也很快传输不再是瓶颈, 压缩收益被吃掉
高并发 (多请求争一 GPU)显著领先文本 prefill 抢算力, TTFT 飙升复用 KV 避免昂贵 prefill, 释放算力
带宽剧烈波动自适应守住 SLO固定等级频繁违约逐块降级/回退文本

论文诚实地暴露了"输"的区间(短上下文、超高带宽、超高端 GPU),而非只报平均。

6. 论证链 #

步骤论断论文内依据
1长上下文可复用,复用 KV cache 可省超线性 prefill§2.2:FiD 长上下文 accuracy 40%→48%;财报/法律/对话历史被多次查询复用
2但被复用 KV cache 常不在本地显存,需经普通网络取回§3:Llama-34B×80K token = 19 GB KV cache;间隔数小时、不命中同 GPU → 卸载到存储服务器
3经单位数 Gbps 云链路取回,网络延迟 ≥ 直接 prefill,成隐藏瓶颈§3 + Fig 2b:传 KV 时间条长过重算计算条
4KV cache 数值有可利用的分布结构(token 局部性 / 浅层敏感 / channel-layer 熵集中)§5.1:Fig 3 delta 方差低 2.4–2.9×;Fig 4 浅层加噪掉分更多;Fig 5 按 channel/layer 分组熵更低
5因此可放弃张量形状,用 delta + 分层量化 + channel-layer AC 编成比特流§5.2 + Fig 6 + Fig 15 消融:三步各自压低熵-精度曲线
6传输时体积大幅下降,同质量 TTFT 降 3.2–3.7×§7.2 Fig 8/9:size 3.5–4.3×、TTFT 3.2–3.7×
7变带宽下逐块自适应可守 SLO§7.4 Fig 13:SLO=1s 违约 81%→8%

7. 实现 cross-reference #

代码公开:https://github.com/UChi-JCL/CacheGen(本地未克隆,具体行号 [实现未公开] 于本仓库;以下按论文 §6 描述定位)。约 2K 行 Python + 约 1K 行 CUDA,基于 PyTorch v2.0 / CUDA 12.0。

框架集成两个接口(§6):

KV 管理两个模块(§6):

关键实现细节(易被忽略的 1–2 个技巧):

  1. anchor token 保留 8-bit 高精度(§5.2):组内其余 token 的 delta 都被激进量化(bin 0.5/1/1.5 由浅到深),但作为参考基准的 anchor 若失真会污染整组所有 delta 的分布,故必须单独高精度——一个小比例的高精度"锚"支配了整块的压缩质量。
  2. GPU 算术编解码 + 传输 pipeline(§6):改造 [101] 的 AC 库为 CUDA,每个 CUDA thread 负责一个 token 的编解码,并把 chunk i 的传输与 chunk i−1 的解码重叠——这是把 AC 从"CPU 慢操作"变成"可忽略开销"的关键,否则额外解码步会吃掉压缩省下的时间。
  3. 自适应逻辑(App. C.1 Algorithm 1)为逐块贪心:测吞吐 → 若重算时间 ≤ 剩余 SLO 则发文本,否则取满足 size/throughput ≤ remaining_time 的最大(最小损失)等级编码发送。默认量化:层分三等距组,bin size 分别 0.5 / 1 / 1.5(§C.2);默认块长 1.5K token,首块默认中等等级(Llama-7B 约 140 MB/chunk)。