SenseNova Loop-9B-Preview 跑不起来——是显存不够还是量化没配对?

文章导读
先分清失败发生在哪一段,再决定是换档还是换环境。SenseNova Loop-9B-Preview 这类 9B 级模型跑不起来,通常落在三种情况之一:权重文件根本没加载完、加载完但第一次前向时显存峰值顶不住、或者量化权重的格式与当前加载器不匹配。这三类现象在日志里的位置和处置动作完全不同,混着调参数往往越调越乱。
📋 目录
  1. 壹 在启动日志里定位报错发生在哪个阶段
  2. 贰 用显存采样区分空闲与加载中的占用
  3. 叁 检查量化权重格式与加载器是否匹配
  4. 肆 缩到最短输入复现一次
  5. 伍 分别验证显存不足与量化不兼容两条假设
A A

先分清失败发生在哪一段,再决定是换档还是换环境。SenseNova Loop-9B-Preview 这类 9B 级模型跑不起来,通常落在三种情况之一:权重文件根本没加载完、加载完但第一次前向时显存峰值顶不住、或者量化权重的格式与当前加载器不匹配。这三类现象在日志里的位置和处置动作完全不同,混着调参数往往越调越乱。

处理顺序建议固定为:看日志判断失败阶段 → 采样显存确认容量 → 检查量化权重与加载器是否配套 → 用最小输入复现。若报错出现在加载权重阶段(缺张量、dtype 不支持、量化配置缺失),优先怀疑量化格式与加载器版本;若日志已打印加载完成、在首次 generate 时报 CUDA out of memory,优先怀疑显存峰值与输入规模。判定依据只能来自你机器上的日志和显存采样,别人的结论不能直接套用。

在启动日志里定位报错发生在哪个阶段

启动命令统一加 tee 保存完整日志,报错被截断后很难判断阶段。

python run_demo.py 2>&1 | tee run.log

加载阶段的日志特征:出现读取 config.json、tokenizer、loading checkpoint shards、Loading weights、解析 quantization_config 或 load_in_4bit 之类的内容后失败。这一阶段的报错类型多为 KeyError(找不到某个权重张量)、ValueError(Unsupported dtype、size mismatch)、ImportError(缺 bitsandbytes、accelerate 等)。

前向阶段的日志特征:模型已经打印 loaded / ready,进入 generate 之后才失败。这一阶段的报错常见为 CUDA out of memory(通常会带 tried to allocate 的大小)、shape mismatch、device 不一致、KV cache 分配失败。

grep -n -iE "traceback|error|out of memory|unsupported|keyerror|size mismatch" run.log
sed -n '110,170p' run.log   # 换成上一步命中行号的前后各 20~40 行

把结果记成固定模板,后面做对照实验时可以直接横向比较:

SenseNova Loop-9B-Preview 跑不起来——是显存不够还是量化没配对?
失败阶段: 加载 / 前向(二选一)
报错原文: (贴最关键的一两行)
触发参数: 量化档位=____,输入长度=____,batch=____,device_map=____
是否已打印 loaded: 是 / 否
环境: torch=____,CUDA=____,transformers=____,bitsandbytes=____,显卡型号与总显存=____

用显存采样区分空闲与加载中的占用

容量是不是真的不够,只能靠采样。空闲基线、加载完成、首次前向这三个数值必须分开记,混在一起看不出峰值出现在哪。

nvidia-smi `--query-gpu`=timestamp,memory.used,memory.total `--format`=csv,noheader -l 1 > mem.csv
# 另开终端跑复现命令,结束后杀掉采样进程

1 秒间隔通常够用。如果日志明确报了 OOM,但 mem.csv 里看不到明显爬升,把间隔改成 0.2 秒重跑一次,因为首次前向的峰值可能只持续很短时间。对比时按下面的格式填,注意标出每个数值对应的时间点:

基线(只有桌面或其他进程): ____ MiB,时间戳 ____
加载权重完成瞬间: ____ MiB,时间戳 ____
首次前向开始后峰值: ____ MiB,时间戳 ____
显卡总显存: ____ MiB

判断方式:加载完成瞬间就已接近总显存,属于容量问题,权重本身放不下;加载完成占用可控、峰值只在首次前向冲高,属于输入规模、激活或 KV cache 引起,动作是缩短输入或换更大显存。跨机器对比时固定同一份权重和同一输入,否则数值不可比。

检查量化权重格式与加载器是否匹配

先看目录里到底有什么文件,再看配置声明了什么。

SenseNova Loop-9B-Preview 跑不起来——是显存不够还是量化没配对?
ls -lh ./loop-9b-preview
python -c 'import json;c=json.load(open("./loop-9b-preview/config.json"));print({k:c.get(k) for k in ("torch_dtype","quantization_config","architectures","model_type")})'

safetensors 的 dtype 字段可以只读文件头拿到,不需要把权重读进内存。单分片示例如下,多分片就对每个文件跑一遍:

python - <<'PY'
import json, struct
p = "./loop-9b-preview/model-00001-of-0000x.safetensors"
with open(p, "rb") as f:
    n = struct.unpack("<Q", f.read(8))[0]
    hdr = json.loads(f.read(n))
print(sorted({v["dtype"] for k, v in hdr.items() if k != "__metadata__"}))
print([k for k in hdr if "scale" in k.lower()][:5])
PY

看两件事:dtype 是 BF16/F16 还是 I8/U8 之类的整型;张量名里有没有 scale、zeros 这类伴随项。常见的不匹配表现有:报错里提到缺某个 weight_scale 或 qweight,说明权重按量化格式打包、加载器却按普通权重读;报 Unsupported dtype 或 cannot convert;config 里写了 quantization_config 但代码路径没启用,实际按 bf16 加载,显存占用接近全精度;缺 bitsandbytes 或相关算子导致 ImportError、CUDA 版本不匹配。这里只记录看到了什么,不要去推断加载器内部怎么实现。

缩到最短输入复现一次

用最小脚本把变量压到最少,官方 demo 如果用的是别的 SDK,把同名参数替换进去即可。

SenseNova Loop-9B-Preview 跑不起来——是显存不够还是量化没配对?
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
MODEL = "./loop-9b-preview"
tok = AutoTokenizer.from_pretrained(MODEL, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(
    MODEL,
    torch_dtype=torch.bfloat16,   # 对照实验时改这一行
    device_map={"": 0},
    trust_remote_code=True,
)
print("loaded ok")
ids = tok("你好", return_tensors="pt").to("cuda")
out = model.generate(**ids, max_new_tokens=8)
print(tok.decode(out[0], skip_special_tokens=True))

需要固定的变量清单:量化档位(bf16 / 8bit / 4bit)、是否加载 quantization_config、device_map、图片尺寸(多模态输入时)、文本输入长度、max_new_tokens、batch 固定为 1、transformers 与 bitsandbytes 版本。每次只改一项,其余全部保持,脚本里加一行 print("loaded ok") 就是为了把加载成功和前向成功这两个信号分开。

分别验证显存不足与量化不兼容两条假设

对照 A 查量化兼容性:同一台机器、同一输入,A1 用量化权重配当前加载器,A2 用非量化 bf16 权重配同一套加载器。A1 失败而 A2 能加载并正常生成,问题在量化格式与加载器,动作是换加载器版本、换量化档位或直接跑 bf16。A1、A2 都在加载阶段报同类缺张量或版本错误,更可能是依赖版本问题,动作是对齐 transformers、accelerate、bitsandbytes 的版本组合。

对照 B 查容量:同一份权重、同一加载器,只改输入。B1 用最短文本和小尺寸图片,B2 用正常输入。B1 在加载阶段就 OOM,说明容量不够,动作是换更大显存机器或更激进的量化档位;B1 能跑而 B2 OOM,说明是峰值问题,动作是缩短输入、降 batch、限制 max_new_tokens、把图片分块处理。

结论: 显存不足 / 量化不兼容 / 依赖版本不匹配(可写组合)
依据: 对照 A 或 B 中哪两条日志、哪组显存数值出现了差异
下一步动作: 换档(____)/ 换机器(显存需不小于 ____)/ 换依赖版本(____)
未验证部分: 如未测多卡、未测更长输入

边界也要写清楚:换量化档位会改变输出质量,需要回归检查;换机器只解决容量,不解决格式问题;对齐依赖版本可能影响项目里其他模型,建议在独立虚拟环境里验证后再合入。