Skip to content
🔗 分享本题
查看我的学习进度 →

自回归解码缓存历史 Key Value 避免重复计算的机制图

🧠 记忆锚点:KV Cache 用显存保存历史 K/V,换掉重复前缀计算;生成越长、并发越高,缓存越大。

💡 答案要点

KV Cache = 缓存 Attention 计算的中间结果

为什么需要 KV Cache?

没有 KV Cache(重复计算):

生成 token1:"今"
  计算 Attention(prompt)

生成 token2:"天"
  计算 Attention(prompt + "今")  ← 重复计算了 prompt

生成 token3:"气"
  计算 Attention(prompt + "今天")  ← 又重复了

...

问题:每生成一个 token,都要重新计算所有历史的 Attention
时间复杂度:O(n²),n 是生成长度

有 KV Cache(缓存复用):

生成 token1:"今"
  计算 Attention(prompt),缓存 KV

生成 token2:"天"
  只计算 "今" 的 KV,复用 prompt 的 KV Cache

生成 token3:"气"
  只计算 "天" 的 KV,复用之前的 KV Cache

...

优化:每个 token 只计算一次
时间复杂度:O(n)

数学原理:

Attention(Q, K, V) = softmax(QK^T / √d) V

生成第 t 个 token:
  Q_t:当前 token 的 Query
  K_{1:t-1}:历史所有 token 的 Key(从 Cache 读取)
  V_{1:t-1}:历史所有 token 的 Value(从 Cache 读取)

只需计算:
  K_t, V_t:当前 token 的 KV(新计算)
  然后拼接到 Cache

性能对比(生成 100 tokens):

方案总计算量延迟
无 Cache5050 次 Attention25s
有 Cache100 次 Attention5s
加速比50x5x

KV Cache 显存占用:

单个 token 的 KV 大小:
  K: [num_layers, num_heads, head_dim]
  V: [num_layers, num_heads, head_dim]

示例(Llama 7B):
  层数:32
  头数:32
  头维度:128
  精度:FP16(2 bytes)

  单 token KV = 2 × 32 × 32 × 128 × 2 = 524KB
  4K 上下文 = 524KB × 4096 = 2GB
  128K 上下文 = 524KB × 131072 = 64GB

面试话术:

"KV Cache 是用空间换时间的经典案例。不用 Cache,每个 token 要重新计算所有历史,O(n²) 复杂度。用了 Cache,复用历史结果,降到 O(n)。代价是显存占用大,长上下文会炸显存。"

📚 参考:vLLM 论文:KV Cache 与 PagedAttention