换句话说,DeiT 本身依然是一个全局 attention、无层级结构、内部缺乏局部归纳偏置的模型。
所以相应的改进思路水到渠成:

如果不只是“引导 Transformer 学习”,而是“直接修改 Transformer 的结构”,会怎样?

这便是在 21 年的论文:Swin Transformer: Hierarchical Vision Transformer using Shifted Windows中提出的 ViT 的另一变体: Swin Transformer 的出发点。

image.png

1. ViT 在实际训练中的问题#

在展开 Swin Transformer 的具体改进前,我们需要简单了解一下原始 ViT 在实际训练中的一些问题。

1.1 CV 中的注意力计算量#

在原始 ViT 中,每一层 Transformer 都对所有 patch token 两两计算注意力。这一步带来了一个非常关键的代价:计算复杂度过高

其实,这倒不能怪 ViT ,归根结底其实是自注意力本身的结构让这一原本应用于序列任务的设计在视觉任务中便显现出一些不适。

假设一张图像被切分为  个 patch,那么 self-attention 的计算复杂度就是:

复杂度本身自然是不变的,但问题在于:图像分辨率一旦提升, 会快速增长,而计算量是平方级爆炸的。

我们用一个问题来对比说明这种情况:

为什么在 NLP 等序列任务中,这个问题并没有这么突出?

其核心原因不在于 attention 机制本身,而在于:序列长度的增长方式是一维的,而图像分辨率的增长是二维的。
 

image.png


如图所示,图像数据分辨率的增长带来的计算量增加是平方级的。

而且,更重要的一点是:高分辨率本就是视觉任务的刚需
在一些视觉任务,如小目标检测、边界精细分割等,都强依赖高分辨率输入。

因此,除去我们一直强调的弱偏置带来的数据依赖问题外,图像数据带来的高计算量也是一个非常现实的问题。

1.2 归纳偏置问题#

对这点我们并不陌生了,我们再用 CNN 和 ViT 的差异简单复述一下:

  1. 因为卷积核,CNN 会优先关注“邻域信息”,并逐步扩大感受范围。 而 ViT 一上来就做全局建模,但边缘、纹理等低级视觉特征需要靠数据自己学出来。
  2. 因为层级结构,CNN 输出的特征图在层级间分辨率逐渐降低,而语义逐渐增强。但在原始 ViT 所有 patch token 的尺度是固定的,不存在多尺度表示。

总之还是我们之前说的:Transformer 在视觉任务中缺乏“结构性约束”,搜索过于自由,以至于收敛慢,数据要求高。

以上便是 原始 ViT 在实际训练中会产生的一些问题,而 Swin Transformer 便是针对它们进行了改进。
我们已经提到过 Swin Transformer 是通过优化自身结构增强了归纳配置,而在展开其具体逻辑前总结一下其核心思想,那就是:

让 Transformer 具备类似 CNN 的归纳偏置。

需要提前说明的是,在这里,包括下面的具体逻辑中,你很可能会产生这样一种疑惑:Swin Transformer 在尽力还原 CNN 的逻辑,就像开倒车一样,那既然都是同一套归纳偏置,两种结构到底差在哪里?这种改进的具体影响又是哪方面的?

我们先展开 Swin Transformer 的具体改进内容,了解完其本身后就来展开这个问题。

2. Window Attention#

Swin 的第一步非常直接:

把“全局 attention”改为“局部 attention”

具体做法很简单:保持 patch token 的二维结构,在此基础上划分多个不重叠的窗口,即 window,每个窗口内部独立进行自注意力计算。

这部分是整个后续设计的前提,我们详细展开如下:
 

image.png

image

总结来说,这一设计其实就是把原本的全面注意力变成局部注意力了,很容易让我们联想到卷积核
实际上,这一改进就是依据局部性先验引入的归纳配置,于此同时,这一操作还引起了计算复杂度的变化:

假设输入图像大小为 ,patch size 为 ,那么 token 数量为:

在标准 ViT 中,每一层 attention 的计算复杂度为:

现在我们引入 window,假设 window size 为 ,那么 window 的数量为:

总计算量就是:

对比一下:

也就是说: 仅通过局部窗口划分,计算量就下降了约 60~70 倍。
而究其根本,是因为当窗口大小固定时,计算复杂度从“平方增长”变成了“线性增长”。

不过,这一改进也带来了相应的问题:

不同窗口之间的信息被完全隔离。

自然,Swin Transformer 也有其相应的策略:

3. Shifted Window(移位窗口)#

就像刚刚说的,如果只有 Window Attention,模型就会退化为“块状 CNN”。
为了解决这个问题,Swin 提出了核心机制: Shifted Window

这步的做法看似简单,但实际上存在一些要注意的细节:

循环平移窗口 ,同时使用掩码遮蔽非法邻接,从而交互跨窗口信息。

我们具体展开如下:

3.1 循环平移#

image.png

复述一下要点,向右下方向平移 token 网格,平移距离一般为:

这样就可以让窗口内容发生变化,交互不同区域里的信息。

但就像图里说的,这里会出现一个问题:

一些本不相邻的区域被强行拉到一起了,比如右下角和左上角。

image.png

对此,Swin 的解决方式是:

对“跨越原边界”的 token 进行 mask,不允许它们参与 attention。

而展开其具体逻辑前,我们要先解释清楚一个问题:

为什么要拒绝直接计算不相邻区域的注意力?这又并不像原始 transformer 的因果掩码一样会透露未来信息。

如果用一句话来总结就是:这是为了局部性偏置的刻意设计
简单展开一下:
如果 shift 后直接 attention,那就会变成:token 之间可以随意跨原 window 交互。
而 Swin 想要的是:“先局部建模,再逐层扩散”。
一旦这么做,模型就成了“弱版 ViT”,又回到了全局注意力的范畴,还多了层 window 的设计。
因此,这里的 mask 为了约束信息只能沿着“窗口重组后的局部结构”传播,从而保留 Swin 的归纳偏置设计。

这点内容,我们展开下面的 mask 具体设计后就可以更好的理解。

3.2 Shifted Window 的 mask 设计#

先总结一下 mask 的设计逻辑就是:在 Shift 前构造一个“窗口分组编号图”,Shift 后再根据编号差异生成 attention mask。
具体如下:

image.png

更多推荐