想在本机跑 Llama 3,顺序建议是先把显存账算清楚,再决定下载哪个量化文件:跑不跑得动,基本由参数量、量化位宽、上下文长度三者共同决定,缺一项都会算错。很多情况下模型文件本身放得下,但一开长上下文就报显存不足,问题通常出在 KV 缓存而不是权重上。下面这套流程的目标是:先量出本机真实可用显存,再用估算表圈定可选范围,最后跑一次最小推理,用日志把估算落成一份可复用的配置记录。
先看真实可用显存,再按「参数量 × 量化每参数字节数 + KV 缓存 + 运行时余量」估算,三者要一起定,不能只盯模型文件大小。建议先跑短上下文最小推理确认能加载,再逐步加长上下文观察显存变化。核显与独显共存、驱动版本过旧、显存被其它进程占用,都会让估算失真;最终以本机运行日志和 nvidia-smi 读数为准,估算表只用于缩小选择范围。
用 nvidia-smi 和系统信息确认本机真实可用显存
标称显存不等于可用显存。桌面环境、浏览器、图形驱动本身都会占用一部分,笔记本上还可能存在核显与独显各带一份显存的情况。先把这几个数字读出来,后面的估算才有意义。
# 显存总量、已占用、当前进程占用、驱动版本与 CUDA 版本
nvidia-smi
# 只取关键字段,方便抄进记录表
nvidia-smi `--query-gpu`=name,memory.total,memory.used,memory.free,driver_version \
`--format`=csv
# 看是哪些进程在吃显存
nvidia-smi `--query-compute-apps`=pid,process_name,used_memory `--format`=csv
# 系统内存与交换分区
free -h
# 确认独显是否被识别、有没有核显同时存在
lspci | grep -i vga
ls /dev/dri
nvidia-smi 输出里要盯三处:Memory-Usage 的 Total 是标称总量,Used 是当前已占用,两者相减才是能分给模型的量级;Driver Version 决定能装哪一档 CUDA 运行时,版本过旧时部分量化内核可能加载不了。如果 lspci 同时列出 Intel/AMD 核显和 NVIDIA 独显,需要确认推理程序实际绑定的是独显,且显示输出没有长期占用独显显存;必要时可以在只接核显输出、独显空载的状态下再测一次。系统内存则决定模型文件能不能被完整读入、量化解压时够不够用。
按参数量和量化位宽列出显存需求区间
权重部分的估算可以简化成一个乘法:权重显存 ≈ 参数量 × 每个参数的字节数。参数量按模型名里的 8B、70B 代入,每个参数的字节数由量化档位决定,通常可以直接用 GGUF 文件名后缀对照:
| 量化档位 | 每参数字节数(约) | 说明 |
|---|---|---|
| FP16 / F16 | 2 | 未量化,体积最大,通常只在小参数量下考虑 |
| Q8_0 | 1 | 接近原始精度,体积约为 FP16 的一半 |
| Q6_K | 0.8 | 体积与质量折中点 |
| Q5_K_M | 0.7 | 常见可用档位 |
| Q4_K_M | 0.6 | 本地部署中使用较多的一档 |
| Q3_K_M | 0.5 | 显存紧张时的退让档位,输出质量需自己比对 |
| Q2_K | 0.35 | 更省显存,质量损失通常较明显 |
例如 8B 模型配 Q4_K_M,权重部分约 8 × 0.6 ≈ 4.8 GB;同样 8B 配 Q8_0,就接近 8 GB。除权重外还要留出运行时开销:CUDA 上下文、计算缓冲区、框架自身占用,建议在权重之外再留出与 KV 缓存同量级或更大的余量,具体多少需要结合上下文长度和批大小确认。下面是可直接填写的估算表模板:
| 参数量 | 量化档位 | 权重估算(GB) | 上下文长度 | KV 估算(GB) | 余量(GB) | 合计(GB) | 可用显存(GB) | 是否可行 |
|---|---|---|---|---|---|---|---|---|
| 8B | Q4_K_M | 4096 | ||||||
| 8B | Q5_K_M | 8192 | ||||||
| 70B | Q4_K_M | 4096 |
把上下文长度换算成额外显存开销
KV 缓存是同一模型从能跑变成不能跑的最常见原因。它随上下文长度线性增长,并且受层数、KV 头数、每个注意力头的维度共同放大:缓存要为每层保存 Key 和 Value 两份张量,所以层数越多、KV 头数越多、上下文越长,占用越大。采用了 GQA 的模型 KV 头数明显少于注意力头数,这是同一参数量下 KV 占用差别较大的原因之一。
可以自己按这个式子估一遍:KV 字节数 ≈ 2 × 层数 × KV 头数 × 每头维度 × 上下文长度 × 每元素字节数。以 32 层、8 个 KV 头、每头维度 128、FP16 存储为例,每 token 大约在百 KB 量级,几千 token 的上下文就是数百 MB,拉到更长上下文时会成倍上升。先代进自己的模型结构参数算个量级,再和 nvidia-smi 的读数对照。
运行时上下文长度一般由启动参数控制,以 llama.cpp 为例:
# -c 指定上下文长度,先用小值验证
./llama-cli -m ./Meta-Llama-3-8B-Instruct.Q4_K_M.gguf \
-c 2048 -ngl 99 -n 128 -p "hello"
# 验证:另开一个终端,边跑边看显存
watch -n 1 nvidia-smi `--query-gpu`=memory.used,memory.free `--format`=csv
验证步骤建议固定成三步:先把 -c 设小(如 2048)跑一次,记下稳定后的显存占用;再把 -c 翻倍(如 8192)用同样的提示词跑一次,比较两次读数的差额,这个差额大致就是 KV 缓存的增长量;把差额代回估算表,就能判断本机上下文长度大概能开到哪里。显存本身不够用时,也可以改用 KV 缓存量化这类参数来压缩每元素字节数,但同样要用日志确认是否被真正启用。
跑一次最小推理并在日志里确认落点
估算只是缩小范围,最终以一次最小推理为准。命令骨架包含四个可替换项:模型路径、量化文件、上下文长度、GPU 层数。GPU 层数决定有多少层真正放进显存,其余层退回 CPU 计算。
./llama-cli \
-m /path/to/model.Q4_K_M.gguf \ # 模型路径与量化文件
-c 4096 \ # 上下文长度
-ngl 99 \ # 卸载到 GPU 的层数,先试全部
-b 512 -n 128 \ # 批大小与生成长度,验证用最小值
-p "用一句话说明什么是张量"
日志里需要确认的落点有几类:加载阶段会打印每层张量落在哪个后端、以及类似 offloaded N/M layers to GPU 的统计,M 小于 N 说明有层退回了 CPU;上下文建立阶段会打印 KV 缓存大小,可直接和估算对照;运行阶段如果出现 CUDA out of memory、buffer allocation failed 一类字样,就是显存确实不够。若程序只打印警告后继续用 CPU 跑,速度会明显下降,这同样是显存不足的信号。
失败时按三个方向调整:一是降 GPU 层数 -ngl,牺牲速度换取能跑;二是缩上下文 -c,减少 KV 缓存;三是换更低的量化档位,减小权重体积。建议一次只改一项,改完重跑并记录读数,否则分不清是哪一项起了作用。
把量化档位与上下文长度写成可复现的配置记录
跑通一次之后,把参数写成一行可复用的记录,下次换模型或换机器可以直接比对。建议至少记录这几列:模型名称与参数量、量化文件名、上下文长度 -c、GPU 层数 -ngl、批大小、nvidia-smi 观察到的显存峰值、是否出现层卸载或显存不足、生成一段测试文本的主观可用度。峰值建议在生成过程中用 watch 采样读取,而不是等进程退出后再看。
# 记录示例(数值请按本机实际填写)
模型 : Llama-3-8B-Instruct
量化文件 : Q4_K_M.gguf
-c : 4096
-ngl : 99
显存峰值 : ___ GB / 可用 ___ GB
层卸载情况 : 无 / 有,M/N = ___
结论 : 可日常使用 / 仅短上下文可用
不同档位的对比方法很简单:固定模型、固定 -c,只改变量化文件,各跑一次并记录显存峰值;再固定量化文件,只改变 -c,各跑一次记录峰值。两组数据放在一起,就能看出显存增长主要来自权重还是 KV 缓存。
取舍规则可以这样判断:如果短上下文下就显存不足,或权重估算已经接近可用显存,优先降量化位宽,因为这时权重是主要开销;如果短上下文能跑、拉长到目标长度才失败,且日志里的 KV 缓存占比明显,优先缩上下文或启用 KV 缓存量化,因为这时是缓存把预算撑满了。两者需要同时压缩时,建议先缩上下文确认边界,再决定是否牺牲量化质量。任何调整之后都要重跑一次最小推理,以日志和显存读数为准,不要沿用上一次的估算值。