由于很多知识网上都可以查到,大的篇幅不会讲Self Attention,本节将围绕以下细节作以分析:Add操作及目的、Norm操作及目的、不用Norm可不可以、为什么将BN不用于transformer任务、Feed Forward操作目的。
Encoder分解之Add & Norm
- Add操作:Add在Encoder中是一种残差连接,指 X + Multi-Head Self-Attention(X) 和 X + Feed Forward(X)。其 ResNet 所用的是相同结构。为了能够相加,二者的维度应保持一直。
- Add操作目的:残差结构通常用于解决深层网络的退化现象,可以让网络只关注当前差异的部分。
- 为什么要Norm操作:Encoder中的norm 指Layer Normalization。transformer堆叠了很多层,Layer Normalization可以防止层内的数值变化过大造成梯度消失或梯度爆炸,从而加快训练速度,让网络不容易陷入过拟合中。
- Norm操作进一步理解:网络在学习的过程中可以理解为传话,一个人传给另一个人会越穿越偏。通过Norm中的w和b可以产生一个新的数据分布,让数据分布稳定下来。当网络训练过程中数据分布产生偏移,通过Norm可以校准数据,使数据重新标准化,便于训练。
- 不用Norm可不可以:不用Norm是可以的,但得调整其他参数,否则偏差的传递会越来越大。一个比较明显的区别是,不用normalization,dropout 需要特殊处理一下,否则training & inference 时候的scale 会不一样,会出问题。还有就是用大的dropout的时候,如果不用Norm,会很不好train.
- 为什么Batch Norm不用于transformer任务:首先要明确BN是跨样本的,即对一个batch中同一个特征做标准化。而Layer Norm是对每个样本的所有特征一起做标准化。BN归一化的是不同样本的同一特征,LN归一化的是同一样本的不同特征。通俗点说:假设有一个二维矩阵,行为batch-size,列为不同特征,那么BN就是每列每列竖着归一化,LN是每行每行横着归一化。因此,如果是CV领域,目标特征依赖于不同样本间的参数统计,BN可以抹杀不同目标特征(eg:同一幅图中的人和动物)之间的大小关系,保留不同样本间(eg:不同图像中的人)的大小关系。而在transformer中,每一个token是时序变化的,这正是要学习的东西,因此需要Layer Norm抹杀不同样本间的大小关系(不同的句子长度是不一样的),保留一个样本内不同特征之间的大小关系。
Encoder分解之Positional Encoding
- 我的一篇博文: CV领域Transformer之Self-Attention零基础学习 曾经讲过,Self Attention是不具有位置信息的。但位置信息对于CV领域或者NLP领域均非常重要,因此 Transformer 中使用位置 Positional Encoding保存token的相对或绝对位置。
Positional Encoding的进化:
- 给定一个长为 T 的token,最简单的位置编码就是计数,即使用
作为每个token的位置编码了。当然这样的瑕疵非常明显,这个序列是没有上界的。设想有500个token,最后一个token的位置编码非常大,这是很不合适的:没有上界。过大的Positional Encoding,跟token相加,很容易导致token本身含义的丢失。所以,我们期望Positional Encoding不要太大,最好在限定在一个区间内。
- 使用文本长度对每个位置作归一化,得到
。这样固然使得所有位置编码都落入[ 0, 1 ] 区间,但是问题也是显著的:不同长度文本的位置编码步长是不同的,在较短的文本中紧紧相邻的两个字的位置编码差异,会和长文本中相邻数个字的两个字的位置编码差异一致。这显然是不合适的。所以,我们有没有一个方法,保证值域固定,且不同长度文本,相差相同字数,差相同值。
- 按照周期函数编码,如下所示。其中pos为token的位置索引,
用来调节位置编码函数的波长,这样的问题也很明显:若
取值大,则波长大,导致相邻位置的差值变小。若
取值过小,则对于长文本来说,很容易导致位置不同,但的Positional Encoding却一样的情况。
- 利用多样性周期函数编码,如下所示。其中pos为token的位置索引,设一共有T个token,则pos的范围为[ 0, T-1 ],i是token的位置索引(或者说维度),假设
为512,则i的范围为[ 0, 255 ] (因为有2i)。这个公式可以为每个token生成
维的Positional Encoding。这样做的好处也很明显:其一是使 Positional Encoding能够适应比训练集更长的token,假设训练集里有 20 个token,突然来了一个长度为 21 的token,则使用公式计算的方法可以计算出第 21 个的Positional Encoding。其二是可以让模型容易地计算出相对位置,对于固定长度的间距 k,PE(pos+k) 可以用 PE(pos) 计算得到。因为 Sin(A+B) = Sin(A)Cos(B) + Cos(A)Sin(B), Cos(A+B) = Cos(A)Cos(B) - Sin(A)Sin(B)。
注意:
- 建模位置信息(无论是绝对位置还是相对位置)并不是必须用到三角函数,使用三角函数只是业内人员根据归纳偏置和一些经验作出的选择罢了。
- 位置编码为啥要跟语义向量
add
到一起,而非concat拼接。实际推理得出结论通过正余弦编码add操作后于concat是无差的,且add较为简单。
Encoder分解之FFN
- Feed Forward 层是由两层的全连接层组成,第一层的激活函数为 Relu,第二层不使用激活函数,对应的公式如下,其中:X是输入,max是Relu激活函数,Feed Forward 最终得到的输出维度与X一致。
- Feed Forward 作用:在Multi-Head Attention的内部结构中,主要操作都是矩阵乘法,即都是线性变换。而线性变换的学习能力是不如非线性变化的强的,所以Multi-Head Attention的输出尽管利用了Attention机制,学习到了每个token的新representation表达,但是这种representation的表达能力可能并不强,所以我们仍然希望可以通过激活函数的方式,来强化representation的表达能力。以NLP为例(图像同理),比如:The animal didn’t cross the road because it was too tired,利用激活函数,我们希望使得通过Attention层计算出的representation中,数值较大的部分则进行加强,数值较小的部分则进行抑制,从而使得相关的部分表达效果更好。(这也是神经网络中激活函数的作用,即进行非线性映射,加强大的部分,抑制小的部分)。这也是为什么在Attention层后加了一个Layer Normalizaiton层,通过对representation进行标准化处理,将数据移动到激活函数的作用区域,使得ReLU激活函数更好的发挥作用。同时在fully-connection中,先将数据映射到高维空间再映射到低维空间的过程,可以学习到更加抽象的特征。通过Feed Forward层,使得token的representation的表达能力更强,更加能够表示token之间的作用关系。