GPT Transformer Bert对比分析

首先,Transformer来自论文Attention Is All You Need,后面笔记很多参考文章The Illustrated Transformer,同时加了一些自己的理解。

1. 从上到下认识Transformer

首先我们把Transformer看做一个黑盒,以机器翻译示例为例,Transformer是输入就是待翻译的句子,输出就是翻译后的句子。

 

然后我们再一步一步打开这个潘多拉魔盒:

 

看到没有,这是一个经典的Encoder-Decoder模型,只是Encoder部分不是一个单独的Encoder,而是6个Encoder的堆栈,Decoder部分也是一样,至于为什么是6个,可能是实验效果最好。把Encoders、Decoders部分打开,就是下面这个样子:

在Encoders部分中每个encoder的结构都是一样的,只是不共享weights。每个encoder打开后,如下图结构:

 

每个Encoder包括一个Self-Attention层和feed-farward NN层。Encoder的输入先进入Self-Attention层(暂时先不关心Self-Attention细节,后面会介绍),Self-Attention层的输出作为feed-farward NN层的输入。

对于feed-farward NN层,是由多个feed-farward network组成的,每word对应一个,而且是互相独立的。

针对每个Decoder如下图,也是有Self-Attention层和feed-farward NN层组成,只是在两个中间加入了一个Encoder-Decoder Attention层,我的理解是对每个Encoder给予不同的注意力,用于表现在输入句子中应该更看着哪一部分。

2. 深入细节

现在开始深入模型的细节,从tensor级别来看看,这些输入向量在模型内部是如何流动和变型,到输出,来认识如何训练一个语言模型。

和一般NLP任务一样,一个句子中每个word用embedding word的形式表示,即每个word是一个向量。

如果embedding word的长度是512,那么每个word就是1*512的向量,下图简化表示每个词:

那么对于最底层的encoder输入就是一个向量的list,其中每个向量的长度是512,至于list的长度作为模型的一个超参数,一般情况去训练数据中最长句子的word个数,假设最长的句子有N个词,那么这个list就是N*512的向量。而对于其他encoder的输入就是它前面一层encoder的输出。

 

这里提到了Transformer一个重要的特性:并行化,原因就在于list经过self-attention层输出后也是一个向量的list,而且每个向量进入各自的feed-forward layer,而且每个feed-forward 都是独立,所以可以并行运算。

下面就以一个简单的示例具体看看在encoder里每个子层究竟做了什么。

-Self-Attention

如果我们要翻译这句话“The animal didn't cross the street because it was too tired”。句子中的it是指的是animal还是street呢,Self-Attention就是为了把animal和it联系起来,也就是说Self-Attention是Transformer去了解句子中词之间的关系。

这是第五层encoder中显示出来的句子中每个词对it的关联度,从图中可以看出注意力机制赋予更多的关注在"The animal"上。

究竟Self-Attention是如何做到这一点的呢,下面一步一步来看计算细节。

第一步——参数:每个encoder的输入就是每个词的word embedding,然后要根据这个输入对每个词创建3个向量,分别是:Query vector, Key vector, Value vector。那么这个三个向量是怎么产生的呢,这三个向量分别是通过输入得word embedding向量乘以三个矩阵产生的,而这三个矩阵就是我们要训练的。

q1 = X1 * WQ, k1= X1*WK, v1 = X1* WV

Query vector, Key vector, Value vector的长度要小于word embedding,word embedding和每个encoder的输入/输出向量长度是512,而Query vector, Key vector, Value vector是64。其实他们不是一定要求要小,只是为了运算更方便。那么这三个向量是怎么帮助计算词之间的注意力的呢,我们继续往下看。

第二步——计算得分:以计算例子中第一个词“Thinking”的self-attention得分为例,我们需要计算输入句子中每个个词对“Thinking”的self-attention得分,这个分数表示了当我们在解析句子特定位置的词时,输入句中其他词对这个词的关注程度。

如果我们要计算第一个位置词的self-attention得分,先计算q1*k1,再计算q1*k2。

第三步,把self-attention得分除以key vector长度的开方,在论文中key vector的长度是64,所以这个除以8。为什么要这么做,论文给的解释是可以得到更稳定的梯度,我的理解是给K的长度一定的惩罚项。

第四步,做一个softmax操作进行归一化,这个归一化的值保证了所有的self-attention得分都为正,而且<=1。

在这里,开始这几个概念开始把我弄得比较晕,现在开始梳理清楚了,首先是词和位置。Query vector表征的是位置向量,Key vector表征的是词向量,根据softmax score的计算可以表征的是词对当前位置的关注程度。根据这个定义,当然通常这个位置上词有最高的softmax score,但同时对表示其他词和当前词的关联程度的表示也是非常有用。

第五步,针对每个词对位置#1的softmax score乘以词#1的value vector得到权重。同时乘以一个很小的数(比如0.001),这样保留需要关注的词,同时丢弃那些不相关的词。

第六步,把每个词针对位置#1的权重相加,就得到位置#1self-attention层的输出值。

上面的计算向量值被送到feed-forward neural层计算。在实际计算中,为了加快计算速度,这些计算是以矩阵的形式进行的。所以下面我们来以矩阵的视角看看是如何计算的。

Self-Attention的矩阵运算

第一步,计算Query、Key、Value矩阵。我们的输入X:word embedding矩阵,然后分别乘以我们要训练的三个权重矩阵WQ、WK、WV。

每个X矩阵对应输入的句子,每一行对应句子一个词。在论文中X的列数是512,图中简化为4,q/k/v的的列数是64,图中以3表示。

然后对前面针对self-attention向量计算,压缩成矩阵运算就是:

“multi-headed” attention

上面计算看似OK了?不,论文作者还加入了“multi-headed”机制,我们先来看什么是multi-headed,再看它带来的性能提升。

简单来说,前文讲到的attention属于一个head,但还不够,我们还要多加几个head。如下图所示,有W0Q、W0K、W0V计算出Q0、K0、W0,这算1个head,同时还有W1Q、W1K、W1V计算出Q1、K1、W1,这算第2个head。

按照上图所示,论文中用了8个不同的矩阵(即8个不同的WQ、WK、WV),即8个head,得到了8个不同的Z矩阵。

好了,这儿又带来一个问题,对于下一步的feed-forward层的输入只期望是一个矩阵,而不是8个,那么如何是的8个矩阵变成1个呢?论文中的方法是将8个矩阵按行链接成一个,然后乘以一个额外的权重矩阵WO,得到最终的输出矩阵Z。

至于为什么multi-head能提升性能,我个人理解就是类似学习器的组合,通过不同的随机初始化矩阵训练,捕获不同的特征,从不同的侧面表征词之间的关联,以组合的形式得到更强大的学习器。下面用一张图来表示前面描述的过程:

下面再来看看multi-head的效果,回顾一下之间的示例,不同位置的词对“it”的关注程度:

通过multi-head不仅捕获了animal和it的强关联,还捕获到了tired和it的强关联。

Positional Encoding

到目前为止,该模型还没有描述词之间的顺序关系,也就是如果将一个句子打乱其中的位置,也应该获得相同的注意力,为了解决这个问题,论文加入了自定义位置编码,位置编码为word embedding长度相同的特征向量,然后和word embedding进行求和操作。

论文中给出的编码公式:

pos is the position and i is the dimension

具体代码的实现参考get_timing_signal_1d()。关于这部分的理解还不是很清楚,后面理清了再补充。

The Residuals

在继续之前,关于self-attention层还有一个细节需要提到就是residuals,如果熟悉CNN,对ResNet了解的,一定对residuals不陌生,residuals的关键点就是skip connection。在Transformer里,在每一个encoder的子层(也就是self-attention,FFNN )有一个residual connection, 输入和输出有一个add和归一化操作。

以向量的视觉来看就是:

同样,在decoder的子层里也有这样的操作,如果我们把Transformer看做2层的encoders和decoders,将是下面这样:

Decoder

下面重点来看Decoder这方是如何工作的。

最顶层的encoder转化成了注意力向量集合K、V。这作为decoder的输入,下面的gif以机器翻译为例,展示了decoder如何工作。

以把目标句子翻译成英语为例

最后的linear+softmax层

decoder栈最后输出的是一个浮点数的向量,如何把它转化为word,这就是最后linear和softmax层的作用。

假设目前词典的大小是10000个,那么linear层就是decoder栈的输出到10000节点的全连接,每个节点就是表示一个词,最后跟上softmax层,表示到目标词的概率到大小,选择概率最大的词作为输出。

training and loss function

和RNN一样,以机器翻译为例,training的y值就是翻译后句子的one-hot编码,loss function一般采用cross-entropy或者Kullback-Leibler divergence。

假设目标词典大小为6(一般情况下,词典大小是目标所有可能出现的词个数),上图展示了每个词的one-hot编码

 

显示了训练后取每个词的概率值

一般有,先取位置1概率最大的值,然后在位置1取值的基础上取位置2的概率最大值,依次往后推。为了捕获更准确或者说更广泛的取值,可以采取beam-search。beam-search中有个参数B,假设B取3,表示在位置1取概率排前3的词,然后在这三个词的基础上选取位置2概率最高的三个值,往后依次类推。

好了,到此为止,我们对transformer有了一个全面的了解,更多细节参考:

1. 论文Attention Is All You Need

2. 代码实现http://nlp.seas.harvard.edu/2018/04/03/attention.html

参考

https://jalammar.github.io/illustrated-transformer/



作者:梯度上升
链接:https://www.jianshu.com/p/e0afd5d348de
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值