本篇文章是依图和新加坡国立联合推出的论文,好像1月份左右就已经出来了,但不知道为什么一直没有掀起比较热烈的讨论。难道因为最近Transformer东西太多,大家已经关注不过来了?CVer说可能是没有足够的在下游任务上的实验数据,因此不太好review,不过看完看,感觉还是挺不错的,先hightlight一下几个要点。
- 提出 Tokens-to-token结构(从前后两个token的单复数形式变化也能看出点端倪),通过将聚在一起的一群token聚合成一个token,来反复渐进地将图片重构成token,这样就能构建出一些局部的特征信息。此外还能大幅度地减少参数量。
- 提出一个deep-narrow结构的backbone(像上面讲的,这个地方可能实验数据不够充分)
- 最后的效果,达到了在同等参数量的情况下,比ResNet和MobileNet更好的效果
简介
以往模型的缺点
当在一个中等大小的数据集上从头训练的时候,ViT的表现会逊于大小类似的CNN,比如ResNet。
怀疑有以下两个原因:
- ViT将图片分成token的过程太简单粗暴了,因此无法对图片的局部结构信息(比如边界和线条)进行建模,因此需要比CNN模型多的多的数据来训练。
- ViT中的attention模块设计得没有CNN好,含有大量冗余的信息,因此在学习特征的丰富程度上会受到限制,且更困难。
从下图中,几种不同模型的 feature map 可视化的结果中,就能看出一些端倪,比如:
- 图片的结构信息建模得很差,然而全局的联系(比如狗的整体)却被所有的 attention 模块建模出来
- 原始的ViT在将图片分解成固定长度的token后,很多局部的信息就直接被忽略了(下图中红框部分)
结构详解
Tokens-to-Token ViT
T2T-ViT 主要有两部分构成:
- 一个逐层的"Tokens-to-Token"模块,对图片的局部结构信息进行建模,并对token的长度逐步进行减少
- 一个有效的"T2T-ViT backbone",来利用上一步传来的全局的注意力关联信息
Tokens-to-Token: Progressive Tokenization
每个Tokens-to-token (T2T) 模块都分两步,第一步是重新构造(restructurization),第二步是软分割(soft split)。
重新建造(restructuration):
如上图,当收到来片上一层的一串输出token T T T 时,用自注意模块将它转换成 T ′ T' T′
T ′ = M L P ( MSA ( T ) ) T^{\prime}=\mathrm{MLP}(\operatorname{MSA}(T)) T′=MLP(MSA(T))
接着将 T ′ T' T′变形成一张空间中的图像
I = Reshape ( T ′ ) I=\operatorname{Reshape}\left(T^{\prime}\right) I=Reshape(T′)
这里 R e s h a p e Reshape Reshape函数将形状为 R l × c \mathbb{R}^{l \times c} Rl×c的 T ′ T' T′变为形状是 R h × w × c \mathbb{R}^{h \times w \times c} Rh×w×c的 I I I,其中 l l l是 T ′ T' T′的长度, h , w , c h, w, c h,w,c分别是高,宽,和通道数,且 l = h × w l = h \times w l=h×w。
软分割(soft split)
我们在这一步用软分割来对局部结构的信息建模,并减少 token 的长度。具体地说,就是将上一步生成的图像,分割成重合的 patch,这样,相邻的 token 之间就有了很强的关联性,并建立起了一个先验。接着,这些 patch 的 token 再拼接(concat)成一个token,这样附近 pixel 和 patch 之间的局部信息就被整合了起来。
这个地方其实和卷积的想法非常接近,下一步中算 token 的大小的时候,用的公式也是几乎和卷积中的一模一样。当然,它的做法并不是卷积,只是窗口滑动的模式和卷积基本相同。
当做软分割的时候,每个patch的尺寸为 k × k k \times k k×k,重叠的尺寸为 s s s,此外还有一个大小为 p p p的填充(padding),这里 k − s k - s k−s就如同卷积运算中的 stride。因此对于一个重建好的,尺寸为 I ∈ R h × w × c I \in \mathbb{R}^{h \times w \times c} I∈Rh×w×c的图像,经过软分割后,输出token T 0 T_0 T0的长度就是
l o = ⌊ h + 2 p − k k − s + 1 ⌋ × ⌊ w + 2 p − k k − s + 1 ⌋ . l_{o}=\left\lfloor\frac{h+2 p-k}{k-s}+1\right\rfloor \times\left\lfloor\frac{w+2 p-k}{k-s}+1\right\rfloor . lo=⌊k−sh+2p−k+1⌋×⌊k−sw+2p−k+1⌋.
上文中 l 0 l_0 l0其实就是一张图像上能滑过多少个窗口
每个分割块的大小为 k × k × c k \times k \times c k×k×c。我们将所有的patch拉成一个形状为 T o ∈ R l o × c k 2 T_{o} \in \mathbb{R}^{l_{o} \times c k^{2}} To∈Rlo×ck2的token,并将输出送入下个T2T过程。
T2T Module
以上的两个过程合在一起,可以用下面的式子表达
T i ′ = M L P ( MSA ( T i ) I i = Reshape ( T i ′ ) T i + 1 = SS ( I i ) , i = 1 … ( n − 1 ) \begin{array}{l}T_{i}^{\prime}=\mathrm{MLP}\left(\operatorname{MSA}\left(T_{i}\right)\right. \\I_{i}=\operatorname{Reshape}\left(T_{i}^{\prime}\right) \\T_{i+1}=\operatorname{SS}\left(I_{i}\right), \quad i=1 \ldots(n-1)\end{array} Ti′=MLP(MSA(Ti)Ii=Reshape(Ti′)Ti+1=SS(Ii),i=1…(n−1)
对于刚输入的图片 I 0 I_0 I0,我们先直接用一个软分割,将它分割成 token: T 1 = SS ( I 0 ) T_{1}=\operatorname{SS}\left(I_{0}\right) T1=SS(I0)。对于最后一次迭代,输出的token T f T_f Tf 是一个固定的尺寸。由于T2T的token的尺寸其实是要大于ViT的,因此可能会消耗更多的内存。为了解决这个问题,我们将通道的数量设置成一个很小的数值(32或者64)来减少内存占用。此外,我们还用更高效的Transformer模型,比如Performer,来进一步减少内存占用。
T2T-ViT Backbone
作者一共尝试了以下几种不同的架构,来减少冗余和提高特征丰富程度:
1. D e n s e c o n n e c t i o n a s D e n s e N e t ; 2. D e e p − n a r r o w v s . s h a l l o w − w i d e s t r u c t u r e a s i n W i d e R e s N e t s ; 3. C h a n n e l a t t e n t i o n a s S q u e e z e − a n − E x c i t a t i o n ( S E ) N e t w o r k s ; 4. M o r e s p l i t h e a d s i n m u l t i − h e a d a t t e n t i o n l a y e r a s R e s N e X t ; 5. G h o s t o p e r a t i o n s a s G h o s t N e t 1. Dense connection as DenseNet;\\2. Deep-narrow vs. shallow-wide structure as in WideResNets;\\3. Channel attention as Squeeze-an-Excitation (SE) Networks;\\4. More split heads in multi-head attention layer as ResNeXt;\\5. Ghost operations as GhostNet 1.DenseconnectionasDenseNet;2.Deep−narrowvs.shallow−widestructureasinWideResNets;3.ChannelattentionasSqueeze−an−Excitation(SE)Networks;4.Moresplitheadsinmulti−headattentionlayerasResNeXt;5.GhostoperationsasGhostNet
并发现使用deep-narrow结构,能简单地通过减少通道数量来降低冗余度,同时提升层的深度来提高特征丰富度,使得在缩小模型尺寸和MACs的同时,提升性能。具体地来讲,它有更少的通道数量,但是层数 d d d要更大。对于从T2T模块中输出的、尺寸固定为 T f T_f Tf的token,我们将一个类token拼接上去,并加上Sine位置嵌入,正如ViT中做分类时一样:
T f 0 = [ t c l s ; T f ] + E , E ∈ R ( l + 1 ) × d T f i = MLP ( MSA ( T f i − 1 ) ) , i = 1 … b y = f c ( L N ( T f b ) ) \begin{array}{lr}T_{f_{0}}=\left[t_{c l s} ; T_{f}\right]+E, & E \in \mathbb{R}^{(l+1) \times d} \\T_{f_{i}}=\operatorname{MLP}\left(\operatorname{MSA}\left(T_{f_{i}-1}\right)\right), & i=1 \ldots b \\y=\mathrm{fc}\left(\mathrm{LN}\left(T_{f_{b}}\right)\right)\end{array} Tf0=[tcls;Tf]+E,Tfi=MLP(MSA(Tfi−1)),y=fc(LN(Tfb))E∈R(l+1)×di=1…b
T2T-ViT Architecture
以下是直接复制的论文中的信息,是作者在实际使用中的一些参数信息,可供参考:
The T2T-ViT has two parts: the Tokens-to-Token (T2T) module and the T2T-ViT backbone (Fig. 4). There are various possible design choices for the T2T module. Here, we set n = 2 as shown in Fig. 4, which means there is n+1 = 3 soft split and n = 2 restructuration in T2T module. The patch size for the three soft splits is P = [7*,* 3*,* 3], and the overlapping is S = [3*,* 1*,* 1], which reduces size of the input image from 224 × 224 to 14 × 14 according to Eqn. (3).
The T2T-ViT backbone takes tokens with fixed length from the T2T module as input, the same as ViT; but has a deep-narrow architecture design with smaller hidden dimensions (256-512) and MLP size (512-1536) than ViT.