模型能加载但回答跟图片无关,或者加载阶段就提示缺少配置,通常是三件事没对上:权重目录里的文件、处理器(processor/tokenizer/image processor)的配置、以及推理脚本里加载的顺序和参数。建议先把这三者的对应关系理清,再按日志报错定位是权重、处理器还是脚本的问题,不要一上来就改 dtype 或显存参数。下面按加载、核对、最小读图、单独验证视觉侧、写检查清单的顺序给出可操作的判断路径。
跑图失败先分两步看:加载阶段报缺少某个配置文件或分片索引,多半是权重目录不完整或与处理器配置不是同一次下载;加载成功但输出与图片无关,则要先确认视觉张量是否真正产出并进入模型。可用一条只输入一张图、只打印原始输出和中间张量形状的最小脚本验证,验证通过后再回到完整脚本排查 prompt 模板与图像占位符。所有判断以日志字段、目录清单和打印结果为准,不同版本目录结构可能不同,需要结合本机实际文件确认。
从加载日志里确认报错出现在权重、处理器还是脚本
建议把加载过程分成三段看日志:第一步是解析模型目录(读 config 类文件、分片索引),第二步是加载处理器(图像处理器、tokenizer 相关配置),第三步才是脚本里自建的调用参数。哪一段炸了就停在哪一段处理,不要跨段下判断。
加载日志里值得盯的字段通常是:报错前最后一条 info 级别日志打印的路径;异常类型名(如 OSError、ValueError、KeyError、TypeError);报错文本中出现的是文件名还是字段名;以及是否打印了“loading checkpoint shards”之类的分片加载提示。
- 指向权重目录:报错文本里出现分片文件名(如 model-0000x-of-0000y 形式)、指向 safetensors 索引缺失、或 key 名在权重里找不到。这类先查目录完整性。
- 指向处理器配置:报错里出现图像处理器或 tokenizer 的配置加载失败、缺少 preprocessor_config 一类文件、或图片与占位符数量不匹配。这类先查处理器与权重的配套关系。
- 指向脚本:异常类型是 TypeError、参数名不认识、或传入的 dtype/device_map 组合不被接受。这类先看调用签名,不要动目录。
判断方式很直接:把报错文本里的文件名与字段名逐个对照目录实际文件名。凡是日志里出现的名字在目录中找不到,问题就在文件层;名字都对得上但取值不对(例如图片尺寸、通道数、最大分块数),问题在配置取值。
核对权重目录与处理器配置是否来自同一次下载
最常见的隐性问题是两套文件拼接使用:权重是某个版本下载的,处理器配置是从另一个仓库或另一份缓存拷过来的。这种组合有时能加载成功,但图像预处理行为会与训练时不一致,表现就是输出和图片无关。
核对时按文件粒度看,不要只看目录名。建议先输出目录清单再逐项比对:
ls -l ./model_dir
# 重点确认这几类文件是否齐全且时间戳接近
# config.json
# 分片索引文件(.safetensors.index.json 一类)
# 实际分片文件(与索引中记录的条目数量一致)
# preprocessor_config.json 或同类图像处理器配置
# tokenizer 相关文件(tokenizer_config.json、tokenizer.model 等)
# generation_config.json(若存在)
几个具体核对点:分片索引文件里记录的权重文件名列表,逐条对照目录里实际存在的分片文件,缺一个就会在加载中途报错;索引文件里声明的总大小与各分片实际大小的一致性通常也能反映文件是否被截断;处理器的配置文件与权重 config 中记录的模型类型、图像相关字段需要能对应上;tokenizer 配置里的特殊 token 与脚本中使用的图像占位符要能对上。
如果时间戳明显分成两批,或者处理器配置来自另一个目录,建议直接用同一来源重新取整套文件,而不是逐个修补。文件对不齐时,后续所有排查都建立在不可靠基础上。
用最小脚本只做一次图片输入并打印原始输出
完整业务脚本里有 system prompt、多轮历史、后处理解析,任何一环都可能让“输出与图片无关”。建议先退到最小脚本,只做一次图片输入,并且只打印原始输出,不做任何格式化和截断判断。
from PIL import Image
# 以下为通用骨架,函数名与参数需按本地实际安装的库版本调整
processor = AutoProcessor.from_pretrained(model_dir, trust_remote_code=True)
model = AutoModel.from_pretrained(model_dir, trust_remote_code=True).eval()
image = Image.open("./one_test.jpg").convert("RGB")
prompt = "\n<image>\n描述这张图片里有什么。\n"
inputs = processor(text=prompt, images=[image], return_tensors="pt")
print({k: (tuple(v.shape) if hasattr(v, "shape") else type(v)) for k, v in inputs.items()})
out = model.generate(**inputs, max_new_tokens=64)
print(repr(out))
print(processor.decode(out[0], skip_special_tokens=False))
输出观察点有三个:第一,inputs 字典里是否真的出现了图像相关的张量键,以及它的形状是否符合单张图片的预期;第二,原始输出 token 序列是否几乎全是重复或空泛起始模式;第三,decode 后是否出现了与图片内容无关但语法通顺的描述。如果图像张量键根本不存在,说明处理器没把图片吃进去,问题在处理器配置或调用参数;如果图像张量存在但输出仍与图片无关,继续做下一节的单独验证。
脚本里图像占位符的写法必须与处理器的模板一致,占位符数量与图片数量不一致时,通常不会直接报错,而是静默丢掉图像输入,这也是“能加载但答非所问”的常见来源。
单独验证图像部分能否产出向量
把视觉侧单独拎出来,确认它是否真的接上了语言部分。做法是只跑图像编码这一段,打印张量形状与数值概况,不进入 generate。
# 通用骨架:属性名需按实际模型结构调整
vision = getattr(model, "vision_model", None) or getattr(model, "vision_tower", None) or getattr(model, "vpm", None)
print("vision module found:", vision is not None)
print("input tensor keys:", list(inputs.keys()))
for k, v in inputs.items():
if hasattr(v, "shape"):
print(k, tuple(v.shape), v.dtype, float(v.float().abs().mean()))
with torch.no_grad():
feats = vision(pixel_values=inputs["pixel_values"])
print("feature shape:", tuple(feats.shape) if hasattr(feats, "shape") else type(feats))
观察点:pixel_values 的形状是否符合该版本预期的通道数、分块数与尺寸;特征输出的维度是否与模型 config 里声明的视觉隐层维度一致;特征张量的均值是否全为零或出现 NaN。若特征全零或形状与声明维度不符,说明权重与视觉配置不配套,回到上一节核对目录;若特征正常但语言侧仍忽略它,则问题在图像特征与文本嵌入的拼接环节,检查脚本里是否把 image 输入正确传给了 generate 而不是只传给 processor。
属性名在不同版本里差异较大,找不到 vision 模块时,先打印模型顶层子模块名列表,再从中定位,不要凭猜测反复改代码。
把对齐后的加载方式写成可复用检查清单
下面这份清单全部落到具体文件与字段,换权重目录时逐条勾一遍即可,不需要重新推理。
- config.json 存在,且其中的模型类型与视觉相关字段与本机代码版本支持的类型一致。
- 分片索引文件存在,索引中列出的每个分片文件名在目录中都能找到,数量一致。
- 各分片文件大小正常,没有被截断成极小文件。
- 图像处理器配置文件存在,且与权重来自同一次下载,时间戳接近。
- tokenizer_config.json 中的特殊 token 与脚本中使用的图片占位符写法一致。
- 脚本中每张图片对应一个占位符,占位符数量与 images 列表长度一致。
- 最小脚本中 inputs 打印结果包含图像张量键,且首维与图片数量一致。
- 单独调用视觉模块能打印出非零特征张量,维度与 config 声明一致。
- generate 收到的关键字参数与本机库版本签名匹配,没有多余参数被静默忽略。
- 更换目录后先只跑最小脚本,通过后再接回完整业务脚本。
这份清单的边界是:它只能确认“文件与配置是否配套、视觉侧是否接通”,不能替代对 prompt 模板和后处理逻辑的检查。若清单全部通过而输出仍与图片无关,排查重点应转向 prompt 模板内容与解码后处理,而不是继续怀疑权重文件。