Swin Transformer V2
Swin Transformer V2: Scaling Up Capacity and Resolution
论文地址: https://arxiv.org/abs/2111.09883
如V2名字所言,这里增大了模型的冗余和输入的分辨率!
V1论文解析参考:https://www.cnblogs.com/dan-baishucaizi/p/14661164.html
V1主要的贡献是shifted window,transformer部分也加入了图像的相对位置偏置,为什么是相对位置偏置,这个问题在NLP方向有足够的研究表面相对位置比绝对位置work的更好。位置信息对于transformer这种结构至关重要,因为它对序列位置不敏感,这是结构设计上的硬伤,而序列建模位置是非常重要的,这是由源数据特点就决定的!关于transformer有许多改进,包括对输入的前处理、attention追加偏置信息等。我们注意到模型要做的就是两件事:token内建模和token间建模!QKV的设计是在self-attention上实现了token间建模,前处理中往往使用了token内建模,即以\(QW^{Q}\)的形式先对token内信息提取,与attention机制互补!V1、V2都是采用了这种形式!那么我们为什么不采用形如\(W^{Q}Q\)的计算方式进行token间的建模呢?首先这里与attention的性能重合,其次不能与attention互补,并且参数量会有指数级的增长,计算量相应增加,这是一个不nice的操作...
Swin Transformer的三个主要创新点:
- res-post-norm:后置的标准化处理,文中指将LN层放在残差分支的末端而不是开头;
- 余弦注意力:将原transformer的Q、K点积生成注意力换成余弦的注意力计算模式;
- log-CPB: 对数间隔连续位置偏置,替换了原来的相对位置偏置,以应对窗口尺寸变换很大的情况,在窗口尺寸变化较大时对数缩放会将差异变的很小,使模型可控!
Swin Transformer结合的三个主要新技术点:
- zero-optimizer:零优化技术;https://dl.acm.org/doi/10.5555/3433701.3433727
- activation check pointing:激活检查点;https://blog.csdn.net/yiran103/article/details/79475945 、
- self-attention:自注意力的新实现.
摘要
大规模NLP模型已经被证明可以显著提高语言任务的性能,并且没有饱和的迹象。他们还展示了惊人的少样本(few-shot)学习能力,就像人类一样。本文旨在探索计算机视觉中的大规模模型。我们解决了大型视觉模型训练和应用中的三个主要问题,包括训练不稳定性、预训练和微调之间的分辨率差距以及对标记数据的饥饿感。提出了三种主要技术:1) 残差后范数法结合余弦注意提高训练稳定性; 2) 一种对数间隔连续位置偏差方法,用于有效地将使用低分辨率图像预先训练的模型传输到具有高分辨率输入的下游任务;3) 一种自我监督的预训练方法SimMIM,用于减少对大量标记图像的需求。通过这些技术,本文成功地训练了一个30亿参数的Swin Transformer V2模型,这是迄今为止最大的稠密视觉模型,并使其能够使用高达1536×1536分辨率的图像进行训练。它在ImageNet-V2图像分类、COCO目标检测、ADE20K语义分割和Kinetics-400视频动作分类等4项具有代表性的视觉任务上创造了新的性能记录。还要注意的是,我们的训练效率远远高于谷歌的十亿级视觉模型,后者消耗的标签数据少了40倍,训练时间少了40倍。
这里微软十分嚣张地内涵了谷歌,虽然我们不知道大佬是锚定的那个项目(猜测他说的应该是scaling vision transformer: https://arxiv.org/pdf/2106.04560.pdf),但是较好的模型还是有不少的,这里我就随便拿一个来比划比划:
Model # Params(M) GFLOPs Top1 Acc(%) Datasets windows VAN-Large 44.8 9.0 83.9 ImageNet SwinV2-S 50 11.5 83.7 ImageNet-1k 8 x 8 SwinV2-S 50 12.6 84.1 ImageNet-1k 16 x 16 ConvNeXt-S 50 8.9 83.1 ImageNet-1k 这里我们可以看出SwinV2-S比VAN-Large模型多了\(\frac{1}{3}\)的计算量,精度提升了千分之二,两种模型性能相当!
Model # Params(M) GFLOPs mIoU Datasets VAN-Large + UperNet 74.7 257.7 50.1 ADE20K Swin-S + UperNet 81 1038 47.64 ADE20K Swin-B + UperNet 121 1841 50.4 ADE20K SwinV2-L + UperNet 240 55.9 ADE20K 这里我们没有V2的语义分割,在V1层面上,明显V1被VAN模型超越了!即使是SwinV2-L模型的性能,我们有信心VAN的大模型(还没有发布)也将有类似的性能!
一、介绍
扩展语言模型取得了难以置信的成功。它显著提高了模型在语言任务上的表现[19、24、49、50、52、53],模型展示了与人类相似的惊人的少样本学习能力[7]。自拥有3.4亿个参数的BERT大型模型以来,语言模型在几年内迅速扩大了1000倍以上,达到5300亿个密集参数[50]和1.6万亿个稀疏参数[24]。研究还发现,这些大型语言模型在广泛的语言任务中,具有越来越强的类似于人类智能的少样本学习能力[7]。
另一方面,视觉模型的扩展一直滞后。虽然人们早就认识到,较大的视觉模型通常在视觉任务上表现更好[29,60],但最近,绝对模型大小刚刚能够达到约10-20亿个参数[17,27,39,56,80]。更重要的是,与大型语言模型不同,现有的大型视觉模型仅应用于图像分类任务[17、56、80]。
为了成功地训练大型和通用的视觉模型,我们需要解决几个关键问题。首先,我们使用大型视觉模型进行的实验揭示了训练中的不稳定性问题。我们发现,在大型模型中,跨层激活幅度的差异变得显著更大。仔细观察原始架构可以发现,这是由直接添加回主分支的残差单元的输出引起的。结果是激活值逐层累积,因此深层的振幅明显大于早期的振幅。为了解决这个问题,我们提出了一种新的规范化配置,称为res-post-norm,它将LN层从每个剩余单元的开头移动到后端,如图1所示。我们发现这种新配置在网络层上产生的激活值要轻得多。我们还提出了一种缩放余弦注意来取代以前的点积注意。缩放余弦注意使得计算与块输入的振幅无关,并且注意值不太可能陷入极端。在我们的实验中,提出的两种技术不仅使训练过程更加稳定,而且还提高了精度,尤其是对于较大的模型。
fig1 transformer模型架构图
![fig1 transformer结构图](https://img2022.cnblogs.com/blog/1319275/202206/1319275-20220609092900811-1913454365.png)
其次,许多下游视觉任务,如目标检测和语义分割,都需要高分辨率的输入图像或大的注意窗。低分辨率预训练和高分辨率微调之间的窗口大小变化可能相当大。当前的常见做法是对位置偏置特征图进行双三次插值[22,46]。这个简单的修复有点特别,结果通常是次优的。我们引入了一种对数间隔连续位置偏差(log-CPB:continuous position bias),它通过在对数间隔坐标输入上应用一个小型元网络,为任意坐标范围生成偏差值。由于元网络采用任何坐标,预先训练的模型将能够通过共享元网络的权重在窗口大小之间自由传递。我们方法的一个关键设计是将坐标转换为对数空间,这样即使目标窗口大小明显大于训练前的窗口大小,外推率也可以很低。模型容量和分辨率的扩大也会导致现有视觉模型的GPU内存消耗过高。为了解决内存问题,我们结合了一些重要的技术,包括零优化器【54】、激活检查点【12】和序列self-attention计算的新实现。使用这些技术,可以显著降低大型模型和分辨率的GPU内存消耗,对训练速度的影响微乎其微。
利用上述技术,我们成功地训练了一个30亿的Swin Transformer模型,并使用Nvidia A100-40G GPU将其有效地转移到各种图像分辨率高达1536×1536的视觉任务中。在我们的模型预训练中,我们还采用了自监督预训练来减少对超大标记数据的依赖。与之前的实践(JFT-3B)相比,标签数据减少了40倍,30亿模型在广泛的视觉基准上达到了最先进的精度。具体而言,它在ImageNet-V2图像分类验证集[55]上获得了84.0%的top-1准确率,在COCO测试开发对象检测集上获得了63.1/54.4 bbox/mask AP,在ADE20K语义分割上获得了59.9mIoU,在Kinetics-400视频动作分类上获得了86.8%的top-1准确率,比原Swin Transformer中的最佳数字高出了分别为+NA%、+4.4/+3.3、,+6.3和+1.9,并比之前的最佳记录高出+0.8%([80])、+1.8/+1.4([74])、+1.5([4])和+1.4%([57])。
通过扩大视觉模型的容量和分辨率,使其在一般视觉任务上具有强大的性能,就像一个好的语言模型在一般NLP任务上的性能一样,我们旨在促进这方面的更多研究,以便最终缩小视觉模型和语言模型之间的容量差距,并促进这两个领域的联合建模。
二、相关工作
语言网络和扩展 自[65]的开创性工作以来,transformer一直作为一个标准网络。自那时起,对这种体系结构进行缩放的探索就开始了,有效的自我监督学习方法的发明,如mask或自回归语言建模,加速了这一进展[19(BERT), 52],缩放定律的发现进一步鼓励了这一进展[36]。从那时起,语言模型的容量在几年内急剧增加了1000多倍,从BERT-340M到Megatron-Turing-530B[7、49、50、53]和稀疏开关变压器-1.6T(sparse Switch-Transformer-1.6T)[24]。随着能力的提高,各种语文基准的准确性已大大提高。零样本或少样本的表现也得到了显著改善[7],这是人类通用智能的基础。
视觉网络和扩展 CNN一直是标准的计算机视觉网络[40,41]。自AlexNet[40]以来,体系结构变得越来越深、越来越大,极大地推进了各种视觉任务,并在很大程度上推动了计算机视觉领域的深度学习浪潮,如VGG[60]、GoogleNet[62] 和ResNet。在过去两年中,CNN架构进一步扩展到大约10亿个参数[27,39],然而,绝对性能可能并不那么令人鼓舞,这可能是由于CNN架构中的归纳偏差限制了建模能力。
去年,Transformers开始接手一个又一个具有代表性的视觉基准,包括ImageNet-1K图像级分类基准[22]、COCO区域级目标检测基准[46]、ADE20K像素级语义分割基准[46、83]、Kinetics-400视频动作分类基准[2]等,已经提出了许多视觉transformer变体,以在相对较小的范围内提高精度[14、21、34、42、63、68、71、75、77、78、82]。只有少数作品试图放大视觉transformer[17,56,80]。然而,它们依赖于具有分类标签的巨大图像数据集(即JFT-3B),并且仅适用于图像分类问题。
变换跨窗口/核分辨率 对于CNN,以前的工作通常在预训练和微调期间固定内核大小。全局视觉变换器,如ViT[22],可以全局计算注意力,等效的注意力窗口大小与增加的输入图像分辨率成线性比例。对于局部vision Transformer架构,如Swin Transformer[46],窗口大小可以在微调期间固定或更改。允许可变窗口大小在使用中更方便,这样就可以被可能可变的整个特征图整除,并调整感受野以获得更好的精确度。为了处理预训练和微调之间的可变窗口大小,双三次插值是预训练的常见做法[22,46]。在本文中,我们提出了一种对数间隔连续位置偏差方法(log-CPB),该方法可以在低分辨率下更平滑地传递预先训练的模型权重,以处理高分辨率窗口。
偏置项学习 研究NLP中的偏置项,与原始transformer中使用的绝对位置嵌入法相比,相对位置偏置法证明是有益的[53]。在计算机视觉中,相对位置偏差方法更常用[31,46,75],这可能是因为视觉信号的空间关系在视觉建模中起着更重要的作用。通常的做法是直接将偏置值学习为模型权重。还有一些作品专门研究如何设置和学习偏差项[38,69]。
连续卷积和变体 我们的Log-CPB方法还与早期关于连续卷积和变体的工作有关【30、45、58、67】,这些工作利用元网络来处理不规则数据点。我们的Log-CPB方法受到了这些努力的启发,同时解决了在任意窗口大小的视觉transformer中转移相对位置偏差的不同问题。我们还提出了对数间隔坐标,以减轻在大尺寸变化之间转换时外推的困难。
综上,我们了解了V2的技术背景,下面我们将看看作者怎么完成V2的架构设计
三、Swin Transformer V2
3.1 Swin Transformer的简短说明
Swin Transformer是一种通用的计算机视觉主干,在区域级目标检测、像素级语义分割和图像级图像分类等各种粒度识别任务中取得了优异的性能。Swin Transformer的主要思想是将几个重要的视觉先验引入到vanilla Transformer编码器中,包括层次、位置和平移不变性,这将两者的优点结合在一起:基本Transformer单元具有强大的建模能力,视觉先验使其对各种视觉任务都很友好。
标准化配置 众所周知,标准化技术[3、35、64、70]对于稳定地训练更深层次的体系结构至关重要。原始的Swin Transformer继承了language Transformers[52] 和 vanilla ViT[22] 中的常见做法,在不进行广泛研究的情况下使用了预标准化配置,如上图所示。在以下小节中,我们将研究此默认规范化配置是否合适。
相对位置偏置 这是Swin V1的关键技术点,关于相对位置偏置在V1中我们详细地解释过了,现在再回顾一次。
相对位置偏置初始化
# 2*Wh-1 * 2*Ww-1, nH self.relative_position_bias_table = nn.Parameter( torch.zeros((2 * window_size[0] - 1) * (2 * window_size[1] - 1), num_heads)) trunc_normal_(self.relative_position_bias_table, std=.02)
self.relative_position_bias_table使用了截断正太分布进行初始化,标准差为0.02。这里我们要注意相对位置偏置是一个nn.Parameter的参数,也即相对位置偏置是逐渐学习得到!
\(M\)标识窗口的大小,那么初始化的偏置矩阵是\(\hat{B} \in \mathbb{R}^{\left( 2M-1\right)\times \left( 2M-1\right)}\),为什么是\(\left( 2M-1\right)\times \left( 2M-1\right)\)?后面再说明这个问题!
WindowAttention层最主要的就是相对位置偏置的编码部分比较复杂,其他操作都是我们熟悉的torch层,所以,这里仔细研究其处理过程。
获取相对位置偏置
相对位置偏置\(B\)是从\(\hat{B}\)的一个token。所以\(\hat{B}\)存储了所有的偏置,\(B\)要通过索引获取。下面是索引的生成:
coords:记录了窗口的坐标,原点为窗口左上角;
coords_flatten:记录了坐标的平铺;sahpe为 ( 2, \(M^{2}\));
relative_coords:记录了窗口内的像素的相对位置;如像素 \(patch_{a}\) 有\(M^{2}\)个相对位置,因为窗口内有\(M^{2}\)个像素。
注:这里我第一次看的时候能够理解,后面在面试过程中被问到是如何实现的,我的记忆是有较大偏差的,这导致了面试的不成功。再次看博客时,发现自己有点看不懂这些操作。为了更直白展示,下面我们详细展示源码及其示例。
# 假设M为5x5的 >>> coords_h = torch.arange(5) # 纵坐标张量tensor([0, 1, 2, 3, 4]) >>> coords_w = torch.arange(5) # 横坐标张量tensor([0, 1, 2, 3, 4]) >>> coords = torch.stack(torch.meshgrid([coords_h, coords_w])) # 2, Wh, Ww >>> coords tensor([[[0, 0, 0, 0, 0], [1, 1, 1, 1, 1], [2, 2, 2, 2, 2], [3, 3, 3, 3, 3], [4, 4, 4, 4, 4]], [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]]]) # 即coords[:, i, j]可以获取window内第i行第j列元素相对窗口左上角的相对坐标 >>> coords_flatten = torch.flatten(coords, 1) # 2, Wh*Ww # 此时coords_flatten记录了window内所有像素点平铺后对应的坐标,如:coords_flatten[:, i*J+j]表示第i行第j列元素相对窗口左上角的相对坐标,J是列的维度
# 上面的coords_flatten是相对左上角的坐标,即绝对位置坐标,但是我们需要相对位置坐标,每一个点都有Wh*Ww个相对位置。而我们又有Wh*Ww个点,所以应该有(Wh*Ww) x (Wh*Ww)个坐标 >>> relative_coords = coords_flatten[:, :, None] - coords_flatten[:, None, :] # 2, Wh*Ww, Wh*Ww # relative_coords.shape=[2, 25, 25],张量太大不方便展示,那么为什么上式可以实现相对位置坐标呢? # 这是因为coords_flatten[:, :, None]的维度为shape=[2, 25, 1]相当于从25个点中循环选择一个像素点的坐标;coords_flatten[:, None, :]的shape=[2, 1, 25]相当于循环每一个像素点的坐标被前面循环中的坐标相减。注意这里比较白话,但也可能有点绕,这个是广播机制,可以查看torch、numpy是如何广播的! >>> relative_coords = relative_coords.permute(1, 2, 0).contiguous() # Wh*Ww, Wh*Ww, 2 # 坐标轴转换这个好理解,将最后一个轴表示横纵坐标x,y的相对坐标,relative_coords[i,j,:]表示平铺后第i个像素相对于第j个像素的相对坐标 >>> relative_coords[:, :, 0] += 5 - 1 # 将相对位置坐标重置为从0开始 # 加上5 - 1相对位置坐标就从0开始了是因为,对于纵坐标而言,最大是4,最小是0,所以最小的相对位置坐标是-4 >>> relative_coords[:, :, 1] += 5 - 1 # 横坐标同理 >>> relative_coords[:, :, 0] *= 2 * 5 - 1 # 为什么要乘以 2 * 5 - 1(2* self.window_size[1] - 1)?见下面的详解 >>> relative_position_index = relative_coords.sum(-1) # Wh*Ww, Wh*Ww 得到两两像素间的相对位置偏置的索引
为什么要乘以 2 * 5 - 1(2 self.window_size[1] - 1)?*
首先我们考虑2* self.window_size[1] - 1是什么?以及相对位置偏置我们要怎么表示?
区间[0, 2* self.window_size[1] - 1)是横坐标(宽度所在轴)的相对位置取值范围;原来的取值范围是[1-self.window_size[1], self.window_size[1]-1],加上self.window_size[1] -1后就是[0, 2* self.window_size[1] - 2], 即2* self.window_size[1] - 1是取不到的,所以在宽度这个轴上不同的相对位置坐标有2* self.window_size[1] - 1个!
我们想要的是相对位置偏置,偏置是由self.relative_position_bias_table表格决定的,relative_position_index是索引,所以我们自然是希望两两之间的相对位置索引不一样(因为两两之间相对位置不一样)。这里relative_coords横纵坐标直接相加也可以得到索引,但是这个所以将大量重复。假设我们以宽度所在轴为基准进行处理,由上一条表诉我们直到乘以2* self.window_size[1] - 1,纵坐标就扩大了2* self.window_size[1] - 1倍,此时不同行间的纵坐标差值就是2* self.window_size[1] - 1,这意味这相邻行间可以标识2* self.window_size[1] - 1个数据,relative_coords.sum(-1)就恰好将所有间隔补齐了!用白话说就是我们希望索引是连续的,那么不同的relative_coords坐标有多少呢?应该有\((2* self.window_size[1] - 1)^{2}\)个!这里我们要考虑空间相对位置,比如右下角这种位置关系最终得到的索引应该是一样的,所以为了归纳这种关系,作者采用了将高这个轴的坐标乘以宽的取值范围,再加上宽、高的坐标值得到索引,直观观察为:
[[40,39,38,37,36,31,30,29,28,27,22,21,20,19,18,13,12,11,10, 9, 4, 3, 2, 1, 0], [41,40,39,38,37,32,31,30,29,28,23,22,21,20,19,14,13,12,11,10, 5, 4, 3, 2, 1], [42,41,40,39,38,33,32,31,30,29,24,23,22,21,20,15,14,13,12,11, 6, 5, 4, 3, 2], [43,42,41,40,39,34,33,32,31,30,25,24,23,22,21,16,15,14,13,12, 7, 6, 5, 4, 3], [44,43,42,41,40,35,34,33,32,31,26,25,24,23,22,17,16,15,14,13, 8, 7, 6, 5, 4], [49,48,47,46,45,40,39,38,37,36,31,30,29,28,27,22,21,20,19,18,13,12,11,10, 9], [50,49,48,47,46,41,40,39,38,37,32,31,30,29,28,23,22,21,20,19,14,13,12,11,10], [51,50,49,48,47,42,41,40,39,38,33,32,31,30,29,24,23,22,21,20,15,14,13,12,11], [52,51,50,49,48,43,42,41,40,39,34,33,32,31,30,25,24,23,22,21,16,15,14,13,12], [53,52,51,50,49,44,43,42,41,40,35,34,33,32,31,26,25,24,23,22,17,16,15,14,13], [58,57,56,55,54,49,48,47,46,45,40,39,38,37,36,31,30,29,28,27,22,21,20,19,18], [59,58,57,56,55,50,49,48,47,46,41,40,39,38,37,32,31,30,29,28,23,22,21,20,19], [60,59,58,57,56,51,50,49,48,47,42,41,40,39,38,33,32,31,30,29,24,23,22,21,20], [61,60,59,58,57,52,51,50,49,48,43,42,41,40,39,34,33,32,31,30,25,24,23,22,21], [62,61,60,59,58,53,52,51,50,49,44,43,42,41,40,35,34,33,32,31,26,25,24,23,22], [67,66,65,64,63,58,57,56,55,54,49,48,47,46,45,40,39,38,37,36,31,30,29,28,27], [68,67,66,65,64,59,58,57,56,55,50,49,48,47,46,41,40,39,38,37,32,31,30,29,28], [69,68,67,66,65,60,59,58,57,56,51,50,49,48,47,42,41,40,39,38,33,32,31,30,29], [70,69,68,67,66,61,60,59,58,57,52,51,50,49,48,43,42,41,40,39,34,33,32,31,30], [71,70,69,68,67,62,61,60,59,58,53,52,51,50,49,44,43,42,41,40,35,34,33,32,31], [76,75,74,73,72,67,66,65,64,63,58,57,56,55,54,49,48,47,46,45,40,39,38,37,36], [77,76,75,74,73,68,67,66,65,64,59,58,57,56,55,50,49,48,47,46,41,40,39,38,37], [78,77,76,75,74,69,68,67,66,65,60,59,58,57,56,51,50,49,48,47,42,41,40,39,38], [79,78,77,76,75,70,69,68,67,66,61,60,59,58,57,52,51,50,49,48,43,42,41,40,39], [80,79,78,77,76,71,70,69,68,67,62,61,60,59,58,53,52,51,50,49,44,43,42,41,40]]
为了说明,下面我们以下图图示进行说明:
![]()
- 主队角线(40所在的红色曲线)全是40,这意味着所有的关系是一致的,那么它代表了什么位置关系呢?根据index张量的坐标我们知道它标识的是\((i,i)\)的关系,即任意token自己与自己的相对位置!
- 紧挨主对角线的橙色曲线即标识\((i,i+1)\)的关系,即任意token与下一个token的关系;但是我们注意这条线上可不是全为39,这里出现了35!35出现的位置不难发现全是token在空间中换行的位置!
- 这里要重点关注38所在是绿色曲线,它标识的是token与之后两位的token之间的关系;同时这里面有34,而且数量比之前较多,这是为什么?实际上,我们的相对位置主要关注了两个方面:1)token1领先token2几个位置;2) token1与token2间相差几行!
\((2M-1)^{2}\)种偏置的证明
这种相对位置的偏置应该讲解的比较清楚了,现在就回到之前的问题了,为什么是\((2M-1)^{2}\) ?前面说了有\((2M-1)^{2}\) 种相对位置关系,那就数一数呗!
我们用\((i,j)\)标识\(token_{i}\)与\(token_{j}\)之间的关系,那么所有的关系可以标识如下:
(i, i-M*M+1), (i, i-1), (i,i), (i, i+1), ..., (i, i+M*M-1)
这里我们将关系分为了\(2M^{2}-1\)类,但是这明显不等于\((2M-1)^{2}\) !
当\(i!=j\)时,\((i,j)\)就一定会跨行,同一类中的跨行如果不同步,则类中应该有两种关系,因为同一类中,\(j-i\)是一个常数,所以我们需要知道\(2M^{2}-1\)类中有多少是不同步跨行的,通过一个简单的减法我们知道,应该是有\(2M^{2}-4M+2\)个类有两种关系!那么这个数据是如何得出的?
当\(j-i=k \times M, k \in Z\),\(Z\)表示整数集,类中不会出现两种关系!因为\(token_{i}\)与\(token_{j}\)换行是同步的!\(j-i=k \times M, k \in Z\)换一种表达方式就是token同列!同列的情况,共有\((2M^{2}-1) //M=2M-1\)类没有两种关系!
另一种不会出现两种关系的发生在token边界,如上图中的右上角与左下角,分别会有\(M\)类不会有两种关系(为什么?这应该是易得吧!自己想想),但是这两个角包含了两种同列的情况,所以这里我们有\(2M-2\)个类不会有两种关系!
所以只有一种关系的类有\((2M-2) + (2M-1) = 4M-3\)个,因此,关系的种类共有:
\[2 \times (2M^{2} -1) - (4M-3) =4M^{2} -4M + 1 = (2M-1)^{2} \]至此,我们完全证明了对于窗口大小为M的transformer结构,相对位置偏置应该有\((2M-1)^{2}\)个!
结合V1论文解读,我们似乎从两个角度对相对位置编码进行了解读,相信已经说的比较清楚了!
扩大模型容量和窗口分辨率
当我们放大Swin transformer的容量和窗口分辨率时,我们观察到两个问题。
-
放大模型容量时的不稳定性问题。当我们将原始Swin Transformer模型从小尺寸放大到大尺寸时,深层的激活值会显著增加。振幅最高和最低的层之间的差异达到了1e4的极值。当我们将其进一步扩大到一个巨大的规模(6.58亿个参数)时,它无法完成培训。
-
跨窗口分辨率转换模型时性能降低。如表1第一行所示,当我们通过双三次插值方法在更大的图像分辨率和窗口大小下直接测试预训练的ImageNet-1K模型(256×256图像,8×8窗口大小)的精度时,精度显著降低。这值得我们重新检查原始Swin Transformer中的相对位置偏差方法。
3.2 扩展模型容量
如第3.1节所述,V1(和大多数视觉transformer)在每个块的开头采用了一个LayerNorm层,继承自vanilla ViT。当我们扩大模型容量时,在深层观察到激活值显著增加(残差分支在合并前没有标准化处理,残差会逐层累积到主分支上)。事实上,在预标准化配置中,每个剩余块的输出激活值直接合并回主分支,导致主分支的振幅在更深的层越来越大。不同层次的振幅差异较大,导致训练不稳定。
后置标准化
为了缓解这个问题,我们建议使用残差后标准化方法,如图1所示。在这种方法中,每个剩余块的输出在合并回主分支之前被标准化,并且当层变深时,主分支的振幅不会累积。如图2所示,这种方法的激活幅度比原始预规范化配置中的激活幅度小得多。
在我们最大的模型训练中,我们在主分支上每隔6个transformer块引入一个额外的LayerNorm层,以进一步稳定训练。
![](https://img2022.cnblogs.com/blog/1319275/202206/1319275-20220614134407742-1903387327.png)
缩放余弦注意力
在原始的self-attention计算中,像素对的注意力attenion被计算为查询和关键向量的点积。我们发现,当这种方法用于大型视觉模型时,一些块和头的学习注意图通常由几个像素对控制,尤其是在res-post-norm配置中。为了缓解这个问题,我们提出了一种缩放余弦注意方法,该方法通过缩放余弦函数计算像素i和j的注意力:
其中\(B_{ij}\)是像素\(i\)与像素\(j\)之间的相对位置偏置;\(\tau\)是一个可学习的缩放参数,不在层间、多头间共享,一般设置其大于0.01. 余弦函数是自然归一化的,因此可以具有较低的注意力值。
3.3 扩展窗口分辨率
本节我们介绍对数空间连续位置偏置方法,因此,相对位置偏差可以在窗口分辨率之间平滑传递。
连续相对位置偏置
连续相对位置偏差法不是直接优化偏差参数,而是在相对坐标上采用一个小型元网络
这里的小型元网络\(\mathcal{g}\)一般采用2层MLP和一个ReLU激活。也即新的偏置是由原偏置学习得到,那为什么不直接学习,还要参考尺度不一样的预训练模型呢?(参考表1我们就知道,如果直接参数化训练,不使用预训练模型的偏置参数,那么窗口在往高分辨率上推广时,性能会下降)
元网络\(\mathcal{g}\)生成任意相对坐标的偏差值,因此可以自然地转移到具有任意变化窗口大小的微调任务。在推理过程中,可以预先计算每个相对位置的偏差值,并将其存储为模型参数,以便推理与原始参数化偏差方法相同。
对数坐标
在很大程度上改变窗口大小时,需要外推大部分相对坐标范围。为了解决这个问题,我们使用对数空间代替线性空间:
其中,\(\Delta x, \Delta y\)是线性空间缩放后的坐标,\(\hat{\Delta x}, \hat{\Delta y}\)是对数空间的坐标!
通过使用对数间隔坐标,当我们跨窗口分辨率传递相对位置偏差时,所需的外推比将远小于使用原始线性间隔坐标的外推比。例如,使用原始坐标将预先训练的8×8窗口大小转换为微调的16×16窗口大小,输入坐标范围将为[−7, 7]×[−7,7]推广至[−15, 15]×[−15, 15]. 外推比为原始范围的\(\frac{8}{7} \simeq 1.14\)倍(增加了1.14倍)。使用对数间隔坐标,输入范围为[−2.079, 2.079] × [−2.079,2.079]推广至[−2.773, 2.773] × [−2.773, 2.773]. 外推比为原始范围的0.33倍,比使用原始线性间隔坐标的外推比小约4倍。
表1比较了不同位置偏差计算方法的推广性能。可以看出,对数间隔CPB(连续位置偏差)方法表现最好,尤其是当转移到较大的窗口大小时。
注意,这里模型的参数是偏置,索引是超参数,使用对数空间连续位置偏置方法可以外推不同大小的偏置矩阵,而索引这种超参数完全可以使用代码生成而不受影响,生成方式和前面详细讲解的相对位置编码的索引一模一样!
3.4 自监督预训练
更大的模型更需要数据。为了解决数据匮乏的问题,以前的大型视觉模型通常使用巨大的标记数据集,如JFT-3B[17、56、80] (B=10亿)。在这项工作中,我们开发了一种自我监督的预训练方法SimMIM[72] (SimMIM是他们团队提出的一个模型),以缓解对标记数据的需求。通过这种方法,我们仅使用7000万个标记图像(JFT-3B中的1/40),就成功地训练了一个30亿参数的强大Swin-Transformer模型,该模型在4个具有代表性的视觉基准上达到了最先进水平(SOTA)。
SimMIM模型论文:https://arxiv.org/abs/2111.09886
SimMIM模型代码:https://github.com/microsoft/simmim
论文解析:
- https://blog.csdn.net/shenlanshenyanai/article/details/121935254
- https://zhuanlan.zhihu.com/p/435389007
- 本人论文精读:(todo)
3.5 节省GPU内存的实现
另一个问题在于,当容量和分辨率都很大时,常规实现的GPU内存消耗难以承受。为了解决内存问题,我们采用以下实现:
- 零冗余优化器(ZeRO)[54]。在优化器的通用数据并行实现中,将模型参数和优化状态广播到每个GPU。这种实现对GPU内存消耗非常不友好,例如,当使用AdamW优化器和fp32权重/状态时,30亿个参数的模型将消耗48G GPU内存。使用零优化器,模型参数和相应的优化状态将被拆分并分布到多个GPU,从而显著减少内存消耗。我们采用DeepSpeed框架,并在实验中使用ZeRO stage-1选项。这种优化对训练速度几乎没有影响。(2018年在优化领域就提出的技术)
- 激活检查点[12]。Transformer层中的特征图也会消耗大量GPU内存,这会在图像和窗口分辨率较高时造成瓶颈。激活检查点技术(亚线性内存优化技术的一种)可以显著减少内存消耗,同时训练速度降低30%。(简单理解就是忽略激活层,不保存其中间状态,反向传播时再计算)
- 顺序self-attention计算。要在非常大的分辨率上训练大型模型,例如,窗口大小为32×32、分辨率为1536×1536的图像,即使使用上述两种优化技术,常规A100 GPU(40GB内存)仍然无法负担。我们发现,在这种情况下,自我注意模块构成了一个瓶颈。为了缓解这个问题,我们按顺序实现了自我注意计算,而不是使用以前的批处理计算方法。该优化应用于前两个stage的层,对整体训练速度影响不大。
通过这些实现,我们成功地使用英伟达A100-40G GPU训练了一个3B模型,用于COCO目标检测,输入图像分辨率为1536×1536,Kinetics-400动作分类,输入分辨率为320×320×8。
四、我夸我自己阶段
图像分类性能
![](https://img2022.cnblogs.com/blog/1319275/202206/1319275-20220614174530194-36066653.png)
如你所见,CoAtNet模型这个被誉为作弊的模型,性能那确实是强!谷歌的实力这是看的见的!这里V2也还是可以!
目标检测性能
![](https://img2022.cnblogs.com/blog/1319275/202206/1319275-20220614174912767-417821203.png)
这里给了基于COCO目标检测、实例分割的结果,一句话V2最牛皮!\(I(W)\)分别表示图像、窗口的分辨率;\(ms\)标识了多尺度的测试被应用!
语义分割性能
![](https://img2022.cnblogs.com/blog/1319275/202206/1319275-20220614175345200-81227633.png)
如图所示,语义分割脑壳我们常用UperNet,好像不用它世界就不完美一样!这里\(mIoU\)几乎达到60%,不得不说确实是牛皮!
动作分类性能
![](https://img2022.cnblogs.com/blog/1319275/202206/1319275-20220614175645816-150081564.png)
预训练模型的强大我们可以感受到...
V2关键技术消融实验
![](https://img2022.cnblogs.com/blog/1319275/202206/1319275-20220614175934822-905359979.png)
后置标准化、缩放余弦注意力技术的消融实验,明显两个都加效果更好,这些技术都是work的!
![](https://img2022.cnblogs.com/blog/1319275/202206/1319275-20220614180150734-137701526.png)
这个实验说明后置处理是更好的,实际使用过程种,残差分支后置Norm确实是效果更好,相信这个技术会有更广的前景!
![](https://img2022.cnblogs.com/blog/1319275/202206/1319275-20220614180418188-1282878087.png)
不同图像分辨率下、不同窗口尺寸下的预训练模型性能表现,和table1对比就知道了!
完!