目录
- 1 简介
- 2 Encoder
- 3 Decoder
- 4 参考
1 简介
Transformer是一个Seq2seq(sequence to sequence)模型,其实质上是一个Encoder和Decoder的结合。其简略结构图如下:
其详细的框架图如下:
下面就详细展开其中的内部构造。
2 Encoder
Encoder实质上就是一个输入是序列(sequence),输出也是序列的东西,对应的是上述详细图中左边的部分:
其中,可以将这个详细的Encoder图概述如下:
在这个图中,每一个Block代表了输入一个序列,经过一个Self-attention,输出一个序列,这个序列在经过一个fully-connected neural network,得到新的序列。而一共有N个这样的Block堆叠在一起,就是说上一个Block得到的序列会传入下一个Block中,重复N次,就能得到Encoder最终的输出结果。而原论文图中还有个Add & Norm
,这个Add
是residual connection
,而这个Norm
是Layer Norm
:
(这个图先看左边,左边最顶上省略号对应右边)residual connection
实质上就是将一个向量输入到self-attention中得到的向量再与这个input vector相加(具体为什么有什么用我也没查过,如果后面有需要学习了再补充)。而Layer Norm
就是一个向量减去其均值并除以其标准差。Layer Norm
给我的感觉就是一个标准化(Standardization)的方法,主要是对特征进行缩放,方便梯度下降。
3 Decoder
Decoder对应的是第一节详细框架图中的右边部分。这一部分在我最开始理解的时候有点绕,因为有两个输入。以李宏毅老师的PPT来说,我们将Decoder看作是一个黑盒子,在语音识别领域,假设输入的是机器学习
这四个字的语音,我们期望能够得到这四个字的文本,其运行流程简略版如下:
那么通过这四张图就可以简单理清Decoder的运行流程,尤其是为何Decoder有两个输入。简单来说步骤如下:
- Encoder将语音信息进行编码,最终输出
机器学习
语音信息的4个向量,将其输入到Decoder中; - 输入一个特殊的字符
BOS(begin of sequence)
,经过Decoder并与Encoder的输出进行运算,得出的向量中,最大概率值就是我们第一个输出的结果(在该例子中我们期望的目标是机
这个字的概率最大); - 接着我们将
机
重新输入到Decoder中(i.e. 成为下一轮Decoder的输入),并与BOS
结合(这里下面会提到Masked Multi-Head Attention
),再与Encoder的输出做运算,得出第二个输出结果,这里我们期望最大概率为器
; - 接着将
器
输入到Decoder中,与BOS
和机
结合,与Encoder做运算,得出学
; - 将
学
输入Decoder,与BOS
,机
和器
结合,与Encoder运算,得出习
; - 当然,图上还少了一个步骤,就是将
习
输入进Decoder,与BOS
,机
,器
和学
结合,再与Encoder运算,得出输出EOS(end of sequence)
,到此结束。
有了这个感性的认识后,我们再细看Decoder中的每个环节。首先是Decoder的输入后会进入一个Masked Multi-Head Attention
,这个模块与Self-attention
的区别就在于下图:
我们发现对于 而言,它只由 决定;对于 ,只由 决定;后面以此类推。就是说Self-attention
中每个输出都由所有的输入决定,但是Masked Self-attention
中每个输出只与其当前的输入与之前的输入决定。直觉上讲,这是因为我们的输出是一个个输出的(就比如上面语音的例子中机,器,学,习
是逐个输出的),所以需要输出当前的内容,只能观测到当前与之前的东西(就是说当 输入时,只有 ,没有 )。当然,采用这种方式的Decoder我们会发现一个很严重的问题,就是没法并行化处理。于是有学者就提出了采用Non-autoregressive的方法,即Decoder的输入从依次输入变为一起输入,如下图:
但是问题来了,NAT如何控制输入多少东西?NAT有两种做法,第一种就是重新训练个预测器,用于预测输入的长度;第二种就是人为设定一个超参数,用于衡量输出的最长长度,接着当输出序列中出现一个EOS后,EOS右边的内容全部不要。这样的优点就是可以并行化处理Decoder的输入了,但是缺点就是性能是差于AT的。接着我们再来看Decoder中第二个block。这里Encoder会提供两个输入,还有一个输入是从Decoder的Maksed Multi-Head Attention
中提供的。其中,Encoder提供的输入是自注意力机制中的 向量,而Decoder提供的输入是 向量:
而对于其损失函数的构建来说,我们可以把这个看作是一个N分类问题(N为词表大小),那么就可以用交叉熵来作为损失函数。
而训练的时候,输入的训练数据是Ground Truth
,但是在测试的时候,则是用Decoder的输出作为输入。那么在这种情况下,极有可能出现只要Decoder输出一个错误后,后续的内容都错误。所以在这种情况下,解决方案是在训练的时候输入一些错误的内容给Decoder。