ZDTaichu5.0-9B 这类 9B 级别模型,本地显存占用没有可以照抄的固定数字,它由两个变量共同决定:权重以多少位量化加载,以及上下文长度开到多大。可行的做法是自己在目标机器上量一遍——先在加载脚本里确认量化参数,再改上下文档位记录显存变化,用系统命令抓推理峰值,最后换一档量化位数重跑一次,两行读数一对比,这台机器能开到什么程度就清楚了。瓶颈也可能不只在显存,CPU 卸载、磁盘读取速度、后端对量化格式的支持情况都会影响能不能跑起来,需要结合环境确认。
显存占用大致分两块:权重和上下文(含 KV 缓存)。权重由量化位数决定,上下文由序列长度与并发数决定。建议先固定量化位数、只改上下文,测出三档之间的差值;再固定上下文、换一档量化位数重测。峰值要用轮询采样拿到,不能看启动完成后的静态读数。下面的读数全部以本机监控命令为准,不同量化格式和后端实现存在差异,最终以你自己填出的对照表为准。
在加载脚本里找到量化参数,确认它和权重的对应关系
先看权重目录里有什么:config.json 里如果有 quantization_config 字段,说明权重本身已经是量化格式(例如 GPTQ、AWQ 一类),加载时不要再叠加运行时量化;如果目录里是 .gguf 文件,走的是另一个推理入口,参数名和下面这段不一样。确认清楚再动手,否则改错参数不会改变显存占用。参数名以实际仓库的配置说明和 config 为准,下面是通用骨架:
from transformers import AutoModelForCausalLM, AutoTokenizer
model_path = './ZDTaichu5.0-9B' # 换成你的权重目录
tok = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(
model_path,
device_map='auto', # 单卡可写 {'': 0}
torch_dtype='auto', # 加载精度,影响权重占用
load_in_4bit=True, # ← 量化参数:4bit;改 8bit 或删掉这一行就是另一档
trust_remote_code=True,
)
会改变显存占用的通常就是这几处:load_in_4bit / load_in_8bit 这类开关,4bit 量化方式下的分组大小、量化类型等细项,以及 torch_dtype。改动前先记录一份基线:加载完成后立刻读一次显存,这是权重部分的大致占用。注意这一步还没跑推理,上下文占用基本没算进来。
把上下文长度设成几个不同档位,记录显存变化
固定量化位数不动,只改上下文相关的上限参数(常见是 max_model_len、max_seq_len、n_ctx 一类,具体名字按你用的后端确认)。选三档,例如 2K、8K、32K,每档做同一件事:加载模型,喂一段接近该档上限的输入,跑完一次生成,记录读数。
- 把上下文上限设为档位一,加载,读一次显存(记作 A1)。
- 用长输入触发一次推理,用监控命令抓峰值(记作 P1)。
- 改档位二、档位三,重复上面两步,得到 A2/P2、A3/P3。
- 做差:P2 减 P1、P3 减 P2,差值大致就是上下文每上一个档位多吃掉的显存;A 系列之间的差则是缓存预分配带来的提前占用。
这样能分清权重占用和上下文占用各占多少:A1 减掉你上一步测的加载后基线,剩下的就是上下文相关部分。如果 P 和 A 几乎一样,说明瓶颈在权重,换量化位数收益更明显;如果 P 明显高于 A,说明长上下文才是压力来源,优先压上下文或换更省 KV 缓存的方案。
用系统自带的显存监控命令记录推理峰值
启动后的静态值没有意义,要看的是推理过程中出现的最高点。NVIDIA 卡上用下面任意一条,放在另一个终端里跑:
# 持续刷新,看实时占用
watch -n 0.5 nvidia-smi
# 每秒采一次,只要显存两列
nvidia-smi `--query-gpu`=memory.used,memory.total `--format`=csv -l 1
# 逐秒打点,便于事后回看
nvidia-smi dmon -s m -d 1
采样间隔建议 0.5 到 1 秒:间隔太长会漏掉首轮 prefill 的尖峰,太短则输出刷屏不容易比对。峰值通常出现在三个时机——第一次前向推理做 prefill 时、上下文长度逼近你设定上限的那一次、以及并发请求叠加时。抓峰值时尽量让输入长度贴近该档上限,否则测出来的是偏低的数。如果用的是 PyTorch 路线,也可以在推理前后各打印一次 torch.cuda.max_memory_allocated(),它给的是分配器口径的峰值,和 nvidia-smi 的整卡口径会不一致,固定用其中一种口径做横向比较即可。
在同一台机器上换不同量化位数重新加载一次
上下文档位先固定住,只动量化参数,重新加载一次,把两次读数按同一口径记下来:
| 加载配置 | 上下文档位 | 加载后读数 | 推理峰值读数 |
|---|---|---|---|
| 4bit | (填你的档位) | (填) | (填) |
| 8bit 或原精度 | (与上行保持一致) | (填) | (填) |
两行的差值就是量化位数对显存的实际影响,这比任何估算都贴近你的机器。加载失败时按下面对号:出现 CUDA out of memory,说明权重加当前上下文一起超了,先降上下文档位再试;出现类似 unsupported quantization、unknown quantization type 的提示,是后端不认这个量化格式,需要换加载入口而不是调数字;出现 bitsandbytes 相关的导入报错,是运行库没装或版本与当前环境不匹配;GGUF 路径报架构不支持,多半是推理程序版本太旧。这些都是配置层面能验证的问题,不建议靠加交换分区硬扛。
把实测结果整理成一张选型对照表
把手上的读数按下面四列填成一张表,以后换卡或换模型版本时可以直接对号入座:
| 量化位数 | 上下文档位 | 显存读数(峰值) | 是否可用 |
|---|---|---|---|
| 4bit | 2K / 8K / 32K | (填) | (填 是 / 否) |
| 8bit | 2K / 8K / 32K | (填) | (填 是 / 否) |
| 原精度 | 2K / 8K / 32K | (填) | (填 是 / 否) |
填写说明:一行的变量只改一个,量化位数和上下文档位逐行交叉;显存读数统一填峰值那一列,并注明采样工具和间隔,否则换台机器就没法比;「是否可用」以能否完整跑完一次生成、且过程中不出现 OOM 为准,跑一半被杀掉就填否。留白的行不要凭印象补,跑一次填一次。整卡容量还要给系统、显示输出和其他进程留余量,所以即使读数看着没顶满,也建议留出一定空间再决定长期用哪一档。最后按你的显卡容量从下往上找第一行「可用」的组合,那就是这台机器比较稳的配置。