为什么选择 Transformer
NLP 任务需要编码器抽取上下文的特征
上下文的语义很重要,每个词的语义和上下文强相关
方向
RNN 只能对句子进行单向的编码
CNN 只能对短句子进行编码
Transformer 可以双向编码,也抽取长距离的特征
顺序(词的位置变换了会产生不同的意思)
速度
RNN 无法并行处理序列,其他都行多头自注意力模块
首先对输入进行 projection,得到 QKV 三个矩阵
(tf 对输入进行了降维 (B, L, D) -> (BL, D))
初始化三个 dense 层 (BL, D) -> (BL, NH) N 为 attention 模块的数量,H 为长度
为什么要在这个进行投影呢?
若不投影,在之后的注意力模块中,相同的 Q 和 V 会进行点积,使得 attention 矩阵对角线的分数特别高(自己和自己的分数?),每个词的注意力都在自己身上,无法获得上下文的关系。所以需要将 QKV 投影到不同的空间中,增加多样性。之后进行 reshape, (BL, NH) -> (B, N, L, H)
为什么要用多注意力头呢?
希望不同的注意力头学到不同的特征,和 CNN 里的 multi-channel 类似多不同的注意力头进行点积、转置
为什么要用乘法呢?(为什么不用加性 attention 呢?)
在 GPU 的场景下,矩阵乘法的效率更高,随着 D 的增大,加性 attention 的效果会更好
为什么要除以√D 呢?
两个的矩阵相乘之后方差会变大,使得有些词注意力很大有些很小,经过 softmax 之后再求导会导致梯度很小,不利于优化,除了之后可以平滑一下。e.g. N (0, √d)*N (0, √d) = N (0, d) -> / √d -> N (0, 1)。乘 mask 矩阵(正常 token 的值为 0,要丢弃的 token 值为 1w)使得正常 token 的值维持原状,被丢弃的 token 值很小。使得进过 softmax 之后,不想要被注意的值无限趋于 0
进行 softmax 归一化得到注意力分数
用 V 矩阵和注意力分数进行加权,再把不同头的分数合并起来
残差连接 & Normalisation
相加操作与 ResNet 相似,相当于在求导时加了一个恒等项,减少梯度消失的问题Layer_Norm
提升神经网络的泛化性
(数据的分布对模型可能会有很大的影响)
所以需要将隐藏层的输出都归一化成均值为 0 方差为 1 的分布
更好的利用模型在训练集中收获的知识
norm 放在激活函数之前,避免数据落入饱和区,减少梯度消失的问题
(实际操作时会初始化一个新的均值和方差,调整分布,增加多样性)NLP的序列是变长的,Batch_Norm在对不同样本的同一个位置去做归一化时,无法获得真实分布的统计值。 Layer_Norm会对同一个样本每一个位置的不同特征做归一化 Normalisation可以放在不同的地方 Post-LayerNorm先做残差再归一化 保持主干网络的方差比较稳定,使模型泛化能力更强。 但把恒等的路径放在norm里,会导致模型更难收敛。 Pre-LayerNorm先归一化再做残差 更容易收敛,但只是增加了网络的宽度而不是深度,效果没有前者好。
Positionwise FFN (Feed Forward Network)
提供了非线性变换,提升拟合能力 (1*1 卷积核的全连接层)。
激活层从 ReLU 变成了 GeLU,引入了正则的思想,越小的值越可能被丢弃掉,相当于 ReLU 和 dropout 的结合。
tanh 和 sigmoid 的双边区域会饱和,导致导数趋于 0,有梯度消失的问题。