赞
踩
Transformer的大名已经听过很久了,一直没有找到机会详细了解该模型的原理及架构,趁着这次要复习的机会把transformer的原理彻底搞懂。本文参考了沐神在B站的论文讲解以及一些其他人的transformer文章。
transformer最初源自Google团队的一篇论文:《Attention is all you need》,文章的目的是解决机器翻译中的问题。机器翻译是一种端到端的模型,input一个序列,output一个序列,如下图所示。
主流的文本翻译使用的是encoder-decoder结构,结构内使用RNN或者CNN进行特征提取和序列生成。
RNN的特点:从左往右一步步计算,对第
t
t
t个状态
h
t
h_t
ht,由
h
t
−
1
h_{t-1}
ht−1和当前词
t
t
t计算。所带来的缺点如下:
CNN的特点:CNN相对于RNN的好处是可以并行计算,但是CNN对于较长的序列难以建模。因为卷积计算的时候一般是一个比较小的窗口,比如33的窗口。如果2个像素相隔的比较远,需要用很多33的卷积层,一层层的叠加上去,才能把间隔很远的2个像素联系起来。
综上,本文提出的transformer架构使用注意力机制,使得机器翻译任务的准确性大幅提升,同时提高了并行能力。其主要效果如下:
Transformer的整体结构如下图所示:
简单介绍下上图,图中的结构可以清晰的分成左右两个部分,左边的是encoder(将输入特征转化为模型认识的形式)、右边的是decoder(输出最终的预测结果)。
总结:Transformer是一个比较标准的encoder-decoder架构。encoder和decoder的内部结构不同,encoder的输出作为decoder的输入。
Encoder结构:重复6次下图的内容就是论文里的一个完整encoder结构。
每个layer有2个sub-layers。
每个sub-layer的输出都会做残差连接和LayerNorm,转化成公式就是
L
a
y
e
r
N
o
r
m
(
x
+
S
u
b
l
a
y
e
r
(
x
)
)
LayerNorm(x+Sublayer(x))
LayerNorm(x+Sublayer(x)),sub-layer代表self-attention或者MLP。
layernorm相比batchnorm的不同在于:batchnorm是按照特征位置进行归一化、layernorm是从样本维度进行归一化。对于本文的机器翻译领域,由于序列的长度变化较大,按照特征进行归一化会出现一些样本没有该特征一些有该特征,归一化时的均值和方差变化较大。
注意力函数是将query和key-value对映射为一个输出的函数,其中所有的query、key、value和output都是向量。也可以说成output是value的加权和,value的权重由query和key的相似度决定。
不同的相似度函数对应的是不同的注意力机制,本节的注意力机制是最简单的一种,该函数的具体计算方法是对每一个query和key做内积,把内积的结果作为相似度。
A
t
t
e
n
t
i
o
n
s
c
o
r
e
=
S
o
f
t
m
a
x
(
q
u
e
r
y
∗
k
e
y
d
k
)
∗
V
Attention_{score}=Softmax(\frac{query*key}{\sqrt{d_k}})*V
Attentionscore=Softmax(dk
query∗key)∗V
query和key做内积:如果两个向量的大小一致,那么内积的值越大,向量的相似度就越高。如果内积的值为0,则这两个向量正交,没有相似度。
d k d_k dkquery和key的长度,其作用是防止Softmax函数的梯度消失:当 d k d_k dk不是很大的时候,÷不÷都可以,但是当值比较大的时候,query和key内积的结果差距会变大。导致最大值的softmax值更加靠近1,剩下的值更加靠近0,值就会更加向两段靠拢,计算梯度的时候就会比较小。
对于decoder部分的attention来说,该如何做mask呢?
为了避免在t时刻看到t时刻之后的输入,只需要在计算权重的时候把t时刻之后的query与key的乘积结果替换成一个很大的负数,如0.00000000000001
前面讲的是一个注意力函数,在实际的使用中不会仅仅使用一个注意力函数,而是把query、key和value全部经过一个线性投影生成WQ、WK和WV。投影h次,然后再做h次的注意力函数,把每个函数的输出拼接到一起,再投影后得到最终的输出,具体结构如下图所示:
输入是原始的Q、K和V,把他们输入到一个线性层中,线性层会把他们投影到一个较低的维度,然后再经过左图的注意力函数计算。
由于线性层的投影会投h次,每次都会得到一个输出,把h个输出concat到一起,最后做一个线性投影得到最终多头注意力机制的输出结果。
这里就有一个问题出现了,为什么一样的注意力机制我要重复h次?为什么要在多头注意力机制前后加一个线性投影层?
首先回答第一个问题,单注意力函数虽然可以学习到序列的权重,但是也只能学习到一种权重。多头注意力机制会关注序列的不同模式,学习到不同的内容,方便我们更全面的理解序列。比如翻译“I like play basketball.”,对于‘play’而言,有的注意力函数更关注’I’,有的更关注’basketball’,会让我们更好的翻译这段话。
对于第二个问题,当我们引入多头注意力机制后,如果不做线性投影,每个注意力函数的Q、K和V都是一样的,没什么好学习的内容,多头注意力也发挥不了作用。一旦引入一个线性投影层之后,每一层的Q、K和V都是不一样的,每一层的投影函数W也是不一样的,可以根据不同的目标学习不同W。
本文的模型涉及三种不一样的注意力层,分别是encoder里面的多头注意力层、decoder里面的多头注意力层和mask多头注意力层。
Encoder的注意力层
假设句子的长度是n,每个单词的词向量维度是d,则encoder的输入是一个n*d的矩阵。
Encoder的注意力层有三个输入,分别是query、key和value。一根线进来,复制了三下,同样的输入即作为query也是key和value,所以叫做自注意力机制。
输入了n个query,每个query对应一个输出,也就是n个输出。输出是value的加权和,当query和key的相似度越高,value的权重越大。不考虑多头机制和有线性投影的情况下,输出是输入的加权和,权重是当前向量与其它向量的相似度。
Decoder的masked多头注意力层
masked体现在模型看不到
t
t
t 时刻以后的decoder输入,也就是图左下角黄圈内的绿色权重是0
Decoder的多头注意力层
和前面两个注意力层不同的是,这里的注意力层不再是self-attention,注意力层的key-value来自encoder的输出而非decoder的输入。
query来自decoder里masked multi-head attention层的输出。
其实就是一个MLP,之所以加上Position-wise是由于MLP对每个词单独作用一次,且每个词使用的MLP是一样的。这里的MLP结构是两层网络,W1层把维度扩展至2048,最后W2层投影缩回到512维,方便后续的操作。
假设一种最简单的情况:没有残差连接、没有layernorm、没有投影,看看transformer和RNN的区别。
模型对比 | Transformer | RNN |
---|---|---|
不同点(对序列的处理) | Attention对输入做加权和,然后进入MLP,每个输入点独立计算输出(以为已经包含了序列信息) | 从上一时刻的信息输出作为下一时刻的输入 |
相同点(语义转化) | 用一个线性层或MLP做语义空间转化 | 用一个线性层或MLP做语义空间转化 |
示意图 |
embedding:将输入的一个词映射为一个长为 d d d 的向量,用这个长为 d d d 的向量表示整个词,这就是embedding,本文的d=512
Softmax:经过用于多分类的类别判定,其特点是所有的类别值加一起是1,其计算函数如下:
S
o
f
t
m
a
x
(
z
i
)
=
e
z
i
∑
c
=
1
C
e
z
c
Softmax(z_i) = \frac{e^{z_i}}{\sum_{c=1}^Ce^{z_c}}
Softmax(zi)=∑c=1Cezcezi
其中
z
i
z_i
zi是第
i
i
i个节点的输出值,C是全部类别的个数。
为什么attention没有时序信息?
这是因为output是value的加权和(权重是query和key之间的相似度,和序列信息无关),一句话打乱后在attention的输出结果也是不变的,这样的效果肯定是我们不希望的。
这时候我们通过positional encoding的方法引入时序信息,假设一个词的embedding表示为一个512维的向量,用另一个512维的向量来表示词的位置(如1 2 3 4 5 6…)。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。