【Bug已解决】Adding a model 解决方案
【Bug已解决】Adding a model 解决方案一、现象长什么样当你按 Transformers 的添加新模型流程把一份第三方权重接进PreTrainedModel子类时常遇到这一类失败# 现象 A初始化权重全零 / 没被 Xavier 初始化 UserWarning: You are using the default init_weights which is not recommended. # 或者更糟forward 输出全是同一个常数因为权重没初始化 # 现象 Bload_weight 时 key 对不上 RuntimeError: Error(s) in loading state_dict for MyModel: Missing key(s) in state_dict: model.layers.0.self_attn.q_proj.weight. Unexpected key(s) in state_dict: transformer.h.0.attn.q_proj.weight. # 现象 Csave_pretrained 后再 from_pretrained 失败 KeyError: base_model_prefix # 或保存出的 config.json 缺关键字段导致二次加载崩溃 # 现象 DCI 的 slow 测试直接报错 ValueError: Could not find dummy objects for model my_model. # 官方 CI 要求提供 _dummy_xxx 输入否则集成测试跑不起来这些都不是模型数学写错而是集成骨架没搭全权重初始化、key 命名、base_model_prefix、dummy 测试对象缺一个就卡一个。二、背景把一个新模型Adding a model接进 transformers需要的不只是modeling_xxx.py里的网络代码还有一整套契约_init_weights/init_weights保证加载前权重被合理初始化。base_model_prefix告诉PreTrainedModel顶层容器叫什么如model、transformer所有get_input_embeddings、tie_weights、state_dict key 前缀都依赖它。权重 key 命名必须与 checkpoint 里的 key 完全一致前缀、层级。_tied_weights_keys/tie_weights词嵌入共享时声明。dummy 测试对象官方 CI 用_init_dummy_inputs等做无权重快速测试。漏掉其中任何一项都会在上文的现象里以不同形式炸出来。这些问题与 596特定模型 D_Nikud 的 Auto 注册是不同层面596 是Auto 体系认不认得你601 是模型自身骨架对不对。三、根因把常见失败归到四类根因没实现_init_weights或没调init_weights()。PreTrainedModel.__init__默认不会自动初始化子模块权重除非你覆盖了_init_weights并在__init__末尾调self.init_weights()。如果漏了权重保持nn.Linear的默认也可能被加载流程跳过→ 全零或常数forward 输出退化。base_model_prefix与权重 key 前缀不一致。 若你写base_model_prefix model但 checkpoint 的 key 是transformer.h.0...加载时所有 key 都Missing/Unexpected。反之保存时也会写出错误前缀二次加载即KeyError。tie_weights相关 key 未声明。 当lm_head.weight与embed_tokens.weight共享却没在_tied_weights_keys里声明保存 checkpoint 时可能重复保存或漏保存导致加载维度错乱。缺 dummy 测试对象。 官方 CI 的models/__init__.py测试会尝试无权重构造模型并跑 dummy 输入。若没提供_init_dummy_inputs或对应的ModelTesterCI 直接ValueError: Could not find dummy objects。四、最小可运行复现下面用纯 Python 模拟base_model_prefix 与 key 前缀不一致导致 load 失败的判定from typing import Dict, List class _PretendModel: def __init__(self, base_model_prefix: str): self.base_model_prefix base_model_prefix def expected_keys(self, layer_keys: List[str]) - List[str]: # 真实 transformers 会把 base_model_prefix 作为 state_dict 顶层前缀 return [f{self.base_model_prefix}.{k} for k in layer_keys] def load_state_dict(model, checkpoint_keys: List[str], model_keys: List[str]): missing [k for k in model_keys if k not in checkpoint_keys] unexpected [k for k in checkpoint_keys if k not in model_keys] return missing, unexpected # 情景 1prefix 不一致 model _PretendModel(base_model_prefixmodel) layer_keys [layers.0.self_attn.q_proj.weight] model_keys model.expected_keys(layer_keys) # [model.layers.0...q_proj.weight] checkpoint_keys [transformer.h.0.attn.q_proj.weight] # 错误前缀 missing, unexpected load_state_dict(model, checkpoint_keys, model_keys) print(missing:, missing) print(unexpected:, unexpected) assert missing and unexpected, 复现失败应当出现 key 不匹配 # 情景 2prefix 一致则正常 model2 _PretendModel(base_model_prefixtransformer) model_keys2 model2.expected_keys([h.0.attn.q_proj.weight]) ckpt2 [transformer.h.0.attn.q_proj.weight] m2, u2 load_state_dict(model2, ckpt2, model_keys2) print(prefix 一致时 missing/unexpected:, m2, u2) # [] [] assert not m2 and not u2运行后情景 1 报missing/unexpectedkey 前缀不符情景 2 正常正好对应现象 B 的Missing/Unexpected key(s)。五、解决方案第一层最小直接修复最直接补齐骨架三个关键点——_init_weights、base_model_prefix、key 命名对齐from transformers import PreTrainedModel, PretrainedConfig import torch.nn as nn import torch.nn.functional as F class MyConfig(PretrainedConfig): model_type my_model def __init__(self, hidden_size768, vocab_size32000, **kwargs): super().__init__(**kwargs) self.hidden_size hidden_size self.vocab_size vocab_size class MyModel(PreTrainedModel): config_class MyConfig base_model_prefix model # 关键 1与 checkpoint key 前缀一致 _tied_weights_keys [lm_head.weight, model.embed_tokens.weight] def __init__(self, config: MyConfig): super().__init__(config) self.embed_tokens nn.Embedding(config.vocab_size, config.hidden_size) self.layers nn.ModuleList([nn.Linear(config.hidden_size, config.hidden_size) for _ in range(2)]) self.lm_head nn.Linear(config.hidden_size, config.vocab_size, biasFalse) # 关键 2初始化权重 self.init_weights() # 会调用下面的 _init_weights def _init_weights(self, module): # 关键 3明确初始化避免全零 if isinstance(module, nn.Linear): module.weight.data.normal_(mean0.0, std0.02) if module.bias is not None: module.bias.data.zero_() def forward(self, input_ids): x self.embed_tokens(input_ids) for layer in self.layers: x F.relu(layer(x)) return self.lm_head(x) # 关键 4保存/加载 key 前缀一致 model MyModel(MyConfig()) model.save_pretrained(./my_ckpt) # 写出 model.* / lm_head.* m2 MyModel.from_pretrained(./my_ckpt) # 前缀对齐正常加载第一层让用户加载/保存/二次加载都正常且权重被正确初始化。六、解决方案第二层结构性改进把新模型骨架检查做成ModelScaffoldValidator在 CI 或加载前自动校验骨架完整性from dataclasses import dataclass from typing import List, Type dataclass class ModelScaffoldValidator: 校验一个新模型类是否满足 transformers 集成骨架契约。 required_attrs: List[str] None def __post_init__(self): self.required_attrs [ base_model_prefix, config_class, _init_weights, init_weights, ] def check(self, model_cls: Type) - List[str]: problems: List[str] [] for attr in self.required_attrs: if not hasattr(model_cls, attr): problems.append(f缺少 {attr}) # base_model_prefix 必须是非空字符串 prefix getattr(model_cls, base_model_prefix, None) if not isinstance(prefix, str) or not prefix: problems.append(base_model_prefix 必须是非空字符串) # 必须有 dummy 测试入口官方 CI 需要 if not hasattr(model_cls, _init_dummy_inputs) and \ not hasattr(model_cls, dummy_inputs): problems.append(缺少 dummy 测试对象CI slow 测试会失败) return problems def assert_ready(self, model_cls: Type): probs self.check(model_cls) if probs: raise RuntimeError(模型骨架不完整:\n \n.join(probs)) # 使用 from my_modeling import MyModel ModelScaffoldValidator().assert_ready(MyModel) # 不抛异常即骨架完整ModelScaffoldValidator把集成骨架从靠经验记忆变成可自动检查作者每次加模型先跑一遍缺什么一目了然。七、解决方案第三层断言 / CI 守护用 pytest 固化骨架契约任何一项缺失都红灯import pytest from transformers import PreTrainedModel from my_modeling import MyModel, MyConfig def test_has_base_model_prefix(): assert isinstance(MyModel.base_model_prefix, str) and MyModel.base_model_prefix, \ base_model_prefix 缺失或为空会导致 state_dict key 前缀错误 def test_init_weights_initializes(): m MyModel(MyConfig(hidden_size64, vocab_size100)) w m.layers[0].weight.data # 不应是全零初始化生效 assert w.abs().sum() 0, _init_weights 未生效权重可能全零 def test_save_load_roundtrip(): import tempfile, os m MyModel(MyConfig(hidden_size64, vocab_size100)) d tempfile.mkdtemp() m.save_pretrained(d) m2 MyModel.from_pretrained(d) # key 前缀应一致能正常加载 assert m2.base_model_prefix m.base_model_prefix def test_has_dummy_inputs_for_ci(): assert hasattr(MyModel, _init_dummy_inputs) or hasattr(MyModel, dummy_inputs), \ 缺少 dummy 测试对象官方 CI 的 slow 测试会 ValueErrorCI 跑pytest tests/test_model_scaffold.py以后只要有人加模型漏了base_model_prefix或_init_weights测试立刻拦截。八、排查清单当你Adding a model遇到加载/保存/CIT 失败按顺序查权重全零或输出常数 → 检查是否实现_init_weights并在__init__调self.init_weights()。Missing/Unexpected key→ 比对base_model_prefix与 checkpoint 真实 key 前缀必须逐字符一致。二次加载KeyError: base_model_prefix→ 保存前确认base_model_prefix已设且config_class正确。共享 embedding 维度错乱 → 在_tied_weights_keys声明lm_head.weight与embed_tokens.weight。CI slow 测试Could not find dummy objects→ 补_init_dummy_inputs或dummy_inputs。九、小结Adding a model 卡住的往往不是网络数学而是集成骨架契约_init_weights初始化、base_model_prefix与 key 前缀一致、_tied_weights_keys共享声明、dummy 测试对象。这四样缺一个就以一种具体现象炸出来。第一层补齐_init_weightsself.init_weights()、base_model_prefix对齐、key 命名一致立即能保存/加载/二次加载。第二层用ModelScaffoldValidator自动校验骨架完整性作者不再靠记忆。第三层pytest 断言prefix 非空、权重已初始化、save/load 往返、有 dummy 对象防止回归。记住加模型先搭骨架再填数学骨架四件套_init_weights/base_model_prefix/_tied_weights_keys/ dummy齐了集成基本不会翻车。

相关新闻

超声波测距模块HC-SR04原理、代码实现与工程实践全解析

超声波测距模块HC-SR04原理、代码实现与工程实践全解析

最近在做一个智能小车项目,需要实现自动避障功能,超声波测距模块就成了我的首选方案。但在实际调试过程中,发现网上很多教程要么代码不完整,要么对原理和误差处理讲得不够透彻,导致新手很容易卡在数据不准或模块不响应…

2026/10/16 9:47:09 阅读更多 →
基于Python与Vosk的《我的世界》本地语音控制自动化方案

基于Python与Vosk的《我的世界》本地语音控制自动化方案

1. 先搞清楚“语音控制MC外挂”到底能做什么,不能做什么 看到“语音控制MC外挂”这个标题,很多人第一反应可能是“用嘴玩游戏”或者“解放双手的神器”。但作为一个在游戏开发和自动化脚本领域折腾过不少项目的人,我得先泼点冷水&#xff1a…

2026/10/16 13:27:32 阅读更多 →
C#单件模式实战:从线程安全到Lazy<T>的最佳实践

C#单件模式实战:从线程安全到Lazy<T>的最佳实践

1. 单件模式:为什么它既是基石,又是“坑王”?在C#开发里,尤其是做上位机、工业控制或者需要长期运行的服务端应用时,你肯定遇到过这样的场景:整个系统只需要一个配置管理器、一个日志记录器,或者…

2026/10/16 12:18:49 阅读更多 →

最新新闻

嵌入式三阶RC滤波器:移位运算替代除法的高效实现

嵌入式三阶RC滤波器:移位运算替代除法的高效实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 1:01:37 阅读更多 →
C++/WinRT 项目集成 SQLite:从工程配置到打包部署的完整实操

C++/WinRT 项目集成 SQLite:从工程配置到打包部署的完整实操

第一次在 VS2019 里用 winrt/C 做应用开发,需要把 SQLite 加进工程时,我在“引用管理器”里翻了好几轮,愣是没找到任何和数据库相关的 SDK 入口。后来才弄清楚,WinRT 应用和普通 Win32 桌面程序不一样,它不能直接挂一个…

2026/10/18 1:01:37 阅读更多 →
SPI通信调试实战:从CPOL/CPHA到DMA的避坑指南

SPI通信调试实战:从CPOL/CPHA到DMA的避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 1:01:37 阅读更多 →
cRIO-9066串口VISA超时-1073807254:从报错到解决的排查指南

cRIO-9066串口VISA超时-1073807254:从报错到解决的排查指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 1:01:37 阅读更多 →
变频器干扰导致工控机死机、通讯掉线?EMC抗干扰实战排查与治理全解析

变频器干扰导致工控机死机、通讯掉线?EMC抗干扰实战排查与治理全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 1:01:37 阅读更多 →
一条龙开发指南:用 TaoToken 统一 Key 打通 MCP AI Agent 理论+项目实战开发你的 MCP Server

一条龙开发指南:用 TaoToken 统一 Key 打通 MCP AI Agent 理论+项目实战开发你的 MCP Server

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 1:00:37 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →