KV Cache为什么能提速却更吃显存?理清显存开销与工程取舍
2026/6/15 1:27:14 网站建设 项目流程

一、KV Cache保存的是历史token的Key和Value

在Transformer的注意力模块中,输入特征会经过三个线性变换,分别得到Query、Key和Value,

注意力计算可以简化表示为,

为了便于理解,可以把三者简单看成,

  • Query表示当前token想查询什么;
  • Key表示每个历史token可以用什么特征被查询;
  • Value表示每个历史token实际携带的信息。

大模型采用自回归方式生成文本,每次通常只生成一个新token。历史token对应的Key和Value在前一步已经计算完成,而且不会因为新token的加入而发生变化。如果不使用KV Cache,每次生成新token时,模型都要重新计算全部历史token的Key和Value。KV Cache的作用,就是把这些结果保存起来。下一步生成时,模型只需要,

  1. 计算当前新token的Query、Key和Value;
  2. 将新的Key和Value追加到缓存;
  3. 使用当前Query查询全部历史Key;
  4. 根据注意力权重读取对应的Value。

即,某个token的Query只在它作为当前查询位置时使用一次,而它的Key和Value会被后面生成的每个token反复访问。

Prefill和Decode需要分开理解

大模型推理通常分为两个阶段。

Prefill阶段

模型一次性处理完整的输入提示词,并为全部输入token建立初始KV Cache。

Decode阶段

模型开始逐个生成token。每生成一个token,就向已有缓存中追加新的Key和Value。KV Cache主要优化的是Decode阶段。假设已经生成了1000 token,没有KV Cache时,为了生成第1001个token,模型需要重新计算前面1000个token的相关中间结果。开启KV Cache后,前面1000个token的Key和Value已经保存在显存中,模型只需要计算第1001个token对应的新结果。不过,KV Cache并没有让生成成本变成固定值。当前token的Query仍然需要访问所有历史Key和Value。随着上下文长度增加,每一步需要读取的缓存也会越来越大。

二、KV Cache显存占用可以提前算出来

对于常见的Decoder-only Transformer,KV Cache的理论显存占用可以近似表示为,

各参数含义如下,

参数含义
BBatch Size,或者并发序列数量
LTransformer层数
S当前缓存的序列长度
2分别表示Key和Value
H_KVKV Head数量
D_head每个Head的维度
P每个元素占用的字节数

从这个公式可以看出,KV Cache与以下因素呈线性关系,

  • 模型层数;
  • 上下文长度;
  • KV Head数量;
  • Batch Size;
  • 缓存数据精度。

模型层数和Head配置通常由模型结构决定。在实际部署中,最容易让显存快速上涨的两个参数是上下文长度和并发请求数。

一个具体的显存计算例子

假设某个模型的配置如下,

  • Transformer层数为32;
  • KV Head数量为 8;
  • Head Dimension为 128;
  • 上下文长度为8192;
  • Batch Size为1;
  • KV Cache使用BF16;
  • 每个元素占用2Bytes。

代入公式,计算结果为1073741824 Bytes,约等于1GB。仅一条长度为8192的序列,就需要大约1 GB的KV Cache。如果Batch Size增加到8,理论占用就会接近8 GB。如果上下文长度从8K增加到128K,在其他配置不变的情况下,单条序列的KV Cache会从约1 GB增加到约16 GB。

而且,这部分占用还没有包括,

  • 模型权重;
  • CUDA工作区;
  • Logits和采样张量;
  • 推理框架预留空间;
  • 内存对齐开销;
  • 显存碎片;
  • 其他临时张量。

用Python估算KV Cache占用

部署模型前,可以用下面的脚本快速估算理论占用,

def estimate_kv_cache_gib( num_layers: int, num_kv_heads: int, head_dim: int, seq_len: int, batch_size: int = 1, bytes_per_element: int = 2, ) -> float: total_bytes = ( batch_size * num_layers * seq_len * 2 * num_kv_heads * head_dim * bytes_per_element ) return total_bytes / (1024 ** 3) memory = estimate_kv_cache_gib( num_layers=32, num_kv_heads=8, head_dim=128, seq_len=8192, batch_size=1, bytes_per_element=2, ) print(f"KV Cache理论占用:{memory:.2f} GB")

这里得到的是理论数据量,不是完整的运行时显存。

实际部署时,不能把模型权重和理论KV Cache相加后,刚好填满整张显卡,还需要给CUDA、推理框架和临时张量预留空间。

GQA能够减少KV Cache占用

KV Cache的大小取决于KV Head数量,而不是Query Head数量。在Multi-Head Attention中,Query Head数量通常与KV Head数量相同。在Grouped Query Attention中,多个Query Head可以共享一组Key和Value。Multi-Query Attention更进一步,所有Query Head共享同一组Key和Value,因此缓存占用还可以继续下降。

三、KV Cache部署中常见的四个误区

误区一、PagedAttention会压缩KV Cache

PagedAttention主要解决的是KV Cache的显存管理问题。如果为每条请求按照最大长度预留一段连续显存,会造成大量浪费。如果频繁扩展和搬移缓存,又容易产生显存碎片。PagedAttention会把KV Cache切分为固定大小的Block,再通过映射关系管理逻辑位置和物理位置。

它主要解决,

  • 显存碎片;
  • 过度预留;
  • 不同长度请求的缓存管理;
  • 缓存 Block 的回收与复用;
  • 相同前缀的缓存共享。

但它不会改变一条完整序列理论上需要保存多少Key和Value。PagedAttention优化的是缓存如何存放和管理,而不是让缓存数据凭空减少。

误区二、语义相似的提示词可以共享缓存

Prefix Cache可以复用相同前缀对应的KV Cache,但这里的相同通常指token化后的前缀一致。只要前缀token发生变化,后续生成的Key和Value就可能不同。Prefix Cache更适合以下场景,

  • 多个请求使用相同的系统提示词;
  • 多个用户查询同一份长文档;
  • 代码助手反复使用同一个仓库上下文;
  • 批量任务使用完全相同的输入模板。

误区三、KV Cache可以跨模型版本复用

KV Cache是模型中间层的计算结果,它依赖当前模型参数。即使输入token完全一致,只要模型参数发生变化,生成的Key和Value也可能不同。

误区四、显存不足时可以直接删除历史KV

删除历史KV确实能减少显存占用,但也会让对应的历史token无法继续参与注意力计算。

对于使用全局注意力的模型,随意删除缓存可能导致,

  • 模型遗忘早期指令;
  • 长文档问答准确率下降;
  • 多轮对话前后矛盾;
  • 长距离依赖能力变差。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询