加载 Mage 时报维度不匹配或缺少某些 key,通常不是环境坏了,而是三份东西没对齐:语言塔权重、分词器词表、多模态投影层。稳妥的顺序是先逐行读报错里的 key 名,把它归到一个具体模块,再决定是换文件还是改配置。改配置能处理的多半是字段路径、维度声明、特殊 token 名字这类问题;如果文件本身来自不同版本,改配置一般只是把报错推到下一步。
判断方向:报错 key 带 multi_modal_projector 前缀,通常是投影层维度或类型与视觉塔、语言塔不匹配;Missing key 集中在 embed_tokens / lm_head,多半是分词器与权重词表不同源。先归类到模块,再只替换对应部分的同源文件,替换前备份原目录。边界:这只定位到模块级别,是否要换整套权重,需要结合发布来源和 config 一起确认。
逐行读报错里的 key 名,归类到语言塔、分词器或投影层
典型的报错长这样,注意它同时给了三类信息:shape 冲突、缺 key、多 key。
RuntimeError: Error(s) in loading state_dict for MageForCausalLM: size mismatch for multi_modal_projector.linear_1.weight: copying a param with shape torch.Size([4096, 1024]) from checkpoint, the shape in current model is torch.Size([4096, 2048]). Missing key(s) in state_dict: "language_model.model.embed_tokens.weight", "language_model.lm_head.weight". Unexpected key(s) in state_dict: "model.embed_tokens.weight".key 名前缀和模块的对应关系,可以先按这套经验对照,具体前缀以你那份 config 为准:
language_model./model.layers./lm_head.→ 语言塔;vision_tower./vision_model.→ 视觉塔;multi_modal_projector./mm_projector.→ 多模态投影层;embed_tokens、lm_head且 shape 与词表规模相关 → 分词器 / vocab_size 一侧。
三类报错的区分点也比较清楚。第一类,size mismatch 落在 projector 上,说明投影层输入维度与视觉塔输出维度不一致,或者 mm_projector_type 指向的结构和权重不是一种。第二类,Missing key 全部落在 embed_tokens 和 lm_head 这类和词表挂钩的层上,优先怀疑分词器词表大小与 config 里的 vocab_size 不一致。第三类,Unexpected key 是一整批前缀都和模型侧对不上,那基本是权重按另一套命名保存的,属于文件版本混搭,改字段名救不回来。
核对权重目录内各部分文件与配置字段是否对应
先看清目录里到底放了什么,再看 config 怎么描述这些文件。
ls -lh ./mage-weights # 需要出现:config.json、tokenizer* 系列、*.safetensors、*.safetensors.index.json python - <<'PY' import json cfg = json.load(open("./mage-weights/config.json")) for k in ("architectures", "model_type", "vocab_size", "hidden_size", "num_hidden_layers", "mm_projector_type", "image_token_index"): print(k, "=", cfg.get(k)) print("vision_config =", cfg.get("vision_config")) PY逐项对照清单,可以按下面顺序过一遍:
- tokenizer.json / tokenizer_config.json / special_tokens_map.json 是否与权重在同一个目录、同一次发布里取到的;
- config.json 的 vocab_size 是否和分词器实际词表长度对得上;
- 视觉塔输出维度与 mm_projector_type 对应的投影层输入维度是否一致;
- image_token_index 指向的 id,在分词器里是不是同一个特殊 token;
- index.json 里的权重名前缀与 architectures 声明的模型类是否配套。
单独调用分词器编码一句中文和图片占位符,看 token 数
这一步是为了验证分词器和模型侧词表同源,不要夹带模型加载,单独跑。
from transformers import AutoTokenizer tok = AutoTokenizer.from_pretrained("./mage-weights") print("len(tok) =", len(tok)) print(tok.encode("你好,这是一张图 <image>")) print(tok.convert_tokens_to_ids("<image>"))期望的形态是:中文句子返回一组数量合理的 token,不会一句话炸出几十上百个字节级碎片;图片占位符应当返回一个固定的单个 id,而不是被拆成若干字符 id 或返回 unk。明显异常的表现包括:len(tok) 与 config.json 的 vocab_size 差出明显量级;中文整句 token 数偏得离谱;占位符返回 None 或 unk id,说明这个特殊 token 没注册进分词器,或者配置里的占位符名字和分词器不一致。
换成同源文件后重新加载,并列两次日志
替换步骤建议按这个顺序做,方便回滚:先把现有目录整体备份;再取一整套同源文件覆盖(权重、config、tokenizer 来自同一次发布,不要只换其中一部分);确认 index.json 的分片列表与实际分片数量对得上;最后重新加载并完整保留日志。
替换前的加载日志,通常长这样:
Some weights of MageForCausalLM were not initialized from the model checkpoint size mismatch for multi_modal_projector.linear_1.weight: ... [4096, 1024] vs [4096, 2048] Missing key(s): language_model.model.embed_tokens.weight Unexpected key(s): model.embed_tokens.weight替换成同源文件后,正常应当看到这一类提示:
All model checkpoint weights were used when initializing MageForCausalLM. All the weights of MageForCausalLM were initialized from the model checkpoint.两次日志的差异点,就是判断依据:如果 size mismatch 和 Missing key 都消失,说明问题确实出在文件不匹配,而不是环境。如果换了同源文件、缺 key 依旧出现在同一批前缀上,下一步优先查这几处:transformers 版本是否认识 config 里的 architectures;本地缓存目录里是否残留旧的 config 或 tokenizer 被优先命中;加载的到底是不是基座权重,还是只剩一个适配器;以及报错是否已经从 key 层面转到 dtype、device_map 这类与权重无关的位置。