书生·浦语本地跑不动 / 是显存不够还是量化档位没调?

文章导读
本地跑不动,多数时候能靠两条硬证据分开:启动日志里的失败位置,和显存占用的实际曲线。如果日志显示模型结构还没打印出来就 OOM,那是权重加载阶段装不下,方向是调量化档位和设备映射;如果权重已经加载完、第一条推理才崩,方向通常是缩短输入、降批大小。先分清这两类,再决定动哪个参数,比反复调量化档位省时间。
📋 目录
  1. 在启动日志里确认报错发生在权重加载还是首次推理
  2. 用一条轮询命令记录实际显存占用曲线
  3. 按通用骨架写一份量化加载配置并逐项开关验证
  4. 显存仍然不够时按顺序缩短输入
A A

本地跑不动,多数时候能靠两条硬证据分开:启动日志里的失败位置,和显存占用的实际曲线。如果日志显示模型结构还没打印出来就 OOM,那是权重加载阶段装不下,方向是调量化档位和设备映射;如果权重已经加载完、第一条推理才崩,方向通常是缩短输入、降批大小。先分清这两类,再决定动哪个参数,比反复调量化档位省时间。

适用场景:本地加载 Qwen、InternLM 一类模型时进程被 Killed 或报 CUDA out of memory。操作动作:先看日志确认报错落在权重加载还是首次推理,再用轮询命令记录显存峰值,然后逐项开关量化参数,最后才按顺序缩短输入。验证方式:改动后重启进程,对比启动日志中的量化生效提示与显存常驻值,再用同一条请求复跑。风险边界:只凭一次报错改参数容易误判,量化改错会静默不生效,降级动作只是让任务先跑通,不等于性能提升。

在启动日志里确认报错发生在权重加载还是首次推理

把失败位置落到具体阶段,判断依据主要看报错前的最后几行日志。

加载阶段失败的特征:日志停在下载或读取权重分片、合并分片、把权重搬到显卡这几步,模型的结构和参数量还没打印出来,进程就退出或被杀。常见报错是 CUDA out of memory,堆栈落在加载权重的函数里;也可能是数据类型不支持、device_map 没配、分片索引文件读不到这类配置错。这类问题说明显存瓶颈出现在「把权重放进显卡」这一步。

推理阶段失败的特征:模型结构、层数、参数量已经打印,日志走到第一次 forward 或 generate 的第一步才报错,而且和输入长度强相关——短输入能过,长输入崩。这类问题说明权重已经装下,瓶颈出现在中间激活和 KV cache 上。

  • 加载阶段失败 → 优先动量化(把权重压小)和设备映射(分散放置、部分权重放内存)。
  • 推理阶段失败 → 优先动输入长度、批大小和并发数,量化收益相对次要。

如果你只看到一行 CUDA out of memory,往上翻到第一处异常,看它发生在哪个函数里,这比看报错本身更有用。进程被系统 Killed 而没有 CUDA 报错时,要看系统日志确认是不是内存或显存被整体拖满。

书生·浦语本地跑不动 / 是显存不够还是量化档位没调?

用一条轮询命令记录实际显存占用曲线

不要凭「感觉跑得动」判断,先拿到连续占用数据。开一个终端持续采样:

nvidia-smi `--query-gpu`=timestamp,memory.used,memory.total,utilization.gpu `--format`=csv -l 1

如果只想临时看一眼,另一个终端执行 watch -n 1 nvidia-smi 也可以,但轮询命令更适合事后回看时间点。

读法分四段:空载基线占用是多少;权重加载完成后稳定在什么值;发一次请求时的峰值是多少;请求结束后是否回落。峰值通常出现在处理整段输入的那一步(prefill),所以输入越长峰值越高,这也是判断「是不是输入太长」的直接依据。

书生·浦语本地跑不动 / 是显存不够还是量化档位没调?

回落是否正常:请求结束后一般会降回一个常驻值,但不一定等于空载基线,因为推理框架会保留显存池。如果占用只涨不降,或者随着请求次数缓慢抬升,多半是缓存或并发没有释放,这时要先把并发降到 1 再看。把这四段数值和日志时间对齐,就能确认报错发生在加载阶段还是推理阶段。

按通用骨架写一份量化加载配置并逐项开关验证

下面是一份通用配置骨架,字段名和层级需要按你实际使用的加载方式替换,不要直接照抄:

model_path: /data/models/your-model
dtype: float16
device_map: auto
quantization:
  enabled: true
  bits: 8            # 先试 8bit,确认不通再试 4bit
  compute_dtype: float16
  group_size: 128
  double_quant: true
max_memory:
  0: 20GiB           # 改成显卡实际可用值,需要结合环境确认
low_cpu_mem_usage: true
offload_folder: /data/offload

各键的用途:bits 决定权重量化档位;compute_dtype 决定计算时用的精度,通常保持半精度;group_size 影响量化粒度与精度损失;double_quant 是二次量化,用来进一步压小常驻占用;device_mapmax_memory 一起决定权重怎么分布到显卡和内存。

验证流程要克制:每次只改一个参数,重启进程,然后按顺序做三件事——看启动日志里是否真的打印了量化生效的信息(通常会写明量化类型或位数),看显存常驻值是否比上一档下降,再用同一条请求复跑一次。

书生·浦语本地跑不动 / 是显存不够还是量化档位没调?

如果改了量化但显存曲线几乎没变化,基本可以判断量化没有真正生效,问题在配置写错、参数被覆盖,或当前环境缺少对应算子支持,需要结合环境确认,而不是继续往下调档位。

显存仍然不够时按顺序缩短输入

硬件不变的前提下,按下面这个顺序降级,每一步都单独验证,不要一次全改。

  1. 缩短单次输入长度。先砍对话历史、检索到的长文档、重复模板,只保留必要指令。验证方式:把同一条问题压到大约一半长度再跑一次,看峰值是否下降、任务是否跑完。这是最直接的一步,通常也最有效。
  2. 降低批大小或并发。把并发请求数或 batch 降到 1,避免多份激活同时占显存。验证方式:单条请求能否通过,结束后显存是否回落。
  3. 分片处理。把长输入切成几段分别推理,再在上层合并结果。验证方式:每段单独跑通、峰值稳定,合并后的结果是否可用需要你人工确认。代价是推理次数变多、总耗时上升,而且模型看不到完整上下文,结果可能和整段输入不一致。

这三个动作都是让任务先跑通的降级手段,不是性能方案。如果缩短输入后仍然在加载阶段就 OOM,说明问题还在权重本身,应该回到量化档位和设备映射那一步继续排查,而不是继续砍输入。