2.1 注意力机制
2.1.1 什么是注意力机制
注意力机制有三个核心变量:Query(查询值)、Key(键值)和 Value(真值)。其中,K和V是整个文本(集合)。通过计算Query和Key得出文本对Query的权重,即Query对整个文本(集合)中每个token的注意力分数。最后将权重和Value进行运算,得出Query和整个文本中的关系。
2.1.2 深入理解注意力机制
例子详见正文。
文中发提到的字典的键值为Key,值为Value。有一点需要注意,在字典中,键唯一,值可以重复。但是在这里,键和值是一一对应的,也就是Key和Value一一对应,不会出现多个Key存在相同的Value。
让我们脱离文中的举例的字典来看。
Query、Key和 Value均是多个词向量堆叠在一起形成的矩阵。三者都是由其对应的权重矩阵得到的。深度学习模型优化的便是这个权重矩阵。
假定Query的第一维度(token数量)大小为N,其中的每一个token的词向量为q ,大小为q_dim。不管Query代表什么,Key和 Value应为同一文本(集合)中每个token在不同空间的映射,即二者第一维度(token数量)相等,大小均为M,其中的每一个token的词向量为k,v ,大小为k_dim,v_dim。在实际情况下,k_dim、q_dim、v_dim通常相等。
首先,我们令q和Key中的每个token进行点积运算,得到q和每个k所代表的token的相似度,大小为M。
通过Softmax层,我们将q对集合中每个token的相似度转化为和为 1 的权重。
最后,我们将所有Query的x同Value做对应乘积,得到了每个q在整个文本中的value。
最后的最后,如果Query和 Key对应的维度 dk 比较大,softmax 放缩时就非常容易受影响,使不同值之间的差异较大,从而影响梯度的稳定性。因此,我们要将Query和Key乘积的结果做一个放缩:
softmax中每个元素在归一化过程中都会进行指数函数的运算。在指数函数中,x越大,y就会更大。维度d的增加就会造成数值大的x的出现,从而出现一个数量级很大的y,这个y会导致softmax函数的得到的概率分布结果全部趋于这个最大值,这会导致导致模型梯度消失,参数无法正常更新。
假设Q和K都是服从期望为0,方差为1的独立的随机变量。除以根号dk后,使得Q和K的点积也趋向于期望为0,方差为1的标准正态分布。
均值为 0、方差为 1 是的数据的分散程度(波动范围)被统一缩放,也可以看成一种归一化,使不同数据之间具有可比性。Softmax 的输出会更平滑,梯度更均衡,避免梯度消失。
2.1.3 注意力机制的实现
代码中并没有可学习的参数。
2.1.4 自注意力
Q、K、V 分别是同一输入对三个权重参数矩阵做积得到,从而拟合输入语句中每一个 token 对其他所有 token 的关系。通过自注意力机制,我们可以找到一段文本中每一个 token 与其他所有 token 的相关关系大小,从而建模文本之间的依赖关系。
2.1.5 掩码自注意力
使用注意力掩码的核心动机是让模型只能使用历史信息进行预测而不能看到未来信息。
掩码矩阵是加在在Q、K计算得到的注意力分数上面的,在经过 Softmax 之后会被置为 0,使得看不到未来信息的token注意力只能聚焦在过去的信息上。
Tips:一个矩阵表示的是一段文本(一句话)。
2.1.6 多头注意力
多头注意力中每个不同的注意力头能够拟合语句中的不同信息。
值得注意的一点是,多头注意力实现的逻辑是:创建多组Q、K、V参数矩阵,再将每组得到的结果拼接起来,再通过一个线性层进行处理,得到最终的输出。
如果只看代码实现,容易进入一个误区。会认为多头注意力是将由一组Q、K、V参数矩阵形成的Q、K、V在特征维度上进行拆分再结合。使得读者搞不清楚多头的作用。
可配合下文进行理解。
2.2 Encoder-Decoder
2.2.1 Seq2Seq 模型
模型输入的是一个自然语言序列 input=(x1,x2,x3...xn),输出的是一个可能不等长的自然语言序列 output=(y1,y2,y3...ym)。
如果输出长度为 1 的目标序列(如在上式中 m = 1),则可视为文本分类任务。
如果输出与输入序列等长的目标序列(如在上式中 m = n),则可视为词性标注任务
对于 Seq2Seq 任务,一般的思路是对自然语言序列进行编码再解码。
所谓编码,就是将输入的自然语言序列通过隐藏层编码成能够表征语义的向量(或矩阵),可以简单理解为更复杂的词向量表示。
而解码,就是对输入的自然语言序列编码得到的向量或矩阵通过隐藏层输出,再解码成对应的自然语言目标序列。
通过编码再解码,就可以实现 Seq2Seq 任务。
Transformer 由 Encoder 和 Decoder 组成,每一个 Encoder(Decoder)又由 6个 Encoder(Decoder)Layer 组成。
输入源序列会进入 Encoder 进行编码,到 Encoder Layer 的最顶层再将编码结果输出给 Decoder Layer 的每一层,通过 Decoder 解码后就可以得到输出目标序列了。
2.2.2 前馈神经网络
前馈神经网络每一层的神经元都和上下两层的每一个神经元完全连接。
Transformer 的前馈神经网络是由两个线性层中间加一个 RELU 激活函数组成的,以及前馈神经网络还加入了一个 Dropout 层来防止过拟合。
2.2.3 层归一化
归一化核心是为了让不同层输入的取值范围或者分布能够比较一致。前文提到的softmax之前除以 也可以视为一种归一化。
一个批量的样本为以下形式:(batch_size, seq_len, featuer_dim)。
批归一化(Batch Norm)是对每个样本的同种的特征(batch_size, seq_len, 1)进行归一化,是针对不同样本之间对应的特征维度。这种对于图像等非时空序列特征来说, 不同Batch之间的分布差不多,且同维度,可以在不同batch之间归一化。
但是对于时空序列、NLP的词向量序列等,不同序列之间的分布差别大(例如,不同句子之间差别很大),而且不同序列维度可能不同,不能使用BN。
层归一化(Layer Norm)对同一样本(一句话)在内部进行归一化(1, seq_len, featuer_dim),使每个样本的分布达到稳定。
2.2.4 残差连接
残差连接是为了避免模型退化,将最底层信息直接传到最高层的思想。
2.2.5 Encoder
一个 Encoder Layer 包括一个注意力层和一个前馈神经网络。注意,Encoder不需要掩码。
一个 Layer 中有两个 LayerNorm,分别在 Attention 之前和 MLP 之前
2.2.6 Decoder
Decoder 由两个注意力层和一个前馈神经网络组成。第一个注意力层是一个掩码自注意力层,即使用 Mask 的注意力计算,保证每一个 token 只能使用该 token 之前的注意力分数;第二个注意力层是一个多头注意力层,该层将使用第一个注意力层的输出作为 query,使用 Encoder 的输出作为 key 和 value,来计算注意力分数。最后,再经过一个前馈神经网络。
一个 Layer 中有三个 LayerNorm,分别在 Mask Attention 之前、Self Attention 之前和 MLP 之前。
2.3 搭建一个 Transformer
2.3.1 Embeddng 层
最原始的输入是自然语言(很多句话),通过分词器tokenizer把自然语言输入切分成 token,每个token赋予一个固定的序号(index),同时将自然语言表示转化为了序号表示,形成了一个(batch_size,seq_len,1)大小的矩阵,第三个维度1代表的就是转化为序号(一个正整数)的token。
Embedding 层的输入便是该矩阵(batch_size,seq_len,1),他将输入的整数序列转换为密集向量表示。通过Embedding 层,我们将会得到(batch_size,seq_len,embedding_dim)大小的词向量矩阵。
2.3.2 位置编码
在 RNN、LSTM 中,输入序列会沿着语句本身的顺序被依次递归处理,因此输入序列的顺序提供了极其重要的信息,这也和自然语言的本身特性非常吻合。
但注意力计算的方式会导致序列中相对位置的丢失。因此,为使用序列顺序信息,保留序列中的相对位置信息,Transformer 采用了位置编码机制。
位置编码信息是直接加在词向量编码中的
2.3.3 一个完整的 Transformer
- 经过 tokenizer 映射后的输出先经过 Embedding 层(将自然语言转为计算机理解的词向量矩阵)和 Positional Embedding 层编码(使注意力机制关注到相对位置信息)。
- 然后进入的 N 个 Encoder 和 N 个 Decoder(在 Transformer 原模型中,N 取为6)。
- 最后经过一个线性层和一个 Softmax 层就得到了最终输出。