当前位置:   article > 正文

语言模型(五)—— Seq2Seq、Attention、Transformer学习笔记_seqselfattention模型图

seqselfattention模型图

按:三个月前的一篇笔记,先发出来,后面还会有第二次学习的笔记,两者结合起来看,更加爽口。
本篇笔记5000余字,可细嚼,亦可跳阅。

机器翻译

本篇笔记中要开始介绍的Encoder-Decoder模型最初是由机器翻译这一任务中脱产而来,所以先从此入手。
机器翻译的通俗解释就是由机器把一种语言翻译成另外一种语言,它的发展大概经历了三大阶段:基于规则的方法、统计机器翻译和目前流行的神经网络机器翻译。

翻译方法(阶段)特点劣势
基于规则的翻译翻译知识来自于人类专家;准确率较高成本较高;周期较长;规则易冲突;
统计机器翻译基于语料库的方法;需要大量语料训练,否则易出现数据稀疏的问题;没有专家规则,准确率不高;
神经网络机器翻译基于Encoder-Decoder框架;准确率比较高;人工训练成本相对比较高

那么神经网络训练出来的机器翻译模型为何就能够大大地提高翻译的准确性呢?

让我们一步步往下看:

Encoder-Decoder框架

image-20200722082642319

上图给我们简单的展示了Encoder-Decoder框架的基本形态,其实不难理解,类似于无线信号的调制与解调,编码-解码的模型也是将一个输入进行编码-解码之后得到一个输出,只不过应用在机器翻译领域的话,输入可能是一种语言,输出又是另外一种语言。这样也就完成了一次翻译的过程。

Seq2Seq

Seq2Seq的全称是sequence to sequence, 基础的seq2seq = Encoder + Decoder + 语义编码c (连接两者的中间状态向量,可以理解成两种语言之间的联系规律)。Encoder 中将可变长度的信号序列变为固定长度的向量表达,其实本质也就是进行了特征压缩;Decoder 将这个固定长度的向量变成可变长度的目标信号序列;Encoder、Decoder可以是CNN、RNN、Transformer三种结构,Encoder和Decoder可以是相同的结构,也可以是不同的结构。

相同结构,即都是RNN,或者CNN,或者都是Transformer;不同结构,比如一个是RNN,另一个CNN(例如:Image Caption)。

seq2seq中Encoder-Decoder框架如下:

image-20200723083410350

我们以一个简单的中英文翻译来举例:在Encoder中,待翻译的原文“欢迎来北京”先是被分词(tokenization)成“欢迎//北京”,然后我们还需要将这些词转换为词向量v(i)(即Embedding),然后与上一时刻的隐状态h(i-1)按照时间顺序进行输入,每一时刻输出一个隐状态h(i),这里用函数f表达RNN隐藏层的变换h(i)=f(v(i),h(i-1))。假设有t个词,最终通过Encoder自定义函数q将各时刻的隐状态变换为向量c=q(h(0),…,h(t)),我们认为c已经提取了输入句子的含义,并将其传入给Decoder部分进行解码。在Decoder部分,每一时刻的输入都是之前输出的c和前一时刻解码输出的s(i-1),以及前一时刻预测出的词向量E(i-1),那么我们是如何定义开始和结束的呢,当预测第一个词的时候,我们的输入词向量是_SOS,解码一直往前,直到解析出 _EOS,表示解码结束。这里用函数来表示解码部分的变换:s(i) = g(c,s(i-1),E(i-1))。

整个过程如下图所示:

image-20200723142424346

**有一点是需要特别说明的:**准确来说,上图反映的是预测阶段的Encoder-Decoder过程,真正模型训练过程中,在Decoder阶段,每一步解码过程的输入并不是上一步的输出,而是我们知道的那个标准答案,我们只在最开始的时候输入一个开始字符SOS,后面每一步的输入都是上一步的样本真实值y,而不是预测值y’,整个过程以输出结束字符EOS为结束标志,如下图所示:

image-20200723143413015

这种训练中传入标准答案进行监督纠正、加快收敛的方式我们称之为“Teacher Forcing”。与之对应的是之前我们展示的方式:下一时刻的输入是上一时刻的输出,这种我们也可以叫它“Free Running”,那么我们为何要用Teacher Forcing来进行训练呢?

因为在Free Running中,本质上每一步的输出有一种盲猜的感觉,如果不加以纠正反馈,就可能出现一步错步步错的结果,这显然不是我们想要看见的。虽然Free Running将每一步的最优解输出作为了下一步的输入,但可能存在一个问题,那就是每一步的局部最优并不一定引发最终结果上的全局最优。小小的误差可能导致最后的“误差爆炸”。

如果在预测阶段,我们不得不面对这种“误差爆炸”的情况,我们可以采用一种叫“Beam Search”的方法从一定程度上缓解这种问题,Beam Search简单来说就是设定一个n值,往后每计算一步都会取最优解排序的top-n,然后继续在这n条分支上继续前进,直到最后得出最终的top-n。这一块我们另外单独来学习。

Teacher Forcing其实也并不是完美的,它也可能造成模型的泛化能力不强,于是我们可以采取一种折中的方法来训练模型——计划采样。一句话来说就是以一定概率p使用Teacher Forcing,有点dropout的意思了。

上面我们已经了解了seq2seq模型的基本结构及原理,由于RNN的结构和中间语义向量的难解释性,它可以做到支持多输入多输出且输入输出长度不要求一致。但同时我们也应该看到:Encoder和Decoder之间的唯一联系就是一个固定长度的语义向量C,即Encoder要将整个序列的信息压缩进一个固定长度的向量中去。因为语义向量无法完全表示整个序列的信息,而且之前先输入的内容带有的信息会被后输入的信息稀释掉,输入的句子越长,输入序列越长,这个现象就越严重。(这点上有点类似与LSTM当时要解决RNN的梯度消失的问题的感觉)这样Decoder时,没有获得输入序列足够的信息, 因此Deocder的准确度自然会降低。

基于这样的不足,人们提出了基于Attention的Encoder-Decoder模型。在Decoder中,使用了Attention机制,不要求Encoder将所有输入信息都编码进一个固定长度的向量中。

Attention 机制

Attention的核心就是加权重。

Encoder-Decoder中加入Attention机制:让Encoder编码出的c向量跟Decoder解码过程中的每一个输出进行加权运算,在Decoder的每一个过程中调整权重取到不一样的 c 向量。

image-20200723162223109

还是以之前翻译“欢迎来北京”为例,当翻译到第一个词“welcome”的时候,网络需要着重去看“欢迎”这个词。这就是所谓的Attention。但具体在计算时是怎么体现的呢?

放两张图,原本在这写了一大段,发现写的没人家好,直接把人家的搬过来了:

经典的Attention模型架构:

image-20200723174737611

image-20200723174840397

通过为每个输出位置计算一个context vector,使得每个位置的输出可以关注到输入中最相关的部分,效果比传统模型更好。

补充说明:其中a(ij)就是attention的权重,是j=1,2,3…,T时刻的一个概率分布,其实是通过softmax函数进行计算得出的:

image-20200723163638337

通俗地解释一下这件事:

原先翻译“北京欢迎你” 的时候,相当于每个词给的权重一样,比如都是0.33,现在加入attention之后,当我翻译“北京”的时候,我会通过一种认定方式去认定我要输出的“Beijing”与输入序列的“北京”相关联程度较大,这样我就会给它给多的权重,可能权重就调整为:<北京,0.9>、<欢迎,0.05>、<你,0.05>,这样我们就更加聚焦我们要翻译的点,“北京”一词到翻译成“Beijing”时保留的信息就更多了,翻译的准确性也就提高了。同时在翻译“北京”时,对应输出的中间语义表征向量是c1,以往是大家统一生成一个c,所有的语义信息都被杂糅进了这一个向量中,特征的个性得不到表达。

那么刚刚我们提及的这个“认定方式”,又是什么呢?网络是怎么知道谁和谁关联程度比较大的呢?其实我们的网络参数初始化都是随机值,其实这个值还是通过一定规则前向传播反向传播学习出来的,那么我们就要定一个规则(也可理解为目标函数)来作为我们的衡量指标,在这里这个规则就是上面提及的相关性计算,比如点积,或者其他距离,我们称之为e距离,通过计算Encoder的输出h(j)与Decoder上一时刻的隐态s(i-1)之间的e距离,再通过softmax函数将其转化为我们要的权重,这样我们要Attention的依据就出来了。

感觉权重与残差的思想一直就没有离开过。

引申:Attention模型提出后,出现了许多Attention模型的变体,包括——

  • Soft Attention、Global Attention、动态 Attention:
    三者是同一种Attention,即上述结构,对输入的每个位置都计算对齐概率
  • Hard Attention:
    同样对每个位置计算对齐概率,但只将最高的一个置为1,其余置为0
  • local Attention:
    只计算一个窗口内的位置的对齐概率,减少计算量

回顾整个Attention机制,不难发现它的内部还是用了大量的RNN模型,那么我们就会想,都Attention了,不用RNN行不行呢,我就只用Attention。答案是可以的,它就是Transformer。

Transformer

Transformer利用Self Attention 来捕捉时序类的特征用Multi-head Attention 来增强数据处理的并行性,解决了RNN几乎不可以并行处理的弊端。利用Feed-Forward前馈层,通过非线性变化来转换数据特征。Transformer用Attention机制代替了RNN搭建了整个模型框架。

说到对Transformer的理解,就不得不提到一篇文章:The Illustrated Transformer,这篇文章写的很好,国内不少人将其翻译转发,以下内容部分也来自于该文章。

全局视角

在Transformer中,我们仍然能够看见他其实也是由传统的Encoder-Decoder演化而来,还是以机器翻译为例,大致的结构图还是与之前一样:

image-20200724081154057

其中Encoders和Decoders 部分都是由6层Encoder或Decoder堆叠而成:

image-20200724081517511

单看每一层Encoder和Decoder:

image-20200724081705432

Encoder部分,输入首先流进一个Self-Attention层(后面单独讨论),该层可以帮助编码器在对特定单词进行编码时查看输入句子中的其他单词(其实也就是相当于原先网络中的RNN,捕获了时序类的特征),该层的输出被馈送到前馈神经网络(Feed Forward Neural Network),通过一些非线性的变换来转换特征(捕获非线性特征)

注意,其实这里有两层全连接层:W2(Relu(W1x+b1))+b2,给模型提供非线性能力

Decoder部分,首先它具有和Encoder部分同样的Self-Attention层和Feed Forward层,不同的是它在两层之间加了一层Attention,这是一层普通的Attention层,和之前我们讨论的原始Attention一样,可以帮助解码器将注意力集中在输入语句的相关部分。

Self-Attention

对于机器翻译中的指代问题,例如翻译以下句子时“it”到底指的是什么?

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

对机器来说怎么让它知道后面的“it”指代的是啥?这是一件不容易的事,Self-Attention机制就可以做到这件事,接下来我们就讨论Self-Attention是怎么工作的。

Attention的目的是要算出一个context vector,原始的Attention模型使用①输出当前位置的隐状态②输入所有位置的隐状态计算匹配程度,并根据匹配程度对③输入所有位置的隐状态进行加权求和得到context vector。

在Self-Attention中,输入输出都是句子本身,对原始Attention做一个转化——

把当前位置看成输出,其映射后的隐状态记为query(上面的①)
把当前位置看成输入,其映射后的隐状态记为key(上面的②)
把当前位置看成输入,其用于加权求和的隐状态记为value(上面的③)

----摘自Seq2Seq – Attention – Transformer

借助上面的理解,我们再来看Self-Attention的基本模型图:

上面的模型是这样运作的:

第一步,我们需要计算出三个向量(query/key/value-vec,对应q、k、v)出来。假设输入的单词是Thinking和Machines,先通过Embedding将输入单词转化为词向量x1和x2,再乘上模型参数来计算q、k、v:

image-20200724145519829

如图:

image-20200724145550091

在这一步我们可以理解q、k、v是我们的三个特征表达代理。

第二步,MatMul。即计算对应Attention的权重值,对“Thinking Machines”这句话,对“Thinking”(pos#1)计算attention 分值。我们需要计算每个词与“Thinking”的评估分(Score),这个分决定着编码“Thinking”时(某个固定位置时),每个输入词需要集中多少关注度。这个分,通过“Thinking”对应query-vector与所有词的key-vec依次做点积得到。所以当我们处理位置#1时,第一个分值是q1和k1的点积,第二个分值是q1和k2的点积。

这一步类似于之前我们用e距离函数计算相似度的感觉,最后经过softmax变成对应的权重。

image-20200724150139341

第三步:对上一步的乘积做一个除法,(1/sqrt(d(k))),这样梯度会更稳定。除根号d(k)是为了把数据分布拉回到正常的正态分布,使分布更平滑。缩放是为了使梯度更加稳定。

第四步:处理后的Score通过一个Softmax函数计算对应的权重。Softmax对Score进行归一化,因此所有Score均为正,且加起来为1。如下图:

image-20200724151137489

第五步,将softmax分值与value-vec按位相乘。保留关注词的value值,削弱非相关词的value值。
第六步,将所有加权向量加和,产生该位置的self-attention的输出结果。(如z1=0.88v1+0.12v2)

整个过程就是:

image-20200724151259213

矩阵运算时,整个过程可以用公式表达(上述求和过程被内化到矩阵运算中了):

image-20200724151821372

或者你可以看着这个图来理解:

image-20200724151907224

如果你细心对照你会发现,对比之前的模型结构图,上述过程并没有体现结构图中Mask操作。在Scaled Dot-Product Attention中,Mask是可选的(实际工程实现是必须的,因为效果还是明显的),在Decoder的时候,我们要获取所有时刻的输入(K, V),即不使用Mask,就像我们只会在Decoder的时候使用Attention机制去重点关注某一些输入一样。

到这里我们就可以看出一件事,Encoder的每一个位置都能被下一层注意到,这其实就起到了类似RNN的处理序列信息的作用。接下来我们是怎么解决并行的问题的呢,那就是多头注意力机制。

Multi-Head Attention

Multi-Head Attention进一步完善了Self-Attention层,增强了模型输入处理的并行性,同时它对输入的 Q,K,V 进行多次不同的映射,相当于把句子投影到不同的子空间中,提高其表达能力。其结构如下:

image-20200724153123975

具体的过程如下:

image-20200724153806133

Transformer整体回顾

image-20200724154423110

对照上图所示整个Transform的网络结构图,结合之前我们已经详细展示过的Scaled Dot-Product Attention和Multi-Head Attention,进行一些个人理解的说明和未涉及知识点的补充说明:

  • 输入文本的预处理包括两个:Input Embedding和Positional Encoding,Input Embedding将文本词语向量化,Positional Encoding使用正弦函数和余弦函数来构造每个位置的值,使得最终输入的向量包含每个词在源文本中的位置信息。这一步合成的输入向量送入N层(一般6层)的Encoders中,每一层Encoder包含一个Self-Attention层和一个Feed Forward层。
  • Self-Attention层可以理解成是我们所说的Multi-Head Attention,这里边包含了很多和Scaled Dot-Product Attention,增加了并行能力及模型表达能力。Scaled Dot-Product Attention之所以实现的是Self-Attention机制,是因为它关注的是自己,即来源可以说同源不同枝的q、k、v。通过一系列计算得出了我们需要的输出z。
  • 从上图中可以看到Multi-Head Attention和Feed Forward之后都跟着一个Add & Norm,这是什么呢,我们没有详细介绍,可以参见The Illustrated Transformer中详细的说明,它其实是加入了一个网络输入的残差,残差网络能让每一层都能获取一些输入的原始信息,不至于梯度消失,有助于提高模型的表达能力。简单说明如下图:

image-20200724160802104

  • Encoder中利用基本单元叠加,key, query, value来自前一层Encoder的输出,即Encoder的每个位置都能注意到前一层Encoder的所有位置。这样也是有助于提升模型的表达能力的。
    • Decoder中有两个与Encoder不同的地方,一个是第一级的Masked Multi-head(使用Mask是因为在预测句子的时候,当前时刻是无法获取到未来时刻的信息),另一个是第二级的Multi-Head Attention不仅接受来自前一级的输出,还要接收Encoder的输出。
    • 第一级Decoder的key, query, value来自前一层Decoder的输出,但加入了Mask操作,即只能Attend到前面已经翻译过的输出的词语。
    • 第二级Decoder也称为Encoder-Decoder attention layer,它的query来自于之前一级的Decoder层的输出,但key和value来自于Encoder的输出,这样Decoder的每一个位置都可以attend到输入序列的每一个位置(k和v的来源总是相同的,q在Encoder及第一级Decoder中与k,v来源相同,在encoder-decoder attention layer中与k,v来源不同)。

还是建议多去读一读Attention Is All You NeedThe Illustrated Transformer,对于我们理解Transform会很有帮助。这篇文章太长了,先到这,还有一些细枝末节需要另外开文讲述,包括但不限于:

介绍position encoding机制。

attention机制的细节探索
transformer机制的一些细节探索

参考文章:

人工智能机器翻译的发展经历了哪几个重要阶段?

Attention机制详解(一)——Seq2Seq中的Attention

Attention Is All You Need

Seq2Seq – Attention – Transformer

The Illustrated Transformer
The Illustrated Transformer【译】

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/870033
推荐阅读
相关标签
  

闽ICP备14008679号