
transformers 5.x: from_pretrained silently returns random-init weights for custom PreTrainedModel subclasses (clean loading_info, no warning)
快速结论:该问题出现在 transformers 5.x 中,当你加载自定义(out-of-tree)的 PreTrainedModel 子类时,from_pretrained() 会返回随机初始化的权重,但 loading_info 显示为干净的加载状态(missing_keys=[], unexpected_keys=[]),没有任何警告。优先排查你使用的自定义模型是否通过 trust_remote_code 加载,以及 _init_weights 中是否直接对 .data 进行操作。
问题场景
在 transformers 5.x(如 5.12.0)中,用户定义了一个自定义的 PreTrainedModel 子类(非内建架构),通过 save_pretrained() 保存后,使用 from_pretrained() 重新加载。加载后的模型权重变成随机值,但 from_pretrained 报告的 loading_info 干净无异常。该问题在 transformers 4.x 中不会出现,内建架构(如 DistilBertForSequenceClassification)也不会受影响。
报错原文
RAW saved weight mean: 0.5
loaded weight mean : 0.0007
loading_info : {'missing_keys': [], 'unexpected_keys': [], 'mismatched_keys': [], 'error_msgs': []}
原因分析
根本原因:权重确实被正确加载,但随后被 _init_weights 方法重新初始化覆盖了。流程如下:
- 在加载阶段,
set_param_for_module从检查点正确加载了参数(如lin.weight),并标记_is_hf_initialized = True。此时missing_keys为空,因为参数已找到。 - 随后,
_finalize_model_loading调用_initialize_missing_keys→initialize_weights()→_initialize_weights(module)。 - 在
_initialize_weights中,有一个“参数级别”的保护逻辑:如果模块的所有直接参数和 buffer 都已标记为_is_hf_initialized,则跳过重新初始化。但该保护逻辑被限制在is_remote_code条件下。 - 对于自定义的 out-of-tree 子类(不是通过
trust_remote_code加载),is_remote_code()返回False,因此保护逻辑被跳过,最终执行了用户定义的self._init_weights(module),其中weight.data.normal_(...)直接覆盖了已加载的权重。
该回归由 commit 6f6095e0cf (#41580 “Refactor weight loading”) 引入。
推荐修复方案:移除 _initialize_weights 方法中 is_remote_code 的门控,使参数级别的 _is_hf_initialized 保护逻辑对所有模型生效。
环境排查
- transformers 版本: 5.x 系列(5.12.0 及更高版本)
- PyTorch 版本: 2.12.0+(与版本无关)
- Python 版本: 3.11(与版本无关)
- 依赖环境: 仅在干净的 venv 中安装
transformers、torch、safetensors即可复现
解决步骤
- 临时规避方案: 使用
trust_remote_code=True加载自定义模型(如果可以的话)。这会使is_remote_code()返回True,从而触发参数级别的保护逻辑,防止_init_weights覆盖已加载的权重。 - 推荐修复方案(可优先尝试): 修改
transformers/src/transformers/modeling_utils.py中的_initialize_weights方法,移除第 2502-2512 行附近的is_remote_code门控条件。具体为:将条件从if is_remote_code and ...改为if ...(直接检查参数级别的_is_hf_initialized标记)。如果不想手动修改源码,可以等待官方发布包含此修复的版本。 - 自定义
_init_weights修改: 在你的自定义_init_weights方法中,使用transformers.initialization中的受保护辅助函数(如@guard_torch_init_functions),而非直接操作weight.data。直接操作.data会创建一个独立的张量,失去_is_hf_initialized标记的保护。 - 回退到 transformers 4.x: 如果上述方案不可行,可以临时降级到
transformers 4.x系列,该问题在 4.x 中不出现。
验证方法
运行公开的最小复现代码(见 Issue 正文),检查控制台输出:
- 修复前:
loaded weight mean应显示接近 0 的随机值(如 0.0007),且loading_info为空。 - 修复后:
loaded weight mean应与RAW saved weight mean一致(均为 0.5),且loading_info仍然为空但权重正确。
额外建议:使用完整的端到端测试验证,确保自定义模型加载后能正常推理并产生一致的结果。



