Skip to content

Commit 4ec85af

Browse files
authored
【Hackathon 8th No.29】RFC:在 PaddleNLP 中复现ModernBERT模型 (#1104)
* Create 20250402_add_modernbert_for_paddlenlp.md * Update 20250402_add_modernbert_for_paddlenlp.md
1 parent 92a8ea8 commit 4ec85af

File tree

1 file changed

+237
-0
lines changed

1 file changed

+237
-0
lines changed
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
# 在 PaddleNLP 中复现 ModernBert 模型
2+
3+
| 任务名称 | 在 PaddleNLP 中复现 ModernBert 模型 |
4+
| --- | --- |
5+
| 提交作者 | robinbg |
6+
| 提交时间 | 2025-04-02 |
7+
| 版本号 | V1.0 |
8+
| 依赖飞桨版本 | develop |
9+
| 文件名 | 20250402_add_modernbert_for_paddlenlp.md |
10+
11+
# 一、概述
12+
13+
## 1、相关背景
14+
ModernBert 是一种现代优化的 BERT 变体,在 2 万亿个词元上训练,支持 8192 长度的序列。相比原始 BERT,ModernBert 在性能与模型大小之间提供了更好的权衡,主要通过以下改进:
15+
16+
* 使用旋转位置编码 (Rotary Positional Embeddings),替代传统的绝对位置编码
17+
* 采用 GeGLU 激活函数,替代传统的 GELU
18+
* 实现滑动窗口注意力机制 (Sliding Window Attention),有效处理长序列
19+
* 针对推理速度优化的架构设计
20+
21+
这些改进使得 ModernBert 在相同参数量下具有更强的性能,且更适合处理长序列输入。
22+
23+
## 2、功能目标
24+
在 PaddleNLP 中实现 ModernBert 模型,对齐 HuggingFace transformers 中的实现,确保在 fp32 下误差小于 1e-5,bf16 下误差小于 1e-3。
25+
26+
## 3、意义
27+
ModernBert 模型的引入将增强 PaddleNLP 处理长文本的能力,为用户提供更高效的预训练模型选择,同时保持与 HuggingFace 生态的兼容性。
28+
29+
# 二、飞桨现状
30+
PaddleNLP 目前已支持多种 Transformer 架构模型,包括 BERT、RoBERTa、ERNIE 等,但尚未支持具有旋转位置编码、GeGLU 激活函数和优化的长序列处理能力的 ModernBert 模型。现有的 BERT 实现可以作为实现 ModernBert 的基础,但需要进行架构上的修改以适配 ModernBert 的特性。
31+
32+
# 三、业内方案调研
33+
目前,HuggingFace transformers 库已实现 ModernBert 模型,地址为:
34+
https://github.com/huggingface/transformers/tree/main/src/transformers/models/modernbert
35+
36+
该实现包含了完整的模型架构、预训练权重以及相关的文档,是 PaddleNLP 实现 ModernBert 的主要参考。ModernBert 模型在 HuggingFace 上已有多个开源检查点,并展示了其在多种下游任务上的出色表现。
37+
38+
# 四、对比分析
39+
与 PaddleNLP 现有的 BERT 实现相比,ModernBert 需要做以下关键改进:
40+
41+
1. 位置编码:从静态绝对位置编码转变为旋转位置编码 (RoPE)
42+
2. 激活函数:从 GELU 转变为 GeGLU
43+
3. 注意力机制:实现滑动窗口注意力,支持处理长序列
44+
4. 模型配置:添加新的配置参数以支持 ModernBert 特有的功能
45+
46+
这些改进将使 ModernBert 能够处理更长的序列(最大 8192 个词元),同时提供更好的性能-大小比。
47+
48+
# 五、设计思路与实现方案
49+
ModernBert 模型在 PaddleNLP 中的实现将参考现有的 BERT 实现结构,主要包含以下几个关键文件:
50+
51+
1. configuration.py:定义 ModernBertConfig 类,包含模型所需的配置参数
52+
2. modeling.py:实现模型的核心架构
53+
3. tokenizer.py:与 BERT tokenizer 兼容,复用现有实现
54+
55+
## 1. ModernBertConfig 配置类
56+
`paddlenlp/transformers/modernbert/configuration.py` 中,需要定义 ModernBertConfig 类,继承自 PretrainedConfig:
57+
58+
```python
59+
from paddlenlp.transformers.configuration_utils import PretrainedConfig
60+
61+
class ModernBertConfig(PretrainedConfig):
62+
"""
63+
ModernBert 模型的配置类,包含所有架构参数
64+
"""
65+
def __init__(
66+
self,
67+
vocab_size=30522,
68+
hidden_size=768,
69+
num_hidden_layers=12,
70+
num_attention_heads=12,
71+
intermediate_size=3072,
72+
hidden_act="geglu", # 使用 GeGLU 替代 GELU
73+
hidden_dropout_prob=0.1,
74+
attention_probs_dropout_prob=0.1,
75+
max_position_embeddings=8192, # 支持更长的序列
76+
type_vocab_size=2,
77+
initializer_range=0.02,
78+
layer_norm_eps=1e-12,
79+
pad_token_id=0,
80+
sliding_window_size=512, # 滑动窗口大小
81+
tie_word_embeddings=True,
82+
tensor_parallel_degree=1, # 模型并行度
83+
**kwargs
84+
):
85+
super().__init__(pad_token_id=pad_token_id, **kwargs)
86+
self.vocab_size = vocab_size
87+
self.hidden_size = hidden_size
88+
self.num_hidden_layers = num_hidden_layers
89+
self.num_attention_heads = num_attention_heads
90+
self.hidden_act = hidden_act
91+
self.intermediate_size = intermediate_size
92+
self.hidden_dropout_prob = hidden_dropout_prob
93+
self.attention_probs_dropout_prob = attention_probs_dropout_prob
94+
self.max_position_embeddings = max_position_embeddings
95+
self.type_vocab_size = type_vocab_size
96+
self.initializer_range = initializer_range
97+
self.layer_norm_eps = layer_norm_eps
98+
self.sliding_window_size = sliding_window_size
99+
self.tie_word_embeddings = tie_word_embeddings
100+
self.tensor_parallel_degree = tensor_parallel_degree
101+
```
102+
103+
## 2. 实现旋转位置编码 (RoPE)
104+
`paddlenlp/transformers/modernbert/modeling.py` 中,需要实现旋转位置编码:
105+
106+
```python
107+
def apply_rotary_position_embeddings(q, k, cos, sin, position_ids):
108+
# 实现旋转位置编码的逻辑
109+
# 参考 HuggingFace transformers 中 ModernBert 的实现
110+
```
111+
112+
## 3. 实现 GeGLU 激活函数
113+
`paddlenlp/transformers/modernbert/modeling.py` 中,实现 GeGLU 激活函数:
114+
115+
```python
116+
def geglu(x, gate):
117+
# 实现 GeGLU 激活函数
118+
# GeGLU(x, gate) = x * GELU(gate)
119+
```
120+
121+
## 4. 实现滑动窗口注意力
122+
在注意力机制中实现滑动窗口注意力,以高效处理长序列:
123+
124+
```python
125+
def sliding_window_attention(query, key, value, window_size, attention_mask=None):
126+
# 实现滑动窗口注意力
127+
# 限制每个 token 只能与其左右 window_size 范围内的 token 进行注意力计算
128+
```
129+
130+
## 5. 实现参数转换方法
131+
`paddlenlp/transformers/modernbert/modeling.py` 中,实现 _get_name_mappings 方法用于参数转换:
132+
133+
```python
134+
@classmethod
135+
def _get_name_mappings(cls, config: ModernBertConfig) -> list[StateDictNameMapping]:
136+
# 实现参数转换方法,用于将 HuggingFace 权重映射到 PaddleNLP 格式
137+
# 参考 LLaMA 代码实现:https://github.com/PaddlePaddle/PaddleNLP/blob/bfd053db0897943f5d4d116dde755dbf21d18b23/paddlenlp/transformers/llama/modeling.py#L1334-L1366
138+
mappings = []
139+
model_mappings = []
140+
141+
# 添加基本参数映射
142+
143+
# 添加层级参数映射
144+
145+
# 初始化名称映射
146+
147+
return mappings
148+
```
149+
150+
## 6. 模型并行实现
151+
`paddlenlp/transformers/modernbert/modeling.py` 中,实现模型并行相关代码:
152+
153+
```python
154+
# 在相关模块中添加模型并行支持
155+
if config.tensor_parallel_degree > 1:
156+
# 实现张量并行化处理
157+
# 实现权重分片
158+
# 实现通信原语封装
159+
# 参考 LLaMA 代码实现:https://github.com/PaddlePaddle/PaddleNLP/blob/bfd053db0897943f5d4d116dde755dbf21d18b23/paddlenlp/transformers/llama/modeling.py#L775-L813
160+
```
161+
162+
**注意:优先完成单卡模型组网,后续再支持模型并行**
163+
164+
# 六、测试验收的考量
165+
ModernBert 模型的实现需要通过以下测试验证:
166+
167+
1. 精度对齐测试:
168+
* 使用 [PaDiff](https://github.com/PaddlePaddle/PaDiff) 工具验证与 PyTorch 实现的对齐程度
169+
* 在 fp32 下误差需小于 1e-5
170+
* 在 bf16 下误差需小于 1e-3
171+
172+
2. 单元测试:
173+
* 为 ModernBert 添加单元测试,验证各个组件的功能正确性
174+
* 测试 RoPE、GeGLU、滑动窗口注意力等关键功能
175+
* 测试 _get_name_mappings 方法的正确性
176+
177+
3. 功能测试:
178+
* 验证模型能够正确处理不同长度的输入序列
179+
* 验证模型在下游任务(如文本分类、序列标注等)上的性能
180+
181+
4. 兼容性测试:
182+
* 验证与 HuggingFace 预训练权重的兼容性
183+
* 验证与 PaddleNLP 生态的兼容性
184+
185+
5. 模型并行测试(后续阶段):
186+
* 验证模型并行功能的正确性
187+
* 验证多卡训练和推理的性能
188+
189+
# 七、可行性分析和排期规划
190+
基于现有的 BERT 实现和 HuggingFace 的 ModernBert 实现,在 PaddleNLP 中复现 ModernBert 是可行的。实现计划如下:
191+
192+
1. 第一阶段(1周):
193+
* 分析 HuggingFace ModernBert 代码结构
194+
* 设计 PaddleNLP 中的 ModernBert 实现方案
195+
* 实现 ModernBertConfig 类
196+
197+
2. 第二阶段(2周):
198+
* 实现 ModernBert 核心组件:RoPE、GeGLU、滑动窗口注意力
199+
* 实现 ModernBertModel 类及相关的下游任务模型类
200+
* 实现 _get_name_mappings 方法
201+
202+
3. 第三阶段(1周):
203+
* 实现与 HuggingFace 权重兼容的转换函数
204+
* 进行精度对齐验证
205+
* 完成单卡模型功能测试
206+
207+
4. 第四阶段(1周):
208+
* 编写单元测试和文档
209+
* 修复问题和优化性能
210+
* 规划模型并行实现方案
211+
212+
5. 第五阶段(2周,后续阶段):
213+
* 实现模型并行相关代码
214+
* 进行模型并行功能测试
215+
* 完善模型并行文档
216+
217+
# 八、影响面
218+
ModernBert 的实现将对 PaddleNLP 产生以下影响:
219+
220+
1. 增强 PaddleNLP 处理长文本的能力,支持最大 8192 长度的序列
221+
2. 提供更高效的预训练模型选择,在相同参数量下提供更好的性能
222+
3. 完善 PaddleNLP 的模型生态,与业界最新进展保持同步
223+
4. 为后续实现更多基于旋转位置编码和 GeGLU 的模型奠定基础
224+
5. 增强 PaddleNLP 的分布式训练能力,支持大规模模型训练
225+
226+
# 名词解释
227+
* RoPE (Rotary Position Embedding): 旋转位置编码,一种能更好处理相对位置信息的位置编码方法
228+
* GeGLU: Gated GELU 激活函数,相比传统的 GELU 提供更好的性能
229+
* 滑动窗口注意力: 一种注意力计算优化方式,限制每个 token 只关注局部上下文,提高长序列处理效率
230+
* 模型并行: 将模型参数分布在多个设备上进行训练和推理的技术
231+
232+
# 附件及参考资料
233+
1. [ModernBert 论文](https://arxiv.org/abs/2412.13663)
234+
2. [HuggingFace ModernBert 实现](https://github.com/huggingface/transformers/tree/main/src/transformers/models/modernbert)
235+
3. [PaddleNLP 模型对齐指南](https://paddlenlp.readthedocs.io/zh/latest/community/contribute_models/model_alignment.html)
236+
4. [LLaMA _get_name_mappings 方法实现](https://github.com/PaddlePaddle/PaddleNLP/blob/bfd053db0897943f5d4d116dde755dbf21d18b23/paddlenlp/transformers/llama/modeling.py#L1334-L1366)
237+
5. [LLaMA 模型并行实现](https://github.com/PaddlePaddle/PaddleNLP/blob/bfd053db0897943f5d4d116dde755dbf21d18b23/paddlenlp/transformers/llama/modeling.py#L775-L813)

0 commit comments

Comments
 (0)