Transformer基础

一、前言

前言
Transformer原论文叫《Attention is all you need》,17年由谷歌团队发表。
Transformer提出时主要针对的是NLP领域里的机器翻译任务。在此之前大家处理这类的任务使用的模型都是RNN、LSTM之类的时序网络,但是这类模型不可避免的存在着记忆长度有限或者说所能利用到的语句信息是有限的这种问题,以及随着序列长度增加带来的梯度爆炸梯度消失等问题,虽然LSTM在RNN的基础上一定程度地缓解了这类问题,但这类基于RNN的网络模型另外一个比较严重的问题是不能并行化。想要计算tn时刻的数据,必须要先计算tn-1时刻的数据,无法并行化带来的问题就是计算效率特别低。针对这些问题,谷歌团队提出了Transformer,现在的Transformer已经成为类似CNN、RNN的基础模型。

二、Transformer

1. 整体架构

整体架构
Transformer整体架构分为两部分Encoder和Decoder,Encoder对输入进行编码,编码后的向量送入到Decoder进行解码。
整体来看Transformer是个对称的架构,但对于内部的数据流动并不是对称的,输入Input要先经过所有的Encoder编码后,再从最后一个Encoder分别进入到对应的Decoder参与计算,最后流经过所有Decoder后输出最终结果Output。
Transformer结构看起来比较复杂,但其实内部主要的组件只有这几个。按模型的顺序来看,有Word Embedding和位置编码、多头自注意力、残差和归一化、前馈神经网络、带掩码的多头自注意力。下面分别介绍。

2. Embedding 和 Positional Encoding

输入编码
以NLP中的机器翻译任务为例,不同于CV中图片可以用像素矩阵表示或者音频等有音频频谱序列向量表示,在NLP里语言这种抽象的工具一开始并没有合适的方法在模型中刻画词语之间的关系。
最开始的解决方法是使用one-hot向量表示每个词语,比如以机器学习为例,使用one-hot向量可以表示为这种形式。当词语量较少的时候这种方法还可以表示,但当词汇量上升到成千上万时,这种方法就不合适了。另外,这种方法仅仅能表示词语,并不能刻画词语之间的关系。比如机器学习中,在语言关系中,机和器应该更相近,学和习之间更相近。One-hot向量就不能表达这种关系了。因此需要另一种方法来表示语言语义。
Embedding这种方法是深度学习的副产物。Embedding本质上其实就是一层全连接层,它主要的作用就是降维,将需要使用大量空间才能表示的one-hot向量形式降维到可以接收的范围内。比如在例子中,机器学习的one-hot形式经过Embedding后维度减半,并且各自的向量表示与语义相关的另一向量更为接近。比如机和器,学和习的向量表示更相近。这里只是为了理解Transformer简单的介绍一下Embedding,Embedding有大量的后续工作,对这方面有兴趣的话可以去深入了解。
对输入Embedding后,还要加上词向量的位置信息。Transformer不同于RNN这种具有天然时序信息的模型,本身是没有任何位置信息的,因此带来的问题就是,如果不对词向量进行位置编码,一个句子的输入和打乱顺序后的输入,模型的输出结果是相同的。还是以机器学习为例,如果不带任何位置信息,对于Transformer来说,输入机器学习还是学习机器两者是等价,输出的都是machine learning。但是就句子语义来说,两者是完全不同的,因此对于Transformer来说,位置编码是必需的。
对于第二个问题,这也是一个很广泛的研究内容,已经有大量的工作研究如何进行编码才能获得更好的表示效果。有兴趣的可以去了解一下,这里简单介绍一下。论文中是对输入进行绝对位置编码,就是用如下的公式分别对奇数位和偶数位的向量编码。具体原理这里就不展开介绍了。另外一种常用的设计成可学习的位置编码,但是经过实验发现这两者没有什么差别,因此现在用的最多的还是这种绝对位置编码。

3. Self-Attention

Self-Attention1
下面介绍Transformer的核心内容Self-Attention。其实图中的公式就是Self-Attention的全部内容了,具体的计算流程接下来详细介绍。只要明确Self-Attention每一步输入输出的维度就不难理解。
这里及后面我们都以输入为机器学习为例,每个字对应一个词向量,因此经过Embedding和encoding之后机器学习的维度就是(4,512),至于为什么词嵌入之后的维度是512,这是经过实验之后得到的结论,这个长度是最合适的,过短不能很好地表征词义,过长增加模型计算量。
Transformer模型以及后续的各种变体里的注意力使用的都是多头注意力,为了便于理解我们先看单头的自注意力。
Self-Attention2
公式中所有的计算使用的都是矩阵形式,这里我们单独拿矩阵中的一行来看。比如以机器学习中的机为例,计算“机”和其它三个词向量之间的注意力分数。这里的a1a2a3a4就是经过词嵌入和位置编码后的词向量。对于要计算的a1对其它的注意力分数,将a1乘上wq参数矩阵生成q1作为待查询的query,其它三个则乘上wk参数矩阵分别生成对应的k2k3k4作为与查询对应的键。注意这里k2k3k4所用到的wk是同一个矩阵,里面所有的参数都是可学习的。为了能够进行矩阵运算,这里设定q和k的维度一致,并且都和输入的a1a2a3a4对齐,所以q和k的维度也是(1,512),因此这里的wq和wk矩阵的维度就是(512,512)。在生成q和k之后,我们就要进行Self-Attention的第一步计算,q1分别和k2,k3k4进行向量乘法,也就是点积计算,最后分别得到α11α12α13α14。这里的α11α12α13α14都是常数作为目前的注意力得分。注意这个α11是q1和自身生成的k1之间点积的结果,q1和k1都是a1经过不同的参数矩阵映射得到的,这就是Self-Attention自注意力名称的由来。
Self-Attention3
计算完qk的点积之后,得出的结果要除以一个常数根号dk,dk就是Embedding之后词向量的维度,在例子里就是√512,至于为什么要将结果都除以一个常数。原因就是有些qk对在经过点积运算后的结果相对于其他点积对来说过大,这就导致在之后的softmax中占据了绝大多数注意力,而其他的点积对在经过softmax之后的分数则趋于0,结果就是会出现梯度消失的问题。因此这里除以一个常数的操作类似于归一化,使得各点积对的结果更加平滑。
所有结果经过softmax之后就可以得到类似图中的结果。
Self-Attention4
计算得到的𝜶(𝟏,𝟏)′, 𝜶(𝟏,𝟐)′, 𝜶(𝟏,𝟑)′, 𝜶(𝟏,𝟒)′再分别和对应的v1v2v3v4进行点积运算,最后加和得到最终的结果b1。这里的v1v2v3v4也是由a1a2a3a4经过另外一个参数矩阵wv映射得到的,作为键值对中的值。至此就是Self-Attention的全部计算内容。
整个Self-Attention中一共出现了三种向量,query,key和value。Key和value是对应的键值对,由query去计算和key对应的注意力分数,最后得到的注意力再和与key对应的value相乘求和。
Self-Attention5
之前计算的a1的自注意力b1,这里需要注意的是,b1b2b3b4并不是依序产生的,实际上,Transformer可以同时计算每个词向量各自的自注意力,就是说b1b2b3b4是可以同时被计算出来的。
Self-Attention6
利用矩阵运算可以实现同时计算所有注意力。还是以之前的机器学习为例,公式中是以qkv为行向量计算的,这里图中画的qkv是列向量,所以这里的qikivi维度为(512, 1),QKV的矩阵维度为(512,4)。
Self-Attention7
用列向量计算为了保持维度一致,这里计算α时需要交换一下Q和K的位置,得到的α的维度是(4,4)。
Self-Attention8
后续的计算过程和之前计算单个注意力的过程一样,需要除以一个常数√(𝒅_𝒌 ),之后再经过softmax,只不过这里计算的不再是向量,而是矩阵。
Self-Attention9
这里同样是因为计算的是列向量,需要将V放在前面保持维度的一致。最后得到最终的结果矩阵。
Self-Attention10
如图所示,将刚才整个过程抽象成矩阵运算,K的转置和Q的乘积经过softmax,再和V相乘得到输出。采用矩阵运算,Self-Attention的代码实现如右下角所示。

4. Multi-Head Self-Attention

Multi-Head
以上都是单头注意力的情况,在模型中使用的都是多头注意力。
多头注意力和单头注意力类似,只不过是在单头的基础上,将q均分成了多个。这里给的就是两个头的例子。计算过程都一样,只是在最后的输出是将结果拼接在一起。官方代码是这样实现的,对于输入的三维数据reshape成四维,多出的维度就是头的数量。

5. Add & Norm 及 Feed Forward

Add
其他组件相对来说就很简单了,Add & Norm就是残差结果后再接一个层归一化。
前馈神经网络的作用是替换全连接层。具体的实现其实是两层一维卷积,所以论文题目Attention is all you need其实有些名不副实。

6. Masked Multi-Head Self-Attention

Masked
在Decoder里使用的是带掩码的Self-Attention,Decoder要对输入解码。对于一个序列,在t时刻,我们的解码输出应该只能依赖于t时刻之前的输出,而不能使用到t时刻之后的信息。但是Self-Attention的计算会看到所有的信息。因此我们需要想一个办法,使得t之后的信息对于Self-Attention来说是不可见。
那么具体做法是产生一个上三角矩阵,上三角的值全为0。把这个矩阵作用在每一个序列上,就可以达到我们的目的。
sequence mask的目的是防止Decoder看到未来的信息,就像防止考生偷看考试答案一样。这里mask是一个下三角矩阵,对角线以及对角线左下都是1,其余都是0。这种做法只对输入为非负的情况有效,当输入存在负数时,这种做法就破坏了得到的注意力。
因此更多的做法是让要忽略的QK注意力分数加上一个无穷小的数,这样在softmax中这部分数据就会趋于0,从而达到遮盖的作用。

整体流程

gif1

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值