赞
踩
近年来,Transformer吸引了越来越多的人对计算机视觉的兴趣,但它们仍然落后于最先进的卷积网络。虽然变形网络往往具有更大的模型容量,但由于缺乏正确的归纳偏差,它们的泛化效果可能比卷积网络差。为了有效地结合这两种体系结构的优点,该论文提出了CoAtNets,这是一个基于两个关键点构建的混合模型结构:(1)深度卷积和自我注意可以通过简单的相对注意自然统一;(2)卷积层和注意层有原则地垂直叠加,在提高泛化能力和效率方面效果惊人。最终得到的效果如下图所示,值得注意的是,当我们用JFT-3B进一步扩展CoAtNet时,它在ImageNet上达到了90.88%的top 1精度,建立了一个新的最先进的结果。
这篇文章很长,图很少,其中模型结构图如下图所示,如果不仔细看,都看不到该论文的图,因为他放在附录里面了。作者表明,卷积层具有较强的归纳偏差先验,具有较好的泛化能力和较快的收敛速度,而注意层(自注意力机制)具有较高的模型容量,可以从较大的数据集中受益。将卷积层和注意层结合起来,可以获得更好的泛化能力和能力;然而,这里的一个关键挑战是如何有效地结合它们,以在准确性和效率之间实现更好的权衡。该文研究了两个关键问题:首先,我们观察到常用的深度卷积可以有效地合并为具有简单相对注意的注意层; 其次,简单地将卷积层和注意力层以适当的方式叠加起来,可能会出人意料地有效地获得更好的泛化和能力。基于这些见解,我们提出了一个简单而有效的网络架构,名为CoAtNet,它兼有ConvNets和transformer的优点。CoAtNet不仅具有Transformer模型的优越可伸缩性,而且可以实现更快的收敛,从而提高效率。
这篇文章作者以两个关键点来进行分析:1、如何在一个基本的计算块中结合卷积和自我注意?2、如何将不同类型的计算块垂直堆叠在一起,形成一个完整的网络?
首先我们根据下面的深度可分离卷积以及自注意力机制的公式来看,为了更好的去进行对比,作者将这样的公式直接分成了三部分:输入、权重以及输出 ,这是为了后面将二者更好地结合起来。我们可以看出,在深度可分离卷积中的权重是和输入没有关系的,但是在自注意力中,权重是和输入是有关系的,也就是说明这样的关系是动态的,能够随着输入的不同而发生变化。因此自我注意力更容易捕捉到不同空间位置之间复杂的关系交互。
第二点自己其实没有读明白,文本如下图所示,如果有知道的同学可以教教我,但是我觉得应该是卷积关注的是相对位置,也就是有平移不变性的特点,那么transformer确没有,就算加上一些绝对位置编码或者相对位置编码,但是却不能解决它的泛华性能,毕竟图像输入大小发生变化,位置编码的向量也需要发生变化。
第三点就是感受野,我们也知道,卷积神经网络关注的是局部信息,而自注意力机制关注的是全局信息。
这是卷积神经网络和transformer的特对比性
根据作者对卷积神经网络和自注意力机制的分析,然后给出了两种结合方式,第一种就是将权重相加,第二种就是将两个权重融合在一起了。最终论文中选择的是第二种。
为了降低这样的计算量,作者弄了三种方法:A、在特征图达到可管理水平后,进行一些下采样以减小空间大小,并利用全局相对注意力。B、强化局部注意力,就像在卷积中一样,将注意力中的全局接受场G限制为局部场。C、用某种线性注意变量替换二次Softmax注意,该线性注意变量的线性复杂度只与空间大小相关。但是通过实验证明,作者选择了A的方法,即将自注意力机制放在网络模型的后面,这样特征图分辨率会降低,那么计算量也就没有那么大了。如下结构图所示。
其实,作者选择了上图的结构,并不是一下子就选择出来的是,是通过不断地尝试才得出的,作者将 C-C-C-C, C-C-C-T, C-C-T-T andC-T-T-T四种结构来进行实验,最终发现 C-C-T-T的效果最好,其中C表示卷积,T表示Transformer。
最终的模型扩展结构如下图所示。代码来源于:大家可以给这位老哥点点赞哈!coatnet-pytorch/coatnet.py at master · chinhsuanwu/coatnet-pytorch · GitHub
- class CoAtNet(nn.Module):
- def __init__(self, image_size, in_channels, num_blocks, channels, num_classes=1000, block_types=['C', 'C', 'T', 'T']):
- super().__init__()
- ih, iw = image_size
- block = {'C': MBConv, 'T': Transformer}
-
- self.s0 = self._make_layer(
- conv_3x3_bn, in_channels, channels[0], num_blocks[0], (ih // 2, iw // 2))
- self.s1 = self._make_layer(
- block[block_types[0]], channels[0], channels[1], num_blocks[1], (ih // 4, iw // 4))
- self.s2 = self._make_layer(
- block[block_types[1]], channels[1], channels[2], num_blocks[2], (ih // 8, iw // 8))
- self.s3 = self._make_layer(
- block[block_types[2]], channels[2], channels[3], num_blocks[3], (ih // 16, iw // 16))
- self.s4 = self._make_layer(
- block[block_types[3]], channels[3], channels[4], num_blocks[4], (ih // 32, iw // 32))
-
- self.pool = nn.AvgPool2d(ih // 32, 1)
- self.fc = nn.Linear(channels[-1], num_classes, bias=False)
-
- def forward(self, x):
- x = self.s0(x)
- x = self.s1(x)
- x = self.s2(x)
- x = self.s3(x)
- x = self.s4(x)
-
- x = self.pool(x).view(-1, x.shape[1])
- x = self.fc(x)
- return x
-
- def _make_layer(self, block, inp, oup, depth, image_size):
- layers = nn.ModuleList([])
- for i in range(depth):
- if i == 0:
- layers.append(block(inp, oup, image_size, downsample=True))
- else:
- layers.append(block(oup, oup, image_size))
- return nn.Sequential(*layers)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。