19.Transformer

简介

首先,我们需要明确Transformer是一个Seq2Seq的模型,输入是一个序列,输出也是一个序列。它由Encoder和Decoder两部分组成,结构图如下:

整个Transformer模型全貌如下:

Encoder

Encoder所做的工作就是输入一个序列,然后输出一个强化的序列,它包含更多的信息。

Encoder由多个Block组成,每个Block中都进行了self-attention处理。

但是其中每一块进行的self-attention不是上一节中最基础的那种,它加上了位置信息,使用了多头注意力机制,使用了residual connection,还使用了Layer Normalization。如下图右边的部分就是Encoder的一个块,像这样的块有N个。

其中添加位置信息和使用多头注意力机制我们已经有所了解,接下来我会简单讲解residual connection和Layer Normalization。

  • residual connection:即残差连接,它会将一个网络的输入加到它的输出上,主要是预防梯度消失。

  • Layer Normalization:即层标准化,相比于 Batch Normalization,它不是将个多个输入向量的同一维度标准化,而是将一个向量的不同维进行标准化。它输入一个向量,输出一个向量。下图中有Layer Normalization的具体做法。

好了,做了这么多铺垫,我们来具体看一下Encoder的一个块里面具体有哪些东西,如下图:

文字总结一个块:Input 先加上位置信息后,经过一个多头注意网络(residual connection),然后进行Layer Normalization,再经过一个全连接层(residual connection),再进行一次Layer Normalization,之后Output输出。

我们需要明白一点,原始的Encoder中的一个块内的各部分是按上述结构组织的,但是随着时间的发展,诞生了效果更好的组织方式。下图中右边这种组织方式的效果就比左边原始的要好。

Decoder

首先,Transformer的Decoder有两种,一种是Autoregressive,另外一种是Non-Autoregressive。

我们先对Autoregressive进行讲解:

Autoregressive,简称AT。它的输入有两部分:Encoder的输出和自己前一时刻的输出(刚开始输入start)。它的输出虽然是一个序列,但其中的元素是一个一个输出的,当然什么时候停止输出也是靠学习得到。

Decoder也由很多块组成,下图的右边展示的就是Decoder中的一块,可以看到它比Encoder还要复杂。

但是我们像下面这样把Decoder的中间那一块给遮住的话,会发现剩下的和Encoder其实是差不多的结构,只是把Multi-Head Attention换成了Masked Multi-Head Attention。

需要注意的是,中间被遮掉的那部分刚好是Decoder连接Encoder的部分,这部分会在下一节中进行讲解。

所以先弄懂剩余部分即可!

那什么是Masked Self-attention?

在Self-attention中,每一个向量都会考虑它和所有向量的联系,然后输出结果。

但在Masked Self-attention中,每一个向量只考虑它之前的向量。如下图,生成b1时只考虑a1,生成b2时只考虑a1,a2...

为什么要使用Masked Self-attention呢?

这是因为Autoregressive这种Decoder的输出是一个字一个字崩的,而且只有前一个输出再次输入Decoder中才会产生下一个输出。举个例子,在产生b2的时候你只有a1,a2能考虑,你根本没有a3和a4。

OK,我们通过下述两幅图再理解一下Self-attention和Masked Self-attention的不同运作方式(以产生b2为例)。

接下来是另外一种Decoder:Non-Autoregressive,它简称NAT,这种Decoder它所有的输出是一起产生的(平行化),而且它还能灵活控制输出的长度。

虽然和AT相比NAT有众多优点,但是NAT的效果一般没有AT好,这是Multi-modality这个问题造成的,在这里不多作解释,感兴趣可以另行了解。

连接部分

在学习完Encoder与Decoder之后,剩下的就是连接部分了,这部分被设置在Decoder里面,就是刚刚遮住的那部分。

连接部分所做的工作就是一个交叉注意,它有三个输入,其中有两个来自Encoder,另外一个来自Decoder。

连接部分具体运转如下图:

来自Encoder的两个输入分别是Encoder输出所产生的key和value。

另一个来自Decoder的输入是连接部分之前的输出所产生的query。

一句话概括此过程:Decoder用自己中间层输出产生query,然后去Encoder中抓取信息。

关于训练

关于训练,因为输出的每一项仍旧是一个个分类问题,所以还是最小化交叉熵那一套东西。

但是由于AT的后一个输出依赖前一个输出,所以为了避免一步错步步错这种情况。在训练时,可以主动给一些错误的输入,这样可以提升模型鲁棒性。