ViT论文阅读

1.视觉领域transformer

论文题目:An Image is Worth 16x16 Words:Transformers for Image Recognition at Scale

论文地址:https://arxiv.org/abs/2010.11929

github:GitHub - lucidrains/vit-pytorch: Implementation of Vision Transformer, a simple way to achieve SOTA in vision classification with only a single transformer encoder, in Pytorch

本文的出发点是彻底抛弃CNN架构,直接使用transformer结构做图像分类任务。由于其结构与transformer中的encoder结构基本没差别,所以读这篇论文之前得先把NLP领域的transformer结构弄明白。

transformer论文地址:https://arxiv.org/pdf/1706.03762.pdf

2. transformer知识铺垫

2.1 CV领域的attention机制常见的有可变形卷积,或是基于通道注意力机制的SENet,其本质是对通道或者空间像素设计可学习的权重,在进行加权操作,试图让网络有聚焦关键信息的能力。

ViT论文阅读_第1张图片

 2.2 NLP领域的attention机制,以seq2seq为例,最普通的seq2seq结构可以抽象为如下的encoder-decoder结构:

ViT论文阅读_第2张图片encoder和decoder可以为RNN或者LSTM等,核心思想都是通过Encoder编码成一个表示向量,即上下文编码向量,然后交给Decoder来进行解码,其解码过程是顺序进行,每次仅解码出一个单词。将其展开,就是如下结构:

ViT论文阅读_第3张图片

 通俗理解是编码器与解码器的连接点仅仅是编码单元输出的隐含向量,其包含的信息有限,对于一些复杂任务可能信息不够,如要翻译的句子较长时,一个上下文向量可能存不下那么多信息,就会造成翻译精度的下降。

2.3 带有注意力机制的seq2seq可以展开为如下结构,可以看到在编码器部分添加了计算注意力权重的部分,这部分会根据解码标志去和编码器得到的上下文项链去计算attention score和attention distribution,这个分布会影响输入到每一步解码器的上下文向量。

ViT论文阅读_第4张图片

 总结来说在没有attention时候,不同解码阶段都仅仅利用了同一个编码层的最后一个隐含输出,加入attention后可以通过在每个解码时间步输入的都是不同的上下文向量,以上图为例,解码阶段会将第一个开启解码标志Query与编码器的每一个时间步的隐含状态(一系列Key和Value)进行点乘计算相似性得到每一时间步的相似性分数,然后通过softmax转化为概率分布,然后将概率分布和对应位置向量进行加权求和得到新的上下文向量,最后输入解码器中进行解码输出

ViT论文阅读_第5张图片

2.4 用QKV解释attention机制

所以的注意力机制其实都可以query,key,value向量来表述,通过使用seq2seq的例子来解释和理解QKV,即将Query(通常是向量)和Key(和Q长度相同的向量)分别计算相似性,然后经过softmax得到q和4个key相似性的概率权重分布,然后对应权重乘以Value(和Q长度相同的向量),最后相加即可得到包含注意力的attention值输出。
理解示例(参考别人的):

  • 假设世界上所有小吃都可以被标签化,例如微辣、特辣、变态辣、微甜、有嚼劲....,总共有1000个标签,现在我想要吃的小吃是[微辣、微甜、有嚼劲],这三个单词就是我的Query
  • 来到东门老街一共100家小吃店,每个店铺卖的东西不一样,但是肯定可以被标签化,例如第一家小吃被标签化后是[微辣、微咸],第二家小吃被标签化后是[特辣、微臭、特咸],第三家小吃被标签化后是[特辣、微甜、特咸、有嚼劲],其余店铺都可以被标签化,每个店铺的标签就是Keys,但是每家店铺由于卖的东西不一样,单品种类也不一样,所以被标签化后每一家的标签List不一样长
  • Values就是每家店铺对应的单品,例如第一家小吃的Values是[烤羊肉串、炒花生]
  • 将Query和所有的Keys进行一一比对,相当于计算相似性,此时就可以知道我想买的小吃和每一家店铺的匹配情况,最后有了匹配列表,就可以去店铺里面买东西了(Values和相似性加权求和)。最终的情况可能是,我在第一家店铺买了烤羊肉串,然后在第10家店铺买了个玉米,最后在第15家店铺买了个烤面筋

 2.5 基于transformer的seq2seq

上述结构的最大问题在于无法并行化,不管是采用RNN、LSTM还是GRU都不利于并行训练和推理,因为相关算法只能从左向右依次计算或者从右向左依次计算,不利于大规模快速训练和部署,也不利于整个算法领域发展,故在Attention Is All You Need论文中抛弃了传统的CNN和RNN,将attention机制发挥到底,整个网络结构完全是由Attention机制组成。其结构如此下:

ViT论文阅读_第6张图片

其包括6个结构完全相同的编码器,和6个结构完全相同的解码器,其中每个编码器和解码器设计思想完全相同,只不过由于任务不同而有些许区别,整体详细结构如下所示:

ViT论文阅读_第7张图片

 由于篇幅原因以及和Vit的相关性,这里只介绍encoder部分,因为Vit是直接将encoder编码的结果拿去做图像分类。

整个transformer翻译流程大致可表示为 编码器输入数据处理->编码器运行->解码器输入数据处理->解码器运行->分类head 

1. 编码器输入数据处理

(1)输入单词embedding

以上面翻译任务为例,原始待翻译输入是三个单词:

preview

 输入是三个单词,使用nlp领域的embedding算法Word2Vec进行向量化。假设每个单词都可以嵌入成长度为512的向量,那么此时输入就是3*512,再加上batchsize(句子个数)就是batchsize*3*512。

(2)位置编码positional encording

采用经过单词嵌入后的向量输入到编码器中还不够,因为transformer内部没有类似RNN的循环结构,没有捕捉顺序序列的能力,或者说无论句子结构怎么打乱,transformer都会得到类似的结果。为了解决这个问题,在编码词向量时会额外引入了位置编码position encoding向量表示两个单词i和j之间的距离,简单来说就是在词向量中加入了单词的位置信息

加入位置信息的方式非常多,最简单的可以是直接将绝对坐标0,1,2编码成512个长度向量即可。作者实际上提出了两种方式:

  • 网络自动学习
  • 自己定义规则

提前假设单词嵌入并且组成batch后,shape为(b,N,512),N是序列最大长度,512是每个单词的嵌入向量长度,b是batch;位置编码得到(1,N,512)的向量,将二者相加得到编码器真正的输入。

2. 编码器前向过程

编码器由两部分组成:自注意力层和前馈神经网络层。

ViT论文阅读_第8张图片

 (1)自注意力层

由于QKV都来自于同一个输入,所以称为自注意力机制,我们在前面说的attention机制通常是寻找输入与结果之间的关联性,而自注意力机制则可以理解为寻找输入各部分的内在关联。

例如下面The animal didn't cross the street because it was too tired,it肯定与the animal最相关,自注意力机制1即可捕获这种相关性。

ViT论文阅读_第9张图片

 自注意力层的内部流程为:输入为X,其shape为(b,N,512);然后定义三个可学习矩阵    (通过nn.Linear实现),其shape为(512,M),一般M等于前面维度512,从而计算后维度不变;将X和矩阵   相乘,得到QKV输出,shape为(b,N,M);然后将Q和K进行点乘计算向量相似性,然后除以维度的平方根(论文中是64,本文可以认为是512)使得梯度更加稳定;再采用softmax转换为概率分布;将概率分布和V进行加权求和即可。其可视化如下:

ViT论文阅读_第10张图片

 论文中又增加一种叫做“多头”注意力(“multi-headed” attention)的机制进一步完善了自注意力层,即多个self-attention,以扩展模型专注于不同位置的能力。

ViT论文阅读_第11张图片

简单来说就是类似于分组操作,将输入X分别输入到8个attention层中,得到8个Z矩阵输出,最后对结果concat即可。并且论文还在前面讲的基础上加入了残差设计和层归一化操作,目的是为了防止梯度消失,加快收敛。

 (2)前馈神经网络层

就是一些全连接层。

整个编码器结构拆开来看就是下图:

ViT论文阅读_第12张图片3. 解码器前向过程

ViT论文阅读_第13张图片

和编码器类似,第一个解码器输入不仅包括最后一个编码器输出,还需要额外的输出嵌入向量,而后续解码器输入是来自最后一个编码器输出和前面解码器输出。 

(1) 目标单词embedding

这个操作和源单词嵌入过程完全相同,维度也是512,假设输出是i am a student,那么需要对这4个单词也利用word2vec算法转化为4x512的矩阵,作为第一个解码器的单词嵌入输入。

(2) 位置编码

同样的也需要对解码器输入引入位置编码,做法和编码器部分完全相同,且将目标单词嵌入向量和位置编码向量相加即可作为第一个解码器输入。

和编码器单词嵌入不同的地方是在进行目标单词嵌入前,还需要将目标单词即是i am a student右移动一位,新增加的一个位置采用提前定义好的标志位BOS_WORD代替,现在就变成[BOS_WORD,i,am,a,student],为啥要右移?因为解码过程和seq2seq一样是顺序解码的,需要提供一个开始解码标志,。不然第一个时间步的解码单词i是如何输出的呢?具体解码过程其实是:输入BOS_WORD,解码器输出i;输入前面已经解码的BOS_WORD和i,解码器输出am...,输入已经解码的BOS_WORD、i、am、a和student,解码器输出解码结束标志位EOS_WORD,每次解码都会利用前面已经解码输出的所有单词嵌入信息。

 这里有两个点比较重要:

1. 上述测试流程是非并行的,为了训练时采用类似编码器的矩阵并行运算,参考编码器的操作,把目标单词嵌入向量组成矩阵一次输入即可,但是在解码am时候,不能利用到后面单词a和student的目标单词嵌入向量信息,否则这就是作弊(测试时候不可能能未卜先知)。为此引入mask,目的是构成下三角矩阵,右上角全部设置为负无穷(相当于忽略),从而实现当解码第一个字的时候,第一个字只能与第一个字计算相关性,当解出第二个字的时候,只能计算出第二个字与第一个字和第二个字的相关性。具体是:在解码器中,自注意力层只被允许处理输出序列中更靠前的那些位置,在softmax步骤前,它会把后面的位置给隐去(把它们设为-inf)。

2. 解码器内部的带有mask的MultiHeadAttention的qkv向量输入来自目标单词嵌入或者前一个解码器输出,三者是相同的,但是后面的MultiHeadAttention的qkv向量中的kv来自最后一层编码器的输入,而q来自带有mask的MultiHeadAttention模块的输出。

3. 分类器

transformer的输出并非直接是结果,而是转化为分类任务(方便计算loss),输出为所有类别(可以理解为单词库)的概率分布。假设我们的模型是从训练集中学习一万个不同的英语单词(我们模型的“输出词表”)。因此softmax后输出为一万个单元格长度的向量,每个单元格对应某一个单词的分数,这其实就是普通多分类问题,只不过维度比较大而已。

 2.6 ViT

在理解了transformer结构后,ViT网络结构上就没啥可以说的了,因为ViT只使用了transformer里的encoder部分,encoder的输出直接接全连接层分类head输出图像的分类结果。

ViT论文阅读_第14张图片

 这里比较关键的点在于如何将图像变成类似nlp里面的文本序列输入到transformer中。

1. 图片分块和降维

因为transformer的输入需要序列,所以最简单做法就是把图片切分为patch,然后拉成序列即可。 假设输入图片大小是256x256,打算分成64个patch,每个patch是32x32像素。

具体来说:假设输入是b,3,256,256,使用rearrange操作是先变成(b,3,8x32,8x32),最后变成(b,8x8,32x32x3)即(b,64,3072),将每张图片切分成64个小块,每个小块长度是32x32x3=3072,也就是说输入长度为64的图像序列,每个元素采用3072长度进行编码。由于3072有点长,可以用nn,linear进行降维到1024。

2. 位置embedding

每个patch的位置编码也是1024维的向量,这里作者尝试了不加位置embedding,发现效果会变差不少,但如果加了位置embedding,无论采用的编码方式简单的1D位置编码,还是2D感知的位置编码,效果都差不多。并且设置为可学习,从最后训练好的pos_embedding进行可视化结果来看,相邻位置有相近的位置编码向量,整体呈现2d空间位置排布一样。说明transformer可以学习到各个patch的位置信息。

ViT论文阅读_第15张图片

 将patch嵌入向量和位置编码向量相加即可作为编码器输入。

3. 增加解码标志

从论文图中可以看到,假设切成9个块,但是最终到transfomer输入是10个向量,额外追加了一个0。原因是我们现在没有解码器了,而是编码后直接就进行分类预测,那么该编码器就要负责一点点解码器功能,那就是:需要一个类似开启解码标志非常类似于标准transformer解码器中输入的目标嵌入向量右移一位操作。就是这里可以理解额外增加的这个向量即解码的Query请求向量。自此现在就是变成10个向量输出,输出也是10个编码向量,然后取第0个编码输出进行分类预测即可。从这个角度看可以认为编码器多了一点点解码器功能。具体做法超级简单,0就是位置编码向量patch是可学习的嵌入向量。

4. 编码器前向过程

与transformer一样,假设输入是(b,65,1024),那么transformer输出也是(b,65,1024)

5. 分类head

在编码器后接fc分类器head即可。

6. 实验结果

作者表示,在中小型数据集上同等训练ViT和基于resnet的网络,ViT的性能要差几个点。但一旦数据量上来了,例如在JFT数据集(18k classes and 303M high-resolution images)上做预训练,再在ImageNet上做finetune,ViT的性能可以很轻松的超过CNN。并且ViT的模型参数量也是要少于CNN的。

ViT论文阅读_第16张图片

ViT论文阅读_第17张图片

ViT论文阅读_第18张图片 

在这里,作者给出的解释是:transformer缺少CNN对于图像平移不变性和局部感知的能力,作者称之为inductive bias:归纳偏置。这个概念实际就是先验,图像任务中的先验在于局部一致性和平移不变性,这也是这也是为什么CNN如此有效。在中小型数据集中,这种强烈的先验可以让CNN快速收敛,而transformer却不行;当数据量足够大时,先验带来的收益将越发不明显,此时transformer自注意力机制寻找数据内在特征的能力就体现出来了,这种能力会随着数据量的增加而越发明显。

并且使用transformer的另一个有点就是可解释性更强,通过解析训练后的注意力权重,可以发现网络的注意力分布在图像中位置。

ViT论文阅读_第19张图片

 

 最后这个训练时长。。。也就谷歌玩得起。

你可能感兴趣的:(计算机视觉,深度学习,目标检测)