百川系列模型从权重下载到真正跑起来,卡住的地方通常只有两处:权重放错了目录层级,启动参数和显存对不上。前者表现为服务看似启动、一请求就报找不到模型;后者表现为加载到一半进程被 OOM 杀掉。稳妥的顺序是先用配置项和日志把路径对齐,再按 GPU 显存把精度、最大长度、批次这几个参数压到能加载的水平,最后用一次极短输入确认服务不只是起来了,而是真能出结果。
适用场景:单机单卡或多卡环境下手动下载百川权重、自行拉起本地推理服务。操作动作:让配置里的模型路径指向权重目录本身,再按显存从保守值逐档调整精度与批次参数。验证方式:看加载日志是否报路径错误、看显存峰值是否留有余量、跑一条短中文提示确认有正常输出。风险边界:路径与参数只保证服务能起来,输出质量、可用的上下文长度和并发上限仍需按业务单独评估。
核对权重目录层级与配置里写的路径
百川权重的常见坑是解压后多套了一层同名目录。手动下载的压缩包解开后,权重文件可能落在 Baichuan2-7B-Chat/Baichuan2-7B-Chat/ 这样的双层结构里,而配置里写的是外层目录。加载器找不到 config.json,就会在启动阶段直接失败。
先确认目录里实际有什么。一个能直接指向的权重目录,内容大致是这样:
/models/Baichuan2-7B-Chat/
├── config.json
├── generation_config.json
├── tokenizer.model
├── tokenizer_config.json
├── model.safetensors.index.json
├── model-00001-of-00003.safetensors
├── model-00002-of-00003.safetensors
└── model-00003-of-00003.safetensors
判断标准很简单:config.json 就在这一层的根下,没有再多一层同名文件夹。配置项里写的路径应当指向这个目录本身,而不是目录里的某个权重文件。无论你用的是 transformers 的 from_pretrained,还是 vLLM 一类加载器的 `--model` 参数,写法都是给目录,例如:
python -m vllm.entrypoints.openai.api_server \
`--model` /models/Baichuan2-7B-Chat \
`--served-model-name` baichuan-local
路径写错时,日志的形态有区分度,可以据此判断错在哪一层:目录不存在时,通常是 OSError: Can't load config for '/models/...' 或 No such file or directory;路径指到了目录里的某个 .safetensors 文件,会报 IsADirectoryError 或提示该路径不是目录;分片权重缺文件时,报错会提到某个 shard 无法加载、或者 index 文件中列出的分片与磁盘上的文件对不上。看到这几类报错,先回到目录层级核对,不要急着改显存参数。
确认模型配置里的层数与精度设置
config.json 里的 num_hidden_layers、hidden_size 这类结构参数,正常情况下不要手改,它们必须和权重张量形状一致,改错会在加载阶段报形状不匹配。真正常需要调整的是精度(dtype)选项。
常见精度按每个参数的字节数区分:fp32 每参数 4 字节,fp16 和 bf16 各 2 字节,int8 约 1 字节,int4 约 0.5 字节。按参数量乘字节数可以粗估权重占用,比如 7B 参数在 fp16 下权重就是十几 GB 量级,再加上 KV 缓存和中间激活,实际显存需求会更高。fp16 与 bf16 的区别主要在数值范围,bf16 对硬件有要求,较老的卡上可能不支持,需要结合你的 GPU 架构确认后再选,否则会回退到别的精度或直接报错。
对比方法很直接:同一份权重、同一条提示,分别用不同 dtype 各起一次,记录每次的显存峰值(nvidia-smi 观察,或看加载器日志里的显存统计),以及是否能正常出结果。建议从 bf16 或 fp16 试起,放不下再考虑 int8、int4 这类量化加载。量化版本对精度通常有影响,是否可接受要用你的实际输入去验证,不能只看能不能跑起来。
按显存大小调分批与并发参数
参数调整的顺序建议是:先固定精度,再从保守值起步逐档放大。第一批参数可以设成单条请求的量级,例如批次大小 1、并发请求数 1、最大序列长度先取一个较小的值(如 2048,需结合模型支持的长度和剩余显存确认)、显存占用比先留出余量,不要一上来就顶满。
逐档调整时,每档只动一个参数,观察这几项指标:加载日志是否出现 OOM 或显存不足的提示;nvidia-smi 上显存峰值距离总显存还剩多少;服务日志里是否出现请求被抢占、排队等待变长或重试;单条请求的首字延迟是否明显变差。批次 1 能稳定跑通后,再依次试 2、4,任何一档出现不稳定就退回上一档。
最大序列长度往往比批次更吃显存,因为 KV 缓存随长度增长。如果业务实际输入很短,先把长度压小,比死磕批次更划算。并发数与实际服务能力相关,本地自用场景从 1 开始即可,不要照搬线上服务的默认值。
启动后用一次最短输入做自检
服务起来不等于能用,用一条极短的输入验证一次。中文提示可以就用:你好,用一句话介绍你自己。期望的返回特征是:输出非空、是通顺可读的中文、没有整段重复或明显乱码、能在正常长度内结束而不是一直吐字。如果服务暴露的是 HTTP 接口,直接用一条 curl 请求验证即可。
三类异常的处理方向不同:请求超时或长时间无响应,先确认模型是否已完全加载、请求是否排在队列里、端口和路由是否写对,而不是先怀疑权重;输出乱码或夹杂无意义字符,多半指向 tokenizer 与权重不匹配(比如词表大小不一致)或精度溢出,需要回到上一节的精度和 tokenizer 文件核对;返回空内容,先检查生成的 token 上限是否设得过小、停止符配置是否把首 token 就截断了,再看提示词模板是否与模型的对话格式一致。
把这次可用的启动命令存档
调通一次后立刻把命令和关键参数记下来,换卡、重装或重启时才不用重新试错。建议的記錄格式是把权重、硬件、精度、长度、批次信息写在命令上方:
# 模型: Baichuan2-7B-Chat
# 权重路径: /models/Baichuan2-7B-Chat
# 硬件: <GPU 型号> / 显存 <GB>
# 精度: bf16
# 最大长度: 2048 批次: 1 并发: 1 显存占用比: 留有余量
python -m vllm.entrypoints.openai.api_server \
`--model` /models/Baichuan2-7B-Chat \
`--served-model-name` baichuan-local \
`--max-model-len` 2048 \
`--dtype` bfloat16
参数名以你实际使用的加载器帮助信息为准,这里给的是通用骨架,替换成对应加载器的写法即可。存档之后有两项内容改动时必须重新验证:一是权重路径与权重版本,目录层级变化或换了新的权重文件后,路径要重新核对并重跑一次短输入自检;二是显存相关参数,精度、最大长度、批次或并发任一改动,都可能让原本刚好够用的显存变得不够,需要重新观察显存峰值并确认能正常出结果。