文章目录
1.标题&作者
- Transformer论文
- Transformer是继MLP、CL和RNN之后的第四大类模型
- 标题Attention Is All You Need
- 该篇论文的八位作者,是不分排名先后的,对该篇论文有着同样的贡献
2.摘要
在主流的序列转录模型里面
- 所谓的序列转录模型就是给你一个序列,你生成另外一个序列,比如机器翻译说给你一句英文, 你翻译成中文
以前的序列转录模型依赖于比较复杂的循环,或者是卷积神经网络,一半是用encoder,另一半是用decoder。
- 编码(encode)由一个编码器将输入序列转化成一个固定维度的稠密向量
- 解码(decode)阶段将这个激活状态生成目标译文
- 具体内容可以看 Encoder-Decoder综述理解,里面有图解可以更好的帮助理解
在性能最好的这些模型里面,通常也会在编码器和解码器之间使用注意力机制
- 读到这里就可以明白,这篇论文讲的是要做序列到序列的生产,但是现在主流的模型是序列转录模型,所以接下来要引入作者的新模型
我们提出了一个新的简单的架构——Transformer,这个模型仅仅依赖于注意力机制,而没有用之前的循环或者是卷积
做了两个机器翻译的实验,显示这个模型在性能上特别好,并行度更好,训练时间少。
该模型在英语到德语的翻译工作中达到了28.4的BLEU,比目前最好的结果还好了2个BLEU
- BLEU是在机器翻译里面大家经常使用的一个衡量标准
在英语到法语的翻译工作中,做了一个单模型,比所有的模型效果都要好,并且只在8个GPU上训练了3.5天
Transformer架构能够泛化到一些别的任务上面都很好
- 总结摘要:作者提出了Transformer模型主要用在机器翻译上面,并且效果非常好,训练时间也很短
- 所以这篇文章一开始写的时候是针对机器翻译这个小任务写的
- 后来被用在了自然语言处理、图片、视频上面,几乎什么东西上都能用,然后就火出圈了
3.结论
我们介绍了Transformer这个模型,这是第一个做序列转录的模型,仅仅使用注意力,将所有的循环层全部换成了multi-headed self-attention
在机器翻译上,Transformer能够训练的比其他架构要快很多,并且在实际结果上效果是好的
对于这种纯基于自注意力机制模型,想应用在一些其他任务上,比如文本以外的数据上,包括图片、语言、视频,使得生成不那么时序化
- 对于这一块,作者相当于预测未来了,本文作者基本上是看准了未来的大方向
这篇论文的所有代码放在https://github.com/tensorflow/tensor2tensor
-现在写论文通常有代码的话,会放在摘要的最后一句话,而本篇文章放在了结论的最后一句话中
4.引言
在时序模型里面包括了LSTM(long short-term memory)和GRU(gated recurrent)
- 在2017年最常用的是RNN
有两个比较主流的模型,一个叫做语言模型,另外一个是当输出结构化信息比较多的时候,大家会用编码器和解码器的结构(encoder-decoder)
RNN的特点:给一个序列,它的计算是把这个序列从左往右移,一步一步往前做
- 假设一个序列是一个句子的话,它就是一个词一个词的看
对于第 t t t个词,会输出 h t h_t ht ,也叫它的隐藏状态,而它的隐藏状态是由前面一个词隐藏状态 h t − 1 h_{t-1} ht−1和当前第 t t t个词本身决定的
- 这样就可以将前面学到的历史信息通过 h t − 1 h_{t-1} ht−1放到当下,然后和当前的词做一些计算,得到输出
- 这也是RNN如何有效处理时序信息的一个关键之处,但是它的问题也来自这里
- 因为是时序,一步一步的进行,不能并行,使得在计算上性能比较差
接下来作者主要讲的是attention在RNN上的应用
- 在这篇文章之前,attention已经被成功的应用在编码器的解码器里面了,主要是应用在如何将编码器的东西很有效的传给解码器
最后一段讲的是这篇文章提出来的Transformer,这是一个新的模型,不再使用之前被大家使用的循环神经层,而是使用纯基于自注意力机制的
这个模型是可以并行的,主要能够在比较短的时间之内做到一个更好的结果
5.相关工作
首先将如何使用卷积神经网络来替换掉循环神经网络,使得减少时序计算
用卷积神经网络对于比较长的序列难以建模
- 这是因为卷积做计算的时候,每一次它去看一个比较小的一个窗口,比如说看一个3×3的像素块,如果两个像素隔得比较远,得用很多层卷积
如果使用Transformer里面的注意力机制的话,每一次能看到所有的像素
- 卷积也有优势,可以做多个输出通道,一个输出通道可以认为是可以去识别不一样的模式
- 所以作者借鉴这个优势,也想要多输出通道的效果
作者提出了Muti-Headed Attention,多头自注意力机制
- 可以模拟卷积神经网络多输出通道的效果
下一段作者提出了Self-Attention
- 因为这个自注意力机制很早就有人提出来了,所以作者强调了一下,这个并不是本篇论文创新的地方
下一段又提出了memory networks
最后一段Transformer是第一个只依赖于自注意力来做这种encoder到decoder架构的模型
- 这才是本篇论文的创新点
6.整体模型
现在比较好的架构是encoder-decoder
- 但是这个模型有缺陷,所以本文提出了一种新的模型
- 编码器的Inputs就是输入,比如中文翻译成英文,输入的就是中文句子
- 解码器的Outputs其实也是输入,只是因为解码器在做预测的时候是没有输入的,实际上就是解码器在之前时刻的一些输出作为输入的地方
- shifted right是一个一个往后往右移
6.1编码器
- 编码器输入进来先进入一个嵌入层,就是进来是一个个词,将它表述成一个个向量
- N×表示有N个这样的架构摞在一起,上图蓝色圈的位置可以叫做Transformer block,也就是Transformer的一个块,论文中叫做layer,有六个
- 每个layer里面会有两个sub-layers,
- 第一个sub-layer叫做multi-head self-attention
- 第二个sub-layer叫做position wise fully connected feed-forward network,说白了就是一个MLP
- 对于每一个sub-layer用了一个残差连接
- 最后再使用 L a y e r N o r m LayerNorm LayerNorm(layer normalization)
- 公式 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)),即输入 x x x进来,先进入子层得到 S u b l a y e r ( x ) Sublayer(x) Sublayer(x),再与 x x x相加,一起进入 L a y e r N o r m LayerNorm LayerNorm
- 因为输入和输出要一样大小,所以作者为了简单起见,就将每一层的输出维度变成512
- 由Muti-Headed Attention(多头自注意力机制)和Feed Forward(前馈神经网络)组成的,和一个往左拐的箭头,就是残差连接
6.2解码器
- 只是多了一个多头自注意力机制
- 解码器跟编码器一样,有六个layers,每个layers有两个子层sub-layers,和一个multi-head attention sub-layer
- 解码器做了一个自回归,当前输出的输入集是上面的一些时刻的输出,意味着在做预测的时候不能看到之后的那些时刻的输出,但是我们知道在注意力机制里面,它每一次能够看到完整的输入,所以这个地方我们要避免这个情况发生,也就是说在解码器训练的时候,在预测第 t t t个时刻输出的时候,你不应该看到 t t t时候以后的那些输入
- 作者的做法是通过一个带掩码的注意力机制,保证在输入进来的时候,在
t
t
t时刻是不会看见
t
t
t时刻以后的那些输入,从而保证训练和预测的时候行为是一致的
7.三个Attention
7.1Attention
注意力函数是由将一个query和一些key-value对,映射成一个输出的一个函数
- 这里所有的query、keys、values、和output都是一些向量
- 具体来时output是value的一个加权和,所以就导致输出的维度跟value的维度是一样的
对于每一个value的权重,都是value对应的key和查询的query的相似度(compatibility function)来计算的
- 不同的注意力机制有不同的算法,如果我们画一个简单示意图
- 假设有是三个value和三个对应的key,现在给一个query,这个query值与第一个和第二个key值比较近(相似度高),输出是三个value值相加,但是第一个和第二个value的权重会大一点,第三个value的权重就会小一点,因为权重是等价于query和对应key的相似度
- 比如说再给一个query的值是与第二个和第三个key值比较近,那么对应的输出权重会发生变化,虽然我们三个value和key值都没有变,但是随着query值的改变,权重分配会不一样,导致最终输出会不一样,这就是注意力机制,因为不同的相似函数导致不一样的注意力版本
7.2Scaled Dot-Product Attention
作者在论文中提到 q u e r y query query和 k e y key key长度是等长的,都等于 d k d_k dk, v a l u e value value长度是 d v d_v dv
对每一个 q u e r y query query和 k e y key key做内积,然后将内积的值作为相似度
- 如果两个向量的长度是一样的,那么内积的值越大,也就是余弦值越大,那么就代表这两个向量的相似度越高,如果内积为0,就代表这两个向量是正交的,也就是垂直的,即没有相似度
- 向量内积公式: a ⋅ b = ∣ a ∣ ∣ b ∣ cos ( a , b ) a·b=|a||b|\cos(a,b) a⋅b=∣a∣∣b∣cos(a,b)
算出内积之后除以 d k \sqrt {d_k} dk,再用 s o f t m a x softmax softmax来得到权重
- 因为给一个 q u e r y query query,假设有 n n n个 k e y key key 和 n n n个 v a l u e value value, q u e r y query query会跟每个 k e y key key做内积,所以会得到 n n n个值,算出来之后再放入 s o f t m a x softmax softmax就会得到 n n n个非负的而且加起来和等于一的权重
- 再将 n n n个权重作用在 v a l u e value value上面,就会得到我们的输出
- 在实际中,我们按照上面的计算会很麻烦,所以作者给了计算公式
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(dkQKT)V
- 作者将 q u e r y query query写成一个矩阵,因为可能不止给出来一个 q u e r y query query,可能有 n n n个 q u e r y query query,所以就是有 n n n行矩阵 Q Q Q,矩阵的列是等于维度的,也就是上面提到的 d k d_k dk
- q u e r y query query和 ( k e y 、 v a l u e ) (key、value) (key、value)的个数可能是不一样的,但是长度一定是一样的,这样的矩阵才能相乘,注意这里的 K K K矩阵需要转置
- 如上图 Q Q Q矩阵和 K K K矩阵相乘就会得到 n × m n×m n×m的矩阵,矩阵的每一行就是一个 q u e r y query query对所有 k e y key key的一个内积值,我们除以 d k \sqrt {d_k} dk,再做 s o f t m a x softmax softmax
- 所谓的 s o f t m a x softmax softmax就是对矩阵的每一行分别做 s o f t m a x softmax softmax,一行一行之间是独立的,这样就会得到每一行的权重,再乘 V V V
- V V V是有一个 m m m行,列数为 d v d_v dv的一个矩阵,这两个矩阵相乘就会得到一个 n × d v n×d_v n×dv的一个矩阵,这个矩阵的每一行就是我们需要的一个输出
- 所以我们可以观察到对于一组 ( k e y 、 v a l u e ) (key、value) (key、value),和 n n n个 q u e r y query query,我们可以通过两次矩阵乘法来融合,而 k e y 、 v a l u e key、value key、value和 q u e r y query query可以说是我们的序列,所以这样导致说基本上可以并行的计算里面的每个元素,因为矩阵乘法是一个非常好并行的东西
作者在论文中提到,有两种比较常见的注意力机制,一种叫做加型的注意力机制(可以处理 q u e r y query query和 k e y key key不等长的情况),另外一种叫做点积的注意力机制(点积的注意力机制与作者提到的机制是一样的,只是作者多除了一个 d k \sqrt {d_k} dk)
- 也就是Scaled Dot-Product Attention名字的由来,其中Scaled是除、成比例的意思,Dot-Product Attention就是点积注意力
- 这两种注意力差不多,作者使用了点积(矩阵相乘),因为这个实现起来比较简单,而且会比较高效
- 但是为什么要除 d k \sqrt {d_k} dk呢
作者提到当 d k d_k dk不是很大的时候,其实除不除都没有关系,但是当 d k d_k dk比较大的时候,也就是两个向量长度比较长的时候,我们做点积的时候,值会比较大,这样相对的差距就会变大,导致说最大的值做出来 s o f t m a x softmax softmax就会更接近于1,剩下的值呢,就会更靠近于0,这样会导致梯度比较小,所以除 d k \sqrt {d_k} dk是一个不错的选择
- 上图中的Mask模块其实就是将 t t t时刻之后的值给取非常大的负数,因为这样就可以不算 t t t时刻之后的值,因为 s o f t m a x softmax softmax里面,非常大的负数就是0
- 只取 q 1 , q 2 … q t − 1 q_1,q_2…q_{t-1} q1,q2…qt−1和 k 1 , k 2 … k t − 1 k_1,k_2…k_{t-1} k1,k2…kt−1、 v 1 , v 2 … v t − 1 v_1,v_2…v_{t-1} v1,v2…vt−1
7.3Multi-Head Attention
作者说与其做一个单注意力的函数,不如将 q u e r y 、 k e y 、 v a l u e query、key、value query、key、value值投影到一个低维,投影 h h h次,然后再做 h h h次的注意力函数,每一个函数的输出再并在一起,再投影,得到最终的输出
- q u e r y 、 k e y 、 v a l u e query、key、value query、key、value值都投影到一个线性层(Linear),再做一个Scaled Dot-Product Attention,这个操作做 h h h次,会得到 h h h个输出,再将这些输出向量通过 C o n c a t Concat Concat合并在一起,最后做一次线性的投影(Linear),就会回到Multi-Head Attention
- 为了识别不一样的模式,我们希望有一些不一样的计算像素的方法
- 先让 q u e r y 、 k e y 、 v a l u e query、key、value query、key、value值都投影到一个低维,这个投影的参数 w w w是可以学的,也就是说给 h h h次机会,希望你能学到不一样的投影方法,使得在投影进去的那个度量空间里面能够去匹配不同模式需要的一些相似函数,最后把这些值再做一次投影
- 上述方法有点类似于卷积网络中有多个输出通道的感觉
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
w h e r e 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 ) where head_i=Attention(QW_i^Q,KW_i^k,VW_i^V) whereheadi=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 k 和 W O ∈ R h d v × d m o d e l W_i^Q \in \mathbb R^{d_{model}×d_k} ,W_i^k\in \mathbb R^{d_{model}×d_k},W_i^V\in \mathbb R^{d_{model}×d_k}和W^O\in \mathbb R^{hd_v×d_{model}} WiQ∈Rdmodel×dk,Wik∈Rdmodel×dk,WiV∈Rdmodel×dk和WO∈Rhdv×dmodel
- 在Multi-Head的情况下,还是以前的 Q 、 K 、 V Q、K、V Q、K、V,但是输出已经是不同头的输出连接起来,再投影到 W O W^O WO里面
- 其中,每一个头(head),就是将 Q 、 K 、 V Q、K、V Q、K、V,通过不同的可以学习的权重参数 W i Q , W i k , W i V W_i^Q,W_i^k,W_i^V WiQ,Wik,WiV投影到一个低维上,再做之前提到的注意力函数(6.3Attention)
- 这里操作类似MLP
作者用的h是8,也就是有8个head
d k = d v = d m o d e l / h = 64 d_k=d_v=d_{model}/h=64 dk=dv=dmodel/h=64
- 因为有残差连接的存在,使得输入和输出的维度是一样的,所以作者的做法是投影的时候,投影的就是输出的维度除h
- 因为之前的输出维度是512,所以除8之后,就是每一次把它投影到一个64维的维度,然后在上面算注意力函数
8.模型计算
8.1编码器的计算
-
编码器的输入,假设句子长度是 n n n,那么输入就是 n n n个长度为 d d d的向量
-
注意力层三个输入,分别表示 q u e r y 、 k e y 、 v a l u e query、key、value query、key、value,图中箭头是一个分成了三个箭头,意思就是同样的一个输入,复制成了3份,即作为 k e y key key,也作为 v a l u e value value,又作为 q u e r y query query,这就叫做自注意力机制
-
有 n n n个 q u e r y query query,每个 q u e r y query query会对应1个输出,就会有 n n n个输出,输出的维度就是 d d d,这个输出其实就是输入( v a l u e value value)的加权和,权重是来自 q u e r y query query和 k e y key key
-
绿色线代表权重,因为权重来自该向量本身与其余各个向量计算相似度,那么它与自己算肯定值是最大的(线的粗细代表相似度的大小)
-
如多头的话,因为有投影,在这个地方就会学习 h h h个不一样的距离空间出来,这样出来的值就是不一样的
8.2编码器的计算
- 解码器输入也是一样的,只是长度可能变成了
m
m
m,维度也是一样的
d
d
d,所以跟编码器是一样的自注意力,唯一不一样的是解码器是Masked,后面的权重需要设置为0,如上图所示
- 第二个注意力不再仅仅是自注意力了, k e y 和 v a l u e key和value key和value来着编码器的输出, q u e r y query query是来自解码器下一个attention的输入
- 编码器最后一层的输出就是 n n n个长为 d d d的向量
- 解码器Masked的输出是
m
m
m个长为
d
d
d的向量
- 解码器的输出与编码器的输出之间的关系紧密,决定着输出的权重
- 这也是Attention是如何在编码器和解码器之间传递信息的时候起到的一个作用
9.Feed Forward
- 全称Position-wise Feed-Forward Networks
- 它其实就是一个MLP,把每一个MLP对每一个词作用一次,然后对每个词作用的是同样一个MLP
F F N ( x ) = m a x ( 0 , x W 1 + b 1 ) W 2 + b 2 FFN(x)=max(0,xW_1+b_1)W_2+b_2 FFN(x)=max(0,xW1+b1)W2+b2
- x W 1 + b 1 xW_1+b_1 xW1+b1就是一个线性层, m a x max max就是ReLu的一个激活层,然后再加一个线性层
- 在注意力层输入,就是每一个 q u e r y query query对应的输出通常是512,也就说说上述公式中的 x x x是512的一个向量, W 1 W_1 W1会将512投影成2048这个维度,等于把这个维度扩大了四倍
- 因为最后有一个残差连接,所以还得投影回去,所以 W 2 W_2 W2又将2048投影回了512
- 所以上面公式就是单隐藏层的MLP,中间隐藏层将输入扩大四倍,最后输出的时候也回到输入的大小
9.1Transformer和RNN对比
- 输入就是长为 n n n的一些向量,经过Attention之后,我们就会得到对应的输出,也就是对应加权的和
- 加权和之后我们进入MLP
- 输入MLP之前已经做了信息整合,信息已经抓取出来了,所以在做MLP的时候,每个MLP只需要对每个独立的点做就行了
- RNN也是输入 n n n个向量
- 第一个点直接做MLP
- 而对于第二个是上一个时刻的输出+第二个点一起输入至MLP(如图绿色的线)
10.Embeddings and Softmax
- 因为输入的是词(token),所以我们需要映射成向量
- Embedding就是给任何一个词学习一个长度为 d d d的一个向量来表示
11.Positional Encoding
- attention是没有时序信息的
- 输出的是value的加权和,权重是query和key之间的距离,与序列信息是没有关系的,意味着一句话将顺序打乱和有序输入attention之后的结果是一样的
- 在输入里面输入信息positional
- 如上图所示对每个词都会拿到一个位置向量