KV缓存显存计算:模型进显存了上下文却爆了

本文用数学公式拆解KV缓存如何让12GB显卡在128K上下文下OOM,并告诉你选模型时真正该看哪两个参数。
本文聚焦一个本地部署大模型时的常见困惑:量化后只占4.9GB的8B模型为何会在长上下文下OOM?原因在于KV缓存——其显存占用随上下文长度线性增长,与模型权重完全独立。文章给出核心公式并以Llama 3.1 8B为例实算:128K上下文下KV缓存高达16GB,是模型权重的三倍多。进一步指出,决定缓存大小的关键是`num_key_value_heads`和`num_hidden_layers`两个参数,而非参数量或量化方式——采用GQA的模型缓存开销可仅为传统MHA模型的四分之一。最终给出实用原则:显存预算须同时计入权重与KV缓存,小GQA模型配大窗口往往优于大MHA模型配小窗口。
一个反直觉的显存难题
很多人在本地部署大模型时都遇到过类似困惑:一个 8B 模型用 Q4_K_M 量化后,磁盘上只占约 4.9GB,理论上 12GB 显存能塞下两份还有余。可当你真正拉长上下文运行时,它却毫不留情地 OOM(显存溢出)了。
这不是显卡的问题,也不是量化没做好,而是几乎没人在下载页面上告诉你的那笔隐藏账单——KV 缓存(KV Cache)。这部分显存开销随上下文长度线性增长,在长上下文场景下甚至能轻松超过模型权重本身的体积。
本文将拆解这套「谁都不给你看」的显存数学,让你花一分钟就能算出自己硬件的真实上限。
KV缓存显存占用的核心计算公式
公式详解
KV 缓存的计算其实非常直白:
KV 字节数 = 2 × 层数 × KV头数 × head_dim × 上下文token数 × 每值字节数
拆解一下各个参数:
- 2:代表 Key 和 Value 两部分缓存
- 每值字节数:fp16 精度下为 2 字节
- 层数(num_hidden_layers) 和 KV头数(num_key_value_heads):这两个才是决定缓存大小的关键变量
用 Llama 3.1 8B 实算一遍
以 Llama 3.1 8B 为例,它的真实配置是:32 层、8 个 KV 头(注意:它用的是 GQA 分组查询注意力,不是 32 个头)、head_dim 为 128。
代入公式计算每个 token 的缓存开销:
2 × 32 × 8 × 128 = 65,536 个值/token
65,536 × 2 字节 = 128 KB/token
于是不同上下文长度下的缓存开销就一目了然了:
| 上下文长度 | KV 缓存占用 |
|---|---|
| 2K | 256 MB |
| 8K | 1 GB |
| 32K | 4 GB |
| 128K | 16 GB |
模型权重是 4.9GB,而在 128K 上下文下,KV 缓存高达 16GB——是模型本身的三倍多。12GB 显卡当然扛不住。
GQA(分组查询注意力,Grouped Query Attention) 是理解这一计算结果的关键前提。传统的多头注意力(MHA)中,每个查询头都有独立对应的 Key 和 Value 头,若模型有 32 个注意力头,则 KV 头数也是 32。GQA 将多个查询头共享同一组 KV 头:Llama 3.1 8B 拥有 32 个查询头,但只有 8 个 KV 头,即每 4 个查询头共用一组 KV。这一设计在不明显损失模型质量的前提下,将 KV 缓存体积直接压缩到 MHA 的四分之一。MQA(多查询注意力)是更极端的变体,所有查询头共享同一组 KV,缓存更小但质量损失相对更大。GQA 是目前主流开源模型(Llama、Mistral、Qwen 等系列)的标配设计,正是因为它在推理效率和模型性能之间取得了较好的平衡。
为什么你可能还没踩到这个坑
答案藏在推理框架的默认设置里。以 Ollama 为例,它默认并不会给你模型宣传的完整上下文窗口。如果你从没手动调整过 num_ctx 参数,那你实际运行的是一个很小的窗口,KV 缓存开销几乎可以忽略不计。
但问题就出在这里:当你在模型卡片上看到「支持 128K 上下文」,兴冲冲地把窗口拉满时——
/set parameter num_ctx 32768
缓存开销就会立刻显现,而且来得又快又猛,因为它是随 token 数线性增长的。很多人误以为是模型「变重了」,其实是自己刚刚打开了这笔隐藏账单。
选模型时真正该看的指标:KV头数与层数
这可能是整篇文章最有价值的一点:两个参数量完全相同的模型,KV 缓存开销可能天差地别。
原因在于 kv_heads(KV 头数)和 layers(层数)的差异:
- 一个 8 个 KV 头 的模型,缓存开销只有 32 个 KV 头 同等模型的 四分之一
- 老式的多头注意力(MHA)模型在长上下文下极为「烧显存」
- 而 GQA(分组查询注意力)模型则便宜得多
关键在于:这些信息既不在参数量里,也不在量化名称里。 你必须自己打开模型的 config.json,去读 num_key_value_heads 和 num_hidden_layers 这两个字段。
麻烦的地方在于,这两个数字几乎从不和「下载按钮」出现在同一个页面上。不过说到底,一份 config.json 加一个计算器,就能得到同样的答案。
除了 num_key_value_heads 和 num_hidden_layers,config.json 中的 head_dim(每个头的维度)同样影响缓存大小,它通常等于 hidden_size / num_attention_heads。在 Hugging Face 模型页面,部分模型会在「Model card」或「Files」标签下直接提供 config.json 的预览,无需下载即可查阅。也可以通过 ollama show <模型名> 命令查看 Ollama 已拉取模型的基本参数,其中会列出 attention heads 和 layers 等关键字段,是快速估算 KV 缓存开销的便捷途径。
实用经验法则:显存预算怎么分配
总结成一条可以直接用的原则:
显存预算 = 模型权重 + KV缓存,永远不要只算权重。
在消费级硬件上,一个小一点的 GQA 模型配上大上下文窗口,通常会打败一个被迫锁在 4K 窗口的大模型。因为对很多实际任务而言,能容纳更多上下文往往比多几十亿参数更有价值。
下次在本地部署模型、纠结选哪个之前,不妨先花一分钟做做这道 KV 缓存的乘法。它能帮你避开一次尴尬的 OOM,也能让你把有限的显存花在刀刃上。
相关推荐

Vercel AI SDK 发布 Vue 3.0.282 补丁更新
Vercel AI SDK 发布 @ai-sdk/vue@3.0.282 补丁更新,同步核心包 ai@6.0.282。本文解析该 Vue 生态 AI 开发工具的更新内容、版本节奏与开发者升级建议。

Vercel AI SDK 沙箱组件发布补丁更新
Vercel AI SDK 发布 sandbox-vercel@1.0.109 补丁更新,同步 harness 依赖至同版本。本文解读这次维护更新的内容及其对 AI 应用开发者的意义。

Claude的承重词汇:哪些关键词真正影响AI行为输出
探索Claude大语言模型中的承重词汇概念,解析特定关键词如何以超额权重影响AI行为输出,以及这一发现对提示工程优化、AI对齐研究和模型安全的实践启示。