Transformer由Google在《Attention Is All You Need》这篇论文中被提出,主要用于处理Seq2Seq(序列到序列,Sequence to Sequence)问题,从论文名称可以看出Google团队的野心和对Transformer模型的自信。最近,在NLP(自然语言处理)领域称霸的Transformer将触手申向了CV(计算机视觉)领域并取得了令人惊叹的效果,本文从Transformer和Attention机制入手,并介绍Transformer在CV领域进行尝试的一些经典案例。
Transformer设计之初主要针对Seq2Seq问题,核心内容为Attention机制和位置编码。
介绍Transformer之前先简单了解一下Seq2Seq模型。以Seq2Seq中最经典的案例翻译为例,Seq2Seq便是将序列A(某语言句子,如中文)转换为序列B(另一种语言的句子,如英文)。介绍Seq2Seq之前,先看看要实现序列A到序列B的转换,RNN(循环神经网络)是如何实现的。图1-1展示了一个RNN模型的结构,红色代表输入序列,蓝色代表输出序列。通过图1-1不难发现,对于RNN实现的序列到序列的转换在输入输出的长度上是严格对其的,显然对于翻译而言输入输出长度完全做到对其是不现实的。(还不熟悉RNN的建议先简单了解一下RNN的基本原理)。
这种输入输出序列长度不对其的情况,通常被描述为N到M的Seq2Seq问题,图1-2为某种简单的Seq2Seq模型结构的示意图,模型包含Encoder(编码器)和Deconder(解码器)两个主要组成部分。通过将输入序列和输出序列的处理独立出来,可以有效避免对长度的限制。
Seq2Seq模型的工作过程可以理解为,输入一个序列,Encoder完成对序列的理解,然后将所理解的信息送入Deconder解码至目标类别的序列。
至此,输入序列和输出序列长度不对其的问题得以解决,但是单独一个上下文向量context能否像我们设想的那样记录输入序列的所有有用信息呢?解码过程中又如何避免信息的丢失?
举个简单的例子,“早上好”翻译至“good morning”,显然“好”对应“good”,“早上”对应“morning”,对于这样的短句子要让模型将“早上好”编码至context并解码出来似乎不是很难,但如果句子很长呢?很长的句子信息完全压缩到一个context中再解码,且不说编码过程中的信息丢失问题,要在解码过程中实现信息的搜寻和对应也并非易事。于是,天降猛男,今天的主角,Attention机制(注意力机制)派上了用场,图1-4为带注意力机制的Seq2Seq模型的示意图。
先不去讨论注意力机制实现的底层原理,先看看Attention机制是如何解决前面我们提到的问题的。Attention实际上就是额外增加一些可学习的参数,推理过程中通过这些参数得到一系列注意力权重来模拟信息之间关联性的强弱。如“good”同“好”的关联性更大,而同“早上”的关联性较小,对应图1-4,我们便希望 w 11 w_{11} w11和 w 12 w_{12} w12相对于 w 13 w_{13} w13要小,在解码得到“good”的过程中,除了输入context向量,同时将分配了注意力权重后的“早上好”对应的每个字的信息也输入到解码器中以达到更好的翻译效果。类似的,可以同相同的方式实现在输出“morning”的过程中增“早上”两个字的权重。
以上便是基于RNN和Attention实现的Seq2Seq模型的简介。
同基于RNN的Seq2Seq一样,Transformer也需要解决几个核心问题:
以上看不懂没事,下面开始带着疑问学习Transformer模型。
Transformer的基本结构同大多数Seq2Seq模型一样,由Encoder(编码器)和Deconder(解码器)两个主要部分组成,完整结构如图1-5所示。
但这个图有点复杂,理解起来有点困难。所以,接下来我们由外到内一步步理解这个模型结构。图1-6为Transformer模型的Encoder-Deconder结构,此结构和大多数Seq2Seq模型的结构还是没有区别的。
图1-5中的”Nx“表示灰色区域包含的单元结构堆叠N次,这里主要是为了提取更抽象的特征,和卷积神经网络堆叠多层的原理是一样的,同样的这里也会采用类似ResNet的残差结构来避免层数过深带来模型性能的消退。Transformer模型原论文中,Encoder和Deconder各自堆叠了6次,所以图1-6所示的模型结构可以进一步拆解为图1-7所示的结构。这里需要注意的是,编码器只会取最后一层的输出,而编码器得到的特征向量会传递给解码器的每一层。
接下来具体看看Encoder编码器和Decoder解码器内部都做了些什么。图1-8为编码器和解码器的内部结构,编码器主要包含Self-Attention(自注意力机制)和Feed Network(前馈神经网络)两个部分,解码器增加了一个编码-解码注意力层。
编码-解码注意力层同前面1.1小节提到的注意力机制类似,实际上可以理解为输入同输出之间的注意力,即得到某个输出需要关注哪些输入,越重要的输入分配越大的权重。但自注意力描述的是同一序列不同数据之间的关系强弱,这也是其被称为Self-Attention的原因。图1-9为某自注意力机制的可视化,可以看到通过自注意力机制,”Law“和”The"、“perfect”被赋予了较强的关联性,这与我们所认知的语法和语义信息是匹配的。
关于注意力机制的详细内容参考1.2.2小节的内容。
通过上一小节可以初步理解Transformer中注意力机制的作用,趁热打铁,本小节介绍一下注意力机制的原理和实现。这之前,先看看图1-10所展示的人类的视觉注意力,人类在观看一张图片时通常会将注意力集中在某些感兴趣区域,这可以帮助人类收集关键信息和减轻大脑处理信息的负担。同样的,在深度学习中,注意力机制的作用也是如此,一方面增强有用信息、减弱无用信息,另一方面在某些情况下可以降低计算成本,如仅对高关注度的信息进行处理。
通过图1-10我们可以发现,注意力机制实际上就是要得到权重信息(图1-10中底图上方的热力图所代表的重要性,颜色越红表示注意力权重越高,反之越低),然后将这些权重同原图相乘,就得到了注意力增强后的图片(这里的原图在深度学习中更多的是特征图)。回到Transformer在处理序列问题时所用的两种注意力网络,自注意力层和编码-解码注意力层。图1-11是我随意绘制的自注意力和编码-解码注意力的区别的可视化示意图,自注意力是同一序列不同数据之间的关系强弱,而编码-解码注意力是解码的序列和编码的序列之间的关系强弱。
那么如何将这种注意力机制通过数学进行表达,并应用到深度学习模型当中呢?
在注意力机制中,输入特征通常会被生成三种特征向量:
前面已经提到,注意力机制实际上就是分配权重的过程,注意力机制中权重的获得通常需要两个过程:
获得权重,参考公式 ( 1 ) (1) (1):
W = S o f t m a x ( Q K T d k ) (1) W=Softmax({\frac{QK^T}{\sqrt{d_k} }}) \tag{1} W=Softmax(dkQKT)(1)
其中, d k \sqrt{d_k} dk是一个尺度参数。
最终输出,参考公式 ( 2 ) (2) (2):
A t t e n t i o n ( Q , K , V ) = W V = S o f t m a x ( Q K T d k ) V (2) Attention(Q,K,V)=WV=Softmax({\frac{QK^T}{\sqrt{d_k} }})V \tag{2} Attention(Q,K,V)=WV=Softmax(dkQKT)V(2)
简单的概括就是,通过Q,K得到分数,用Softmax归一化后乘以V得到最终输出。对于自注意力和编码-解码注意力而言,其K,Q,V的来源存在区别,可参考表1-1。不难理解,对于自注意力而言,K,Q,V来源是相同的,其关注的是序列本身不同数据之间的关联性,而对于编码-解码注意力而言Q来自Decoder-自注意力层输出,而K,V来自Encoder的输出,这也是编码-解码注意力层能够建立输入序列同输出序列之间的联系的原因。
注意力机制类型 | Q | K | V |
---|---|---|---|
Encoder部分的自注意力 | Encoder输入(上一层Encoder输出) | Encoder输入 | Encoder输入 |
Decoder部分的自注意力 | Decoder输入(上一层Decoder输出) | Decoder输入 | Decoder输入 |
编码-解码注意力 | Decoder-自注意力层输出 | Encoder输出 | Encoder输出 |
补充:
Transformer使用注意力机制的优势
自注意力机制的优势:self-attention可以有效地解决长时依赖问题
长时依赖问题:对于RNN而言,序列信息依次传递,传递过程中会面临梯度消失问题,导致跨度较大的数据之间的信息难以得到有效的传递。当然如果输入较长的序列导致self-attention计算量太大,可以用窗口限制self-attention的计算数量
此外,注意力机制会生成权重信息,这对于提升模型可解释性具有非常重要的作用。
Mutli-Head Attention的实现
通过多个个不同的线性变换得到多组Q,K,V,最后将不同的attention结果拼接起来,这样做的好处是可以学习多种关联模式。这里需要补充的是,这些Q,K,V之间的运算是可以组成一个大的矩阵来一起计算的。
M u t l i H e a d A t t = concat ( h e a d 1 , h e a d 2 , . . . , h e a d n ) (3) MutliHeadAtt=\text{concat}(head_1, head_2,...,head_n) \tag{3} MutliHeadAtt=concat(head1,head2,...,headn)(3)
h e a d n = A t t e n t i o n ( Q n , K n , V n ) (4) head_n=Attention(Q_n,K_n,V_n) \tag{4} headn=Attention(Qn,Kn,Vn)(4)
Decoder中的mask操作
Decoder中接受输入的attention多加了一个mask,因为训练时的output都是ground truth,这样可以确保预测第i个位置时不会接触到未来的信息。难理解的可以回想一下RNN的输出,基于RNN的解码过程也是依次进行,只会接受之前的信息。
对序列信息进行建模的过程中,相对位置是非常重要的,比如:
虽然两句话字符完全相同,只不过顺序发生了改变,内容就完全不一样了。而Transformer抛弃了RNN,RNN最大的优点就是对序列信息的抽象和建模,所以Transformer用了Positional Encoding(位置编码)的方法引入相对位置信息。
在《Attention is All You Need》中作者给出了两种方法:
实验分析后,作者选择了第一种方法,具体公式如下:
P E p o s , 2 i = s i n ( p o s 1000 0 2 i / d m o d e l ) (5) {PE}_{pos,2i}=sin(\frac{pos}{10000^{2i/{d_{model}}}}) \tag{5} PEpos,2i=sin(100002i/dmodelpos)(5)
P E p o s , 2 i + 1 = c o s ( p o s 1000 0 2 i / d m o d e l ) (6) {PE}_{pos,2i+1}=cos(\frac{pos}{10000^{2i/{d_{model}}}}) \tag{6} PEpos,2i+1=cos(100002i/dmodelpos)(6)
最终得到的位置编码值为公式 ( 5 ) (5) (5)和 ( 6 ) (6) (6)得到的结果的拼接后的编码向量。如图1-11为位置编码的可视化效果,每一行对应一个词的位置编码,左半部分的值由 s i n ( ) sin() sin()函数生成,而右半部分由 c o s ( ) cos() cos()函数生成。
第一种方法的优点是能够扩展到未知的序列长度(例如,当我们训练出的模型需要翻译远比训练集里的句子更长的句子时)。而第二种基于学习的方法会一定程度上受训练数据的影响,序列长度扩展后性能会受到影响。
[1]. Attention Is All You Need
[2]. 完全解析RNN, Seq2Seq, Attention注意力机制
[3]. 【NLP】Transformer模型原理详解