KV Cache 与 PagedAttention
自回归解码有个隐藏的巨量开销:每生成一个 token,都要对所有历史 token 算注意力。如果每步都重算,开销随序列平方增长——所以每层的 K、V 被缓存下来,这就是 KV cache。它是推理显存的第一大户(经常超过权重本身),也是"为什么推理服务这么吃显存"的答案。PagedAttention 解决它的碎片问题。
KV cache 有多大
Section titled “KV cache 有多大”每层每 token 的 KV cache(16 位数值):
全部层加起来,几个真实模型的每 token KV 大小:
| 模型 | 结构 | 每 token KV(BF16) | 4k 序列 | 32k 序列 |
|---|---|---|---|---|
| Llama-3-8B | 32 层,8 KV 头 | ~256 KB | 1 GB | 8 GB |
| Llama-3-70B | 80 层,8 KV 头 | ~640 KB | 2.5 GB | 20 GB |
| GPT-3-175B 级 | 96 层,全注意力 | ~3.2 MB | 13 GB | 100 GB |
对比权重:70B 模型权重 140 GB,KV cache 在长序列下轻松再吃 20–100 GB——KV cache 是推理显存的第一大户,尤其在高并发(batch × 序列 × 每请求一份)时:
batch 32、32k 序列的 70B:640 GB——比权重还大数倍。这就是推理服务的显存战争。
碎片问题:为什么要有 PagedAttention
Section titled “碎片问题:为什么要有 PagedAttention”朴素实现按"最长可能序列"预留连续显存:
请求1: [██░░░░░░░░░░] 预留 32k,实际用了 2k ← 94% 浪费请求2: [█████░░░░░░░] 预留 32k,实际用了 5k ← 84% 浪费预留式分配的浪费高达 60–90%(实际序列远短于预留上限),加上外部碎片,显存利用率惨不忍睹。并发度 = 显存 ÷ 每请求预留量——浪费直接决定能服务多少并发。
PagedAttention(vLLM 提出)借鉴操作系统虚拟内存的分页:
| 预留式 | PagedAttention | |
|---|---|---|
| 分配 | 每请求预留最长序列的连续块 | 按页(如 16 token/页)动态分配 |
| 碎片 | 内部 60–90% + 外部碎片 | 仅最后一页的少量内部碎片 |
| 显存利用率 | 20–40% | ~90%+ |
| 并发 | 低 | 2–4 倍提升 |
物理页表 → 逻辑块表(每请求一张页表,映射到物理 KV 块);按需分配、共享前缀可以共享物理页(system prompt 的 KV 多请求共享,再省一截)。
三个直接推论
Section titled “三个直接推论”一、并发上限由 KV cache 决定,不由权重决定。 权重 140 GB 是固定的;KV 是 batch × 序列的变量。"这个模型最多服务多少并发"的第一问是"你允许多大的 KV 显存池"。
二、KV cache 决定了批处理的收益边界。 连续批处理能堆多少并发,受限于 KV 池;PagedAttention 提高利用率,就是直接提高批处理的上限。
三、KV 是"省字节"的主要战场。 减小 KV 的手段按侵入性排:
| 手段 | 原理 | 压缩 | 代价 |
|---|---|---|---|
| GQA/MQA(结构) | 多 Q 头共享一组 KV 头 | 4–8× | 模型结构决定,已普及 |
| KV 量化(FP8/INT8) | KV 存储降精度 | 2× | 长程注意力要抽测 |
| 滑动窗口/稀疏注意力 | 只存最近窗口 | 窗口比 | 模型能力取舍 |
| PagedAttention | 消碎片 | 1.5–2×(利用率) | 无,纯工程收益 |
- KV 池的显存规划:总显存 − 权重 − 激活峰值 − 余量(~10%)= KV 池;
gpu_memory_utilization(vLLM)就是这个比例 - max_model_len 别虚设:预留按最大序列长度算,设一个实际需要的值(不是模型支持的上限),否则 KV 池被虚高需求挤压
- 前缀共享:system prompt、few-shot 前缀的 KV 多请求共享(automatic prefix caching),长 system prompt 场景收益显著
- 监控:KV 池使用率、页命中率、因 KV 不足被抢占(preemption)的次数——抢占频繁 = 并发配置超出 KV 容量
- KV cache 是推理显存第一大户:每 token 几百 KB 到几 MB,batch × 序列线性放大,长序列下超过权重。
- 预留式分配浪费 60–90%;PagedAttention 按页动态分配,利用率到 90%+,并发提升 2–4 倍。
- 并发上限由 KV 池决定;"能服务多少并发"先算 KV 池大小。
- 省 KV 四手段:GQA(结构,4–8×)> KV 量化(2×)> 滑动窗口(取舍)> 分页(纯工程收益)。
- 前缀共享(system prompt KV 复用)是免费的并发提升。
- 连续批处理与调度 — 下一章:KV 之上的调度
- 内存层次与 HBM — KV 的物理载体
- 量化:权重、激活与 KV cache — KV 量化的细节
- 分布式推理:Prefill/Decode 分离 — KV 在两种负载里的不同角色