10.3 Transformer结构#

10.2节内容中我们详细介绍了自注意力机制的动机和原理,在介绍下来的这节内容中我们将继续介绍Transformer的整个网络结构,以及多头注意力机制的实现。

10.3.1 单层Transformer结构#

整体来看Tansformer模型同样是基于多层的编码器-解码器构造而来,而编码器和解码器又都是基于多头注意力机制构建而来,如图10-18所示便是Transformer网络结构的示意图。

图 10-18单层Transformer结构图

在图10-18中,左侧为编码器,右侧为解码器。下面,我们分别对其中的各个部分进行介绍。

1. 编码器

对于编码器来说其网络结构如图10-18(左)侧所示。尽管论文中的编码器是由6个相同的编码层结构堆叠而成,但这里我们还是先以堆叠一层时的情况来进行介绍。在每一个编码层中,其内部主要由两部分网络所构成:多头注意力机制和两层前馈神经网络。同时,对于这两部分网络来说都加入了残差连接,并且在残差连接后还进行了层归一化操作。这样,对于每个部分来说其输出均为$\text{LayerNorm}(x+\text{SubLayer}(x))$,并且在都加入了Dropout操作。

进一步,为了便于在这些地方使用残差连接,这两部分网络输出向量的维度均相同,默认为$d_{\text{model}}=512$,并且对于第2部分的两层全连接网络来说,其具体计算过程为

$$ \text{FFN}(x)=\text{ReLU}(xW_1+b_1)W_2+b_2\tag{10-10} $$

其中输入$x$的维度为$d_{\text{model}}=512$,第1个全连接层的输出维度为$d_{ff}=2048$;第2个全连接层的输出为$d_{\text{model}}=512$。

2. 解码层

同编码器一样,解码器也采用了6个完全相同的网络层堆叠而成,不过这里我们依旧只是先看1层时的情况。对于解码器部分来说整体上与编码器类似,只是多了一个用于与编码器输出进行交互的多头注意力机制, 如图10-18(右)侧所示。

不同于编码器部分,在解码器中一共包含有3个部分的网络结构。最上面的前馈神经网络和最下面的掩码多头注意力机制(暂时忽略掩码)与 编码器相同,只是多了中间与编码器输出(Memory)进行交互的部分,称之为“Encoder-Decoder attention”。 对于这一多头注意力机制,Q来自于下方的掩码多头注意力机制的输出,而K和V均是编码器部分的输出经过线性变换后所得到。当然这样设计也是在模仿传统编码器-解码器网络模型的解码过程,即在对当前时刻的状态解码时需要同编码器中每个时刻的隐含状态计算得到对应的注意力权重完成注意力的分配过程,更多具体细节可以参见9.3节内容。

例如对于编码器输入为”我 是 谁“编码结束后,编码器-解码器交互注意力机制的整个过程便可以通过如图10-19和图10-20所示的过程来进行表示。

图 10-19 编码器-解码器注意力计算示意图一

如图10-19所示,对于左上角待解码向量和编码器的输出结果来说,分别进行对应的线性变换得到$Q$、$K$和$V$。

图 10-20 编码器-解码器注意力计算示意图二

如图10-20所示,首先$Q$通过与$K$进行交互得到权重向量,此时可以看做是$Q$在 $K$中查询各个位置与$Q$有关的信息;然后将权重向量与$V$进行运算得到解码向量,此时这个解码向量便可以看作是考虑了memory中各个位置编码信息的输出结果。进一步,在得到这个解码向量并经过图10-18(右)中最上面的两层全连接层后,便将其输入到分类层中进行分类得到当前时刻的解码预测输出。

3. 推理解码过程

如同我们在9.7.2节内容中介绍的编码器-解码器结构一样,在Transformer解码器的推理过程中,当第1个时刻的解码过程完成之后,解码器便会将解码器第1个时刻的输入,以及解码第1个时刻后的输出均作为解码器的输入来解码预测第2个时刻的输出,后续过程以此类推直到达到指定长度或某个时刻的预测输出为结束符时停止。

假设现在需要将" 我 是 谁"翻译成英语"who am i",且解码预测后前两个时刻的结果为"who am", 接下来需要对下一时刻的输出"i"进行预测,那么整个过程就可以通过图 10-21来进行表示。

图 10-21 推理解码过程示意图

如图10-21 所示,左上角的矩阵是解码器对输入 "<s> who am"这 3 个字经过解码器中自注意力机制编码后的结果;左下角是编码器对输入"我 是 谁"这 3 个字编码后的结果;两者分别经过线性变换后便得到了$Q$、$K$和$V$这3个矩阵。此时值得注意的是,左上角矩阵中的每一个向量在经过自注意力机制编码后,每个向量同样也包含了其它位置上的编码信息。

进一步,$Q$与$K$作用后便得到了一个权重矩阵;再将其与$V$进行线性组合便得到了编码器-解码器多头注意力机制部分的输出。最后在经过解码器中的两个全连接层后,便得到了解码器最终的输出结果。同时,这里需要注意的是模型在进行实际的预测时,只会取解码器输出的其中一个向量进行分类,然后作为当前时刻的解码输出。例如上述示例中解码器最终会输出一个形状为[3,vocab_len]的矩阵,那么只用取其最后一行向量输入到分类器中进行分类得到当前时刻的解码输出,具体细节可见后续代码实现。

4. 训练解码过程

从上面介绍的内容可以看出,在推理过程中解码器需要将上一个时刻的输出作为下一个时刻解码的输入,然后逐时刻地进行解码操作。显然,训练时也采用同样的方法将十分耗时。因此,在训练过程中解码器也同编码器一样,一次接收解码时所有时刻的输入进行计算。 这样做的好处,一是通过多样本并行计算能够加快网络的训练速度;二是在训练过程中直接输入解码器正确的结果而不是上一时刻的预测值能够更好的训练网络,这一点我们在9.9.5节内容中也介绍过。

例如在用平行预料"我 是 谁"与"who am i"对网络进行训练时,编码器的输入便是"我 是 谁",而解码器的输入则是"<s> who am i",对应的正确标签则 是"who am i <e>"。假设现在解码器的输入"<s> who am i"分别进行线性变换后得到了$Q$、$K$和$V$,且$Q$与$K$作用后得到了注意力权重矩阵(此时还未进行$\text{softmax}$操作),如图10-22所示。

图 10-22 训练时解码器掩码多头注意力计算过程图一

从图10-22可以看出,此时已经计算得到了注意力权重矩阵。不过现在有一个问题就是,模型在实际推理过程中只能看到(包括)当前时刻之前的信息来预测下一时刻,而图10-22所示的情况则是在对任意时刻进行解码时都能看到解码器输入所有时刻位置上的信息。因此,Transformer中的 解码器通过加入注意力掩码机制来解决了这一问题。

如图10-23所示,左侧是通过$Q$和$K$计算得到的注意力权重矩阵(此时还未进行$\text{Softmax}$操作),而中间便是所谓的注意力掩码(Attention Mask)矩阵。两者在相加并进行$\text{Softmax}$操作之后再乘上矩阵$V$便得到了整个自注意力机制的输出,这也就是图10-18中的掩码多头注意力(Masked Multi-Head Attention)。

图 10-23 注意力掩码示意图

我们接着看注意力掩码矩阵是如何来解决这一问题的。以图10-23中第1行权重为例,当解码器对第1个时刻进行解码时其对应的真实输入应该只有"<s>",而这就意味着此时应该将所有的注意力放在第1个位置上(尽管在训练时解码器一次喂入了所有的输入)。换句话说也就是第1个位置上的权 重应该是 1,而其它位置则是 0。从图10-23中可以看出,第1行注意力向量在加上第1行注意力掩码,再经过$\text{Softmax}$操作后便得到了一个类似[1,0,0,0,0]的向量。 那么,通过这个向量就能够保证在解码第1个时刻时只能将注意力放在第1个位 置上的特性。同理,在解码后续的时刻也是类似的过程。

10.3.2 多层Transformer结构#

经过第10.3.1节内容的介绍我们已经清楚了单层Transformer网络结构的详细原理,并且尽管多层 Transformer就是在此基础上堆叠而来,但依旧有必要在这里稍微提及一下。

49