0%

KV Cache 机制与优化

KV Cache 机制与优化

一句话定位:KV Cache 用显存换算力——它让自回归生成从 O(n²) 重复计算变成增量计算,但自身的显存开销随 batch × 序列长度线性增长,成为LLM 推理吞吐的头号上限

1. 机制:为什么需要缓存 K/V

自回归生成逐个 token 产出。生成第 t 个 token 时,注意力需要用到前面所有 token 的 Key 和 Value。

  • 若不缓存:每步都要对全部历史 token 重算 K/V,总计算量随序列长度平方增长,且大量重复。
  • KV Cache:把历史 token 的 K/V 张量缓存下来,每步只计算新 token 的 Q/K/V,并把新 K/V 追加进缓存。于是每步计算量与序列长度成线性关系而非重算全部。

由此推理天然分两阶段:

  • Prefill(处理 prompt):一次性并行计算全部输入 token 的 K/V,计算密集
  • Decode(逐 token 生成):每步只算一个 token,读取整个 KV Cache,访存/带宽密集、算力利用率低。

2. 代价:显存随 batch × 序列长度线性增长

KV Cache 大小 ≈ 2(K和V)× batch × 序列长度 × 层数 × KV头数 × head_dim × 精度字节数

  • 关键点:它随 batch 与序列长度线性膨胀,很快就超过模型权重本身的显存占用;
  • 于是能同时容纳多少并发请求由剩余显存决定 → KV Cache 直接决定了最大并发数与吞吐上限,这是”吞吐上不去”最常见的根因。

3. 优化方向

  • 分页管理(Paged):不连续分配、按固定 block 管理,消除碎片与预留浪费 → 见 3.5 PagedAttention/vLLM。
  • 量化 KV:把 KV Cache 存为 INT8/FP8,显存直接减半以上,代价是可能引入精度损失(长上下文更敏感)。
  • 共享前缀复用:多个请求共享相同 system prompt / few-shot 前缀时,前缀的 KV 只存一份并被多请求引用(配合 Copy-on-Write),在 Agent、批量结构化抽取等场景收益极大 → 对应 3.9 SGLang 的 RadixAttention。
  • 附:GQA/MQA 通过减少 KV 头数从模型结构层面缩小 KV Cache。

参考:论文《Efficient Memory Management for Large Language Model Serving with PagedAttention》;Hugging Face 博客《LLM 推理中的 KV Cache 详解》