学习视频:Vision Transformer 网络详解
其原始架构图如下所示,可以看到首先输入图片分为很多 patch,论文中为 16。将 patch 输入一个 Linear Projection of Flattened Patches 这个 Embedding 层,就会得到一个个向量,通常就称作 token。紧接着在一系列 token 的前面加上加上一个新的 token(类别token,有点像输入给 Transformer Decoder 的 START,就是对应着 * 那个位置),此外还需要加上位置的信息,对应着 0~9。然后输入到 Transformer Encoder 中,对应着右边的图,将 block 重复堆叠 L 次。Transformer Encoder 有多少个输入就有多少个输出。最后只进行分类,所以将 class 位置对应的输出输入 MLP Head 进行预测分类输出。
对于标准的 Transformer 模块,要求的输入是 token 向量的序列,即二维矩阵 [num_token, token_dim]。
在具体的代码实现过程中,实际是通过一个卷积层来实现的。
以 ViT-B/16 为例,使用卷积核大小为 16 × 16 , stride 为 16,卷积核个数为 768 来实现,即 [224,224,3] --> [14,14,768] --> [196, 768]。一共 196 个token,每个 token 向量长度为 768。
此外我们还需要加上一个类别的 token,为此我们实际上是初始化了一个可训练的参数 [1, 768],将其与 token 序列进行拼接得到 Cat([1, 768], [196,768]) --> [197, 768]。然后再叠加上位置编码 Position Embedding: [197,768] --> [197, 768]。
拼接[class]token: Cat([1, 768], [196, 768]) -> [197, 768]
叠加Position Embedding: [197, 768] -> [197, 768]
考虑Position Embedding,如果不是用 Position Embedding 得到的结果是 0.61382,使用一维的位置编码得到的结果是 0.64206,明显比不使用位置编码高了三个百分点。使用 2D 以及相对位置编码其实和 1D 差不多啊。论文中也提到说 the difference in how to encoder spatial information is less important
,即位置编码的差异其实不是特别重要。1D 的话,简单效果好参数少,所以默认使用 1D 的位置编码。
论文中有给这样一个图(上图),我们训练得到的位置编码与其他位置编码之间的余弦相似度。这里的 patches 大小是 32 × 32 的,224 / 32 = 7 ,所以这里的大小是 7 × 7 。这张图怎么理解呢?我们会在每个 token 上叠加一个位置编码,中间那个图的 49 个小图中,每个小图其实也是 7 × 7 的。左上角第一行第一个 patch 的位置编码与自己的位置编码是一样的,所以余弦相似度是1,所以左上角是黄色。然后在与其他位置编码进行计算。就得到了左上角的小图。其他的也都是类似的规律。注意,这个是学出来的。
Transformer Encoder 就是将 Encoder Block 重复堆叠 L 次。我们来看看单个 Encoder Block。
MLP Block 其实也很简单,就是一个全连接,GELU 激活函数,Dropout,全连接,Dropout。需要注意,第一个全连接层的节点个数是输入向量长度的 4 倍,第二个全连接层会还原原来的大小。
有一个地方要注意,看源码才知道,在 Transformer Encoder 前有个 Dropout 层,在之后有一个 Layer Norm 层,这些在图中还没有画出来的。在 Transformer Encoder 前有个 Dropout 层,对此我的理解是在原图上随机加 Mask 遮挡,然后依然要进行分类。
在训练 ImageNet21K 时候是由 Linear + tanh 激活函数 + Linear 构成的。
但是迁移到 ImageNet1k 之后或者做迁移学习时,其实只需要一个 Linear 就足够了。(获得类别概率需要一个 softmax)
假设输入图为 224 × 224 × 3 ,首先经过一个卷积层,然后进行高度和宽度方向的展平处理。紧接着 concat 一个 class token,再加上 Position Embedding 的相加操作,这里的 Position Embedding 也是可训练的参数。经过 Dropout 之后输入 12 个堆叠的 Encoder Block。Encoder 输出经过 LN 得到的输出为 197×768,即是不变的。然后我们提取第一个 class token 对应的输出,切片之后即变成了 1 × 768 ,将其输入 MLP Head 中。如果在 ImageNet21K 预训练的时候,Pre-Logits 就是一个全连接层,tanh 激活函数。如果是在 ImageNet1k 或者自己的数据集上的时候训练的时候,可以不要这个 Pre-Logits。
ViT B 对应的就是 ViT-Base,ViT L 对应的是 ViT-Large,ViT H 对应的是 ViT-Huge。
首先用传统的神经网络 backbone 来提取特征,然后再通过 ViT 模型进一步得到最终的结果。这里的特征提取部分采用的是 ResNet50 网络,但是和原来的有所不同,第一点是采用 stdConv2d,第二点则是使用GN而非BN,第三点是将 stage4 中的 3 个 block 移动到 stage3 中。R50 backbone 的输出为 14 × 14 × 1024 ,然后通过 1 × 1 卷积变为 14 × 14 × 768 ,然后进行展平处理就得到 token 了。之后就是和 ViT 一摸一样的了。
混合模型比纯 transformer 模型的效果会好一些,这也是迁移学习之后的结果。在少量微调中混合模型占有,但是随着迭代次数的上升,纯 transformer 也能达到混合模型的效果,例如 14 个 epoches 时 ViT-L/16 和 Res50x1+ViT-L/16 就基本一样了。
学习视频:Swin Transformer 网络详解
Swin Transformer名字的前部分Swin来自于Shifted Windows,Shifted Windows(移动窗口)也是Swin Transformer的主要特点。Swin Transformer的作者的初衷是想让Vision Transformer像卷积神经网络一样,也能够分成几个block做层级式的特征提取,从而导致提出来的特征具有多尺度的概念。
标准的Transformer直接用到视觉领域有一些挑战,难度主要来自于尺度不一和图像的resolution较大两个方面。首先是关于尺度的问题,例如一张街景的图片,里面有很多车和行人,并且各种物体的大小不一,这种现象不存在于自然语言处理。再者是关于图像的resolution较大问题,如果以像素点为基本单位,序列的长度就变得高不可攀,为了解决序列长度这一问题,科研人员做了一系列的尝试工作,包括把后续的特征图作为Transformer的输入或者把图像打成多个patch以减少图片的resolution,也包括把图片划成一个一个的小窗口,然后再窗口里做自注意力计算等多种办法。针对以上两个方面的问题,Swin Transformer网络被提出,它的特征是通过移动窗口的方式学来的,移动窗口不仅带来了更大的效率,由于自注意力是在窗口内计算的,所以也大大降低了序列的长度,同时通过Shiting(移动)的操作可以使相邻的两个窗口之间进行交互,也因此上下层之间有了cross-window connection,从而变相达到了全局建模的能力。
层级式结构的好处在于不仅灵活的提供各种尺度的信息,同时还因为自注意力是在窗口内计算的,所以它的计算复杂度随着图片大小线性增长而不是平方级增长,这就使Swin Transformer能够在特别大的分辨率上进行预训练模型。
基于全局的自注意力计算会导致平方倍的复杂度,当进行视觉里的下游任务时尤其是密集预测型任务或者非常大尺寸的图片时,基于全局计算自注意力的复杂度会非常的高,而Swin Transformer则采用了窗口计算自注意力。
如图,原来的图片会不重叠的分成多个窗口,但窗口并不是最小的计算单元,最小的计算单元是窗口里的patch图像块,每个窗口里都有m*m个patch,在Swin Transformer的原文中,m的值一般默认为7,此时每个窗口里就有49个patch,自注意力计算都是分别在窗口内完成的,所以序列长度永远都是49。
基于窗口计算自注意力的方式虽然很好的解决了内存和计算量的问题,但是窗口与窗口之间没有了通信,没能达到全局建模的效果,这就限制了模型的能力。移动窗口被提出后,先进性一次窗口的自注意力计算,再进行一次移动窗口后的自注意力计算,这样就实现了窗口与窗口之间的通信,从而达到了全局建模的效果。
图layer1+1 是由 图layer1 向右下角移动2个patch的单位得到,原来的窗口与移动后的窗口有了重叠的部分,这样就到达了窗口与窗口之间的相互通信。虽然已经能达到窗口与窗口之间的通信,但是原来的特征图只有4个窗口,经过移动窗口后,得到了9个窗口,窗口的数量有所增加并且9个窗口的大小也不是完全相同,这就导致计算难度增加。
Swin Transformer原作者团队使用了循环移位和掩码操作的方式,既保证了移动窗口后窗口的数量保持不变,也保证了每个窗口内的patch数量不变。
想要有多尺寸的特征信息,就要构建一个层级式的Transformer,也就是说我们要像卷积神经网络里一样有一个池化的操作,所以就提出了patch merging。Patch merging 顾名思义,合并小patch成一个大patch,这样就起到了下采样一个特征图效果的了。
经过这六周的入门学习,理解了深度学习的基础知识(主要是卷积神经网络)、对各种图片分类神经网络算法有了一个大致的了解,并且学习了如何使用pytorch构建网络架构、如何去训练和预测结果。感觉这些知识是有难度的,还需要进一步的学习和理解~