Skip to content

Commit a52af67

Browse files
committed
[103] 新增tie_weights 能力 提交rfc文档 v3
1 parent 6929649 commit a52af67

File tree

8 files changed

+92
-5
lines changed

8 files changed

+92
-5
lines changed

docs/community/rfcs/20230304_api_design_for_tie_weight_task_103.md

Lines changed: 92 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
|API名称 | 新增API名称 |
66
|---|----------------------------------------------------|
77
|提交作者<input type="checkbox" class="rowselector hidden"> | 丘文波, 刘旺旺 |
8-
|提交时间<input type="checkbox" class="rowselector hidden"> | 2022-03-05 |
9-
|版本号 | V2 |
8+
|提交时间<input type="checkbox" class="rowselector hidden"> | 2022-03-10 |
9+
|版本号 | V3 |
1010
|依赖飞桨版本<input type="checkbox" class="rowselector hidden"> | 如无特殊情况,都应基于develop版本开发 |
1111
|文件名 | 20230304_api_design_for_tie_weight_task_103.md<br> |
1212

@@ -78,8 +78,51 @@ def tie_weights(self):
7878
self._tie_or_clone_weights(output_embeddings, self.get_input_embeddings())
7979
```
8080

81+
(3) [代码链接3](https://github.com/PaddlePaddle/PaddleNLP/blob/develop/paddlenlp/transformers/ernie/modeling.py#L748)
82+
```python
83+
class ErnieLMPredictionHead(nn.Layer):
84+
r"""
85+
Ernie Model with a `language modeling` head on top.
86+
"""
87+
88+
def __init__(
89+
self,
90+
config: ErnieConfig,
91+
embedding_weights=None,
92+
weight_attr=None,
93+
):
94+
super(ErnieLMPredictionHead, self).__init__()
95+
96+
self.transform = nn.Linear(config.hidden_size, config.hidden_size, weight_attr=weight_attr)
97+
self.activation = getattr(nn.functional, config.hidden_act)
98+
self.layer_norm = nn.LayerNorm(config.hidden_size)
99+
self.decoder_weight = (
100+
self.create_parameter(
101+
shape=[config.vocab_size, config.hidden_size],
102+
dtype=self.transform.weight.dtype,
103+
attr=weight_attr,
104+
is_bias=False,
105+
)
106+
if embedding_weights is None
107+
else embedding_weights
108+
)
109+
self.decoder_bias = self.create_parameter(
110+
shape=[config.vocab_size], dtype=self.decoder_weight.dtype, is_bias=True
111+
)
112+
```
113+
114+
115+
其实paddlenlp内大部分的tie_weights实现是直接在模型layer定义层面实现的,见[代码](https://github.com/PaddlePaddle/PaddleNLP/blob/develop/paddlenlp/transformers/ernie/modeling.py#L748)
116+
,而不是类似transformers一样在模型以外统一实现的。这个项目的目标就是看一下能否在模型外统一实现,而不用每个模型都自己实现一次
117+
118+
paddle里面tie_weghts实现主要有两种方式:
119+
* 一种在modeling.py中定义了tie_weghts函数,相应的模型也实现了get_input_embeding()和get_output_embeding()来获取输入和输出embeding层权重,然后通过赋值方式进行绑定。如上面的代码链接(1)(2)
120+
* 另外一种是 在定义模型层的时候 直接将输入input_embeding的weight,赋值给输出层weight. 将embedding的weight直接传给head来构建linear输出层,期望是在get_input_embeding()拿到weight,然后传给head层,如上面代码链接(3)
121+
81122

82-
最好是给基础模型加上tie weight的函数,减少调用者的开发.
123+
124+
最好是在模型[基类里面model_utils.py#L897](https://github.com/PaddlePaddle/PaddleNLP/blob/be80a3e30fb681e53773c265babe611d4df62ead/paddlenlp/transformers/model_utils.py#L897)
125+
去统一实现 tie_weights,减少调用者的开发.
83126

84127
# 三、业内方案调研
85128
描述业内深度学习框架如何实现此功能,包括与此功能相关的现状、未来趋势;调研的范围包括不限于TensorFlow、PyTorch、NumPy等
@@ -152,15 +195,16 @@ self.fc2 = Linear(in_channels, out_embed_dim)
152195
paddle和 huggingface的transformers 都是基于动态图进行开发, 所以准备参照huggingface的transformers 的 tie weight 函数思路去实现功能.
153196

154197
# 五、设计思路与实现方案
155-
156198
参考huggingface的 transformers中的实现思路来基于paddle进行开发
157199

158200
实现tie_weight函数步骤:
159-
160201
1. 获取模型input embedding 权重对象 A
161202
2. 获取模型 output embedding 权重对象 B
162203
3. 让A和B 都指向同一个权重值
163204

205+
206+
207+
164208
## 命名与参数设计
165209
参考:[飞桨API 设计及命名规范](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/dev_guides/api_contributing_guides/api_design_guidelines_standard_cn.html)
166210
## 底层OP设计
@@ -169,7 +213,50 @@ paddle和 huggingface的transformers 都是基于动态图进行开发, 所以
169213
# 六、测试和验收的考量
170214
参考:[新增API 测试及验收规范](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/dev_guides/api_contributing_guides/api_accpetance_criteria_cn.html)
171215

216+
测试tie_weight有两个办法:
217+
* 直接判断输出层weight和输入层weight的id,如果一致即通过,否则Failed.
218+
* 训练几个step,经过几个反向后,看下输出层weight和输入层weight是否一致,如果一致即通过,否则Failed.
219+
220+
用过id的一致性判断是否绑定成功, 简单高效,后面准备采用这种方式进行单侧:
221+
构建单元测试, 测试模型的get_input_embeding得到的权重的id 和get_output_embeding 得到的权重id 是都一致, 如果是一致就通过,都则不通过
222+
223+
224+
172225
# 七、可行性分析和排期规划
226+
227+
设计一个小脚本验证一下这种方式的有效性:
228+
```python
229+
import numpy as np
230+
from paddle.nn import Embedding
231+
232+
"""step1 定义两个不同的embedding 对象 AA 和 BB"""
233+
print('------------step1')
234+
AA = Embedding(1,2)
235+
BB = Embedding(1,2)
236+
237+
AA.weight = BB.weight # 进行权重的绑定
238+
239+
""" step2 测试一下绑定结果"""
240+
print('------------step2')
241+
print('检测 AA 和 BB 的id是否一致:', AA is BB,id(AA), id(BB)) # AA 和 BB 的id 不一致
242+
print('检测 AA.weight 和 BB.weight 的id是否一致:',AA.weight is BB.weight,id(AA.weight), id(BB.weight)) # 但是AA.weight 和 BB.weight 的id是一致的
243+
244+
print("AA.weight: ",AA.weight)
245+
print("BB.weight: ",BB.weight)
246+
247+
248+
249+
""" step3 尝试修改一下AA的weight的值 BB的weight的值是否也跟着会一起修改"""
250+
# 修改一下其中一个AA 的权重值, 看一下 BB的权重值会不会变化
251+
print('------------step3')
252+
AA.weight.set_value(np.array([[4.0,6.0]],dtype=np.float32))
253+
254+
print('检测 修改后的 AA.weight 和 BB.weight 的id是否一致:',AA.weight is BB.weight,id(AA.weight), id(BB.weight)) # AA.weight 和 BB.weight 的id是一致的
255+
print("AA.weight 修改后的值: ",AA.weight)
256+
print("BB.weight:",BB.weight)
257+
258+
```
259+
173260
时间和开发排期规划,主要milestone
174261
- 3.10 跟官方确认好开发思路
175262
- 3.17 提交实现代码

docs/community/rfcs/img.png

-212 KB
Binary file not shown.

docs/community/rfcs/img_1.png

-212 KB
Binary file not shown.

docs/community/rfcs/img_2.png

-212 KB
Binary file not shown.

docs/community/rfcs/img_3.png

-735 KB
Binary file not shown.

docs/community/rfcs/img_4.png

-329 KB
Binary file not shown.

docs/community/rfcs/img_5.png

-550 KB
Binary file not shown.

docs/community/rfcs/img_6.png

-350 KB
Binary file not shown.

0 commit comments

Comments
 (0)