1. 引言
RNN、LSTM和Gated RNN被认为是序列建模和翻译任务的SOTA。
循环神经网络通过一步一步地将输入和上一步的输出结果输入到模型中来得到下一步的输入。这个特点天生地让它只能用于串行计算,不能很好地利用并行化技术。虽然进来有一些用于改进的技术,但效果仍不理想。
注意力机制已经在序列化预测与转化任务中取得了广泛的应用,允许模型将不同位置的输入或输出建立联系。在少数情况下,注意力机制还被用于RNN中。
在这份工作中我们提出了Transformer,一种新的模型结构,抛弃了卷积和循环,仅仅使用注意力机制捕输出和输入间的获全局联系。
并且在翻译任务中取得了最优的效果。
2. 背景
减少顺序计算使得模型训练能够放在GPU上进行。许多模型采用卷积作为基本块,并行的计算中间表示和输出,如ByteNet和ConvS2S。这些模型对于长输入,不能很好的处理输入之间的联系性——计算所消耗的资源将会增长,ConvS2S是线性的,ByteNet是对数的,而我们的模型结构会将其压缩到常量复杂度。
自我注意力,是一种用于将某个序列的各个部分联系起来的计算序列的表示的注意力机制。已经被用于各种任务。
端到端记忆网路基于循环注意力机制,而不是对齐循环网络(关于对齐神经网络可以参考Neural Machine Translation by Jointly Learning to Align and Translate),在单一语言问答和语言模型任务中表现良好。
就目前而言,Transformer是第一个仅仅依靠自注意力机制获取句子表示的模型,下面我们将会介绍该模型的结构。
3. 模型结构
许多序列翻译模型使用编解码结构。这里,编码层负责将符号输入$ (x_1,…,x_n) 转 化 成 向 量 中 间 表 示 转化成向量中间表示 转化成向量中间表示z=(z_1,…,z_n) 。 给 出 。给出 。给出z$,解码器每次计算一个Token。每一步,模型都是自回归的,使用前面的Token生成下一个Token。Transformer同样遵循这个结构:堆叠的子注意力和全连接层(编码器和解码器)。
3.1 编码器、解码器列
-
编码器
编码器部分由6个基本单元组成。每一个单元含有两个子层,第一层是多头注意力机制,第二层是一个全连接层。每一个子层后接了一个残差结构和Layer Norm层,也就是说每一个子层的输出是 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)),其中的 S u b L a y e r SubLayer SubLayer是对两个子层来说是不一样的,第一个子层对应的是多头注意力,第二个子层对应的是全连接层。为了方便计算,所有层的输出维度设置为 d m o d e l = 512 d_{model}=512 dmodel=512。
-
解码器
解码器部分同样由六个基本单元组成,每个单元由三个子层组成,后两层和编码器相同。第一个子层的结构稍作修改,目的是以防泄露后面的子序列的位置信息。这里的掩码的意思是将输出表示向右移动一个位置,确保预测第 i i i个位置时仅仅依靠 i i i前面的元素。
3.2 注意力
注意力可以表示为查询(q)、键(k)和值(v)的函数,是用于增强一条输入元素之间的联系的机制。在[【Attention九层塔】注意力机制的九重理解这篇文章中有一个详细的解释。
3.2.1 放缩点积注意力
我们把我们用到的注意力称为“放缩点积注意力”。输入由* d k d_k dk维的查询和键和 d v d_v dv维的值*组成。
我们计算查询(q)和键(k)的点积,并用 d k \sqrt{d_k} dk 缩放,应用softmax计算得到值(v)的权重。
在实际计算时,会将多次查询合并成一个查询矩阵
Q
Q
Q,键和值同样的被拼接为一个矩阵
K
K
K和
V
V
V,最终的计算是以矩阵形式的:
A
t
t
e
n
t
i
o
n
(
Q
,
K
,
V
)
=
s
o
f
t
m
a
x
(
Q
K
T
d
k
)
V
Attention(Q, K, V ) = softmax(\frac{QK^T}{\sqrt{d_k}})V
Attention(Q,K,V)=softmax(dk
QKT)V
最常用的注意力算子是加性注意力和点积注意力。点积注意力就是上式的形式,除了这个
1
d
k
\frac{1}{\sqrt{d_k}}
dk
1缩放因子。加性注意力使用包含一层隐含层的前馈网络。虽然两者在理论复杂度上是相似的,但是点积注意力在时间和空间上更有优势。对于较小的
d
k
d_k
dk,两者是相似的,对于较大的
d
k
d_k
dk,加性注意力效果更好(点积注意力未使用缩放)。我们怀疑是因为对于较大的
d
k
d_k
dk,点积注意力的中间结果较大,使得经过softmax运算结果过于小,导致效果不好。因此在这里我们为点积注意力加上了一个缩放因子。
3.3.2 多头注意力机制
在上一小节中,我们选定了一组(q,k,v)去计算得到了注意力向量。但实际上,(q,k,v)的组合有很多,有什么理由限制我们仅仅选择一组(q,k,v)吗?并没有。那么我们就可以选取多种(q,k,v)组合,来计算注意力矩阵。实际上,注意力矩阵要比注意力向量效果好很多。注意力向量在图2(左)中描绘,注意力矩阵在图2(右)中描绘。我们将每一组(q,k,v)计算得到的注意力向量拼接到一起,通过一层线性神经网络,得到更高一级的表示:多头注意力向量。从我们这个计算过程可以发现,注意力矩阵只是一个表述方式,实际上得到的最终结果还是一个向量,矩阵只是中间的一个计算结果。
多头注意力机制能够将不同的注意力表示融合在一起,得到比单个注意力更多的元素联系性。
多头注意力计算式:
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
)
W
O
MultiHead(Q, K, V ) = Concat(head_1, ...,head_h)W^O
MultiHead(Q,K,V)=Concat(head1,...,headh)WO
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, V W_i^V) headi=Attention(QWiQ,KWiK,VWiV)
其中, W i Q ∈ R d m o d e l × d k , W i K ∈ R d m o d e l × d k , W i V ∈ R d m o d e l × d v , W O ∈ R h d v × d m o d e l W^Q_i\in R^{d_{model}×d_k}, W^K_i\in R^{d_{model}×d_k}, W^V_i\in R^{d_{model}×d_v}, W^O\in R^{hd_v×d_{model}} WiQ∈Rdmodel×dk,WiK∈Rdmodel×dk,WiV∈Rdmodel×dv,WO∈Rhdv×dmodel。
在我们的工作中,选择 h = 8 , d k = d v = d m o d e l / h = 64 h=8,d_k=d_v=d_{model}/h=64 h=8,dk=dv=dmodel/h=64。由于在多头注意力中,每个头的维度减少,所以总的计算量和单头注意力机制是差不多的。
3.3.3 注意力在我们的模型中的应用
Transformer在三个方面应用了多头注意力机制:
- 在编解码层,查询来自前面的解码曾,值和键来自编码层的输出。这使得解码器的所有位置都能注意到输入序列的所有位置。这里模仿了很多其他序列转化模型的常规做法。
- 编码层包含自注意力层。自注意力层中查询、键和值的值是一样的,在这里都来自上一编码层层的输出。编码层的每一个位置都能注意到上一编码层的所有位置。
- 解码器中的自注意力机制允许解码器中的每一个位置都能够注意到从初始位置直到当前位置(包括当前位置)的所有位置。由于解码器是做预测用的,因此不能给它当前位置左侧的信息(会造成信息泄露),因此我们在这里添加了一个掩码。具体做法是讲值设为负无穷,这样在softmax中结果就为0了。图2中有说明。
3.3 前馈神经网络(FFN)
在编码器和解码器的每一个子层之间,会设置一个前馈网络,该网络由两层组成,包含两个全连接层和一个:
F
F
N
(
x
)
=
m
a
x
(
0
,
x
W
i
+
b
1
)
W
2
+
b
2
FFN(x)=max(0,xW_i+b_1)W_2+b_2
FFN(x)=max(0,xWi+b1)W2+b2
所有的前馈神经网络虽然结构相同,但它们之间的权重是独立的。该层的输入和输出都是512维,内部网络是2048维。
3.4 编码和softmax
和其他序列转换模型一样,我们也使用预训练的词向量将输入字符转化为向量表示。对解码器也是如此。编码器和解码器共享相同的词向量。原文中还说了在the pre-softmaxlinear transformation中同样共享词向量。笔者目前还没找到这个结构指的是那里。共享词向量的配置和Using the output embedding to improve language models相同。在嵌入层,对词向量的值乘以 d m o d e l \sqrt{d_{model}} dmodel 。
3.4 位置编码
由于在上面的所有结构和输入都没有涉及到输入的位置信息,而位置信息在模型学习中的重要性不言而喻。为了得到位置信息,我们在数据输入的时候添加了位置编码。位置编码设定为
d
m
o
d
e
l
d_{model}
dmodel,所以它直接可以和输入向量相加。位置编码的计算方式没有限定,在这里我们选择正弦和余弦函数:
P
E
(
p
o
s
,
2
i
)
=
s
i
n
(
p
o
s
1000
0
2
i
d
m
o
d
e
l
)
PE_{(pos,2i)}=sin(\frac{pos}{10000^{\frac{2i}{d_{model}}}})
PE(pos,2i)=sin(10000dmodel2ipos)
P E ( p o s , 2 i + 1 ) = c o s ( p o s 1000 0 2 i d m o d e l ) PE_{(pos,2i+1)}=cos(\frac{pos}{10000^{\frac{2i}{d_{model}}}}) PE(pos,2i+1)=cos(10000dmodel2ipos)
其中, p o s pos pos是位置, i i i是维度索引。我们假设正弦和余弦函数能够使得模型更好的学习相对位置信息,因为它们有这条性质:对于任意的 k k k, P E p o s + k PE_{pos+k} PEpos+k能够用 P E p o s PE_{pos} PEpos的线性表示。
表1:相关复杂度,n为序列长度,d是词向量维度,k是卷积核大小,r是受限自注意力层的参数。
层 | 复杂度 | 序列操作数 | 最大路径长度 |
---|---|---|---|
自注意力层 | O ( n 2 d ) O(n^2d) O(n2d) | O ( 1 ) O(1) O(1) | O ( 1 ) O(1) O(1) |
循环层 | O ( n d 2 ) O(nd^2) O(nd2) | O ( n ) O(n) O(n) | O ( n ) O(n) O(n) |
卷积层 | O ( k n d 2 ) O(knd^2) O(knd2) | O ( 1 ) O(1) O(1) | O ( l o g k ( n ) ) O(log_k(n)) O(logk(n)) |
受限自注意力层 | O ( r n d 2 ) O(rnd^2) O(rnd2) | O ( 1 ) O(1) O(1) | O ( n r ) O(\frac{n}{r}) O(rn) |
受限自注意力层是指当n比较大时,只限制r个词计算注意力,在下一节有详细描述。
我们也尝试让模型自己学习位置编码,但是两者几乎导出了相同的结果(请参考表3)。但是正弦函数还有一个好处,它能够很好地适应长度和维度的剧烈变化。
位置编码这里论文中就只说了这么点,这里有一个博客,对正弦函数还做了一些分析,可以参考一下。Transformer Architecture: The Positional Encoding - Amirhossein Kazemnejad’s Blog
4 为什么是自注意力
在这部分我们考虑三个因素。
第一份是每层的总计算复杂度,另一个是可以并行化的计算量,用必要串行计算量的最小值衡量。
第三个是网络中长依赖的路径长度。影响模型学习长依赖的一个因素是依赖的长度。输入和输出序列中位置组合之间的路径越短,就越容易学习其相关性。因此,我们还比较了由不同层类型组成的网络中任意两个输入和输出位置之间的最大路径长度。
在表一中,自注意力机制的依赖路径长度是一个常数,而循环层则是 O ( n ) O(n) O(n)。就计算复杂度而言,当序列长度n小于表示维度d时,自注意层比循环层快。为了提高涉及到很长序列的任务的计算性能,自注意层的计算可以限制为只考虑大小为 r r r的,以各自的输出位置为中心的邻域的输入序列。这会将最大路径长度优化到 O ( n r ) O(\frac{n}{r}) O(rn)。我们计划在未来的工作中进一步研究这种方法。
核大小 k < n k < n k<n的卷积核不能连接所有的位置。要想连接所有的位置需要使用 O ( n k ) O(\frac{n}{k}) O(kn)个普通卷积核或 O ( l o g k ( n ) ) O(log_k(n)) O(logk(n))个连续卷积核(Neural machine translation in linear time)。即使后来的可分离卷积(Neural machine translation in linear time),在k k = n k=n k=n的情况下才和我们的方法复杂度相同。
另一方面是注意力机制能够提供更多解释,这在附录中给出了一些信息。可以发现很多注意力头都有更加擅长的方面。