1. 显存这道坎,到底卡住了多少人
每次有人问我"我这卡能不能跑某个模型",我脑子里第一反应不是去看显卡型号,而是先算一笔账。因为显卡型号只是标签,真正决定你能不能把模型跑起来的,是显存容量和显存带宽这两个硬指标。我见过太多人拿着 8G 显存的卡兴冲冲去拉一个 13B 的模型,结果加载到一半直接 OOM(Out Of Memory),然后跑来问是不是驱动没装好。其实跟驱动一点关系都没有,就是显存不够。
这篇内容我想把"显存计算"这件事从头到尾讲透。不是给你一个在线计算器让你填数字,而是让你理解显存到底被谁吃掉了、为什么同样的模型别人能跑你不能跑、量化到底省的是什么、以及在不同显存档位下应该怎么选模型。适合所有想在本地跑大模型但被显存问题困扰的人,不管你是 6G 的入门卡还是 24G 的工作站卡,这套计算方法都通用。
先说一个反直觉的结论:模型参数量并不直接等于显存占用。一个 7B 的模型,FP16 精度下权重大约占 14GB,但实际运行时显存占用可能远不止这个数,也可能通过量化压到 4GB 以内。这中间的差距,就是这篇文章要拆开讲的东西。
2. 显存到底被谁吃掉了:四笔账拆解
2.1 第一笔账:模型权重本身
模型权重是显存占用的最大头,也是最容易算的一部分。公式很简单:
权重显存 = 参数量 × 每个参数的字节数
不同精度下每个参数占的字节数不一样:
| 精度格式 | 每参数字节 | 7B 模型权重 | 13B 模型权重 | 70B 模型权重 |
|---|---|---|---|---|
| FP32 | 4 bytes | 28 GB | 52 GB | 280 GB |
| FP16/BF16 | 2 bytes | 14 GB | 26 GB | 140 GB |
| INT8 | 1 byte | 7 GB | 13 GB | 70 GB |
| INT4 | 0.5 byte | 3.5 GB | 6.5 GB | 35 GB |
这张表你存下来,以后选模型先查这张表。注意 INT4 的 0.5 字节是理论值,实际实现中因为分组量化、缩放因子等额外开销,真实占用会比理论值高 10% 到 20%。比如 7B 的 INT4 模型,实际文件大小通常在 3.8GB 到 4.2GB 之间,而不是精确的 3.5GB。
这里有个很多人忽略的点:你下载的模型文件大小,基本就等于权重加载到显存后的大小。所以在你下载之前,看一眼文件大小就能预判显存够不够。比如你在模型仓库看到 ggml-model-q4_0.gguf 是 3.8GB,那权重部分就是 3.8GB 左右的显存占用。
2.2 第二笔账:KV Cache 才是隐形杀手
权重只是静态占用,真正让很多人翻车的是KV Cache。这是 Transformer 架构在推理时缓存注意力键值对的开销,它跟你的上下文长度和并发请求数直接相关。
KV Cache 的计算公式:
KV Cache = 2 × 层数 × 注意力头数 × 头维度 × 序列长度 × 精度字节 × 并发数
这个公式看着复杂,我把它简化成一个经验值:对于常见的 7B 模型(32 层,4096 隐藏维度),在 FP16 精度下,每 1000 token 的上下文大约消耗 0.5GB 显存。如果你开到 8192 上下文,光 KV Cache 就要吃掉 4GB 左右。
这就是为什么很多人遇到这种情况:模型权重明明只占 4GB,8G 的卡却跑不起来。因为加上 KV Cache 和下面的运行时开销,总占用直接顶到 9GB 以上。
提示:KV Cache 可以通过量化来压缩。把 KV Cache 也量化到 INT8,显存占用直接减半,对生成质量的影响在大多数场景下几乎感知不到。
2.3 第三笔账:运行时框架的固定开销
CUDA 上下文、cuDNN 句柄、PyTorch 的缓存分配器,这些加起来通常会占用300MB 到 1.5GB不等的显存。这个开销跟你跑什么模型无关,只要用了 CUDA 就会有。
具体数字取决于:
- CUDA 版本(新版本通常开销略大)
- 框架类型(PyTorch 的缓存分配器会预留一部分显存)
- 是否开启了 cuDNN benchmark
我实测下来,PyTorch 环境下这个固定开销大约在 600MB 到 1GB 之间。llama.cpp 这种纯 C++ 实现会小很多,大约 200MB 到 400MB。
2.4 第四笔账:激活值和临时缓冲区
推理过程中,每一层的中间计算结果(激活值)也需要显存。这部分跟 batch size 强相关。batch size 为 1 的时候,激活值占用很小,通常几百 MB。但如果你做批量推理,batch size 开到 8 或者 16,这部分会线性增长。
对于单用户本地部署场景,这部分通常不是瓶颈。但如果你打算做一个多人用的推理服务,就必须把它算进去。
把四笔账加起来:
总显存需求 = 权重 + KV Cache + 框架开销 + 激活值
以 7B INT4 模型、4096 上下文、单用户为例:
- 权重:约 4GB
- KV Cache:约 2GB
- 框架开销:约 0.8GB
- 激活值:约 0.3GB
- 合计:约 7.1GB
所以 8G 显存的卡跑 7B INT4 模型,在 4096 上下文下是刚好够用的,但几乎没有余量。如果你想开更大的上下文或者跑更长的对话,就会 OOM。
3. 量化不是万能药:精度、速度与显存的三角博弈
3.1 量化到底在做什么
量化的本质是把模型权重从高精度浮点数映射到低精度整数。比如 FP16 的权重范围是 -65504 到 65504,量化到 INT4 就是把它压缩到 -8 到 7 这 16 个整数上。为了减少精度损失,实际实现会采用分组量化:把权重分成若干组,每组单独计算缩放因子和零点。
主流的量化方案有这么几种:
- GPTQ:训练后量化,需要校准数据集,4bit 下质量损失较小
- AWQ:激活感知量化,对重要通道保留更高精度,推理速度好
- GGUF(llama.cpp 格式):支持从 Q2 到 Q8 多种档位,CPU/GPU 混合推理友好
- bitsandbytes:HuggingFace 生态里最方便的 4bit/8bit 量化,一行代码就能用
3.2 不同量化档位的实际表现
我拿同一个 7B 模型在不同量化档位下做了对比测试,硬件是 RTX 3060 12G:
| 量化档位 | 文件大小 | 显存占用 | 生成质量 | 推理速度 |
|---|---|---|---|---|
| FP16 | 13.5 GB | 14.2 GB | 基准 | 基准 |
| Q8_0 | 7.2 GB | 7.8 GB | 几乎无损 | 略慢于 FP16 |
| Q5_K_M | 4.8 GB | 5.3 GB | 轻微损失 | 较快 |
| Q4_K_M | 4.1 GB | 4.6 GB | 可接受 | 快 |
| Q3_K_M | 3.3 GB | 3.8 GB | 明显损失 | 快 |
| Q2_K | 2.7 GB | 3.2 GB | 严重损失 | 最快 |
从这张表可以看出来,Q4_K_M 是性价比拐点。从 Q4 降到 Q3,显存只省了不到 1GB,但质量下降明显。从 Q5 升到 Q8,显存多花 2.5GB,质量提升却很有限。
我的经验是:能跑 Q5 就别用 Q4,能跑 Q4 就别用 Q3。Q2 除非实在没显存,否则不建议碰,那个质量损失在对话场景下很容易感知到。
3.3 量化对推理速度的影响
这里有个反直觉的地方:量化并不总是让推理变快。在 GPU 上,INT4 的计算需要反量化回 FP16 才能做矩阵乘法,这个反量化过程有额外开销。所以有时候 Q4 的推理速度反而比 Q8 慢。
真正让量化提速的场景是显存带宽受限的情况。当模型大到显存装不下、需要频繁在显存和内存之间搬运数据时,量化减少的数据量就能显著提速。这也是为什么在消费级显卡上跑大模型,量化几乎是必选项。
4. 按显存档位选模型:从 6G 到 48G 的实战方案
4.1 6G 到 8G 显存:小模型加高量化
这个档位是最难受的,选择很有限。我的建议是:
- 3B 级别模型:Q4_K_M 量化,上下文开到 4096,基本能流畅跑
- 7B 级别模型:必须 Q4 以下量化,上下文限制在 2048 到 4096,单用户使用
- 13B 级别模型:基本别想,除非用 CPU 混合推理,但速度会慢到难以忍受
具体操作上,用 llama.cpp 的 GPU offload 功能,把部分层放到 GPU 上,其余层留在 CPU。比如 7B Q4 模型,你可以设置-ngl 20把 20 层放到 GPU,剩下的在 CPU 跑。这样虽然速度慢一些,但至少能跑起来。
# llama.cpp 示例:7B Q4 模型,20 层 offload 到 GPU ./main -m models/7b-q4_k_m.gguf -n 512 -ngl 20 -c 40964.2 12G 显存:甜点档位
12G 是目前最主流的消费级显存容量(RTX 3060 12G、RTX 4070 等)。这个档位可以:
- 7B 模型:Q5 或 Q8 量化,上下文开到 8192,体验很好
- 13B 模型:Q4_K_M 量化,上下文 4096,单用户流畅
- 20B 级别:Q3 或 Q4,上下文限制在 2048,勉强能跑
12G 的卡我建议优先考虑 13B Q4 模型,这是质量和速度的最佳平衡点。7B 模型在 12G 上跑有点浪费,除非你需要很长的上下文。
4.3 16G 到 24G 显存:开始有选择权
到了这个档位,选择就多了:
- 13B 模型:Q8 量化,上下文 8192,几乎无损
- 34B 模型:Q4_K_M 量化,上下文 4096,可用
- 70B 模型:Q2 或 Q3 量化,上下文 2048,能跑但质量堪忧
24G 的卡(RTX 3090、4090)跑 34B Q4 是很舒服的组合。如果你主要做中文任务,34B 级别的模型比 13B 有明显提升,值得为此牺牲一些量化精度。
4.4 48G 及以上:专业级部署
这个档位通常是双卡或者专业卡(A6000、A100 等)。可以:
- 70B 模型:Q4_K_M 量化,上下文 8192,流畅
- 120B 级别:Q4 量化,需要双卡
- 多并发服务:13B Q8 模型,batch size 开到 8 以上
到这个级别,显存计算的重点就从"能不能跑"变成了"能跑多少并发"。KV Cache 的占用会成为主要矛盾,需要仔细规划上下文长度和并发数的平衡。
5. 那些计算器不会告诉你的实操细节
5.1 显存碎片化:为什么明明够却 OOM
这是最让人抓狂的问题:算下来显存刚好够,但实际跑起来就是 OOM。原因通常是显存碎片化。
PyTorch 的缓存分配器会预留显存块,当你的模型加载顺序不当时,会出现"总共剩 2GB 但没有一块连续的 2GB"的情况。解决办法:
- 设置
PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True让分配器支持可扩展段 - 加载模型前先
torch.cuda.empty_cache()清空缓存 - 避免在加载模型后再创建大张量
import torch import os os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "expandable_segments:True" # 加载模型前清空缓存 torch.cuda.empty_cache() # 查看当前显存分配情况 print(torch.cuda.memory_summary())5.2 Windows 下的显存占用陷阱
Windows 系统本身会占用一部分显存用于桌面渲染。如果你用 WSL2 跑模型,WSL2 还会额外占用一部分。我实测下来,Windows 桌面 + WSL2 的组合会吃掉 1.5GB 到 2.5GB 显存。
这意味着你在 Windows 上算好的显存预算,实际可用量要打八折。如果你在 Windows 上跑 7B Q4 模型觉得吃力,换成纯 Linux 环境可能就流畅了。
提示:WSL2 的显存占用可以通过
.wslconfig文件限制。在用户目录下创建.wslconfig,设置[wsl2]下的memory和gpuMemory参数。
5.3 多卡显存不能简单相加
很多人以为两张 12G 的卡就等于 24G 显存,这是错的。模型并行(tensor parallelism)需要卡间通信,而且每张卡都要存一份完整的 KV Cache(除非用流水线并行)。实际可用显存通常只有总和的 70% 到 80%。
而且消费级显卡大多不支持 NVLink,卡间通信走 PCIe,带宽有限。用两张卡跑一个模型,速度可能还不如单卡跑量化版。
5.4 实时监控显存占用的正确姿势
不要用任务管理器看显存,那个数字不准。用nvidia-smi或者更详细的工具:
# 每秒刷新一次显存占用 nvidia-smi --query-gpu=memory.used,memory.total,utilization.gpu --format=csv -l 1 # 更详细的进程级显存占用 nvidia-smi --query-compute-apps=pid,process_name,used_memory --format=csv如果你想要图形化监控,nvtop是个好选择,比nvidia-smi直观得多。安装方式:
# Ubuntu/Debian sudo apt install nvtop # 或者用 snap sudo snap install nvtop6. 模型选择的决策树:从需求反推硬件
6.1 先明确你的使用场景
选模型不是先看显卡,而是先看你要干什么。我把它分成三类:
对话助手类:需要较长的上下文(至少 4096),对生成质量要求高,速度要求中等。这类场景优先保证质量,量化档位可以高一些,模型参数量可以小一些。
文本处理类:翻译、摘要、改写,输入输出都比较短,上下文 2048 就够。这类场景对速度要求高,可以用更激进的量化。
代码生成类:需要专门的代码模型,上下文要求高(至少 8192),对质量极其敏感。这类场景建议用 13B 以上的代码专用模型,量化档位不要低于 Q5。
6.2 再根据场景定模型规模
| 使用场景 | 推荐参数量 | 最低量化 | 最低显存 |
|---|---|---|---|
| 简单对话 | 3B-7B | Q4 | 6 GB |
| 通用助手 | 7B-13B | Q4 | 8 GB |
| 高质量对话 | 13B-34B | Q5 | 12 GB |
| 代码生成 | 7B-13B | Q5 | 12 GB |
| 复杂推理 | 34B-70B | Q4 | 24 GB |
| 多并发服务 | 13B-34B | Q8 | 24 GB+ |
6.3 最后才是看显卡
有了上面的表,你就能反推自己的显卡能跑什么。比如你有 8G 显存,那就在"简单对话"和"通用助手"之间选,模型规模 7B,量化 Q4。如果你有 12G,可以上到"高质量对话"的入门档,13B Q4。
这里有个实用技巧:先下载模型文件,看文件大小,再决定量化档位。比如你想跑 13B 模型,先看 Q4 版本的文件大小是 7.8GB,加上 KV Cache 和框架开销大约 3GB,总共 10.8GB,12G 的卡刚好够。如果 Q5 版本是 9.2GB,加上开销就超了,那就老老实实用 Q4。
7. 几个高频踩坑场景的排查思路
7.1 模型加载成功但推理时报 OOM
这种情况通常是 KV Cache 超了。模型权重加载时只占静态显存,推理时才会分配 KV Cache。排查方法:
- 先把上下文长度减半试试,如果好了就是 KV Cache 的问题
- 检查是否开启了 KV Cache 量化
- 看
nvidia-smi在推理瞬间的显存峰值
7.2 显存够但速度极慢
如果显存占用没满,但生成速度只有几个 token 每秒,大概率是模型部分层跑在 CPU 上。检查你的 GPU offload 设置,确保该 offload 的层都 offload 了。
另一个可能是显存带宽瓶颈。用nvidia-smi dmon看显存带宽利用率,如果接近 100%,说明瓶颈在带宽,换更激进的量化能提速。
7.3 多版本 CUDA 共存导致的兼容问题
很多人机器上装了多个 CUDA 版本,跑模型时调用了错误的版本导致报错。排查方法:
# 查看当前 CUDA 版本 nvcc --version # 查看 PyTorch 使用的 CUDA 版本 python -c "import torch; print(torch.version.cuda)" # 查看驱动支持的 CUDA 版本 nvidia-smi | grep "CUDA Version"这三个版本必须兼容。PyTorch 的 CUDA 版本不能高于驱动支持的版本,否则会报错。如果版本不匹配,要么升级驱动,要么降级 PyTorch。
7.4 显卡识别但装不上驱动
这种情况在 Linux 上比较常见,通常是内核模块冲突。排查步骤:
- 检查是否安装了开源驱动 nouveau,如果有需要禁用
- 检查 Secure Boot 是否开启,开启状态下第三方驱动可能无法加载
- 用
dmesg | grep nvidia看内核日志里的报错信息
# 禁用 nouveau echo "blacklist nouveau" | sudo tee /etc/modprobe.d/blacklist-nouveau.conf sudo update-initramfs -u sudo reboot8. 我自己的显存管理习惯
跑了几年本地模型,我养成了几个习惯,分享出来可能对你有用。
第一个习惯是建一张自己的显存账本。每跑一个新模型,记录下模型名称、量化档位、上下文长度、实际显存占用、生成速度。积累多了之后,你看到一个新模型就能大致判断能不能跑,不用每次都试错。
第二个习惯是永远留 1GB 显存余量。算下来刚好够的配置,实际跑起来大概率会 OOM。留 1GB 余量给显存碎片和临时峰值,能避免很多莫名其妙的崩溃。
第三个习惯是优先用 llama.cpp 而不是 transformers。同样的模型,llama.cpp 的显存占用通常比 PyTorch 少 20% 到 30%,因为它没有 PyTorch 那套缓存分配器的开销。如果你显存紧张,换 llama.cpp 可能就直接能跑了。
第四个习惯是关注显存带宽而不是容量。很多人只看显存多大,忽略了带宽。实际上对于大模型推理,显存带宽往往比容量更影响速度。同样是 12G 显存,带宽 360GB/s 的卡和带宽 504GB/s 的卡,跑同一个模型速度能差 40%。
最后一个习惯是定期清理显存碎片。长时间运行多个模型后,显存会碎片化。重启推理进程或者调用torch.cuda.empty_cache()能缓解这个问题。如果你做的是长时间运行的服务,建议加一个定时重启机制。
显存计算这件事,说到底就是四笔账:权重、KV Cache、框架开销、激活值。把这四笔账算清楚,你就能在买卡之前就知道能跑什么模型,而不是买回来才发现跑不动。这个能力比任何在线计算器都值钱,因为计算器不会告诉你碎片化、不会告诉你 Windows 的额外开销、不会告诉你量化档位怎么选。这些只有自己踩过坑才知道。