transformers 5.x: from_pretrained silently returns random-init weights for custom PreTrainedModel subclasses (clean loading_info, no warning

在 transformers 5.x (如 5.12.0)中,用户定义了一个自定义的 PreTrainedModel 子类(非内建架构),通过 save_pretrained() 保存后,使用 from_pretrained() 重新加载。加载后的模型权重变成随机值,但 from_pretraine

transformers 5.x: from_pretrained silently returns random-init weights for custom PreTrainedModel subclasses (clean loading_info, no warning

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_keysinitialize_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 中安装 transformerstorchsafetensors 即可复现

解决步骤

  1. 临时规避方案: 使用 trust_remote_code=True 加载自定义模型(如果可以的话)。这会使 is_remote_code() 返回 True,从而触发参数级别的保护逻辑,防止 _init_weights 覆盖已加载的权重。
  2. 推荐修复方案(可优先尝试): 修改 transformers/src/transformers/modeling_utils.py 中的 _initialize_weights 方法,移除第 2502-2512 行附近的 is_remote_code 门控条件。具体为:将条件从 if is_remote_code and ... 改为 if ...(直接检查参数级别的 _is_hf_initialized 标记)。如果不想手动修改源码,可以等待官方发布包含此修复的版本。
  3. 自定义 _init_weights 修改: 在你的自定义 _init_weights 方法中,使用 transformers.initialization 中的受保护辅助函数(如 @guard_torch_init_functions),而非直接操作 weight.data。直接操作 .data 会创建一个独立的张量,失去 _is_hf_initialized 标记的保护。
  4. 回退到 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 仍然为空但权重正确。

额外建议:使用完整的端到端测试验证,确保自定义模型加载后能正常推理并产生一致的结果。

参考来源

huggingface/transformers #46620

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

celebrityanime
celebrityanime
文章: 9616

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注