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)
152195paddle和 huggingface的transformers 都是基于动态图进行开发, 所以准备参照huggingface的transformers 的 tie weight 函数思路去实现功能.
153196
154197# 五、设计思路与实现方案
155-
156198参考huggingface的 transformers中的实现思路来基于paddle进行开发
157199
158200实现tie_weight函数步骤:
159-
1602011 . 获取模型input embedding 权重对象 A
1612022 . 获取模型 output embedding 权重对象 B
1622033 . 让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 提交实现代码
0 commit comments