Vision Transformer 学习笔记

1. 摘要

Transformer最初是针对NLP领域提出的,因为Transformer在NLP中的拓展性很好,越大的数据或模型,最后的performance就会一直上升,并且没有饱和现象,那么如果把Transformer应用到CV领域中会有什么样的效果呢?本篇论文《An Image Is Worth 16x16 Words: Transformers For Image Recognition At Scale》就是受到其启发,尝试将Transformer应用到CV领域上,但是这样也会遇到一些问题,比如在Transformer中输入的是序列,那么在CV领域就要考虑如何将一张2d的图片转化为1d的序列,而且在Transformer中序列的长度并不是无限长,而是有限的。正常的bert序列也就512,如果将一张224224的图片按照像素进行转化为1d就是224224=50176,这就太长了,导致复杂度很高。那么如何处理呢?

2. Vit模型

Vit动态示意图
对于上面所说的序列长度的问题,我们有四种解决办法:

  1. 使用网络中间的feature map,比如用res50最后一个stage res4 的feature map size只有14*14=196,序列长度是满足预期的
  2. 使用局部窗口,而不是整张图,输入的序列可以有窗口大小进行控制
  3. 轴自注意力,将2d图片的自注意力改成分别在宽和高两个维度上进行自注意力,可以大大降低复杂度,但很难支持大规模数量级
  4. 将图片切分成一个个patch,然后将每个patch作为一个token输入到transformer中去。(也就是论文中的方法)

在模型设计中,我们尽可能遵循原始Transformer,因为这样就避免我们做过多的更改,可扩展的NLP Trans former架构及其高效性几乎可以开箱即用。
下图是原论文中给出的关于Vision Transformer的模型框架,模型由三个模块组成:

  • Linear Projection of Flattened Patches(Embedding层)
  • Transformer Encoder(图右侧有给出更加详细的结构)
  • MLP Head(最终用于分类的层结构)
    在这里插入图片描述

2.1 Linear Projection of Flattened Patches:

如下图,token0-9对应的都是向量,以ViT-B/16为例,每个token向量长度为768,对于一个图像来说,它是一个三维的向量,明显与Transformer的输入不符,Transformer Encoder需要的是一个向量,shape为[num_token, token_dim],对于图片数据来说,shape为[H,W,C]是不符合要求的,所以就需要转换,要将图片数据通过这个Embedding层转换成token,所以要通过一个Embedding层来对数据进行变换。
在这里插入图片描述
我们可以将图片按照给定大小分成一堆patches。这样做的原因是:将一个个小块图像视为token(token可以理解为NLP中的一个字或词),在Transformer中计算每个token之间的相关性。这一点就和卷积神经网络有很大区别了。以往的CNN,以卷积 + 池化的方式不断下采样,这样理论上模型可以通过加深模型深度,达到增大感受野的目的。不过这样会有两个缺点:

  • 实际结果中显示,CNN对边缘的响应很弱。这也非常好理解,越靠边缘的像素,因为被卷积次数少,自然在梯度更新时,贡献更少。
  • CNN只能和临近像素计算相关性。由于其滑窗卷积的特性,无法对非领域的像素共同计算,例如左上角的像素无法和右下角的像素联合卷积。这就导致了某些空间信息是无法利用的。同时根据MAE论文中所说的,自然图像具有冗余性,即相邻像素点代表的信息是差不多的,所以只计算领域像素无法最大化利用图像特征。

以VIT-B/16为例,将输入图片(224✖️224)按照16*16大小的patch进行划分,划分后会得到(224/16)^2 = 196个Patches。接着通过线性映射将每个Patch映射到一维向量中,每个Patch数据shape[16,16,3]通过映射到一个长度为768的向量(后面都直接称为token)。[16,16,3]-->[768]

根据源码看,这里的维度转换就是通过一个卷积层来实现,以ViT-B/16为例,直接使用一个卷积核大小为16*16,stride=16,卷积核个数为768的卷积来实现,通过卷积[224,224,3]->[14,14,768],然后把H以及W两个维度展平即可[14,14,768]---->[196,768],此时正好变成了一个二维矩阵,正是Transformer想要的。

类似于 BERT 的类别 token ,在输入Transformer Encoder之前需要加上[class]token以及Position Embedding。在原论文中,在输入的一堆token中要插入一个专门的用于分类的【class】token,这个【class】token是一个可训练的参数,数据格式和其他token一样都是一个向量,就像NLP中做句子分类的 就是一句话有很多词,我们在前面加上cls它就能吸取整个句子里面的信息,用它就可以代表整个句子,这里的【class】token能够从一些相互交流tokens中吸取到有用的信息,然后输出。以ViT-B/16为例,就是一个长度为768的向量,与之前从图片中生成的tokens进行拼接,即Cat([1,768],[196,768])->[197,768]。然后关于Position Embedding 就与Transformer中的一样,因为图片的每个patch是固定的,打乱顺序就不是原始图片了,所以要加上位置信息,这里采用的是一个可训练的参数(1D Pos.Emb.),是直接叠加在tokens上的(add),所以shape要一样。刚刚拼接[class]token后shape[197,768],那叠加Position Embedding的shape也是【197,768】。
在这里插入图片描述
论文中对于Position Embedding 的表示方法,比如无位置嵌入1-D 位置嵌入2-D 位置嵌入 ,以及相对位置嵌入,做了对比实验,结果表明如下:在这里插入图片描述
第一行是完全没有位置编码,即没有提供位置信息,相当于将一堆patch直接输入进去;第二行是一维位置编码,即将输入patch看作是序列;第三行是二维位置编码,将输入看作是二维的patch网格;第四行是相对位置编码,考虑到patch之间的相对距离,将空间信息编码为而不是其绝对位置。

注意:如果要使用相对位置编码,一定要考虑好自己的任务需不需要绝对位置信息,如目标检测,由于要输出预测的边界框的坐标,因此绝对位置信息是必须的,这时使用相对位置编码就不合适了

最后发现如果 不提供位置编码效果会差,但其它各种类型的编码效果效果都接近,这主要是因为 ViT 的输入是相对较大的图像块而非像素,所以学习位置信息相对容易很多。Transformer 原文中默认采用 固定位置编码,ViT 则采用 标准可学习/训练的 1-D 位置编码嵌入。

2.2 Transformer Encoder

Transformer Encoder其实就是重复堆叠Encoder Block L次,主要由以下几部分组成:

  • Layer Norm,这种Normalization方法主要是针对NLP领域的,这里是对每个token进行Norm处理的
  • Muti-Head Attention
  • Dropout
  • MLP Block,如下图所示,就是由全连接+GELU激活函数+Dropout组成,需要注意的是第一个全连接层会把输入节点个数翻4倍[197,168]->[197,3072],第二个全连接层会还原节点个数[197,3072]->[197,768]
  • 在这里插入图片描述

2.3 MLP Head

上面的结构通过Transformer Encoder 后输出的shape是保持不变的,以ViT-B/16为例,输入的是[197,168] 输出的还是[197,168] 。注意,在Transformer Encoder 后其实还有一个LN(源码中有),这里我们只需要分类的信息,所以我们只需要提取出[class]token生成的对应结果就行,也就是从[197,768] 中抽出[class] token对应的[1,768]。接着我们通过MLP Head 得到我们最终的分类结果。MLP Head 原论文中说在训练ImageNet21K时是由Linear+tanh激活函数+Linear组成。但是迁移到ImageNet1K或者自己的数据上,只用一个Linear即可
在这里插入图片描述

2.4 VIT整体网络架构图(VIT-B/16)

在这里插入图片描述

2.5 Hybrid 模型详解

在论文中讲到了Hybride模型,就是上面提到的如何解决向量序列长度问题,这里是用传统的CNN特征提取和传统的Transformer进行结合。下图是根据ResNet50作为特征提取器的混合模型,但是略有区别,这里的R50的卷积层采用的是StdConv2d不是传统的Conv2d,将所有的BN换成GN,在原始的Res50网络中,stage1重复堆叠3次,stage2重复堆叠4次,stage3重复堆叠6次,stage4重复堆叠3次,但在这里的R50中,把stage4中的3个Block移至stage3中,所以stage3中共重复堆叠9次。

通过R50 Backbone进行特征提取后,得到的特征矩阵shape是[14, 14, 1024],接着再输入Patch Embedding层,注意Patch Embedding中卷积层Conv2d的kernel_size和stride都变成了1,只是用来调整channel。后面的部分和前面ViT中讲的完全一样,就不在赘述。
在这里插入图片描述
下表是论文用来对比ViT,Resnet(和刚刚讲的一样,使用的卷积层和Norm层都进行了修改)以及Hybrid模型的效果。通过对比发现,在训练epoch较少时Hybrid优于ViT,但当epoch增大后ViT优于Hybrid
在这里插入图片描述

————————————————
参考原文链接:https://blog.csdn.net/qq_37541097/article/details/118242600
————————————————

3. 总结

基于自注意力的架构,尤其是Transformer,已经成为模型首选,其基本方法就是在大型数据集上进行预训练,然后再较小或特定的任务数据集上进行微调,虽然有很多工作尝试将CNN与自注意力机制相结合,甚至有些工作直接用自注意力代替卷积,后一种虽然在理论上有效,但由于使用了特定的自注意力机制,尚未在硬件加速器上有效的扩展,因此在大规模的图像识别上,Resnet架构仍最先进,从实验给出的结果,在当时也达到了SOTA,但是相比于CNN,它需要更多的数据集。在小数据集上训练出来的精度是不如CNN的,但在大数据集上ViT精度更高。一个直观的解释是:ViT因为self-attention独特的机制,更多的利用token与token跨像素之间的信息,而CNN只是对领域的像素进行计算,所以相同参数的情况下,ViT获得的信息更多,在某种程度上可以看成是模型深度更深。所以小数据集上ViT是欠拟合的。实际开发中的做法是:基于大数据集上训练,得到一个预训练权重,然后再在小数据集上Fine-Tune。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值