使用方法:
1构建modular__**.py文件
1.1分析基础模型
在开始构建 modular_xxx.py文件之前,首先需要深入分析要基于的基础模型。这个基础模型通常是 paddle/ Transformers 库中已有的成熟模型。
1.1.1 选择合适的基础模型
选择标准:
- 架构相似性:新模型与基础模型的架构应尽可能相似
- 任务类型:基础模型应支持相同的任务(如文本生成、分类等)
- 代码质量:选择代码结构清晰、文档完善的模型
常见基础模型选择:
# 基于BERT架构的模型
基础模型:BertModel, RobertaModel, DebertaModel
# 基于GPT架构的模型
基础模型:GPT2Model, LlamaModel, GPTNeoXModel
# 基于Encoder-Decoder架构的模型
基础模型:T5Model, BartModel, PegasusModel
1.1.2 分析基础模型的关键组件
对于选定的基础模型,需要分析其核心组件:
1. 配置文件 (configuration_xxx.py)
# 分析配置参数
# 关注:hidden_size, num_attention_heads, num_hidden_layers,
# vocab_size, max_position_embeddings 等关键参数
2. 模型架构 (modeling_xxx.py)
# 分析模型类结构
import inspect
from transformers import BertModel
# 查看类的方法和属性
print(inspect.getmembers(BertModel, predicate=inspect.ismethod))
# 重点关注:__init__, forward, 以及其他关键方法
1.1.3 识别需要修改的部分
基于分析结果,确定哪些部分需要自定义:
| 组件 | 是否需要修改 | 修改原因 |
|---|---|---|
| 配置参数 | ✅ 通常需要 | 调整模型尺寸、注意力头数等 |
| 前向传播逻辑 | ✅ 通常需要 | 适配新的架构变化 |
| 注意力机制 | ⚠️ 可能需要 | 如果使用不同的注意力机制 |
| 位置编码 | ⚠️ 可能需要 | 如果使用不同的位置编码方案 |
| 输出头 | ✅ 通常需要 | 适配不同的任务需求 |
| 初始化方法 | ⚠️ 可能需要 | 如果使用不同的初始化策略 |
1.2编写modular文件结构
在完成基础模型分析后,您需要创建一个结构清晰、符合规范的 modular_xxx.py文件。这个文件是代码生成器的模板,其结构直接决定了最终输出的 modeling_xxx.py文件的质量。
1.2.1 文件基本结构
一个标准的 modular_xxx.py文件应包含以下部分,按顺序排列:
# coding=utf-8
# 版权声明 (可选)
""" 新模型的简要文档字符串 (可选) """
# 1. 导入部分
from typing import Optional, Tuple, Union
import torch
import torch.utils.checkpoint
from torch import nn
from torch.nn import CrossEntropyLoss
# 从基础模型导入必要的组件
from transformers.models.llama.modeling_llama import (
LlamaConfig,
LlamaModel,
LlamaForCausalLM,
LlamaDecoderLayer,
# ... 其他需要继承或引用的组件
)
from transformers import PreTrainedModel, PreTrainedTokenizerBase
from transformers.utils import logging
logger = logging.get_logger(__name__)
# 3. 注意力机制 (如果需要自定义)
class MyNewAttention(nn.Module):
"""自定义注意力机制"""
def __init__(self, config: MyNewModelConfig):
super().__init__()
# 实现自定义注意力逻辑
pass
def forward(self, hidden_states, attention_mask=None):
# 实现前向传播
pass
# 4. 解码器层 (如果需要修改层结构)
class MyNewDecoderLayer(LlamaDecoderLayer):
"""
自定义解码器层,继承自LlamaDecoderLayer
重写需要修改的方法
"""
def __init__(self, config: MyNewModelConfig):
super().__init__(config)
# 替换或修改注意力机制
if config.use_custom_attention:
self.self_attn = MyNewAttention(config)
def forward(self, hidden_states, attention_mask=None):
# 可以完全重写或部分修改父类逻辑
if self.config.use_custom_attention:
# 自定义逻辑
return self._custom_forward(hidden_states, attention_mask)
else:
# 回退到父类逻辑
return super().forward(hidden_states, attention_mask)
def _custom_forward(self, hidden_states, attention_mask):
"""自定义前向传播实现"""
pass
# 5. 主模型类
class MyNewModel(LlamaModel):
"""
我的新模型主类,继承自LlamaModel
通常需要重写 __init__ 和 forward 方法
"""
def __init__(self, config: MyNewModelConfig):
super().__init__(config)
# 替换解码器层
self.layers = nn.ModuleList([
MyNewDecoderLayer(config) for _ in range(config.num_hidden_layers)
])
# 其他自定义初始化
self.custom_layer = nn.Linear(config.hidden_size, config.custom_param)
def forward(self, input_ids, attention_mask=None):
# 调用父类获取基础输出
super().forward(input_ids, attention_mask)
# 添加自定义处理
hidden_states = outputs[0]
custom_output = self.custom_layer(hidden_states)
# 返回修改后的输出
return (custom_output,) + outputs[1:]
# 6. 任务特定模型 (如用于因果语言建模)
class MyNewForCausalLM(LlamaForCausalLM):
"""
用于因果语言建模的我的新模型
"""
def __init__(self, config: MyNewModelConfig):
super().__init__(config)
# 替换主模型
self.model = MyNewModel(config)
def forward(self, input_ids, attention_mask=None, labels=None):
# 可以完全重写或扩展父类逻辑
outputs = self.model(input_ids, attention_mask=attention_mask)
# 计算损失等
loss = None
if labels is not None:
# 计算损失逻辑
pass
return {"loss": loss, "logits": outputs[0]}
# 8. 更新 __all__ 列表,声明哪些类应该被导出
__all__ = [
"MyNewModelConfig",
"MyNewModel",
"MyNewForCausalLM",
"MyNewDecoderLayer",
]
1.2.2 关键编写原则
清晰的继承关系
# ✅ 正确:明确继承关系
class MyNewModel(LlamaModel):
pass
# ❌ 避免:直接继承过于通用的基类
class MyNewModel(PreTrainedModel):
pass # 这会导致需要实现大量抽象方法
最小化重写
# ✅ 正确:只重写需要修改的方法
class MyNewDecoderLayer(LlamaDecoderLayer):
def __init__(self, config):
super().__init__(config) # 先调用父类初始化
# 只修改需要定制的部分
if config.use_custom_attention:
self.self_attn = CustomAttention(config)
# ❌ 避免:完全重写整个类,除非必要
保持接口一致性:
def forward(self, input_ids, attention_mask=None, **kwargs):
# 处理自定义逻辑
result = custom_processing(input_ids)
# 调用父类实现剩余逻辑
super().forward(result, attention_mask, **kwargs)
充分利用现有组件:
# ✅ 正确:复用基础模型的组件
from transformers.models.llama.modeling_llama import (
LlamaRMSNorm,
LlamaRotaryEmbedding,
apply_rotary_pos_emb,
)
2.执行转换命令
通过一个用户主脚本main来驱动整个流程。其标准使用方式如下:
#自动查找各个模型文件下的modular__**.py模块化构建代码,执行转换生成modeling__***.py文件
python main.py
自动化处理流水线
最终输出
最终,在模型对应的目录下(如 src/transformers/models/qwen2/)会生成目标文件:
modeling_qwen2.py:这是唯一的输出文件,也是最终成果。 它包含了:模型架构(如Qwen2Model,Qwen2ForCausalLM)内联的配置类(如Qwen2Config)所有相关的函数、工具类和常量****正确的导入语句(只导入标准库或 transformers 的通用组件)文件顶部的警告注释:明确告知开发者此文件为自动生成,不可手动编辑。