Transformer 看这一篇就够了

之前我在这篇语言模型(五)—— Seq2Seq、Attention、Transformer学习笔记中说过要对Transformer来一个抠细节的笔记,今天它来了。由于大部分内容在上文中已有过系统地介绍,本篇笔记将侧重点放在各个环节中一些重要的细节中,当然也会尽量按照主线流程来展开。欢迎食用。


全局视角

语言模型(五)—— Seq2Seq、Attention、Transformer学习笔记中,我们已经看到过这样的全局视角,这里引述一小段过来,以便在接下来的探索中不迷失:

在Transformer中,我们仍然能够看见他其实也是由传统的Encoder-Decoder演化而来,还是以机器翻译为例,大致的结构图还是与之前一样,其中Encoders和Decoders 部分都是由6层Encoder或Decoder堆叠而成(也可以改的更多层):

image-20200724081154057image-20200724081517511

基础版 Encoder = Self-Attention + FFN

每一个Encoder结构我们称之为一个Encoder Block。它的内部结构如下:

image-20201202111627553

语言模型(五)—— Seq2Seq、Attention、Transformer学习笔记中所讲,Encoder Block由Self-Attention和一个FFN组成。这里需要再次强调一下Self-Attention与传统Sequence to Sequence 中Attention(称之为Encoder-Decoder Attention)的不同:

Encoder-Decoder Attention中是由Decoder作为Query来Attention Encoder中的隐藏态,是一个序列对另一个序列的Attention;而Self-Attention则是在一个序列样本的上下文词之间相互的Attention。

比如说机器翻译中的指代问题,翻译以下句子时“it” 能Self-Attention到"animal" 。而原先,可能只是”动物“Attention到"animal" 。这便是最大的区别。

The animal didn't cross the street because it was too tired

那下面我们具体来看Self-Attention的细节,还是那张图,这次我们标记出部分向量的维度和运算过程:

image-20201202121945636

从图中一点点往下看,第一个细节:

**Embedding的对象不一样了。**对于中文来讲,之前我们Embedding的对象是词级别,比如说对于“中国欢迎您”这句话,在seq2seq中,我们一般会分词”中国/欢迎/您“,但是在这里我们一般会将一句话切分成所谓的token级别,也就是一个字符一个字符的”中/国/欢/迎/您“。那为什么可以这样呢?因为当我们分词成”欢迎“的时候,其实就是预先提供了一定的语义特征,而现在模型学习能力更强了,我们认为”欢/迎“能学习到”欢迎“在上下文中的意思了,所以Embedding的对象也就可以不一样了。

第二个细节:

输入的Embedding加入了位置信息。为了让模型能够学习到词语在语句中不同位置时可能的不同含义,Self-Attention中的Embedding在传统的Embedding基础上加入了位置编码Position Encoding。这是个什么意思呢?它其实就是给了相邻的token以不同的初始化位置信息。为了方便计算,这样的位置信息往往又是有周期性的。不要懵。看到下面的公式可能更懵:

image-20201202211652930

但不要被这个公式迷惑,重点是要理解这个位置编码是要干嘛以及简单的实现原理:偶位置按照正弦函数编码、奇位置按余弦函数编码。这样当你在坐标轴上画出正余弦函数图像的时候你会发现,相邻位置的token一个在正弦函数上一个在余弦函数上,每个token都有他自己独特的位置,即:各token初始化位置按sin/cos周期分布

还有一个问题,不用这种正余弦函数进行位置编码可不可以?当然可以,你也可以给一串token进行0-99的位置编码,99号用完下一个再编号0。

继续看下图,我们回到Self-Attention的主流程上来:

image-20201202221610453
  1. 单词Thinking对应的embedding维度是512维,乘上神经网络参数W_Q(512x64),得到对应的Query:q1(64维),同理得到k1。

  2. q、k点乘得到Score,这一步我们已经在Seq2Seq中说过,含义其实是求了一个相似度。

  3. Score除以根号d_k。再将得到的值通过softmax进行归一化,得到Attention Weight。

    那么细节又来了,为什么要缩放?又为什么是根号d_k?

    需要收缩的原因在于:使数据分布更平滑,防止梯度消失。解释:(如下图softmax的图像)由于需要做softmax,数据分布太不集中可能会导致某些分布点的数据在反向求导的时候没有梯度。我们需要通过缩放将数据分布拉回到一个正常的分布区间里来。那为什么是除以根号d_k呢,因为我们期望的是数据分布要服从(0,1)标准正态分布,但不缩放的时候数据分布是服从均值为0,方差为根号d_k的正态分布,所以要除以根号d_k,将方差拉回到1。

    image-20201202214709682

  4. 加权求和得结果z(对应Encoder-Decoder Attention中的context vector)。

回顾上面的四步,对照Encoder-Decoder Attention中的整个计算流程,不难发现一个细节:q对应Encoder-Decoder Attention中Decoder 输出的上一时刻的隐藏层输出h_t-1,k、v对应的Encoder-Decoder Attention中Encoder的隐藏层输出h_s。如果有点迷糊,可以回去看一眼:Attention机制全流程详解与细节学习笔记

得到z向量之后,按照Encoder Block的结构图,下面将各个z传入FFN,这样便完成了一个Encoder Block的工作。好,暂停一下,我们来看一看这个FFN。

细节:

这里的FFN有两层全连接层:W2(Relu(W1x+b1))+b2,为什么要加这个FFN?因为里边的激活函数Relu为整个网络提供了非线性的学习能力,不然拿一个线性的网络去学习这个复杂的世界,那些重要的非线性特征都没法被发掘出来。

升级版Encoder = Multi-Head Attention + Add&Norm +FFN

先来一张表,看看这个transformer中真正发育完全的升级版是长啥样,再看看它和基础版的差异。

注:”基础版“和”升级版“是我自己起的名字(原论文作者勿怪),实际上”升级版“是真正的Transformer,为了理解上的方便,我在这里给起了名字进行区分,也可以理解成基础版就是没有多头注意力机制、没有Add&Norm的原始版本。

基础版升级版
整体结构image-20201203000546541image-20201203000405155
Encoder Blockimage-20201202111627553image-20200724160802104
Self-Attention的形态image-20200724153123975

当你看完这个表,你会发现,升级版的升级点主要在两点:

  • Self-Attention的形态由单头变为多头,原先是一个Scaled Dot-Product Attention,现在变成了多个Scaled Dot-Product Attention并行。
  • Self-Attention和FFN之后都多了一步Add&Norm 的处理。

来吧,我们一个个来。先说Multi-Head Attention,为什么要搞这么一个东西出来?两点原因:

  1. 增强了模型输入处理的并行性
  2. 同时它对输入的 Q,K,V 进行多次不同的映射,相当于把句子投影到不同的子空间中,提高其表达能力。(原文中8个头,其实就有八组QKV,可以理解成每一组学习的角度不一样,学到的东西也不一样)

那这个多头注意力机制又是怎么实现的呢?直接看图:

image-20201203004455584

整个Multi-Head Attention出来之后就来到了Add&Norm层,这里边主要包含两部分:加入残差(Add)和Layer Normalization(Norm)。

即:Layer Norm(X + Z)

那么灵魂三问来了:

为什么要加入残差结构?

答:为了解决网络层数过深带来的梯度消失问题。

Layer Normalization是什么?

层级的Normalization。LN与BN作用一样:防止梯度消失,加快收敛速度。

为什么不用BN而用LN?

因为在这里我们数据规范化的对象的维度一般都是(batch_size, seq_lenth, 512),如果是BN,归一化的对象是整个一批数据(可以理解为是对batch_size这一维度)进行归一化,因为每一条数据里都可能会有padding补充的0元素,导致一个BN下来,整个数据的均值会降低,数据分布也就改变了。如果是LN。它是针对于每一条数据的(可以看作是seq_lenth这一维度),一行行的归一化不会包含padding进来的0,这样数据的分布也就能不被改变。

以图说明如下:

image-20201203012722816

而为什么在图像处理中,可以用BN,因为图像的每一个像素点都有值,没有padding 0带来的问题。所以可以用BN。

延申:介于LN和BN之间还有一个Group Normalization,可以另行学习。

到这里我们就看完了Encoder部分的所有东西,那么问题又来了:

Transformer中只要Encoder可以吗?

当然可以,事实上,整个Encoder就像一个RNN,它就是一个特征提取器,它生成的特征向量可以去做很多事情,比如加一个FC做分类任务、甚至可以把它当词向量、句向量等等。

只有在生成式任务中我们才需要用到Decoder部分,其他任务Encoder就足以胜任。

image-20201203013648308

再继续,我们来看看Decoder部分到底有啥?

Decoder = Masked Self-Attention + Encoder_Decoder Attention

还是先看基础版的Decoder:

image-20201203020147940

重点都在图上标注了:

Decoder中第一部分的Self-Attention与Encoder中的Self-Attention基本一致,Q、K、V都来源于自己对输入y的学习。只不过多加了一个mask操作,这个mask操作是干嘛的呢?

因为在Decoder时(比如预测句子的时候),当前时刻是不能提前获取到未来时刻的信息,即得把后面的答案遮住,不能提前把答案包进去学习了。遮住后面的答案,这就是mask操作。

第二部分,有一个Encoder-Decoder Attention,这就跟Seq2Seq中讲的Attention是一样的了,需要拿Encoder的输出和Decoder的隐态来计算Attention Weight。这里边的Q是自己第一部分学习到的,K和V都是Encoder输出过来的。这点需要注意。

说完了基础版的Decoder , 升级版自然就是多头并行了,原理和Encoder一样,便不再赘述。

回顾

还是这张图,在语言模型(五)—— Seq2Seq、Attention、Transformer学习笔记的回顾环节,也是这张图,现在当你再看到这张图,你会发现整个Transformer的流程和一些细节应该都藏在这张图里了。不信你品,你仔细品。

image-20200724154423110

最后有一个小小的剧透,左边的Encoder将会是BERT的基础,而右边的Decoder却又是GPT的基础。

小结

一篇长文,花了将近五个小时来写,但却觉得很是值得。现在又到了凌晨两点半,准备洗洗睡。诸位看官,看到这里如果觉得还不错请给一个赞|收藏|关注,一键三连对我来说便是最好的鼓励了。

不积跬步,无以至千里。加油!

两篇神文继续贴在这:

Attention Is All You Need

The Illustrated Transformer

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 博客之星2020 设计师:CY__0809 返回首页