一、基础知识点的普及
1.ImageNet 1k and 22k
Currently ImageNet 22k is the whole ImageNet
Imagenet 1k is ISLVRC2012
2.Transformer中编码信息的解决
3.原生transformer的适用场景
Encoder-Deocder
正如我们在上面所介绍的完整Transformer架构,这种编解码形式通常用于序列到序列的建模,例如神经机器翻译
。
Encoder only
仅使用编码器,编码器的输出用作输入序列的表示,这种结构通常用于分类或序列标记问题,例如图像分类。
Decoder only
使用了解码器,其中也删除了编码器-解码器交叉注意模块,这种结构通常用于序列生成,例如语言建模
。
4.Transformer与其他网络模型的比较
(1)归纳偏差分析
众所周知,CNN会通过局部共享的卷积核
来加强网络的平移不变性和局部的归纳偏差
。 类似地,RNN通过其马尔可夫结构
携带时间不变性和局部的归纳偏差
。另一方面,Transformer架构对数据的结构信息几乎没有假设。这使得Transformer成为一种通用且灵活的架构。作为副作用,缺乏结构性偏差使得Transformer容易过拟合小规模的数据集
。此外,Transformer其实可以看成是在一个带有完整有向图(with self-loop)上所定义的图神经网络(Graph Neural Network, GNN),其中每个输入都可视为图中的一个节点。然而,Transformer和GNN之间的主要区别在于Transformer没有引入关于如何构造输入数据的先验知识。【Transformer中的信息传递过程完全取决于内容的相似性度量】
Inductive bias,即归纳偏置,定义为关于目标函数的必要假设。正所谓”There ain’t no such thing as a free lunch“,这句话应用再机器学习上可以理解为在没有先验知识的前提下,模型是无法学习的
。因此,归纳偏置可以理解为基于固有的先验知识对目标函数进行一定的预判,即将带有未知解的目标函数约束在一个限定的假设域内,使模型能够在这范围内进行有效的学习。
在CNN
中,归纳偏置可以理解为局部性和空间不变性
。首先,局部性体现在卷积核的大小是有限的。其次,空间不变性是由于卷积核共享权重所决定的。
在RNN
中,归纳偏置则可以理解为时间不变性
,这是由于RNN中序列顺序的每个时间步之间都是有关联的。
在Transformer
中,归纳偏置几乎是不存在的
,这使得其更具备通用性(即不会只针对某种特定类型的任务有效),缺陷便是会导致其对小数据集更容易过拟合。因此,需要引入结构先验、正则化,或者使用无监督预训练。关于归纳偏置更详细的理解可参考该论文[5]。
(2)关系归纳偏差
简单的讲,归纳偏置是学习过程中的模型选择指标,指导着我们选择什么模型
,比如,通常我们利用奥卡姆剃刀原则作为众多模型的偏置,当多个模型性能差不多时候,基于奥卡姆剃刀,我们会选择最简单的那个模型作为最终模型。而关系归纳偏置则是在学习过程,在归纳偏置上加入的实体间的关系和作用的约束
。
我们知道,神经网络虽然复杂,但是它也是有众多构建块构造而成
,例如,多层感知器是由全连接层构造块构造,卷积网络则是由卷积层构造块构造,而一个图像识别模型神经网络则是由卷积层和全连接层共同构造而成的。
对于全连接网络
,它的实体是层间的神经元,而层级间神经元是相互连接的,所以神经元之间的关系是多对多(All-to-all),关系归纳偏置是弱的
,实体间的关系和作用都是相互影响的(每个实体全连接)。
对于卷积网络
,它的实体是网格元素(图像区域),自然卷积之间的关系是局部(Local)的,而它们的关系归纳偏置是局部性(Locality)
,具有空间不变性。
对于递归网络
,它的实体是时间步数上的网络,关系是序列关系,关系归纳偏置也是序列的
,具有时间不变性。
二、Vision Transformer
0.Vision Tranformer中的相关变体
CPVT
这篇论文主要的侧重点在于位置的编码。常见的position encoding方式包括绝对位置编码和相对位置编码等。
目前常用的一般是绝对位置编码,包括在Transformer中提出的sinusoidal编码方式,以及在GPT,ViT等中所使用的可训练的位置编码等。但是一般的绝对位置编码针对特定分辨率的任务,在训练时就会生成固定尺寸的编码,无法处理不同分辨率大小的图片,这极大地妨碍了Transformer地灵活性和更大的应用空间。常见的处理方式是在处理不同分辨率的图像时,对训练好的position encoding进行插值适用,但需要fine-tune来恢复,不然会造成较大的精度下降。
所以,该文提出了提出一种能够根据不同尺寸输入改变长度的position encoding 方式(比较适用于基于弱监督的病理组织切片的相关问题)。
具体的步骤详解;
首先对上一个transformer encoder的输出进行reshape,回退为2D的图像形式;
然后对该2D信息进行一个2D可分离卷积等来进行局部信息的提取;
最后对新生成的tensor重新reshape到序列化信息格式作为输出。
由于class token中不包含位置相关信息,因此将其隔离不参与PEG的操作。
CPVT:一个卷积就可以隐式编码位置信息
对于transformer来说,由于self-attention操作是permutation-invariant的,所以需要一个positional encodings(PE)来显示地编码sequence中tokens的位置信息。ViT模型是采用学习的固定大小的positional embedding,但是当图像输入大小变化时,就需要对positional embedding来插值来适应输入tokens数量带来的变化,这一过程会造成性能损失。CPVT的解决方案是引入一个带有zero-padding的卷积来隐式地编码位置信息(PEG),从而省去了显式的positional embedding,最重要的是CPVT模型在输入图像大小变化时性能是稳定的。CPVT这种特性是很多图像任务所需要的,比如分割和检测往往需要大小变化的输入图像。
位置编码:
由于self-attention的permutation-invariant使得transformer需要一个特殊的positional encodings来显式地引入sequence中tokens的位置信息,因为无论是文本还是图像sequence,位置信息都是非常重要的。论文中以DeiT-tiny为实验模型,分别采用no positional encodings,learnable absolute positional encodings,fixed sin-cos positional encodings以及relative postional encodings等,不同的策略在ImageNet下的效果如下表所示:
主要结论如下:
- positional encodings对模型性能比较关键,不采用任何PE效果最差;
- relative postional encodings相比absolute positional encodings效果稍差,绝对位置编码比较重要;
- 采用显式的PE,当图像分辨率提升时直接对PE插值处理,性能会下降;
对于显式的PE,当图像分辨率与训练时不一致,往往需要finetune来弥补PE插值带来的性能损失。另外,论文中还提到了采用显式的PE会破坏图像tokens的“平移等价性”(translation equivariance,论文中说的是translation invariance:“平移不变性”,但是我理解应该前者更合适):当一个物体在图像中进行平移时,只是物体对应的tokens发生了变化,但是token embeddings并不会变(卷积也具有平移等价性:物体平移,“特征”也是同样平移)。但是不同位置的PE是不同的,虽然token embeddings是一样的,但是会加上不同的PE,那么平移等价性就被破坏了。
PEG:Conditional Positional Encodings
基于上面的实验分析,论文中认为一个理想的positional encoding应该满足一下条件:
- 处理sequence时,操作具有permutation-variant但translation-equivariance特性:对位置敏感但同时具有平移等价性;
- 能够自然地处理变长的sequence;
- 能够一定程度上编码绝对位置信息(absolute position)。
基于这三点,论文中给出的方案是采用一个带有zero padding的2D卷积( kernel size k ≥ 3)来充当positional encodings。卷积是一种局部运算,所以当tokens顺序被打乱,特征就发生了变化,卷积天生具有平移等价性,所以卷积满足第一点,对于第二点更是毫无疑问。现在关键的是第三点,因为从直觉来看,卷积具有平移等价性,那么是无法编码绝对信息,这两个特性其实是相互矛盾的。但是其实CNN已经被证明了可以编码图像的绝对位置信息,这主要是因为图像的boundary effects以及卷积的zero-padding操作造成的。感兴趣的可以看看参考文献中的论文[2-4]。
全局平均池化的实现效果:
首先全局平均池化的目的是提取每一张特征图的平均值。
实现全局平均池化大部分用的是keras的库。先看代码。
import tensorflow as tf
import torch
a=torch.arange(0,24).view(2, 3, 2,2)
a=a.float()
a=a.numpy()
print("This is x: ",a)
y = tf.keras.layers.GlobalAveragePooling2D(data_format='channels_first')(a)
print(y,y.shape)
这是输出:
This is x: [[[[ 0. 1.]
[ 2. 3.]]
[[ 4. 5.]
[ 6. 7.]]
[[ 8. 9.]
[10. 11.]]]
[[[12. 13.]
[14. 15.]]
[[16. 17.]
[18. 19.]]
[[20. 21.]
[22. 23.]]]]
tf.Tensor(
[[ 1.5 5.5 9.5]
[13.5 17.5 21.5]], shape=(2, 3), dtype=float32) (2, 3)
如何实现低版本的tensorflow中的torch对象的输出?
‘
但是通过Pytorch 我可以直接用mean()函数来实现这个功能。
import torch
a=torch.arange(0,24).view(2, 3, 2,2)
print("This is input: ",a)
a=a.float()
a=a.mean(dim=-1)
a=a.mean(dim=-1)
print("This is output: ",a,a.shape)
这是输出:
This is input: tensor([[[[ 0, 1],
[ 2, 3]],
[[ 4, 5],
[ 6, 7]],
[[ 8, 9],
[10, 11]]],
[[[12, 13],
[14, 15]],
[[16, 17],
[18, 19]],
[[20, 21],
[22, 23]]]])
This is output: tensor([[ 1.5000, 5.5000, 9.5000],
[13.5000, 17.5000, 21.5000]]) torch.Size([2, 3])
CeiT是一种可将卷积设计整合到视觉Transformers中。它结合了CNN在提取low-level特征,增强局部性以及Transformer在建立远程依赖项的优势,表现SOTA。
为了克服这些限制,我们分析了直接从NLP借用Transformer架构时的潜在弊端。然后,我们提出了一个新的卷积增强图像Transformer(CeiT),它结合了CNN在提取low-level特征,增强局部性方面的优势以及Transformer在建立远程依赖项方面的优势。对原始的Transformer进行了三处修改:
(1) 不是从原始输入图像中直接进行标记化,我们设计了一个Image-to-Tokens(I2T)模块,该模块从生成的low-level特征中提取patch
(2)每个编码器块中的前馈网络(Feed Forward Layer)被Local-enhanced Feed-Forward(LeFF)层代替,该层促进空间维度上相邻标记之间的相关性。将token重新拼接成feature map,然后采用深度可分离卷积进行局部化处理。
(3)Layer-wise Class-token Attention(LCA)附加在使用多级表示形式的Transformer的顶部。
LCA模块会将所有Transformer Block所得到的class token作为输入,然后在其基础上使用一个MSA+FFN得到最终的logits作为输出。作者认为这样可得到多尺度的特征。
实验结果:
在ImageNet和七个下游任务上的实验结果表明,与以前的Transformers和最新的CNN相比,CeiT的有效性和泛化能力无需大量的训练数据和额外的CNN teachers。
1.Transformer最初提出是针对NLP领域的,并且在NLP领域大获成功。这篇论文也是受到其启发,尝试将Transformer应用到CV领域
。关于Transformer的部分理论之前的博文中有讲,链接,这里不在赘述。通过这篇文章的实验,给出的最佳模型在ImageNet1K上能够达到88.55%的准确率(先在Google自家的JFT数据集上进行了预训练。后来在ImageNet-1k上进行了迁移学习)
,说明Transformer在CV领域确实是有效的,而
(1)且效果还挺惊人。
注:表格中的ViT-H/14中的14代表的是Patch size,即每张patch的大小是patch_size×patch_size。第三列数据是在ImageNet-22K上进行了预训练并且在ImageNet-1k上进行了迁移学习。
模型详解
在这篇文章中,作者主要拿ResNet、ViT(纯Transformer模型)以及Hybrid(卷积和Transformer混合模型)
三个模型进行比较,所以本博文除了讲ViT模型外还会简单聊聊Hybrid模型。
Vision Transformer模型详解
下图是原论文中给出的关于Vision Transformer(ViT)的模型框架。简单而言,模型由三个模块组成:
- Linear Projection of Flattened Patches(Embedding层)
- Transformer Encoder(图右侧有给出更加详细的结构)
- MLP Head(最终用于分类的层结构)
Embedding层结构详解
ps:可以这么理解每一个patch经过embedding层,就生成了一个向量(Tocken)。
对于标准的Transformer模块,要求输入的是token(向量)序列,即二维矩阵[num_token, token_dim]
,如下图,token0-9对应的都是向量,以ViT-B/16为例,每个token向量长度为768。
对于图像数据而言,其数据格式为[H, W, C]是三维矩阵明显不是Transformer想要的。所以需要先通过一个Embedding层来对数据做个变换。如下图所示,首先将一张图片按给定大小分成一堆Patches。以ViT-B/16为例,将输入图片(224x224)按照16x16大小的Patch进行划分,划分后会得到( 224 / 16 )^ 2 = 196 个Patches。接着通过线性映射将每个Patch映射到一维向量中,以ViT-B/16为例,每个Patche数据shape为[16, 16, 3]通过映射得到一个长度为768的向量(后面都直接称为token)。[16, 16, 3] -> [768]
在代码实现中,直接通过一个卷积层来实现。 以ViT-B/16为例,直接使用一个卷积核大小为16x16,步距为16,卷积核个数为768的卷积来实现。通过卷积[224, 224, 3] -> [14, 14, 768]
,然后把H以及W两个维度展平即可[14, 14, 768] -> [196, 768]
,此时正好变成了一个二维矩阵,正是Transformer想要的。
在输入Transformer Encoder之前注意需要加上[class]token以及Position Embedding。 在原论文中,作者说参考BERT,在刚刚得到的一堆tokens中插入一个专门用于分类的[class]token,这个[class]token是一个可训练的参数,数据格式和其他token一样都是一个向量
,以ViT-B/16为例,就是一个长度为768的向量,与之前从图片中生成的tokens拼接在一起,Cat([1, 768], [196, 768]) -> [197, 768]
。然后关于Position Embedding就是之前Transformer中讲到的Positional Encoding,这里的Position Embedding采用的是一个可训练的参数(1D Pos. Emb.)
,是直接叠加在tokens上的(add),所以shape要一样。以ViT-B/16为例,刚刚拼接[class]token后shape是[197, 768]
,那么这里的Position Embedding的shape也是[197, 768]
。
对于Position Embedding作者也有做一系列对比试验,在源码中默认使用的是1D Pos. Emb.
,对比不使用Position Embedding准确率提升了大概3个点,和2D Pos. Emb.
比起来没太大差别。
**注:**为什么要是使用余弦相似度来计算位置编码呢?–>是在Transformer文章所提及的,并且结果显示第一行第一列的patch与自身计算余弦相似度时为1,并且他与其所在行或者所在列的余弦相似度较高。
Transformer Encoder详解
Transformer Encoder其实就是重复堆叠Encoder Block L次,下图是我自己绘制的Encoder Block,主要由以下几部分组成:
- Layer Norm,这种Normalization方法主要是针对NLP领域提出的,这里是对每个token进行Norm处理,之前也有讲过Layer Norm不懂的可以参考链接
Multi-Head Attention,这个结构之前在讲Transformer中很详细的讲过,不在赘述,不了解的可以参考链接
- Dropout/DropPath,在原论文的代码中是直接使用的Dropout层,在但
rwightman
实现的代码中使用的是DropPath(stochastic depth),可能后者会更好一点。 - MLP Block,如图右侧所示,就是全连接+GELU激活函数+Dropout组成也非常简单,需要注意的是第一个全连接层会把输入节点个数翻4倍
[197, 768] -> [197, 3072]
,第二个全连接层会还原回原节点个数[197, 3072] -> [197, 768]
-
MLP Head详解
注:MLP Head层中有两个非常重要的事项:1)Transformer Encoder的前面有一个Dropout层;2)在Transformer Encoder后其实还有一个Layer Norm没有画出来。
上面通过Transformer Encoder后输出的shape和输入的shape是保持不变的,以ViT-B/16为例,输入的是[197, 768]输出的还是[197, 768]。注意,在Transformer Encoder后其实还有一个Layer Norm没有画出来,后面有我自己画的ViT的模型可以看到详细结构。这里我们只是需要分类的信息,所以我们只需要提取出[class]token生成的对应结果就行,即[197, 768]中抽取出[class]token对应的[1, 768]。接着我们通过MLP Head得到我们最终的分类结果。MLP Head原论文中说在训练ImageNet21K时是由Linear+tanh激活函数+Linear组成。但是迁移到ImageNet1K上或者你自己的数据上时,只用一个Linear即可(即去掉了下图中的Pre-logits模块)
。在这里其实可以将MLP Head简单地理解为全连接层即可,如果需要类别概率时则需要再接上一个softmax激活函数即可。
自己绘制的Vision Transformer网络结构
为了方便大家理解,我自己根据源代码画了张更详细的图(以ViT-B/16为例):
ViT模型搭建参数
在论文的Table1中有给出三个模型(Base/ Large/ Huge)的参数,在源码中除了有Patch Size为16x16
的外还有32x32
的。其中的
- Layers就是Transformer Encoder中重复堆叠Encoder Block的次数
- Hidden Size就是对应通过Embedding层后每个token的dim(向量的长度)
- MLP size是Transformer Encoder中MLP Block第一个全连接的节点个数(是Hidden Size的四倍)
- Heads代表Transformer中Multi-Head Attention的heads数。
Hybrid模型详解
在论文4.1章节的Model Variants
中有比较详细的讲到Hybrid混合模型,就是将传统CNN特征提取和Transformer进行结合
。下图绘制的是以ResNet50作为特征提取器的混合模型,但这里的Resnet与之前讲的Resnet有些不同。首先这里的R50的卷积层采用的StdConv2d不是传统的Conv2d,然后将所有的BatchNorm层替换成GroupNorm层
。在原Resnet50网络中,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。三、Swin Transformer
0.前言
Swin Transformer是2021年微软研究院发表在ICCV上的一篇文章,并且已经获得ICCV 2021 best paper
的荣誉称号。Swin Transformer网络是Transformer模型在视觉领域的又一次碰撞。该论文一经发表就已在多项视觉任务中霸榜。该论文是在2021年3月发表的,现在是2021年11月了,根据官方提供的信息可以看到,现在还在COCO数据集的目标检测以及实例分割任务中是第一名(见下图State of the Art表示第一
)。
1.Swin Transformer与Vision Transformer有以下几点的不同之处:
- Swin Transformer使用了类似卷积神经网络中的
层次化构建方法
(Hierarchical feature maps),比如特征图尺寸中有对图像下采样4倍的,8倍的以及16倍的
,这样的backbone有助于在此基础上构建目标检测,实例分割等任务。而在之前的Vision Transformer
中是一开始就直接下采样16倍
,后面的特征图也是维持这个下采样率不变。 - 在Swin Transformer中使用了Windows Multi-Head Self-Attention(W-MSA)的概念,比如在下图的4倍下采样和8倍下采样中,将特征图划分成了多个不相交的区域(Window),并且Multi-Head Self-Attention只在每个窗口(Window)内进行。相对于Vision Transformer中直接对整个(Global)特征图进行Multi-Head Self-Attention,这样做的目的是能够减少计算量的,尤其是在浅层特征图很大的时候(即此时的下采样倍率比较低地情况下)。这样做
虽然减少了计算量但也会隔绝不同窗口之间的信息传递
,所以在论文中作者又提出了Shifted Windows Multi-Head Self-Attention(SW-MSA)
的概念,通过此方法能够让信息在相邻的窗口中进行传递
,后面会细讲。
接下来,简单看下原论文中给出的关于Swin Transformer(Swin-T)网络的架构图。通过图(a)可以看出整个框架的基本流程如下:
- 首先将图片输入到Patch Partition模块中进行分块,即每4x4相邻的像素为一个Patch,然后在channel方向展平(flatten)。假设输入的是RGB三通道图片,那么每个patch就有4x4=16个像素,然后每个像素有R、G、B三个值所以展平后是16x3=48,所以通过Patch Partition后图像shape由
[H, W, 3]
变成了[H/4, W/4, 48]
。然后在通过Linear Embeding层对每个像素的channel数据做线性变换,由48变成C,即图像shape再由[H/4, W/4, 48]
变成了[H/4, W/4, C]
。其实在源码中Patch Partition和Linear Embeding就是直接通过一个卷积层实现的,和之前Vision Transformer中讲的 Embedding层结构一模一样。 - 然后就是通过四个Stage构建不同大小的特征图,
除了Stage1中先通过一个Linear Embeding层外,剩下三个stage都是先通过一个Patch Merging层进行下采样
(后面会细讲)。然后都是重复堆叠Swin Transformer Block注意这里的Block其实有两种结构,如图(b)中所示,这两种结构的不同之处仅在于一个使用了W-MSA结构,一个使用了SW-MSA结构
。而且这两个结构是成对使用的,先使用一个W-MSA结构再使用一个SW-MSA结构。所以你会发现堆叠Swin Transformer Block的次数都是偶数
(因为成对使用)。 - 最后对于分类网络,
stage4后面还会接上一个Layer Norm层、全局池化层以及全连接层得到最终输出
。图中没有画,但源码中是这样做的。
2 Patch Merging详解
前面有说,在每个Stage中首先要通过一个Patch Merging层进行下采样(Stage1除外)。如下图所示,假设输入Patch Merging的是一个4x4大小的单通道特征图(feature map),Patch Merging会将每个2x2的相邻像素划分为一个patch,然后将每个patch中相同位置(同一颜色)像素给拼在一起就得到了4个feature map。接着将这四个feature map在深度方向进行concat拼接
,然后在通过一个LayerNorm层。最后通过一个全连接层在feature map的深度方向做线性变化,将feature map的深度由C变成C/2。通过这个简单的例子可以看出,通过Patch Merging层后,feature map的高和宽会减半,深度会翻倍
。
3.W-MSA详解
引入Windows Multi-head Self-Attention(W-MSA)模块是为了减少计算量
。如下图所示,左侧使用的是普通的Multi-head Self-Attention(MSA)模块,对于feature map中的每个
像素(或称作token,patch
)在Self-Attention计算过程中需要和所有的像素去计算。
但在图右侧,在使用Windows Multi-head Self-Attention(W-MSA)模块时,首先将feature map按照MxM(例子中的M=2)大小划分成一个个Windows,然后单独对每个Windows内部进行Self-Attention。这里使用Windows Multi-head Self-Attention的缺点是窗口之间无法进行信息交互
,这样会使感受野变小,导致无法看到一个全局的视野,会对最终预测结果有影响。
两者的计算量具体差多少呢?原论文中有给出下面两个公式,这里忽略了Softmax的计算复杂度。: - h代表feature map的高度
- w代表feature map的宽度
- C代表feature map的深度
- M代表每个窗口(Windows)的大小
这个公式是咋来的,原论文中并没有细讲,这里简单说下。首先回忆下单头Self-Attention的公式,如果对Self-Attention不了解的,请看下我之前写的文章。
MSA模块计算量
W-MSA模块计算量
4 SW-MSA详解
前面有说,采用W-MSA模块时,只会在每个窗口内进行自注意力计算,所以窗口与窗口之间是无法进行信息传递的
。为了解决这个问题,作者引入了Shifted Windows Multi-Head Self-Attention(SW-MSA)模块,即进行偏移的W-MSA。如下图所示,左侧使用的是刚刚讲的W-MSA(假设是第L层),那么根据之前介绍的W-MSA和SW-MSA是成对使用的,那么第L+1层使用的就是SW-MSA(右侧图)
。根据左右两幅图对比能够发现窗口(Windows)发生了偏移(可以理解成窗口从左上角分别向右侧和下方各偏移了⌊ M /2 ⌋ 个像素)。看下偏移后的窗口(右侧图),比如对于第一行第2列的2x4的窗口,它能够使第L层的第一排的两个窗口信息进行交流。再比如,第二行第二列的4x4的窗口,他能够使第L层的四个窗口信息进行交流,其他的同理。那么这就解决了不同窗口之间无法进行信息交流的问题。
注意:理解成窗口从左上角分别向右侧和下方各偏移了⌊ M /2 ⌋ 个像素
根据上图,可以发现通过将窗口进行偏移后,由原来的4个窗口变成9个窗口了。后面又要对每个窗口内部进行MSA,这样做感觉又变麻烦了。为了解决这个麻烦,作者又提出而了Efficient batch computation for shifted configuration
,一种更加高效的计算方法。下面是原论文给的示意图。
感觉不太好描述,然后我自己又重新画了个。下图左侧是刚刚通过偏移窗口后得到的新窗口,右侧是为了方便大家理解,对每个窗口加上了一个标识。然后0对应的窗口标记为区域A,3和6对应的窗口标记为区域B,1和2对应的窗口标记为区域C。
然后先将区域A和C移到最下方。
接着,再将区域A和B移至最右侧。
移动完后,4是一个单独的窗口;将5和3合并成一个窗口;7和1合并成一个窗口;8、6、2和0合并成一个窗口
。这样又和原来一样是4个4x4的窗口了,所以能够保证计算量是一样的。这里肯定有人会想,把不同的区域合并在一起(比如5和3)进行MSA,这信息不就乱窜了吗?是的,为了防止这个问题,在实际计算中使用的是masked MSA即带蒙板mask的MSA,这样就能够通过设置蒙板来隔绝不同区域的信息了
。关于mask如何使用,可以看下下面这幅图,下图是以上面的区域5和区域3为例。
5 Relative Position Bias详解
关于相对位置偏执,论文里也没有细讲,就说了参考的哪些论文,然后说使用了相对位置偏执后给够带来明显的提升。根据原论文中的表4可以看出,在Imagenet数据集上如果不使用任何位置偏执,top-1为80.1,使用了绝对位置偏执(ViT中绝对位置编码)时的top-1的准确率为80.5,但是再COCO数据集和ADE20数据集上的top-1准确率相较于ImageNet却降低了,但使用了相对位置偏执(rel. pos.)后top-1为81.3,提升还是很明显的。
第一行中的w/o代表的是without shifting,全部使用的是W-MSA,而不是用SW-MSA的话,top-1为80.2。
第二行代表的是我们使用了SW-MSA时,top-1为81.3。
这两行的结果表示让窗口与窗口进行交互是非常有必要的。
由于论文中并没有详解讲解这个相对位置偏执,所以我自己根据阅读源码做了简单的总结。如下图,假设输入的feature map高宽都为2,那么首先我们可以构建出每个像素的绝对位置(左下方的矩阵),对于每个像素的绝对位置是使用行号和列号表示的。比如蓝色的像素对应的是第0行第0列所以绝对位置索引是( 0 , 0 ),接下来再看看相对位置索引。首先看下蓝色的像素,在蓝色像素使用q与所有像素k进行匹配过程中,是以蓝色像素为参考点。然后用蓝色像素的绝对位置索引与其他位置索引进行相减,就得到其他位置相对蓝色像素的相对位置索引
。例如黄色像素的绝对位置索引是( 0 , 1 ) ,则它相对蓝色像素的相对位置索引为( 0 , 0 ) − ( 0 , 1 ) = ( 0 , − 1 ) ,这里是严格按照源码中来讲的,请不要杠。那么同理可以得到其他位置相对蓝色像素的相对位置索引矩阵。同样,也能得到相对黄色,红色以及绿色像素的相对位置索引矩阵。
接下来将每个相对位置索引矩阵按行展平,并拼接在一起可以得到下面的4x4矩阵 。
请注意,我这里描述的一直是相对位置索引,并不是相对位置偏执参数。因为后面我们会根据相对位置索引去取对应的参数
。比如说黄色像素是在蓝色像素的右边,所以相对蓝色像素的相对位置索引为( 0 , − 1 ) 。绿色像素是在红色像素的右边,所以相对红色像素的相对位置索引为( 0 , − 1 ) 。可以发现这两者的相对位置索引都是( 0 , − 1 ) ,所以他们使用的相对位置偏执参数都是一样的
。其实讲到这基本已经讲完了,但在源码中作者为了方便把二维索引给转成了一维索引。具体这么转的呢,有人肯定想到,简单啊直接把行、列索引相加不就变一维了吗?比如上面的相对位置索引中有( 0 , − 1 )和( − 1 , 0 )在二维的相对位置索引中明显是代表不同的位置,但如果简单相加都等于-1那不就出问题了吗?接下来我们看看源码中是怎么做的。首先在原始的相对位置索引上加上M-1(M为窗口的大小,在本示例中M=2),加上之后索引中就不会有负数了。
注意:整个取值范围【-M+1,M-1】,经过排列组合后,就变成【2M-1】×【2M-1】.
接着将所有的行标都乘上2M-1。
最后将行标和列标进行相加。这样即保证了相对位置关系,而且不会出现上述0 + ( − 1 ) = ( − 1 ) + 0 的问题了,是不是很神奇。
注意:图片中的relative position bias才是我们在公式中最终所使用的B。并且在网络训练过程中,我们真正训练的是relative position bias table中的参数值。上图中所提到的relative position index 索引则是固定的。
6 模型详细配置参数
首先回忆下Swin Transformer的网络架构:
下图(表7)是原论文中给出的关于不同Swin Transformer的配置,T(Tiny),S(Small),B(Base),L(Large)
,其中:
- win. sz. 7x7表示使用的窗口(Windows)的大小
- dim表示feature map的channel深度(或者说token的向量长度)
- head表示多头注意力模块中head的个数
concat 4×4。96-d,LN代表的是patch partition和Linea embeedingceng,与patch merge的功能是一样的。
concat 4×4。96-d,LN代表的是下采样四倍,channel为96,通过Layer normal