Transformer学习

RNN(Recurrent Neural Network)

在这里插入图片描述
计算公式如下:
h t = f W ( h t − 1 , x t ) h t = t a n h ( W h h h t − 1 + W x h x t ) y t = W h y h t h_t=f_W(h_{t-1},x_t) \\ h_t=tanh(W_{hh}h_{t-1}+W_{xh}x_t)\\ y_t=W_{hy}h_t ht=fW(ht1,xt)ht=tanh(Whhht1+Wxhxt)yt=Whyht

LSTM

LSTM(Long Short-Term Memory)是RNN的一种变体,为了解决长期记忆问题,c是长期记忆,h是短期记忆。f:遗忘门,i:输入门,o:输出门。
在这里插入图片描述

GRU

参数比LSTM更少,zt为更新门,rt为重置门
在这里插入图片描述

seq2seq

seq2seq模型:输入是一个序列,输出也是一个序列。
seq2seq 相关的论文:
[1] Sutskever et al., 2014. Sequence to Sequence Learning with Neural Networks
[2] Cho et al., 2014 . Learning Phrase Representations using RNN Encoder-Decoder for Statistical Machine Translation
[3] Bahdanau et al., 2014. Neural Machine Translation by Jointly Learning to Align and Translate

论文1模型:

在这里插入图片描述
等价于下图:
在这里插入图片描述

论文2模型:

在这里插入图片描述
编码器隐藏状态 h < t > h_{<t>} h<t>计算公式:
h < t > = f ( h < t − 1 > , x t ) h_{<t>}=f(h_{<t-1>},x_t) h<t>=f(h<t1>,xt)
解码器在时间 t t t的隐藏状态 h < t > h_{<t>} h<t>计算公式:
h < t > = f ( h < t − 1 > , y t − 1 , c ) h_{<t>}=f(h_{<t-1>},y_{t-1},c) h<t>=f(h<t1>,yt1,c)
下一个符号的条件概率分布为:
P ( y t ∣ y t − 1 , y t − 2 , . . . , y 1 , c ) = g ( h < t > , y t − 1 , c ) P(y_t|y_{t-1},y_{t-2},...,y_1,c) = g(h_{<t>},y_{t-1},c) P(ytyt1,yt2,...,y1,c)=g(h<t>,yt1,c)
整个序列生成概率为:
P ( y 1 , y 2 , y 3 , . . . , y T ∣ x 1 , x 2 , . . . , x T ) = ∏ t = 1 T p ( y t ∣ x 1 , . . . x t − 1 , y 1 , . . . , y t − 1 ) = ∏ t = 1 T p ( y t ∣ c , y 1 , . . . , y t − 1 ) P(y_1,y_2,y_3,...,y_T|x_1,x_2,...,x_T)\\ =\prod^T_{t=1}p(y_t|x_1,...x_{t-1},y1,...,y_{t-1})\\ =\prod^T_{t=1}p(y_t|c,y1,...,y_{t-1}) P(y1,y2,y3,...,yTx1,x2,...,xT)=t=1Tp(ytx1,...xt1,y1,...,yt1)=t=1Tp(ytc,y1,...,yt1)
所以对于训练样本,我们要做的就是在整个训练样本下,所有样本的 P ( y 1 , y 2 , y 3 , . . . , y T ∣ x 1 , x 2 , . . . , x T ) P(y_1,y_2,y_3,...,y_T|x_1,x_2,...,x_T) P(y1,y2,y3,...,yTx1,x2,...,xT)概率之和最大。即最大化条件对数似然概率:
max ⁡ θ 1 N ∑ n = 1 N l o g p θ ( y n ∣ x n ) \displaystyle\max_\theta \tfrac{1}{N} \sum_{n=1}^Nlogp_\theta(y_n|x_n) θmaxN1n=1Nlogpθ(ynxn)

论文3模型:

在这里插入图片描述
目标单词 y i y_i yi的概率定义为:
p ( y i ∣ y 1 , . . . , y i − 1 , x ) = g ( y i − 1 , s i , c i ) p(y_i|y_1,...,y_{i-1},x)=g(y_{i-1},s_i,c_i) p(yiy1,...,yi1,x)=g(yi1,si,ci)
其中
s i = f ( s i − 1 , y i − 1 , c i ) s_i=f(s_{i-1},y_{i-1},c_i) si=f(si1,yi1,ci)

c i c_i ci是编码阶段的每个时刻输出状态的加权平均和
c i = ∑ j = 1 T x a i j h j c_i=\sum^{T_x}_{j=1}a_{ij}h_j ci=j=1Txaijhj
这里 h j hj hj为Encoder阶段的每个时刻输出状态, a i j a_{ij} aij为每个Decoder阶段的输入i 对应的 h j h_j hj 的权重值大小。具体的计算公式为:
a i j = e x p ( e i j ) ∑ k = 1 T x e x p ( e i k ) a_{ij}=\tfrac{exp(e_{ij})}{\sum_{k=1}^{T_x}exp(e_{ik})} aij=k=1Txexp(eik)exp(eij)
其中 e i j e_{ij} eij的公式为:( a a a是需要训练的参数)
e i j = a ( s i − 1 , h j ) e_{ij}=a(s_{i-1},h_j) eij=a(si1,hj)

Transformer

相关的论文:
[1] Attention is All You Need

Transformer Architecture

下图是简化的 Transformer 的模型架构示意图,先来大概看一下这张图, Transformer 模型的架构就是一个 seq2seq 架构,由多个 Encoder Decoder 堆叠而成。
在这里插入图片描述
而每个 Encoder Decoder 长什么样子可以看下图,原本编解码的基本单元是 RNN ,这里改用了 Self-attention layer 和 Feed Forward, 而 Decoder 则由 Self-Attention、Encoder-Decoder Attention、 Feed Forward 组成。 Transformer 其实就是 seq2seq model with self-attention。
在这里插入图片描述
概括来说,我们输入法语:je suis étudiant,经过六个 Encoder 后得到了类似于 Context Vector 的东西,然后将得到的向量放进 Decoder 中,每个 Decoder 会对上一个 Decoder 的输出进行 Self-Attention 处理,同时会把得到的结果与 Encoder 传递过来的 Vector 进行 Encoder-Decoder Attention 处理,将结果放入前馈网络中,这算是一个 Decoder,而把六个 Decoder 叠加起来学习,便可得到最后的结果。这里叠起来的编解码器的数量不是固定的,至于 Encoder 和 Decoder 的工作原理在下面章节介绍。

Encoder和decoder的大致结构分别如下图的左半部分和右半部分所示。
在这里插入图片描述

Attention原理

Attention定义

A t t e n t i o n ( Q , K , V ) = s o f t m a x ( Q K T d v ) v Attention(Q,K,V)=softmax(\tfrac{QK^T}{\sqrt{d_v}})v Attention(Q,K,V)=softmax(dv QKT)v
其中 Q ∈ R n × d k , K ∈ R m × d k , V ∈ R m × d v Q\in R^{n×d_k},K\in R^{m×d_k},V\in R^{m×d_v} QRn×dk,KRm×dk,VRm×dv。如果忽略激活函数 s o f t m a x softmax softmax的话,那么事实上它就是三个 n × d k , d k × m , m × d v n×d_k,d_k×m,m×d_v n×dk,dk×m,m×dv的矩阵相乘,最后的结果就是一个 n × d v n×d_v n×dv的矩阵。于是我们可以认为:这是一个 A t t e n t i o n Attention Attention层,将 n × d k n×d_k n×dk的序列 Q Q Q编码成了一个新的 n × d v n×d_v n×dv的序列。
那怎么理解这种结构呢?我们不妨逐个向量来看。
A t t e n t i o n ( q t , K , V ) = ∑ s = 1 m 1 Z e x p ( < q t , k s > d k ) v s Attention(q_t,K,V)=\sum_{s=1}^m\tfrac{1}{Z}exp(\tfrac{<q_t,k_s>}{\sqrt {d_k}})v_s Attention(qt,K,V)=s=1mZ1exp(dk <qt,ks>)vs
其中Z是归一化因子。事实上 q , k , v q,k,v q,k,v分别是 q u e r y , k e y , v a l u e query,key,value query,key,value的简写, K , V K,V K,V是一一对应的,它们就像是 k e y − v a l u e key-value keyvalue的关系,那么上式的意思就是通过 q t q_t qt这个query,通过与各个 k s k_s ks内积的并softmax的方式,来得到 q t q_t qt与各个 v s v_s vs的相似度,然后加权求和,得到一个 d v d_v dv维的向量。其中因子 d k \sqrt {d_k} dk 起到调节作用,使得内积不至于太大(太大的话softmax后就非0即1了,不够“soft”了)。

Multi-Head Attention

把Q,K,V通过参数矩阵映射一下,然后再做Attention,把这个过程重复做h
次,结果拼接起来就行了。具体来说
h e a d i = A t t e n t i o n ( Q W i Q , K W i K , V W i V ) head_i=Attention(QW_i^Q,KW_i^K,VW_i^V) headi=Attention(QWiQ,KWiK,VWiV)
Q ∈ R n × d k , K ∈ R m × d k , V ∈ R m × d v Q\in R^{n×d_k},K\in R^{m×d_k},V\in R^{m×d_v} QRn×dk,KRm×dk,VRm×dv
这里 W i Q ∈ R d k × d k ~ , W i K ∈ R d k × d k ~ , W i V ∈ R d v × d v ~ W_i^Q\in R^{d_k×\tilde{d_k}},W_i^K\in R^{d_k×\tilde{d_k}},W_i^V\in R^{d_v×\tilde{d_v}} WiQRdk×dk~,WiKRdk×dk~,WiVRdv×dv~
然后
M u l t i H e a d ( Q , K , V ) = C o n c a t ( h e a d 1 , . . . , h e a d h ) MultiHead(Q,K,V)=Concat(head_1,...,head_h) MultiHead(Q,K,V)=Concat(head1,...,headh)
最后得到一个 n × ( h d ~ v ) n×(h\tilde{d}_v) n×(hd~v)的序列。所谓“多头”(Multi-Head),就是只多做几次同样的事情(参数不共享),然后把结果拼接。

Self Attention

到目前为止,对Attention层的描述都是一般化的,我们可以落实一些应用。比如,如果做阅读理解的话,Q可以是篇章的向量序列,取K=V为问题的向量序列,那么输出就是所谓的Aligned Question Embedding。

而在Google的论文中,大部分的Attention都是Self Attention,即“自注意力”,或者叫内部注意力。

所谓Self Attention,其实就是Attention(X,X,X),X就是前面说的输入序列。也就是说,在序列内部做Attention,寻找序列内部的联系。Google论文的主要贡献之一是它表明了内部注意力在机器翻译(甚至是一般的Seq2Seq任务)的序列编码上是相当重要的,而之前关于Seq2Seq的研究基本都只是把注意力机制用在解码端。类似的事情是,目前SQUAD阅读理解的榜首模型R-Net也加入了自注意力机制,这也使得它的模型有所提升。
当然,更准确来说,Google所用的是Self Multi-Head Attention: Y = M u l t i H e a d ( X , X , X ) Y=MultiHead(X,X,X) Y=MultiHead(X,X,X)

Position Embedding

然而,这样的模型并不能捕捉序列的顺序!换句话说,如果将K,V按行打乱顺序(相当于句子中的词序打乱),那么Attention的结果还是一样的。

于是Google再祭出了一招——Position Embedding,也就是“位置向量”,将每个位置编号,然后每个编号对应一个向量,通过结合位置向量和词向量,就给每个词都引入了一定的位置信息,这样Attention就可以分辨出不同位置的词了。
构造Position Embedding的公式:
{ P E 2 i ( p ) = s i n ( p / 1000 0 2 i / d p o s ) P E 2 i + 1 ( p ) = c o s ( p / 1000 0 2 i / d p o s ) \begin{cases} PE_{2i}(p)=sin(p/10000^{2i/d_{pos}}) \\ PE_{2i+1}(p)= cos(p/10000^{2i/d_{pos}}) \end{cases} {PE2i(p)=sin(p/100002i/dpos)PE2i+1(p)=cos(p/100002i/dpos)
这里的意思是将id为p的位置映射为一个 d p o s d_{pos} dpos维的位置向量,这个向量的第i个元素的数值就是 P E i ( p ) PE_i(p) PEi(p)。Google在论文中说到他们比较过直接训练出来的位置向量和上述公式计算出来的位置向量,效果是接近的。因此显然我们更乐意使用公式构造的Position Embedding了,我们称之为Sinusoidal形式的Position Embedding。

结合位置向量和词向量有几个可选方案,可以把它们拼接起来作为一个新向量,也可以把位置向量定义为跟词向量一样大小,然后两者加起来。FaceBook的论文和Google论文中用的都是后者。直觉上相加会导致信息损失,似乎不可取,但Google的成果说明相加也是很好的方案。

Encoder

下面是 Encoder 的示意图,在这里我们假设输入的句子只有两个词,简单高效的讲解 Encoder 的工作原理。
在这里插入图片描述
细节暂且不看,这个 Encoder 模块可以实现什么功能呢?上图所示,我们输入了两个编码后的向量 x 1 , x 2 x_1,x_2 x1,x2,其中 x 1 x_1 x1是对单词 Thinking 的表示, x 2 x_2 x2是对 Machines 单词的表示。 通过 Encoder 模块得到了两个向量 r 1 , r 2 r_1,r_2 r1,r2,虽然 r 1 , r 2 r_1,r_2 r1,r2也分别代表 Thinking、Machines 单词的信息,但是 r 1 , r 2 r_1,r_2 r1,r2是加权后的结果,也就是说 r 1 r_1 r1中不仅仅包含 Thinking 单词的信息,而且还有 Machines 单词的信息,只不过 Thinking 单词信息占的比重可能很高,毕竟单词和单词本身的相关性是很高的(这里为了方便理解,距离一个例子,具体权重如何分配的是模型学习出来的)。这里用两个词语举例子,如果输入的句子单词很多,可能不同单词之间的相关度就不一样,最后得到的 r r r向量分配的权重也就不同。

所以,原始输入的向量 x 1 , x 2 x_1,x_2 x1,x2各自包含各自的信息,而最后得到的 r 1 , r 2 r_1,r_2 r1,r2便分别包含了原始输入所有向量的信息,只是各占的比重不同。试图去学习到不同单词之间的相关度有什么作用呢?看下图:
在这里插入图片描述
如上图所示,很明显,单词 it 和 the animal 的相关度最高,这就是我们所期望的。因为本句话的语义 it 就是指的 the animal。

怎样才能每个单词的信息按不同权重糅合起来呢 ?没错,Self-Attention 机制。

Self-Attention

看下图这一个 Encoder 模块,此模块的 Self-Attention 中发生了信息的融合,也就是在这期间按不同权重来组合新的向量。
在这里插入图片描述
Self-Attention 中的细节如下图所示,当单词 Thinking、Machines 进行 Embedding 后,分别与矩阵 W Q , W K , W V W^Q,W^K,W^V WQ,WK,WV相乘。例如 Thinking 单词 Embedding 后变成 X 1 X_1 X1向量,此向量与 W Q W_Q WQ相乘后为q1向量,也称为 Queries , X 1 X_1 X1 W K W^K WK相乘得到k1向量,以此类推。我们称q1,k1,v1向量分别为 Queries、Keys、Values 向量。
图9:K、V和Q的计算过程
输入的每个单词都都可以通过同一个矩阵计算得到对应的qi,ki,vi向量,x1通过下图的过程生成z1 。用q1即 Thinking 单词的 Queries, 分别与其它单词的k1向量相乘,比如 q 1 ⋅ k 1 = 122 , q 1 ⋅ k 2 = 96 q1\cdot k1=122,q1\cdot k2=96 q1k1=122,q1k2=96。然后用得到的值除以根号下 d k d_k dk( d k d_k dk为上方提及的矩阵的第一个维度 ) 得到 14 和 12,对除法的结果进行 softmax,于是 Thinking 单词对应的比例是 0.88,而Machines 对应比率的是 0.12 ,接下来使用 softmax 后得到的比率与对应的 Values 向量相乘,便得到了v1和v2,v1=0.88v1,v2=0.12v2 。由于 0.12 占的比例较小,得到的v2向量颜色较浅。最后将得到的v1,v2加起来便是z1。
Self-Attention的向量计算
于是z1便包含了两个单词的信息,只不过 Thinking 单词的信息占的比重更大一些,而 Machines 单词的信息占的比例较小。
同样z2向量可以通过相同的方式计算出来,只不过计算 Score 的时候需要用 q 2 ⋅ k 1 , q 2 ⋅ k 2 q2\cdot k1,q2\cdot k2 q2k1,q2k2。需要使用q2去分别乘k1和k2。除以 8 并且 Softmax 后可以与v1,v2相乘,相加后便得到的z2,z2包含了两个单词的向量,只不过各占的比重不同。

向量化

到目前为止,还有一个性能上的问题,不知道大家有没有发现。回顾下图:
在这里插入图片描述
当我们计算q1,k1,v1的时候,我们需要用向量x1分别与三个矩阵 W Q , W K , W V W^Q,W^K,W^V WQ,WK,WV相乘,而计算q2,k2,v2的时候又得需要进行三次乘法。这里仅仅有两个词就进行了 6 次运算。如果一个句子中有很多词呢 ?那对性能是不是非常大的消耗 ?这里就需要用到向量化的操作了,如下图所示,不在拿x1,x2分别去和三个矩阵相乘,而是将x1,x2叠加起来看着一个新的矩阵X,再去和三个矩阵相乘。得到三个新的矩阵Q,K,V, 这三个矩阵的每一行代表着一个词转化后的值。
在这里插入图片描述
进行z值计算的时候也可以用向量化的思想,最后的矩阵Z就是z1和z2叠加在一起的结果。
在这里插入图片描述
其中矩阵 W Q , W K , W V W^Q,W^K,W^V WQ,WK,WV是学习出来的,我们试图去学习三个矩阵 W Q , W K , W V W^Q,W^K,W^V WQ,WK,WV,与 Embedding 向量相乘后得到 Query,Key,Value 向量。而期望得到的 Query,Key,Value 向量最契合当前的任务。因为矩阵 W Q , W K , W V W^Q,W^K,W^V WQ,WK,WV是学习出来的,所以得到的 Query,Key,Value 向量是比较抽象的。在这里,我认为 W Q , W K , W V W^Q,W^K,W^V WQ,WK,WV矩阵的功能相当于抽取特征。这里的命名 Query,Key,Value 也非常有意思, 大家自己想想每个向量的功能就能对应上了。这里应该是借鉴了信息检索的相关思想。

Multi-Head Attention

刚刚的例子,我们有三个矩阵 W Q , W K , W V W^Q,W^K,W^V WQ,WK,WV与单词的 embedding 相乘,如果不仅仅是这三个矩阵呢 ? 还有 W 1 Q , W 1 K , W 1 V W_1^Q,W_1^K,W_1^V W1Q,W1K,W1V , W 2 Q , W 2 K , W 2 V W_2^Q,W_2^K,W_2^V W2Q,W2K,W2V 等等,这样就不仅仅得到一个Z, 还会有Z1,Z2等等。如下图所示:
在这里插入图片描述
这样就得到了多个Z向量,由于每组的参数矩阵 W i Q , W i K , W i V W_i^Q,W_i^K,W_i^V WiQ,WiK,WiV是不一样的,所以多个Z向量的出现会使得信息更加丰富。看下图会帮助理解,如果不是多头的注意力机制,it 和 the animal 是相关度最高的,这符合我们的预期。但根据句子中 it was too tired 可知,it 除了指代 the animal 还是 tired 的。如果再引入一个 attention layer,这个 layer 就可能捕获 it 与 tired 的相关度。所以,multi-headed attention 能够使得信息更加丰富。
在这里插入图片描述
那么问题来了,本来只能输出一个向量,但是出现了多个向量,该怎么把这些向量信息进行融合呢 ?
其实很简单,只需要三步:
1.将 8 个向量 concat 起来得到长长的参数矩阵
2.将该矩阵与一个参数矩阵 W 0 W^0 W0进行相乘,该参数矩阵的长是一个Z向量的长度,宽是 8 个Z向量 cat 后的长度
3.相乘的结果的形状就是一个Z向量的形状
这样我们通过一个参数矩阵完成了对 8 个向量的特征提取。
图16:Multi-Head输出的拼接压缩
上面的步骤涉及很多步骤和矩阵运算,我们用一张大图把整个过程表示出来,如下图所示。
图17:Multi-Head计算完整过程
在Transformer里,有3个地方用到了MultiHeadedAttention:
1.Encoder的Self-Attention层query,key和value都是相同的值,来自下层的输入。Mask都是1(当然padding的不算)。
2.Decoder的Self-Attention层query,key和value都是相同的值,来自下层的输入。但是Mask使得它不能访问未来的输入。
3.Encoder-Decoder的普通Attention
query来自下层的输入,而key和value相同,是Encoder最后一层的输出,而Mask都是1

Feed Forward

到这里,再来回顾 Encoder 的细节。刚刚上文已经讲解了怎么把 x 1 x_1 x1转化为 z 1 z_1 z1, 接下来只需要把学习到的 z i z_i zi和原始输入进行融合和 Normalize 后输入到一个 feed forward neural network 中 ,相当于做了一个 skip-connection,也就是下图中的虚线箭头进行的操作。 z i z_i zi进入 feed forward neural network 是单独进行的,没有揉合在一起。紧接着,feed forward neural network 的输出和它的输入再进行融合和 Layer Normalize 操作才得到了 r i r_i ri

Layer normalization

Normalization 有很多种,但是它们都有一个共同的目的,那就是把输入转化成均值为 0 方差为 1 的数据。我们在把数据送入激活函数之前进行 normalization(归一化),因为我们不希望输入数据落在激活函数的饱和区。

说到 normalization,那就肯定得提到 Batch Normalization。BN 的主要思想就是:在每一层的每一批数据上进行归一化。我们可能会对输入数据进行归一化,但是经过该网络层的作用后,我们的数据已经不再是归一化的了。随着这种情况的发展,数据的偏差越来越大,我的反向传播需要考虑到这些大的偏差,这就迫使我们只能使用较小的学习率来防止梯度消失或者梯度爆炸。

BN 的具体做法就是对每一小批数据,在批这个方向上做归一化。如下图所示:
在这里插入图片描述
可以看到,右半边求均值是沿着数据 batch_size 的方向进行的,其计算公式如下:
B N ( x i ) = α × x i − μ b σ B 2 + ϵ + β BN(x_i)=\alpha \times \frac {x_i-\mu_b}{\sqrt {\sigma_B^2+\epsilon}} + \beta BN(xi)=α×σB2+ϵ xiμb+β
那么什么是 Layer normalization 呢?它也是归一化数据的一种方式,不过 LN 是在每一个样本上计算均值和方差,而不是 BN 那种在批方向计算均值和方差!
在这里插入图片描述
下面看一下 LN 的公式:
L N ( x i ) = α × x i − μ L σ L 2 + ϵ + β LN(x_i)=\alpha\times\frac {x_i-\mu_L}{\sqrt {\sigma_L^2+\epsilon}} + \beta LN(xi)=α×σL2+ϵ xiμL+β
到此为止,把 encoder 的一个单元的原理讲清楚了,也就是如何将 x i x_i xi转化为 r i r_i ri
1.对输入的数据进行 Embedding 得到 x i x_i xi
2.把 Embedding 后的结果融入Positional 信息后输入到 Encoder 网络中。
3.输入信息输入到 Attention layer 中来捕获多维度的上下文信息,得到 z i z_i zi
4.将注意力学习到的结果和原始输入进行融合后进入 Feed Forward 网络进一步学习。
5.前馈网络的结果和也会和前馈网络的输入做一个融合,类似于 skip-connection。
6.这样便得到了一个 Encoder 单元后的结果 r i r_i ri
在这里插入图片描述
刚刚给出的一个 encoder 的设计细节,transformer 是可以有很多 encoder 单元组合起来的,如下图所示是两个 encoder 单元叠加起来:
在这里插入图片描述
Positional Encoding
循环神经网络每个时间步输入一个单词,通过这样的迭代操作能够捕获输入句子中单词的位置信息。 但是 transformer 模型没有类似于循环神经网络的结构, 所以必须提供每个单词的位置信息给 transformer, 这样才能识别出语言中的顺序关系。

所以,输入进 encoder 中的向量不仅仅是单词的 embedding,而是单词的 embedding 和 位置向量 positional encoding 融合后的结果。位置向量 positional encoding 是如何构造的呢 ?
图20:位置编码

Decoder

Decoder 中的模块和 Encoder 中的模块类似,都是 Attention 层、前馈网络层、融合归一化层,不同的是 Decoder 中多了一个 Encoder-Decoder Attention 层。这里先明确一下 Decoder 模块的输入输出和解码过程:

  • 输出:对应 位置的输出词的概率分布。
  • 输入:Encoder 模块的输出 & 对应 位置 Decoder 模块的输出。所以中间的 Encoder-Decoder Attention 不是 self-attention,它的 K,V 来自 ncoder模块,Q 来自上一位置 Decoder 模块的输出。
  • 解码:这里要特别注意一下,编码可以并行计算,一次性全部encoding出来,但解码不是一次把所有序列解出来的,而是像rnn一样一个一个解出来的,因为要用上一个位置的输入当作 attention的query。
    如下图所示:
    在这里插入图片描述
    输入序列经过 encoder 部分,然后将最上面的 encoder 的输出变换成一组 attention 向量 K 和 V, 这些向量会用于每个 decoder 的 encoder-decoder attention 层,有助于解码器聚焦在输入序列中的合适位置。
    在这里插入图片描述
    重复上面的过程,直到 decoder 完成了输出,每个时间步的输出都在下一个时间步时喂入给最底部的 decoder,同样,在这些 decoder 的输入中也加入了位置编码,来表示每个字的位置。
    再来回顾这张图,圈出来的 self-attention 是 masked self-attention。
    在这里插入图片描述
Mask

mask 表示掩码,它对某些值进行掩盖,使其在参数更新时不产生效果。Transformer 模型里面涉及两种 mask,分别是 padding mask 和 sequence mask。

其中,padding mask 在所有的 scaled dot-product attention (具体该操作施加在哪个地方,可以看下图)里面都需要用到,而 sequence mask 只有在 decoder 的 self-attention 里面用到。
在这里插入图片描述

Padding Mask

什么是 padding mask 呢?因为每个批次输入序列长度是不一样的也就是说,我们要对输入序列进行对齐。具体来说,就是给在较短的序列后面填充 0。但是如果输入的序列太长,则是截取左边的内容,把多余的直接舍弃。因为这些填充的位置,其实是没什么意义的,所以我们的 attention 机制不应该把注意力放在这些位置上,所以我们需要进行一些处理。

具体的做法是,把这些位置的值加上一个非常大的负数(负无穷),这样的话,经过 softmax,这些位置的概率就会接近0!

而我们的 padding mask 实际上是一个张量,每个值都是一个Boolean,值为 false 的地方就是我们要进行处理的地方。

Sequence mask

sequence mask 是为了使得 decoder 不能看见未来的信息。也就是对于一个序列,在 time_step 为 t 的时刻,我们的解码输出应该只能依赖于 t 时刻之前的输出,而不能依赖 t 之后的输出。因此我们需要想一个办法,把 t 之后的信息给隐藏起来。

那么具体怎么做呢?也很简单:产生一个上三角矩阵,上三角的值全为0。把这个矩阵作用在每一个序列上,就可以达到我们的目的。

  • 对于 decoder 的 self-attention,里面使用到的 scaled dot-product attention,同时需要 padding mask 和 sequence mask 作为 attn_mask,具体实现就是两个 mask 相加作为 attn_mask。
  • 其他情况,attn_mask 一律等于 padding mask。

参考:
seq2seq学习笔记
Seq2Seq模型概述
NLP之Seq2Seq
【深度学习】Transformer详解
《Attention is All You Need》浅读(简介+代码)
【通俗易懂】大白话讲解 Transformer

  • 20
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值