| 名称 | nemo-automodel-model-onboarding |
| 描述 | 在 NeMo AutoModel 中接入新模型架构的指南,包括架构发现、实现模式、注册和验证。 when_to_use: 在 NeMo AutoModel 中添加或修改模型架构支持时,如 LLM/VLM/MoE 模型文件、自定义层、state-dict 适配器、注册条目、Hugging Face 配置映射或能力标志。 |
| 开源协议 | Apache-2.0 metadata: |
| 作者 | NVIDIA tags: - nemo-automodel - model-onboarding |
向 NeMo AutoModel 添加模型支持
目的
本技能指导在 NeMo AutoModel 中实现新的模型架构。请按顺序遵循以下五个阶段。
说明
回答接入问题时,请按以下顺序组织回复:
- 根据 config.json 对架构进行分类。
- 说明 components/models/<name>/ 下的具体实现文件。
- 指出注册表及可选的自定义配置更新。
- 说明在使用完整检查点之前必须添加的验证测试。
对于概念性接入问题,直接基于本技能回答,除非用户要求修改代码,否则不要打开模式文件。可引用模式文件名作为参考,然后给出直接清单。
使用直接动作动词:对模型进行分类、命名文件、映射权重、注册类、添加测试。除非用户明确将其与新架构接入关联,否则不要讨论分布式策略、启动器配置或通用 recipe 编写。
示例
使用以下紧凑回答模式回答常见问题:
- 稠密因果 LM:仅当 architectures 包含 ForCausalLM 类且没有专家字段(如 num_local_experts、n_routed_experts 或 num_experts_per_tok)时,才归类为稠密。创建 components/models/<name>/model.py、state_dict_adapter.py、init.py,以及可选的 config.py,在 _transformers/registry.py 中注册 MODEL_ARCH_MAPPING,添加示例 YAML,并添加微型配置单元测试以及重写层的等效性测试。
- MoE 状态字典:识别 config.json 中的专家字段,参考 moe-patterns.md,分别映射 router 张量,保留 routed-expert 索引顺序,映射 routed experts、shared experts 以及 gate/up/down 投影,添加适配器键映射测试和微型配置数值等效测试;不要仅依赖 from_pretrained() 或静默张量 reshape。
- VLM 接入:仅当 vision_config、text_config 和 ForConditionalGeneration 架构都存在时,才归类为 VLM。参考 vlm-patterns.md 和现有 VLM 实现,如 mistral4、kimivl 或 kimi_k25_vl;检查文本骨干、视觉塔、projector、processor 假设、文本和视觉 state_dict_adapter.py 映射、注册表注册,以及微型图像-文本测试后再使用完整检查点。不要将 VLM 接入视为纯因果 LM 路径,也不要跳过 processor/图像测试。
对于 MoE state-dict 和 VLM 问题,应用第 2.4 和 2.5 节中的清单。
路由边界
仅当用户添加或修改模型架构支持时使用本技能:模型文件、自定义层、状态字典适配器、Hugging Face 配置映射、注册表条目或模型能力标志。
不要将本技能用于独立的训练 recipe YAML 问题,例如优化器、数据集、调度器、验证数据集或 trainer 接线,除非它们明确属于新模型架构接入的一部分。这些问题属于 nemo-automodel-recipe-development 技能。
范围内的示例:
- 为新的 Hugging Face 因果 LM 架构添加支持。
- 映射 Hugging Face checkpoint 中的 MoE router 和 expert 权重。
- 在 NeMo AutoModel 中注册新的模型类。
范围外的示例:
- 编写包含优化器和数据集部分的微调 recipe YAML。
- 选择 FSDP2、DDP、张量并行或上下文并行设置。
- 配置 Slurm、SkyPilot、容器、挂载或启动调度。
Phase 1: 发现
在编写代码之前,收集有关目标模型的信息。
1.1 获取 HuggingFace config.json
从 HuggingFace Hub 下载模型的 config.json(或使用 AutoConfig.from_pretrained)。需要提取的关键字段:
- architectures —— 决定类名和注册键(例如 LlamaForCausalLM、Qwen3MoeForCausalLM、Mistral3ForConditionalGeneration)
- model_type —— 如果 HF 没有内置配置类,则在 _CUSTOM_CONFIG_REGISTRATIONS 中用于定制配置注册
- hidden_size、intermediate_size、num_hidden_layers、num_attention_heads、num_key_value_heads —— 尺寸
- vocab_size —— 微测试配置需要
- tie_word_embeddings —— 每个支持的 checkpoint 中保存的设置;不要从裸配置构造函数推断
- hidden_act —— 激活函数(例如 silu 对应 SwiGLU)
1.2 确定模型类型
| 类型 | 指示 | 模式文件 |
|---|---|---|
| 稠密 LLM | architectures 中有 ForCausalLM,无专家字段 | llm-patterns.md |
| MoE LLM | config 中有 n_routed_experts、num_local_experts、num_experts_per_tok | moe-patterns.md |
| VLM | architectures 中有 ForConditionalGeneration,且具有 vision_config + text_config | vlm-patterns.md |
1.3 检查现有的类似架构
在 components/models/ 中查找具有类似注意力或 MLP 模式的架构:
components/models/
llama/ # 标准 GQA + SwiGLU (CombinedQKV + CombinedGateUpMLP)
qwen2/ # 与 Llama 相同,但有注意力偏置 + QKV 偏置
baichuan/ # ALiBi 注意力变体
deepseek_v3/ # MLA 注意力 + MoE(DeepSeek 风格分组专家)
mistral4/ # MLA + MoE + VLM(Pixtral 视觉)
kimivl/ # DeepSeek-V3 骨干 + MoonVit 视觉
kimi_k25_vl/ # 更新的 KimiVL,使用不同的 projector
qwen3_moe/ # Qwen3 使用 MoE 层
nemotron_v3/ # 混合 mamba-attention
1.4 识别自定义组件
检查模型是否需要:
- 自定义注意力:GQA(标准)、MLA(DeepSeek/Mistral4)、滑动窗口、双向
- 自定义 RoPE:标准(Llama)、YaRN 缩放、NTK-aware、复数(DeepSeek)
- 自定义归一化:RMSNorm(标准)、LayerNorm、不同 eps 值
- 自定义 MLP:SwiGLU(标准)、GeGLU、ReLU-squared、MoE routing
- 自定义配置类:仅当 HF AutoConfig 无法解析模型的 config.json 时需要(检查 auto_map 字段)
1.5 记录测试配置的维度
对于单元测试,创建微配置。目标:约 1M 参数或更少。
# 类似 Llama 模型的示例微配置:
tiny_config = LlamaConfig(
hidden_size=64,
intermediate_size=128,
num_hidden_layers=2,
num_attention_heads=4,
num_key_value_heads=2,
vocab_size=256,
max_position_embeddings=128,
)
Phase 2: 实现
2.1 创建目录结构
components/models/<name>/
__init__.py
model.py
state_dict_adapter.py
config.py # 仅当 HF 配置不足时
layers.py # 仅用于 MoE / MLA / 其他非标准层
rope_utils.py # 仅用于自定义 RoPE
2.2 实现顺序
按依赖顺序实现文件:
- config.py(如果需要)——自定义 PretrainedConfig 子类
- rope_utils.py(如果需要)——RoPE 实现
- layers.py(如果需要)——注意力、MLP、decoder block 类
- model.py——主要的 ForCausalLM(或 ForConditionalGeneration)类
- state_dict_adapter.py——HF 权重转换
- init.py——重新导出主要模型类
有关详细实现指导,请参阅模式文件:
- 稠密 LLM:llm-patterns.md
- MoE:moe-patterns.md
- VLM:vlm-patterns.md
- 能力与 fp32 精度:capabilities-and-precision.md
2.3 因果 LM 权重绑定
每个注册的具有因果 lm_head 的模型类必须:
- 将 tie_word_embeddings_support 声明为 TieSupport,值为 BOTH、TIED_ONLY 或 UNTIED_ONLY。
- 在 init 顶部调用 reject_unsupported_tie_word_embeddings(type(self), config),使用原始 config,在解包 text_config 或 thinker_config 之前。
只有没有因果 LM 头的类才能被注册表测试显式豁免。
根据实现和实际支持的 checkpoint 配置选择策略,而不是根据裸配置构造函数:
- BOTH:支持绑定和未绑定配置。
- TIED_ONLY:仅支持绑定配置。
- UNTIED_ONLY:仅支持未绑定配置。
运行时辅助程序必须将 TIED_ONLY 和 UNTIED_ONLY 视为权威,仅对 BOTH 解析每 checkpoint 的配置标志。所有当前 BOTH VLM 都遵循外部 tie_word_embeddings 标志,因此在支持的 BOTH 模型实际需要另一个配置路径之前,不要添加模型特定的解析器。
对于 BOTH 和 TIED_ONLY,始终声明 _tied_weights_keys 并使用实际的 lm_head 和输入嵌入 FQN 实现 tie_weights()。不要依赖继承的 Hugging Face 绑定,并在任何语言模型交换后重新绑定。
添加策略特定测试:
- BOTH:绑定别名;未绑定不别名。
- TIED_ONLY:绑定别名;未绑定被拒绝。
- UNTIED_ONLY:权重保持分离;绑定被拒绝。
不要绑定具有有意分离的头部、不对称 vocab 大小或不拥有两个张量的阶段的架构。
对于 from_pretrained,checkpoint 中保存的 tie_word_embeddings 值是权威的,即使对于 BOTH 也是如此。NeMoAuto* 桥接器在任一方向都拒绝翻转。模型拥有的绕过该桥接器的 from_pretrained 必须调用 reject_tie_word_embeddings_flip(checkpoint_config, requested_config, model_class_name)。
2.4 MoE state-dict 适配器检查清单
对于 MoE 模型,不要停留在通用加载。适配器必须显式映射:
- Router 权重,当 Hugging Face 模型有 gate bias 或 correction-bias 张量时。
- 专家权重,保留本地和路由专家的专家索引顺序。
- Gate/up/down 投影,包括组合或拆分投影布局。
- Shared experts 与 routed experts 分开,当架构两者都有时。
添加断言预期键映射的测试,并使用微配置在完整 checkpoint 前运行数值等效测试。
不要使用这些捷径:
- 不要仅通过调用 from_pretrained() 验证适配器。
- 不要在没有明确映射原因的情况下接受缺失或多余的专家键。
- 不要更改 dtype、转置维度或 reshape 张量,除非 HF 和 NeMo 布局需要且测试证明转换可逆。
- 不要因为稠密层测试通过而跳过 router 或 shared-expert 测试。
2.5 VLM 接入检查清单
对于 VLM,确认 Hugging Face config 具有 vision_config 和 text_config,并且 architectures 指向条件生成类。从最接近的 VLM 模式文件开始,通常是 vlm-patterns.md,并比较现有实现,例如 mistral4、kimivl 或 kimi_k25_vl。
实现应显式涵盖:
- 文本骨干、视觉塔、projector 和 processor 或图像预处理假设。
- state_dict_adapter.py 中文本和视觉模块的权重映射。
- 在 _transformers/registry.py 中注册 ForConditionalGeneration 类。
- 使用图像-文本输入并验证适配器往返的微测试。
2.6 在注册表中注册
在 _transformers/registry.py 的 MODEL_ARCH_MAPPING 中添加模型:
# 在 _transformers/registry.py 中
MODEL_ARCH_MAPPING = OrderedDict([
# ... 现有条目 ...
(
"NewModelForCausalLM",
("nemo_automodel.components.models.new_model.model", "NewModelForCausalLM"),
),
])
如果模型具有自定义配置类且在其 config.json 中有 auto_map,则也在 _CUSTOM_CONFIG_REGISTRATIONS 中注册:
_CUSTOM_CONFIG_REGISTRATIONS: Dict[str, Tuple[str, str]] = {
# ... 现有条目 ...
"new_model": ("nemo_automodel.components.models.new_model.configuration", "NewModelConfig"),
}
2.7 声明能力和精度敏感参数
MODEL_ARCH_MAPPING 中注册的每个类必须声明并行能力,可以使用静态嵌套 ModelCapabilities dataclass 或变体感知的 get_capabilities(cls, config) 方法。选择恰好一种模式。能力应反映已经端到端验证的 recipe YAML。
如果模型有精度敏感参数,如 Mamba A_log / dt_bias、MoE sigmoid gate bias、attention-sink bias 或每头 scale,则声明 _keep_in_fp32_modules_strict,以便分片将这些参数保持在 fp32 计算中。参见 capabilities-and-precision.md 获取示例、变体分派规则和冻结子模块 dtype 指导。
Phase 3: 接入示例配置
本阶段仅为添加一个最小示例配置,证明新接入的架构可以加载和运行。对于通用 recipe 编写或现有 recipe 修改,使用 nemo-automodel-recipe-development。
3.1 创建示例 YAML 配置
在 examples/llm_finetune/<name>/(或 examples/vlm_finetune/<name>/)下创建示例配置:
model:
_target_: nemo_automodel.NeMoAutoModelForCausalLM.from_pretrained
pretrained_model_name_or_path: <org>/<model-name>
trainer:
max_steps: 100
gradient_clip_val: 1.0
accumulate_grad_batches: 1
# ... 数据、优化器配置 ...
3.2 验证模型加载
测试模型能从 HuggingFace checkpoint 加载:
from nemo_automodel import NeMoAutoModelForCausalLM
model = NeMoAutoModelForCausalLM.from_pretrained("<org>/<model-name>")
3.3 先使用微配置测试
在使用完整模型之前,使用微配置(1-2 层、小隐藏维度)验证,以尽早发现形状不匹配。
Phase 4: 测试
在加载完整 checkpoint 之前,创建 tests/unit_tests/models/<name>/ 并覆盖以下检查:
- 使用微配置的前向形状冒烟测试。
- state-dict 适配器往返:from_hf -> to_hf 保留映射名称、形状、dtype 和值。
- 对所有重写的注意力、MLP、归一化、RoPE 或 MoE 层的层等效测试。使用配置中的模型 dtype、相同的播种权重、相同的输入和 dtype 适当的 torch.allclose 容差。
- 验证训练几步后损失下降的简短功能测试。
Phase 5: 文档
5.1 更新模型覆盖页面
编辑 docs/model-coverage/ 中的相应文件:
- LLM/MoE:docs/model-coverage/llm/index.md
- VLM:docs/model-coverage/vlm/index.md
添加一行,包含模型名称、支持的功能(TP、PP、FSDP、LoRA、QLoRA)以及任何限制。
Phase 6: 奇偶校验测试
在实现和单元测试完成后,运行完整的奇偶校验工作流,以验证新模型产生的数值结果与参考 HuggingFace 实现一致。
运行三个级别的比较:
- state-dict 往返:加载参考 HuggingFace checkpoint,转换为 NeMo AutoModel 布局,导出回去,并验证所有映射张量在预期容差内匹配参考名称、形状、dtype 和值。
- 组件级奇偶校验:在固定种子和相同 dtype 下,将重写的注意力、MLP、归一化、RoPE 和 MoE 组件与 HuggingFace 实现进行比较。
- 端到端前向传递:在相同的 tokenized 输入上运行完整的 NeMo AutoModel 和 HuggingFace 模型,比较 logits、隐藏状态和 loss。
不要跳过此阶段。通过单元测试的模型仍可能因微妙的权重转换错误、后端差异或仅在完整奇偶校验比较中出现的 RoPE 不匹配而与 HF 发散。
关键文件参考
| 文件 | 用途 |
|---|---|
| _transformers/registry.py | MODEL_ARCH_MAPPING 和 _CUSTOM_CONFIG_REGISTRATIONS |
| components/models/common/init.py | 导出 CombinedQKVAttentionMixin、CombinedGateUpMLP、BackendConfig、HFCheckpointingMixin 等 |
| components/models/common/combined_projection/combined_qkv.py | CombinedQKVAttentionMixin,包含 setup_qkv_projection() 和 compute_qkv() |
| components/models/common/combined_projection/combined_mlp.py | CombinedGateUpMLP,具有交错 gate/up 布局 |
| components/models/common/combined_projection/state_dict_adapter.py | CombinedProjectionStateDictAdapter 基类 |
| components/models/common/hf_checkpointing_mixin.py | HFCheckpointingMixin,用于保存/加载 |
| components/models/common/utils.py | BackendConfig、initialize_rms_norm_module、initialize_linear_module、get_rope_config |
| components/moe/config.py | MoEConfig dataclass |
| components/moe/fsdp_mixin.py | MoEFSDPSyncMixin,用于分布式专家处理 |
| components/moe/layers.py | MoE 层,MoE 块的 MLP(稠密) |
| components/moe/experts.py | GroupedExperts、GroupedExpertsDeepEP、GroupedExpertsTE |
检查清单
- [ ] 获取并分析来自 HuggingFace 的 config.json
- [ ] 确定模型类型(稠密 LLM / MoE / VLM)
- [ ] 识别自定义组件(注意力、RoPE、归一化、MLP)
- [ ] 创建 components/models/<name>/ 目录
- [ ] 实现 config.py(如果需要自定义配置)
- [ ] 实现 layers.py(如果需要自定义层)
- [ ] 实现 rope_utils.py(如果需要自定义 RoPE)
- [ ] 使用 HFCheckpointingMixin 实现 model.py
- [ ] 实现 state_dict_adapter.py
- [ ] 实现 init.py 并重新导出
- [ ] 在 _transformers/registry.py 的 MODEL_ARCH_MAPPING 中注册
- [ ] 在 _CUSTOM_CONFIG_REGISTRATIONS 中注册自定义配置(如适用)
- [ ] 声明 ModelCapabilities 嵌套 dataclass(静态)或 get_capabilities(cls, config) classmethod(变体分派,例如 ERNIE-4.5 MoE 与稠密)——两者不能同时,也不能都无
- [ ] 为每个带有因果 lm_head 的类声明 TieSupport 并调用构造函数守卫(或添加显式无头豁免)——参见 §2.3
- [ ] 为 BOTH / TIED_ONLY 添加显式 _tied_weights_keys 和 tie_weights(),并添加策略特定的别名和拒绝测试——参见 §2.3
- [ ] 如果任何绕过 NeMoAuto* 桥接器的模型自有 from_pretrained 防止 checkpoint 翻转,则添加守卫——参见 §2.3
- [ ] 创建示例 YAML 配置
- [ ] 通过 NeMoAutoModelForCausalLM.from_pretrained() 验证模型加载
- [ ] 创建单元测试(前向形状、state_dict 往返)
- [ ] 为每个内部 fp32 参数声明 _keep_in_fp32_modules_strict(SSM A_log/dt_bias、Mamba D(当参考为 fp32 时)、MoE gate bias、attention-sink bias、scale 等)——参见 §2.7
- [ ] 为每个重写的层创建层等效测试(匹配模型 dtype)
- [ ] 创建功能测试(训练 loss 下降)
- [ ] 更新 docs/model-coverage 页面
- [ ] 运行 state-dict 往返、组件奇偶校验和 E2E 前向传递奇偶校验
- [ ] 在模块底部设置 ModelClass = <Name>ForCausalLM