🚩🚩🚩Transformer实战-系列教程总目录
有任何问题欢迎在下面留言
本篇文章的代码运行界面均在Pycharm中进行
本篇文章配套的PPT资源已经上传
1、SwinTransformer
- SwinTransformer 可以看作为一个backbone
- 用来做分类、检测、分割都是非常好的
- 也可以直接套用在下游任务中
- 不仅源码公开了,预训练模型也公开了
- 预训练模型提供大中小三个版本
图像中的像素点太多了,如果需要更多的特征就必须构建很长的序列
很长的序列会导致效率问题
SwinTransformer 针对ViT使用了窗口和分层的方式来替代长序列进行改进
CNN经常提起感受野,怎样在Transformer中体现出来呢?进行分层
SwinTransformer 怎样进行分层呢?在ViT或者原始Transformer中,假如最开始是400个Token,在堆叠过程中,还是会有400个Token。
而SwinTransformer 将原本的400个Token进行了合并处理,在堆叠过程中400个Token会变成200、100
也就是说SwinTransformer 就是在堆叠Transformer过程中,Token数量会不断减少,每一层的特征提取效率就会更高
2、网络架构
- 首先输入还是一张图像数据,2242243
- 通过卷积得到多个特征图,把特征图分成每个Patch,和ViT一样
- 堆叠Swin Transformer Block,与ViT 的Block不同的是,Swin Transformer
Block在每次堆叠后长宽减半特征图翻倍,这与CNN的堆叠过程有点类似,特别像VGG - 减少序列的长度,同时增加模型每一层的特征通道数,可以看作为是一个下采样的操作,是Patch Merging完成的
- Block最核心的部分是对Attention的计算方法做出了改进
3、Swin Transformer Block
- W-MSA与SW-MSA是一个组合
- W-MSA:基于窗口的注意力计算
- SW-MSA:窗口滑动后重新计算注意力
- 串联在一起就是一个Block
4、Patch Embbeding
- 输入:图像数据(224,224,3)
- 输出:(3136,96)相当于序列长度是3136个,每个的向量是96维特征
- 通过卷积得到,Conv2d(3, 96, kernel_size=(4, 4), stride=(4, 4))
- 3136也就是 (224/4) * (224/4)得到的,也可以根据需求更改卷积参数
实际上就是一个下采样的操作,是不同于池化,这个相当于间接的
(对H和W维度进行间隔采样后拼接在一起,得到H/2,W/2,C*4)
maxpooling是将4个特征中,选择最大的一个留下,所以说会长宽减半,通道数不变,而Patch Embbeding是将这4个特征分开利用,所以也会长宽减半,但是通道数乘以4
5、window_partition
- 输入:特征图(56,56,96)
- 默认窗口大小为7,所以总共可以分成8*8个窗口
- 输出:特征图(64,7,7,96)
- 之前的单位是序列,现在的单位是窗口(共64个窗口)
56=224/4,5656分成每个都是77大小的窗口,一共可以的得到8*8的窗口,因此输出为(64,7,7,96),因此输入变成了64个窗口不再是序列了
6、W-MSA
W-MSA,Window Multi-head Self Attention
- 对得到的窗口,计算各个窗口自己的自注意力得分
- qkv三个矩阵放在一起了:(3,64,3,49,32)
- 3个矩阵,64个窗口,heads为3,窗口大小7*7=49,每个head特征96/3=32
- attention结果为:(64,3,49,49) 每个头都会得出每个窗口内的自注意力
原来有64个窗口,每个窗口都是77的大小,对每个窗口都进行Self Attention的计算
(3,64,3,49,32),第一个3表示的是QKV这3个,64代表64个窗口,第二个3表示的是多头注意力的头数,49就是77的大小,每头注意力机制对应32维的向量
attention权重矩阵维度(64,3,49,49),64表示64个窗口,3还是表示的是多头注意力的头数,49*49表示每一个窗口的49个特征之间的关系
7、window_reverse
- 通过得到的attention计算得到新的特征(64,49,96)
- 总共64个窗口,每个窗口7*7的大小,每个点对应96维向量
- window_reverse就是通过reshape操作还原回去(56,56,96)
- 这就得到了跟输入特征图一样的大小,但是其已经计算过了attention
attention权重与(3,64,3,49,32)乘积结果为(64,49,96),这是新的特征的维度,96还是表示每个向量的维度,这个时候的特征已经经过重构,96表示了在一个窗口的每个像素与每个像素之间的关系
8、SW-MSA
SW-MSA,Shifted Window Multi-head Self Attention
- 为什么要shift?原来的window都是算自己内部的
- 这样就会导致只有内部计算,没有它们之间的关系
- 容易上模型局限在自己的小领地,可以通过shift操作来改善
通过W-MSA我们得到的是每个窗口内的特征,还没有每个窗口与窗口之间的特征,SW-MSA就是用来得到每个窗口与窗口之间的特征
窗口与窗口之间的特征,是用一种滑动shift 的方式计算
不管是SW-MSA还是W-MSA,实际上都是在做self-Attention的计算,只不过W-MSA是只对一个窗口内部做self-Attention的计算,SW-MSA是使用了一种偏移的方式,但是还是对一个窗口内部做self-Attention的计算。
实际上SW-MSA的偏移就是窗口在水平和垂直方向上分别偏移一定数量的像素
假设这是原始特征图:
+---+---+---+---+
| A | B | C | D |
+---+---+---+---+
| E | F | G | H |
+---+---+---+---+
| I | J | K | L |
+---+---+---+---+
| M | N | O | P |
+---+---+---+---+
偏移后的特征图:
+---+---+---+---+
| 0 | 0 | 0 | 0 |
+---+---+---+---+
| 0 | A | B | C |
+---+---+---+---+
| 0 | E | F | G |
+---+---+---+---+
| 0 | I | J | K |
+---+---+---+---+
原本多出来的地方,可以用0填充也可以用偏移后没有用到地方填充:
+---+---+---+---+
| M | N | O | P |
+---+---+---+---+
| D | A | B | C |
+---+---+---+---+
| H | E | F | G |
+---+---+---+---+
| L | I | J | K |
+---+---+---+---+
实际上就是像素点发生了挪动
如图所示,红色线是窗口的分割,灰色是patch的分割,W-MSA将相邻的patch进行拼凑成窗口,但是这就导致了,窗口之间没有办法连接,SW-MSA的偏移计算会重新划分窗口,但是窗口不可以重叠的情况下,窗口由4个变成了9个。窗口的数量和大小都发生了变化
如图所示原文给出了一个办法,将窗口的大小做出了限制
论文中使用了pad和mask的方法解决了这一问题,如上图中cyclic shift部分,对边缘部分尺寸较小的windows进行了填充(图中蓝色、绿色和黄色部分),使得每个windows都能够保持原来的大小,并且论文还采用了mask的方法来使得模型只在除了pad的部分做self-attention计算,这样一来就能够解决上面所提到的问题
如图所示,4自始至终都没有改变,原来在W-MSA使用self-Attention进行计算,在SW-MSA还是使用self-Attention进行计算,但是比如1和7发生了变化
7和1的计算,假如了mask和padding的一些处理
一开始是4个窗口,经过偏移后变成了9个,但是计算不方便,还是按照4个窗口进行计算,多出来的值mask掉就行了。
位移中的细节
- 只需要设置好对应位置的mask,让其值为负无穷即可(softmax)
- 输出结果同样为(56,56,96)
- 不要忘记,计算完特征后需要对图像进行还原,也就是还原平移
- 这俩组合就是SwinTransformer中的核心计算模块
无论是W-MSA和SW-MSA,数据的维度始终都没有发生变化
所以一个Swin Transformer Block就是先后经过W-MSA和SW-MSA,而Swin Transformer主要就是Swin Transformer Block的堆叠
9、分层计算
- 分层计算
- 一次下采样后(3136->784也就是5656->2828),和卷积非常类似
- 然后继续执行W-MSA和SW-MSA,也就是各个stage的流程
- 最后根据任务来选择合适的head层即可(分类,分割,检测等)