Google 2017年的论文 Attention is all you need !论文提出了Transformer模型,抛弃传统的RNN和CNN。
阅读本篇,您将获得如下:
1.为什么要用transformer?结合自身感悟谈!
2.transformer是什么?带你一起剖析!对结构BN,LN的理解!
3.最简洁让你理解transformer!
4.transformer在视觉任务中的进展,以及下篇中将涉及到的模型。
以下是本篇文章正文内容
1) CNN在图像上是非常成功的应用,卷积提取高层特征,卷积和池化的平移不变性等,拥有强大的拟合能力,并在残差的结构下得到了进化,更深的网络和更好地弥补上下文的结合,提高的泛化能力。CNN没有什么问题,只是以人的视觉机制来说,似乎看起来,transformer以其注意力机制去更好捕获上下文,更加符合人类的角度,使得特征之间建立更长远的依赖,提取更优的特征,那么研究者们当下,就是想把两者融合,实现1+1>2的效果,毕竟DL一直都存在着后验性。
2)对于RNN,时序性的结果意味着并行计算能力不足,因为BERT的transformer结构将使得注意力机制很好的应用,以及可以同时并行去接受词句(在其内部self-attention中,以向量组成的矩阵实现并行计算,这点是突破RNN的关键)这里后面会在结构里详细说明。
我们之前接触的模型,比如检测系列的yolo,ssd等需要大量的先验anchor和人为干预的后处理nms去筛选BOX,这样不只是加大计算量,带来的精度和人工调整超参也是很耗时的,最终使得任务不够精简,其实并不是人们心中的“完美检测”,而transformer就是以自注意力机制去模仿人类关注应该关注的目标。
那么anchor free 那种以点来取代BOX的做法,在我个人看来,本质上仍旧是指标不治本,anchor base和anchor free的本质都是多个BOX或者多个点,来匹配唯一的目标,即都是多对于一效果。而分割比如论文Segmentation Is All You Need,则无法满足性能需求!(这里给出该论文的叙述,意思一样,但是人家写的好)
边界框(Bounding Box)不应该存在:
虽然 anchor 的存在减少了很多计算量,但是也带来了超参数增加、人为调参过拟合评测数据集、前后景目标类别不平衡等一系列令人头疼的问题。
让我们回到边界框的本质。所有的边界框其实都是一种无限制保证前景物体像素召回率的标注方式,它会尽可能贴着外轮廓,因此会导致背景像素大量进入框内。然而,真实世界的物体可以随意转动,不同的机位拍一个3D 物体出现的结果可以大不相同,因此用框作为一个表征工具来把东西框起来,本身就不稳健。而且,框的标注本身也带有一定的随机性,毕竟要遵守标注规则把框标得非常好可能花的成本也会很高。
非极大值抑制(NMS)不应该存在:
NMS 是一项很神奇的工作,目标检测领域用 NMS作为选框策略已经有大概几十年了,因为没有一项工作能超越它。然而如上所述,既然边界框本身并不稳健,选出的框再优秀也无济于事。更何况选出的框也不会格外优秀,因为真实世界里不可能有一个具体的阈值来控制所有的场景,例如遮挡问题。现实世界中的遮挡问题十分复杂,挡了一部分和挡了一大半完全不是同一种情况。既然如此,用一个单一的阈值怎么可能解决问题?事实上,在之前的工作中,动态调整NMS 的 SoftNMS、动态调整 IoU 的 Cascade RCNN方案都取得了很不错的结果,但前者依然回避了「复杂遮挡」的复杂性,后者参数量激增,速度慢到难以想象。
那么彻底来抛弃anchor和Nms的做法,化繁为简,试想以下,这是否更符合一个更接近人类视觉的模型。
在行业领域也是多模态算法发展的一个成果。将不同任务或处理不同数据的模型trick彼此结合使用,NLP和CV的互相进步就是典型案例了,当下AI的趋势不仅仅只偏向于工程部署落地,大家都会炼丹跑Demo,DL拉低了门槛,但同时也突破了上限,那就是结合业务需求绑定,比如CV和NLP的结合,点云和图像,图像和文本等,也就是基于数据和不同模型方法的多模态趋势,因此不管你是搞啥的,只要有兴趣就可以开始从NLP中transformer开始。
走个程序,还是要规规矩矩,按照论文开始,毕竟可以盗图用,下面我会以一个最简单方式且附我的理解去说明。
首先,我们全局看下transformer结构:
如图,transformer的结构主要就是由多个编解码器组成,且这些编码器和解码器各自的内部构造是完全相同,只是权重参数不同!先分析编码器,按顺序来!
从这个输入部分开始看,embedding——词嵌入,简单理解为将原始数据转换成向量形式 ,通过一种映射的形式,有独热编码,也有worf2vec等初始化方法(感兴趣的具体自行查阅资料),那么这里的步骤:
逃课关键词:框架的结构精髓——矩阵化输入向量并行计算,RNN做不到!
在以上得到编码位置相加后的新向量,进入第2层注意力层,也是核心!它需要调整去分析我们关注目标的权重,那在NLP中,我们如何确定要关注的权重呢?先来说下如何attention?
具体操作:主要计算两个句子之间词与词的相似度,这里词向量的相似度用的是点积(两个词向量越接近,它们的距离和夹角就越小,所以乘积也会越大),所以乘积结果越大越相似!!然后,归一化后作为权重,并通过权重以及另一个句子的各个词向量,结合起来得到用另一个句子表示的该词的词向量。
原始的注意力计算框架是由谷歌提出的,通过这个框架,我们可以计算出权重(也就是分配的注意力),并最终计算出一个对应的attention value,但它不是主角,有兴趣的自行学习理解,给个公式:
注意力机制有多种,这里我们只讲transformer的核心:自注意力机制,这里简单说明下:输入序列和输出序列的内容甚至长度都是不一样的,注意力机制是发生在编码器和解码器之间,也可以说是发生在输入和输出之间。而自注意力模型中的自注意力机制则发生在输入序列内部,或者输出序列内部,也就是该层网络的输入和输出,可以抽取到同一个句子内间隔较远的单词之间的联系,给出关键公式:
这个self-attention 计算过程,如图:
首先,需要3个矩阵,Q为查询向量,K为键向量,V为值向量,
但是在当前经历了输入后,我们只有词向量,如何获取这三个向量呢?
图中以及告诉我们了,在词嵌入后的 所有的词向量X1,X2,都共享一套参数,图中右侧的WQ,WK,WV的可学习参数矩阵——对应相乘,得到的Q,K,V三个向量。这些都是词向量的线性变换得到的!
接下来,按照下图顺序进行计算,很清晰的:用上述提到的相似度计算——点乘
然后将分数除以8(8是论文中使用的键向量的维数(dk=64)的平方根,这会让梯度更稳定?)
NLP小白的个人理解:在Q和K相乘后,如果值很大或者很小,在softmax归一化计算后,会影响梯度,那么做这种操作无非就是为了控制方差,稳定梯度。
使用 Softmax 计算每一个单词对于其他单词的 attention 系数
然而实际中,这些计算是以矩阵形式完成的,同时也完成了并行化的计算,如下图:
最后一步:按照计算过程的步骤图,对softmax后加权值向量求和然后即得到自注意力层的最终输出。得到的向量Z就可以传给前馈神经网络,具体形式如下盗图所示,助于理解~
这个多头机制,盲猜后续的很多CV论文都会用这种结构去训练!(果然,此时此刻,1个月后的我发现了transformer的产出越来越多,优秀的多头机制在Onenet中也得到了应用)
如下图,就是多加了一套而已。。由于这种操作效果比较好,其实类似于多尺度的思想,只不过这个是多空间,将多头下的输出向量合并——信息融合,就是多头注意力机制的输出,将输入的X分别送进不同的HEAD里面计算,最后拼接起来,做一次liner线性矩阵乘法。
下面具体总结下:
如下图,是一个2头的Multi-Head Attention实验分析图,绿色代表的层密集一些,代表更关注全局信息,而红色则更关注局部信息。
每个编码器中的每个子层(自注意力、前馈网络)的周围都有一个残差连接,并且都跟随着一个“层-归一化”步骤,这个CV小伙伴门老掉牙问题,解决的问题就是梯度消失+网络加深,但是小batch还是精度会低,所以才有了各种变相扩大batch的trcik,这里不做讨论,一笔带过!
重点来了LN是一个很重要的点,如果是nlp方向的小伙伴会了解到在NLP的任务BN的使用因为效果较差使用较少,那么为什么呢?关于这点,有很多解释和理论推到,太多的理论就不说了,那么BN为什么在RNN等NLP的任务中不行嘛呢?我会以多个角度讲懂你!
我自己的理解是:本质我认为是数据的差异和处理的维度不同!一句话解释:各自学习所关注的维度不同!
在图像中由于训练尺度往往在CNN中固定,那么BN可以达到效果,总归是数据结构的差异,那么RNN中由于样本的词句是不同长度的,比如你有10个句子,前9个句子都有5个词,那么第10个句子有10个词,那么当你用BN计算前9个句子的每个单词的均值和方差时候,当后面的5个词的位置是空的,那么有值得地方就是第10个句子的后5个词了,以偏盖全,就不好了!
上述说明用BN在样本长度不一的情况下,计算的均值和方差实际没有意义了。
我们继续,那么再说LN层,LN处理维度是和BN不同的,盗个图表示下:
因为每个样本的词句长度不同,而LN的方向明显不同,简单来说,有3个轴,一个是样本数量,一个是样本的特征向量,那么LN保证了在空间中会获得相同的数量(通道数)个数值的归一化方差和均值。(想象一下,BN和LN图中的样本维度其实是不固定的,按着BN的计算方向是断章取义了)
encoder的整体流程,如下图!回顾一遍:
由于结构和原理计算阐述在encoder部分已经详细说明过,所以这里不做赘述,decoder结构如下图:
先看下所有的输入input,包括两个部分:一个decoder的output和encoder的输出,这里如上图我画了圈圈的地方就是encoder的输出…所以中间的attention不是self-attention,它的K和V两个向量是来源于自encoder,Q 是docoder的第一层的output。
这里要特别注意一下,编码模块可以并行计算,但解码部分不是一次把所有序列解出来的,而是和RNN一样按照顺序
解出来的,因为要用上一层的输出当作attention的query向量。
这里第一层的多头注意力机制是带有掩码mask的!为什么?
这里说明下deocer解码部分的Masked -多头自注意力层.
逃课关键词:Decoder 的时候,是需要根据之前的翻译,求解当前最有可能的翻译
换个角度,这里要分详细来解释:
逃课关键词:Decoder 在训练和推理测试部分是不同的策略:测试类似RNN个个顺序输出,训练则是类似encoder的矩阵并行化策略,且masked是在softmax前计算的
for di in range(target_length):
decoder_output, decoder_hidden, decoder_attention = decoder(decoder_input, decoder_hidden, encoder_outputs)
loss += criterion(decoder_output, target_tensor[di])
decoder_input = target_tensor[di] # Teacher forcing
另一个细节就是,在decoder训练中是一次性把目标序列的embedding通通输入到block中,然后在多头attention模块对序列进行mask.
关于Loss流程,小节后面会提到。
和encoder结构相同!!不做复述,只是区别在于:其中 Self-Attention 的 K, V矩阵不是使用第一层的注意力输出计算的,而是使用 Encoder 的编码输出来计算的。
整体详细交互结构,如下两图,交互过程:产生的所有的编码器的输出结果是K,V矩阵和decoder的Q矩阵交互!
该图和上述交互过程一致,encoder的输出和每一个decoder的交互层都需要对应计算!好处是在 Decoder 的时候,每一位单词都可以利用到 Encoder 所有单词的信息 。
上述也说到,训练过程比较特殊,采用了teaching force,完成并行化,在进入decoder时候,样本是整个放进去的,首先Encoder端得到输入的encoding表示,并将其输入到Decoder端的第二层不带mask操作的交互层attention,之后在Decoder端接收其相应的输入(见1中有详细分析),经过多头self-attention模块之后,结合Encoder端的输出,再经FFN前馈层,得到Decoder端输出之后,最后经过mlp层就可以通过softmax来预测下一个单词(token),然后根据softmax的Loss反向传播。
你也可以这么理解 ,测试部分类似rnn,就是一个词一个词解出来 ,训练其实一样,完全也可以一个个作,但是作者仿照了encoder并行矩阵运算,但是不能让当前词语被输入的后面词语影响attention到,所以加入了mask。
以上transformer的原理重点阐述完毕。
阅读以上所述,您应该有以下理解