这个报错就是权重文件是用 DataParallel 多卡训练保存的,所有参数名字前面自动带上了 module. 前缀,但是你现在加载的时候用的是原生模型,没有包 DataParallel,原生模型的参数名是 encoder.embedding.weight,对不上带 module. 的键,所以直接报意外 key 的错误,这个问题在加载模型前做前缀处理就能解决,优先推荐在加载 state_dict 之前检查、去掉 module 前缀,而不是直接关掉 strict 模式,避免掩盖其他参数不匹配的问题。
一、核心原因
DataParallel 包装模型之后,会在外面套一层 module 容器,保存 state_dict 的时候,每一层参数名称都会多出module.开头。
保存时(DP 包装):module.encoder.embedding.weight
加载时(普通模型):期望 encoder.embedding.weight
两边 key 名字不一致,触发 unexpected key 报错。
二、推荐处理步骤(加载前执行,也就是你要求的检查 DataParallel 前)
- 先加载 checkpoint 文件,取出 state_dict
- 遍历 state_dict,把所有 key 开头的module.删掉,生成新的字典
- 使用清理完前缀的新 state_dict 给原生模型加载
- 加载完成之后,再按需套上 DataParallel 做后续推理或者训练
示例代码:
import torch
from collections import OrderedDict
1、加载权重
ckpt = torch.load("your_model.pth", map_location="cpu")
old_state_dict = ckpt["state_dict"]
2、清理module前缀
new_state_dict = OrderedDict()
for k, v in old_state_dict.items():
if k.startswith("module."):
new_k = k[7:] "module."一共7个字符
new_state_dict[new_k] = v
else:
new_state_dict[k] = v
3、加载到原生模型
model = YourModel()
model.load_state_dict(new_state_dict)
4、加载成功后,再包装DataParallel(需要多卡才执行)
model = torch.nn.DataParallel(model)
三、另外两种可选方案
- 方案 A:先把原生模型包上 DataParallel,再加载原始权重,适合后续一直用多卡跑
- 方案 B:使用consume_prefix_in_state_dict_if_present官方接口一键去除前缀,新版本 PyTorch 支持
from torch.nn.parallel import consume_prefix_in_state_dict_if_present
consume_prefix_in_state_dict_if_present(old_state_dict, "module.")
四、避坑提醒清单
- ❌ 不要上来直接写 load_state_dict (xxx, strict=False),会隐藏其他层参数不匹配的问题
- ✅ 保存模型好习惯:保存的时候存model.module.state_dict(),直接保存不带 module 前缀的权重,以后加载不用反复处理
- ✅ 顺序不能颠倒:原生模型加载权重 → 再套 DataParallel;而不是先套 DP 再加载不带 module 的权重,会报 missing key
五、快速自检表格
| 保存模型时状态 | 加载模型时状态 | 报错类型 | 处理方式 |
|---|---|---|---|
| DataParallel 包装 | 原生模型 | unexpected key module.xxx | 去掉 module 前缀再加载 |
| 原生模型 | DataParallel 包装 | missing key module.xxx | 先加载权重,再包装 DP |
| DataParallel 包装 | DataParallel 包装 | 正常 | 直接加载 |
【相关 FAQ】
问题 1:unexpected key "module.encoder.embedding.weight" in state_dict,我能不能在加载模型前直接判断 state_dict 有没有 module 前缀?
回答 1:可以,加载 DataParallel 保存的权重前,循环遍历 state_dict 的 key,判断是否以module.开头,存在就自动剔除前缀,这也是处理这个 unexpected key 报错最稳妥的前置检查方式,不会破坏其他参数名称。
问题 2:处理完 module 前缀之后,后续再用 DataParallel 包装模型,还会再次出现 unexpected key 这个报错吗?
回答 2:不会,原生模型加载清理完 module 前缀的 state_dict 之后,再包装 DataParallel,DataParallel 会自动给内部参数加上 module 容器,内部参数名称匹配,不会再触发这个 state_dict 的 key 不匹配报错。
问题 3:使用 consume_prefix_in_state_dict_if_present 处理 state_dict,能解决 unexpected key "module.encoder.embedding.weight" 吗?
回答 3:可以,这个官方接口就是专门用来移除 DP/DDP 产生的 module 前缀,在 load_state_dict 之前调用这个接口,自动清理前缀,解决这个 state_dict 的 unexpected key 问题。
【参考资料】
[2026-04-09](RuntimeError Missing Keys Loading state_dict in PyTorch — Fix & Causes)The Neural Base
[2025-07-25](torch.nn.modules.utils.consume_prefix_in_state_dict_if_present)PyTorch 中文文档
[2023-02-01](Error (s) pytorch 加载 checkpoint state_dict 出错:Missing key (s) && Unexpected key (s) in state_dict)阿里云开发者社区
[2022-07-29](RuntimeError: Error (s) in loading state_dict for DataParallel: Missing key (s) in state_dict)PyTorch Forums
[2019-03-15]([solved] KeyError: 'unexpected key "module.encoder.embedding.weight" in state_dict')PyTorch Forums
【免责声明】
本内容仅针对 PyTorch DataParallel 场景下 state_dict 出现 unexpected key 报错提供技术参考,不同 PyTorch 版本、模型结构、checkpoint 存储格式可能存在差异;代码示例请在测试环境验证后再投入正式训练或推理,因直接复制代码引发的模型加载异常、权重加载失败等问题,本内容不承担相关责任。
