1. transfomerXL
1.1 transformer的缺点
Transformer编码固定长度的上下文,即将一个长的文本序列截断为几百个字符的固定长度片段,然后分别编码每个片段,片段之间没有任何的信息交互。比如BERT,序列长度的极限一般在512。总结如下:
- Transformer无法建模超过固定长度的依赖关系,对长文本编码效果差
- Transformer把要处理的文本分割成等长的片段,导致上下文碎片化
1.2 transfomerXL的改进
- 提出片段级递归机制(segment-level recurrence mechanism),引入一个记忆模块(类似于cache或cell),循环用来建模片段之间的联系;使得长距离依赖的建模成为可能;使得片段之间产生交互,解决上下文碎片化问题。
- 提出相对位置编码机制(relative position embedding scheme),代替绝对位置编码
1.3 transformerXL模型架构
(1)Segment-Level recurrence state reuse
在训练期间,处理每个段后,我们将隐藏层状态序列存储起来,在处理下一段时作为上下文信息扩展。但是从下图我们可以看到:每个位置都只拿其前面segment_length个词的隐藏层状态向量做上下文信息。我们知道这个范围的隐藏层状态向量也包含了前面不再这个范围的上下文信息,因此它能够建模长期依赖信息,并且避免上下文碎片
公式表示如下:
令每个片段长为
L
L
L,相邻的两个段为
S
t
=
[
x
t
,
1
,
x
t
,
2
,
…
,
x
t
,
L
]
S_{t}=\left[x_{t, 1}, x_{t, 2}, \ldots, x_{t, L}\right]
St=[xt,1,xt,2,…,xt,L] 和
S
t
+
1
=
[
x
t
+
1
,
1
,
x
t
+
1
,
2
,
…
,
x
t
+
1
,
L
]
S_{t+1}=\left[x_{t+1,1}, x_{t+1,2}, \ldots, x_{t+1, L}\right]
St+1=[xt+1,1,xt+1,2,…,xt+1,L],
S
t
S_t
St 产生的第
n
n
n层的隐藏层状态序列为
h
t
n
∈
R
L
×
d
h_{t}^{n} \in R^{L \times d}
htn∈RL×d,
d
d
d 是隐藏层的维度;然后
S
t
+
1
S_{t + 1}
St+1 的第
n
n
n 层的隐藏层序列计算公式如下:
h ~ τ + 1 n − 1 = [ SG ( h τ n − 1 ) ∘ h τ + 1 n − 1 ] \widetilde{\mathbf{h}}_{\tau+1}^{n-1}=\left[\operatorname{SG}\left(\mathbf{h}_{\tau}^{n-1}\right) \circ \mathbf{h}_{\tau+1}^{n-1}\right] h τ+1n−1=[SG(hτn−1)∘hτ+1n−1]
q τ + 1 n , k τ + 1 n , v τ + 1 n = h τ + 1 n − 1 W q ⊤ , h ~ τ + 1 n − 1 W k ⊤ , h ~ τ + 1 n − 1 W v ⊤ \mathbf{q}_{\tau+1}^{n}, \mathbf{k}_{\tau+1}^{n}, \mathbf{v}_{\tau+1}^{n}=\mathbf{h}_{\tau+1}^{n-1} \mathbf{W}_{q}^{\top}, \widetilde{\mathbf{h}}_{\tau+1}^{n-1} \mathbf{W}_{k}^{\top}, \widetilde{\mathbf{h}}_{\tau+1}^{n-1} \mathbf{W}_{v}^{\top} qτ+1n,kτ+1n,vτ+1n=hτ+1n−1Wq⊤,h τ+1n−1Wk⊤,h τ+1n−1Wv⊤
h τ + 1 n = Transformer-Layer ( q τ + 1 n , k τ + 1 n , v τ + 1 n ) \mathbf{h}_{\tau+1}^{n}=\text { Transformer-Layer }\left(\mathbf{q}_{\tau+1}^{n}, \mathbf{k}_{\tau+1}^{n}, \mathbf{v}_{\tau+1}^{n}\right) hτ+1n= Transformer-Layer (qτ+1n,kτ+1n,vτ+1n)
其中: S G ( ⋅ ) S G ( ⋅ ) SG(⋅)表示梯度停止(stop-gradient), [ h u ◦ h v ] [ h_u ◦ h_v ] [hu◦hv]表示隐藏层状态序列的拼接; W W W是模型的参数; τ + 1 \tau+1 τ+1表示下一片段, τ \tau τ表示上一片段
- 第一个式子表示将上一片段的第 n − 1 n-1 n−1 层的隐藏状态和下一片段的第 n − 1 n-1 n−1 层的隐层拼接在一起
- 从第二个式子可以看出它引入了上一片段的隐层【表示】只会用在key和value上,对于query还是保持原来的样子。这样做也好理解,query只是表示查询的词,而key,value表示的是这个查询的词的相关信息,我们要改变的是只是信息,因此只要在key,value中引入上一片段的信息就可以了,剩下的就和Transformer一致
1.4 Relative position encodings
标准的Transformer使用是绝对位置编码,将位置编码与embedding相加作为输入,如果简单的将这个思想使用到transformerXL的模型中可以得到下面的公式:
h
t
+
1
=
f
(
h
t
,
E
s
t
+
1
+
U
1
:
L
)
h
t
=
f
(
h
t
−
1
,
E
s
t
+
U
1
:
L
)
\begin{aligned} h_{t+1} &=f\left(h_{t}, E_{s t+1}+U_{1: L}\right) \\ h_{t} &=f\left(h_{t-1}, E_{s_{t}}+U_{1: L}\right) \end{aligned}
ht+1ht=f(ht,Est+1+U1:L)=f(ht−1,Est+U1:L)
其中: E s t ∈ R L × d E_{s_{t}} \in R^{L \times d} Est∈RL×d 为 S t S_t St的embedding矩阵, f f f为transformer函数, U 1 : L U_{1: L} U1:L 为 1-L 的编码
由上面公式我们可以看出 E s t + 1 E_{s_{t+1}} Est+1 和 E s t E_{s_t} Est 使用相同的位置编码 U 1 : L U_{1: L} U1:L 会导致模型无法区分 x t , j x_{t,j} xt,j和 x t + 1 , j x_{t+1,j} xt+1,j的位置
为了避免上面的问题,基本思想是仅对隐藏状态的相对位置信息进行编码。不是将位置embeding静态地加入到词embeding中去,而是将位置embeding信息加入到每层的注意力分数中去,即将embeding信息加入到每层隐藏层状态序列中去
对于标准的Transformer,注意力分数的计算公式如下:
修改后的Transformer(transformerXL),注意力分数的计算公式如下
其中,R是正弦编码的矩阵,是不可学习的参数
这里我们将key向量的线性映射矩阵写成了两部分: W k , E W k , R W_{k, E} \quad W_{k, R} Wk,EWk,R 分别来生成词embeding的key向量和相对位置的embeding的key向量;并使用可训练的 u , v u, v u,v向量代替查询词 x i x_i xi的位置embeding, 原因在于原因:询词 x i x_i xi和待查询词 x j x_j xj位置信息是一样的,所以对所有的查询词都使用可训练的向量 u , v u, v u,v来表示其位置信息
2. RoBERT
2.1 改进1:使用动态mask
原始的 BERT 在训练之前就把数据 Mask 了,然后在整个训练过程中都是保持数据不变的,称为 Static Mask。即同一个句子在整个训练过程中,Mask 掉的单词都是一样的。
RoBERTa 使用了一种 Dynamic Mask 的策略,将整个数据集复制 10 次,然后在 10 个数据集上都 Mask 一次,也就是每一个句子都会有 10 种 Mask 结果。使用 10 个数据集训练 BERT
2.2 其他改进
- 更大的数据集
- 更大的batch
- 去掉NSP Loss
3. ALBERT
3.1.Introduction
通常来说,模型深度与模型效果成正比,但是模型越深也会带来动则数亿甚至数十亿的参数量,这就对计算内存有了一定的要求。而在分布式训练中,通信开销与参数也成正比,所以其对训练速度也产生了显著的影响。
目前已有的解决方案要么是并行化,要么是内存管理,但是都没有解决通信开销,即降低模型本身的参数。
在本文,作者设计一种轻量级的 Bert,并取名为 ALBERT(A Lite BERT),ALBERT 的参数比传统的 BERT 要少得多,有效的解决了模型通信开销的问题。
ALBERT 提出了两种降低参数的技术,包括 factorized embedding parameterization
和 cross-layer parameter sharing
。前者是将 Embedding 参数矩阵分解为两个小矩阵,后者是跨层的参数共享。
除了降低参数外,为了提高性能,作者还引入了一种自监督的句子预测目标(sentence-order prediction,SOP),主要用来关注句子间的连贯性,旨在解决 BERT 中 next sentence prediction(NSP)的无效性问题。
最终 ALBERT 比 BERT-large 参数更少,效果更好,并在多个 NLP 任务中刷榜。
3.2 ALBERT
ALBERT 架构的主干和 BERT 类似,都使用了基于 GELU 的非线性激活函数的 Transformer。但是其分别在两个地方减少了参数量。
以下图为例可以看到模型的参数主要集中在两块,一块是 Token embedding projection block,另一块是 Attention feed-forward block,前者占有 20% 的参数量,后者占有 80% 的参数量。
3.2.1 Factorized embedding parameterization
在 BERT 中,Token Embedding 的参数矩阵大小为
V
∗
H
V*H
V∗H ,其中 V 表示词汇表长度,H 为隐藏层大小。
而 ALBERT 为了减少参数数量,在映射中间加入一个大小为 E 的隐藏层,这样矩阵的参数大小就从
O
(
V
∗
H
)
O(V*H)
O(V∗H) 降低为
O
(
V
∗
E
+
E
∗
H
)
O(V*E + E*H)
O(V∗E+E∗H),而
E
<
<
H
E<<H
E<<H 。
之所以可以这样做是因为每次反向传播时都只会更新一个 Token 相关参数,其他参数都不会变。而且在第一次投影的过程中,词与词之间是不会进行交互的,只有在后面的 Attention 过程中才会做交互,我们称为 Sparsely updated。如果词不做交互的话,完全没有必要用一个很高维度的向量去表示,所以就引入一个小的隐藏层。
3.2.2 Cross-layer parameter sharing
ALBERT 的参数共享主要是针对所有子模块内部进行的,这样便可以把 Attention feed-forward 模块参数量从 O ( 12 ∗ L ∗ H ∗ H ) O(12*L*H*H) O(12∗L∗H∗H) 降低到 O ( 12 ∗ H ∗ H ) O(12*H*H) O(12∗H∗H),其中 L 为层数,H 为隐藏层大小。
ALBERT 之所以这样做是因为,考虑到每次层其实学习到内容非常相似,所以尝试了将其进行参数共享。下图为不同层 Attention 学到的东西
这样变完成了参数降低的第二个模块
3.2.3 Sentence order prediction
BERT 设计了 NSP 来保证句子的连续性,即用两个连续的句子对作为正例子,并随机挑选一个句子作为负例。但这样会出现一个问题:句子对不仅有连续性,还包括句子的主题,如果是随机选取的句子模型可能会通过句子的主题不同而判定为负例。
于是,作者对此进行改进,提出 Sentence order prediction(SOP),做法很简单,就是将原来预测的句子调换下顺序,sentence1 预测 sentence2 为正例,而 sentence2 预测 sentence1 为负例,这样就不用担心模型通过句子的主题而进行预测了。
3.3 总结
(1)ALBERT 设计了 factorized embedding parameterization 和 cross-layer parameter sharing 两种方式分别对模型的两个部分降低参数。
(2)利用 Sentence order prediction 来改进 BERT 的 NSP
(3)通过设计一个更深的网络,移除 dropout,并在十倍的数据集上进行训练
ALBERT 在多项 NLP 任务重刷榜,但由于其结构更大,计算代价昂贵,所以其训练速度下降,虽然其减少了一定内存,但计算量增加了,下图为BERT 和 ALBERT 的参数对比
参考
4. DistilBERT
DistilBERT 模型与 BERT 模型类似,但是 DistilBERT 只有 6 层,而 BERT-base 有 12 层,DistilBERT 只有 6600 万参数,而 BERT-base 有 1.1 亿参数。DistilBERT 在减少 BERT 参数和层数的情况下, 仍然可以保持比较好的性能,在 GLUE 上保留了 BERT 95% 的性能。
6.1 改进1:损失函数
DistilBERT 使用 KL 散度作为损失函数,q
表示 student 模型的分布,而 p
表示 teacher 模型输出的分布,损失函数如下:
K L ( p ∥ q ) = E p ( log ( p q ) ) = ∑ i p i × log ( p i ) − ∑ i p i × log ( q i ) K L(p \| q)=E_{p}\left(\log \left(\frac{p}{q}\right)\right)=\sum_{i} p_{i} \times \log \left(p_{i}\right)-\sum_{i} p_{i} \times \log \left(q_{i}\right) KL(p∥q)=Ep(log(qp))=i∑pi×log(pi)−i∑pi×log(qi)
DistilBERT 最终的损失函数由 KL 散度 (蒸馏损失) 和 MaskLM (遮蔽语言建模) 损失两部分线性组合得到。
6.2 其他改进
- DistilBERT 移除了 BERT 模型 segment embedding 和 NSP 任务,保留了 BERT 的其他机制,然后把 BERT 的层数减少为原来的 1/2
- 使用了 teacher 模型的参数对 DistilBERT 模型进行初始化;
- 采用 RoBERTa 中的一些训练方法,例如大的 batch,动态 Mask
参考
5. XLNet
todo...