-
Transformer
-
什么是transformer
-
为什么需要用transformer
-
encoder
-
sub-encoder block
-
multi-head self-attention
-
FFN
-
-
input
-
-
decoder
-
input with look-ahead mask
-
sub-decoder block
-
-
output layer
-
summary
-
-
transformer的缺点
-
transformer的应用
-
ref
-
-
Transformer-XL
-
The motivation for Transformer-XL.
-
Transformer-XL: the proposed solution: Basic idea.
-
combine hidden states
-
how to compute self-attention
-
-
Absolute Positional Encoding & Memory:
-
summary
-
应用和不足
-
ref
-
-
Self-Attention with Relative Position Representations
-
Relation-aware Self-Attention
-
Relative Position Representations
-
Implement
-
ref
-
-
Reformer
Transformer
什么是transformer
首先我们先说结论:Attention Is All You Need提出的transformer 其实就是 seq2seq + self attention。 代码实现, 非常清晰
seq2seq 任务指的是输入和输出都是序列的任务。例如说法语翻译成英文。
通常来说,Seq2Seq任务最常见的是使用encoder+decoder的模式,先将一个序列编码成一个上下文矩阵,在使用decoder来解码。当然,我们仅仅把context vector作为编码器到解码器的输入。
这样子往往得不到好的效果,因为我们的编码器的很多信息都无法完全编码在这个向量中,并且我们在解码的时候,对于输入的每个单词的权重是不一致的,所以在NMT任务上,还添加了attention的机制。
所以目前来说,我们可以直接先把transformer当成一个黑盒,就是transformer可以当成是一个序列转码的模型,只是它其中用了特殊的self-attention的机制。如下图所示:
为什么需要用transformer
在提到为什么需要用transformer的时候,我们需要了解,在没有transformer的时候,我们都是用什么来完成这系列的任务的呢?
其实在之前我们使用的是RNN(或者是其的单向或者双向变种LSTM/GRU等) 来作为编解码器。
RNN模块每次只能够吃进一个输入token和前一次的隐藏状态,然后得到输出。它的时序结构使得这个模型能够得到长距离的依赖关系,但是这也使得它不能够并行计算,模型效率十分低。
当然这边的的RNN可以通过CNN替换,从而达到并行的效果,可以看到下图,总共是两层的卷积层,第一层画出了两个filter,每个1D filter的size是2,到了第二层的卷积层的filter的size是3。
第一层的filter考虑的是两个字之间的关联,但是到了第二层,考虑了三个前一层输出的交互,从而考虑到了较长序列之间的关系。比如说这边序列是 , 第一层只考虑了 , .. 的交互,第二层考虑了 ,而 是前一层两两交互关系的结果,所以第二层考虑了 这个序列的结果了。
但是对于CNN每次一般我们的卷积核设的长度为3/5这种较小的值,对于序列长度较长的,比如512,就需要堆叠多层的卷积层,导致模型过于冗杂。
那么,我们有没有办法提出一个新的模型,能够并行,并且能够考虑到输入序列不同token的权重?聪明的科学家们提出了一种新的模型叫做transformer。
其实他就encoder+decoder模式,只是其中的编解码器采用了self-attention的机制。
当然transformer真的就比RNN好吗?有人提出,凡事用RNN做的模型,都可以直接用self-attention替代。这个我们会在transformer的缺点中讨论。# tranformer的内部结构
transformer其实是由encoder以及decoder不是单一模块,而是由小的多个sub-encoder block和sub-decoder block组成。
我们来看看transformer的具体结构图。由下图所示,它主要由左边的encoder+input以及右边的decoder+input+output组成。我们将会一一介绍。
encoder
这边的encoder由input以及多个sub-encoder blocks组成。我们将会先讲sub-encoder,再讲输入,因为输入的设计是为了弥补self-attention的缺陷的。
sub-encoder block
首先每个sub-encoder都由两个主要的部分组成(略过部分细节,之后会写),分别是self-attention layer以及ffn layer。
具体的实现机制就是:我们的输入每个词经过embedding 之后,然后经过self-attention ,根据自己的路径,经过转换得到新的输出vector,最后再经过ffn layer,得到新的输出,作为下一层sub-encoder的输入。
multi-head self-attention
首先我们先了解一下self-attention的作用,其实self attention大家并不陌生,比如我们有一句话,the animal didnot cross the street, because it was too tired. 这里面的it,指代的是the animal。我们在翻译it的时候会将更多的注意力放在the animal身上,self-attention起的作用跟这个类似,就是关注句子中的每个字,和其它字的关联关系。参考实现
我们来看看这些词是怎么经过multi-head attention,得到转换的。
首先我们每个字的输入vector 会经过变换得到三个vector,分别是query , key 以及value , 这些向量是通过输入 分别和query矩阵 ,key矩阵 ,value矩阵 相乘得来的。query矩阵 ,key矩阵 ,value矩阵 都是训练时学习而来的。
将 x1 和 WQ weight matrix 做矩阵乘法得到 q1, 即这个字对应的query向量. 类似地,我们最终得到这个字对应query向量,value向量,key向量。- query向量:query顾名思义,是负责寻找这个字的于其他字的相关度(通过其它字的key) - key向量:key向量就是用来于query向量作匹配,得到相关度评分的 - value向量:Value vectors 是实际上的字的表示, 一旦我们得到了字的相关度评分,这些表示是用来加权求和的