软件系统开发定制深度网络架构的设计技巧(三)之ConvNeXt:打破Transformer垄断的纯CNN架构


单位:FAIR (DenseNet共同一作,曾获CVPR2017 best paper),UC伯克利
ArXiv:
Github:

导读:提到“年代”一词,软件系统开发定制不免让人提前设想当时软件系统开发定制有如何的大事件或大人物。软件系统开发定制正当其时的“2020s”年代,从开始,软件系统开发定制引爆了一股“咆哮”的热潮,软件系统开发定制各种框架层出不穷,软件系统开发定制借用凯明一句话“without bells and whistles”,软件系统开发定制沉淀下来的实用性如何?软件系统开发定制本文作者长篇分析设计CNN软件系统开发定制架构的若干技巧,对照Swin Transformer软件系统开发定制的设计理念,渐进式“现代化”改造ResNet,软件系统开发定制取得了良好的效果,软件系统开发定制对深度网络的设计具有软件系统开发定制较大的参考价值。 ConvNeXt在与Transformer的较量中,给CNN掰回一局。


目录


摘要

软件系统开发定制计算机视觉迎来了一个“咆哮”的2020s年代,软件系统开发定制它的起点从引入视觉Transformer开始,即ViT,软件系统开发定制它能快速超过并取得SOTA软件系统开发定制的识别性能。而原始的ViT架构,软件系统开发定制在通用的计算机视觉任软件系统开发定制务上如目标检测和语义软件系统开发定制分割等面临不少困难。软件系统开发定制直到具有分层架构的Transformer如Swin Transformer,软件系统开发定制通过重新引入ConvNet一些设计,软件系统开发定制它作为一种通用的视觉backbone软件系统开发定制并在多个视觉任务上取软件系统开发定制得优良的表现,才让Transformer变得实用。但是,软件系统开发定制这种混合架构的有效性,软件系统开发定制在很大程度归功于Transformer软件系统开发定制的内在优势,软件系统开发定制而不是卷积固有的归纳偏差(inductive biases)。软件系统开发定制这篇文章重新审视设计的空间,软件系统开发定制并测试一个纯CNN软件系统开发定制网络能取得什么样的上限。软件系统开发定制作者通过逐渐将一个标准的ResNet模型,不断往ViT的设计中改造,并发现了几个关键的成分导致了性能的差异。作者构造的纯ConvNet系列模型,能够取得超过Swin Transformer的性能,在ImageNet-1K上取得了超过87.8%的Top1精度。


如图,作者分别对比了CNN和Transformer中最具代表性的模型,CNN模型如、ConvNeXt,Transformer模型如DeiT、Swin Transformer,ConvNeXt在精度和运算量上能取得最好的平衡,在扩展性上也能与Swin Transformer相当但设计更加简单。圆圈的直径越大,运算量越大。

一、引言

回顾 2010 年代,这十年以深度学习的巨大进步和影响为标志。主要驱动力是神经网络的复兴,特别是卷积神经网络 (ConvNets)。十年来,视觉识别领域成功地从工程特征转向设计(ConvNet)。尽管反向传播训练的卷积网络的发明可以追溯到 1980 年代,直到 2012 年底,我们才看到视觉特征学习的真正潜力。 AlexNet [40] 的引入沉淀了“ImageNet 时刻”[59],开创了计算机视觉的新时代。此后,该领域迅速发展。 VGGNet [64]、Inceptions [68]、ResNe(X)t [28, 87]、DenseNet [36]、MobileNet [34]、EfficientNet [71] 和 RegNet [54] 等代表性 ConvNet 专注于不同方面,如准确性、效率和可扩展性,并推广了许多有用的设计原则。

ConvNets在计算机视觉中的统治地位并非巧合:在许多应用场景中,“滑窗”设计是视觉处理所固有的,尤其是在处理高分辨率图像时。ConvNets有几个内置的归纳偏置,使得它们能够适合各种计算机视觉任务处理。其中最重要的一个是平移不变性,这对于目标检测任务是一种理想的属性。ConNets本质上也是高效的,因为当以滑窗方式处理时,计算是共享的。几十年来,在有限种类的识别任务如数字、人脸、人体中,默认使用ConvNets。进入2010s年代后,基于区域的检测器进一步将ConvNets提升到成为视觉识别系统中基本构造单元的地位。

大约在同一时间,自然语言处理NLP的神经网络设计之旅(the odyssey of network design,奥德赛,漫长而惊险的旅行)走上了一条截然不同的道路,因为Transformers去掉了循环神经网络RNN成为主导的主干网络。尽管语言与视觉领域之间感兴趣点存在差异,但随着视觉转换器(ViT)的引入彻底改变了网络架构设计的格局,这两个领域流惊奇地在2020s汇合了。除了最初的“patchify”层将图像分割成一系列补丁之外,ViT没有引入图像特定的归纳偏置,并只在原始的NLP transformer上做最小的改动。ViT的一个主要关注点是可扩展性的行为上:借助更大的模型和数据集,Transformers可以取得显著超过标准ResNet的性能。这些在图像分类任务上取得的结果是令人鼓舞的,但计算机视觉不仅限于图像分类。如之前所述,过去十年很多计算机视觉任务的解决方法很大程度上取决于滑窗,全卷积的范式。在没有ConvNets归纳偏置的情况下,普通的ViT模型在被用作通用视觉主干时面临许多挑战。最大的挑战是ViT的全局注意力设计,它相对输入尺度大小具有二次方复杂度。这对于ImageNet分类可能是接受的,但难以处理高分辨率的输入。

分层Transformer采用混合方法去弥补这一差距。例如,“滑窗”策略(如局部窗口内的注意力)被重新引入到Transformers中,使得他们的行为与ConvNets相似。Swin Transformer是朝着这个方向发展的里程碑式的工作,它首次证明了Transformer可以用作通用的视觉主干,并在图像分类之外的一系列计算机视觉任务上实现了SOTA的性能。Swin Transformer的成功和迅速采用也解释了一件事:卷积的本质并没有变得无关紧要;反而,它仍然很受欢迎,并从未褪色。

从这个角度来看,Transformers在计算机视觉方面的许多进步都旨在恢复卷积。然而,这些尝试有代价的:滑窗自注意力的朴素实现可能很昂贵;使用循环移位等先进方法,可以优化速度但在系统设计上更加复杂。另一方面,具有讽刺意味的是,ConvNets已经满足了许多所需要的属性,尽管是以一种直接、简洁的方法。ConvNets失去动力的唯一原因是分层的Transformers在许多计算机视觉任务中超过了它们,而性能差异通常是归因于Transformer卓越的可扩展性,其中关键组件是多头注意力。

与过去十年中逐渐改进的ConvNet不同,ViT的采用是箭步改变。在最近的文献中,在比较两者时通常采用系统级比较,如Swin Transformer与ResNet。ConvNets与分层ViT同时具有相似性与差异性:它们都具备了相似的归纳偏置,但在训练过程中和宏观/微观层面的架构设计上存在显著差异。在这篇文中,作者研究了ConvNets和Transformer之间的架构区别,并在比较网络性能时尝试定位混在因子。作者的研究旨在弥合ConvNet在ViT出现前后的差距,并测试纯ConvNet所能达到的极限。

为此,作者从标准的ResNet开始,以一种渐进式的改进过程。作者逐渐将架构“现代化”,朝着分层Transformer如SwinT去构建。该探索由一个关键的问题引导:Transformer中的设计决策如何影响ConvNet的性能?作者发现了几个关键组件导致了该性能的差异。在COCO目标检测与分割,ADE20K语义分割等任务上评估,令人惊讶的是,完全由标准ConvNet模块构建的ConvNeXt,具有相当竞争力。作者希望这些新的观察与讨论能够挑战一些共同的观念,并鼓励人们重新思考CNN在计算机视觉中的重要性。

二、现代化ConvNet:路线图


如图,作者将标准的ResNet朝着Swin Transformer现代化迈进,而不引入任何基于注意力的模块。前景条是ResNet50、Swin-Tiny在FLOPs上的精度。ResNet200、Swin-Base方法的结果用灰色条显示。阴影线表示未采用修改。很多Transformer架构能够合并到ConvNet中,它们会带来不断提升的性能。最后,ConvNeXt模型,可以超过Swin Transformer。题外话,虽然看过论文不少,但没有像作者如此总结与归纳,体现差距的地方在于:从归纳中发现影响因子,并实验论证。

本章节中,作者提供了ResNet到类似于Transformer的ConvNet的轨迹。作者根据FLOP考虑两种模型大小,一种是ResNet50、Swin-Tiny体,其FLOPs约为4.5G;另一种是ResNet200、Swin-Base体,其FLOPs为15.0G。

在高层次上,作者探索旨在调查和遵循Swin Transformer的不同设计级别,同时保持作为标准ConvNet的简洁性。路线图如上图所示,作者开始的起点是ResNet50模型。作者首先使用训练Transformer的类似训练技术对其进行训练,并与原始的ResNet50相对获得了很大改进的结果。这将是作者的基线工作。然后,作者设计了一系列设计决策,总结为:

  • 宏观设计
  • ResNeXt
  • 倒置的BottleNeck
  • 大卷积核
  • 各种层的微观设计。

上图展示了作者“现代化”网络的每一步的实现过程与步骤。由于网络复杂性与性能密切相关,因此在探索过程中对FLOPs进行了粗略控制,尽管在中间步骤中,FLOPs可能高于或低于参考模型。所有模型都在ImageNet-1K上进行训练与测试。

2.1 训练技巧

除了网络架构的设计,训练过程也会影响最终性能。ViT不仅带来了一组新的模块和架构设计决策,而且还为视觉引入了不同的训练技巧,如AdamW优化器。这主要与优化策略相关的超参设置有关。因此,我们探索的第一步就是使用视觉Transformer训练过程来训练基线模型,如ResNet50/200。最近的研究表明,一组现代训练技术可以显著提高ResNet50的性能。在作者的研究中,作者使用了接近Deit和Swin Transformer相近的训练方法。训练ResNet从原始的90个epoch到300个epoch,使用AdamW优化器、数据增强技术如Mixup、Cutmix、RandAugment、Random Erasing等,随机深度、标签平滑等正则化方法。就其本身而言,这种提升的训练方案将ResNet50性能从76.1%提高到78.8%,这意味着传统ConvNet和Transformer之间的很大一部分性能差异可能来自训练技巧。 作者在整个“现代化”过程中使用这种固定超参的训练方法。ResNet50报告的精度是通过三种不同的随机种子进行训练获得的平均值。

2.2 宏观设计

作者先从Swin Transformer的宏观设计开始分析。Swin Transformer遵循ConvNet使用多阶段设计,其中每个阶段具有不同的分辨率。有两个有趣的设计因素考虑:阶段计算比例,和“主干细胞”结构。

(1) 改变阶段计算比例。
ResNet跨阶段计算分布的原始设计在很大程度上经验性的。res4阶段旨在与目标检测等下游任务兼容,其中检测头网络在 14 × 14 14 \times 14 14×14特征图上运行。另一方面,Swin Transformer遵循相同的设计原则,但阶段计算比例略有不同,为 1 : 1 : 3 : 1 1:1:3:1 1:1:3:1。对于较大的Swin Transformer,比例是 1 : 1 : 9 : 1 1:1:9:1 1:1:9:1。按照设计,作者将每个阶段的块数从ResNet50中的 3 : 4 : 6 : 3 3:4:6:3 3:4:6:3调整为 3 : 3 : 9 : 3 3:3:9:3 3:3:9:3,这也使FLOPs与Swin-Tiny对齐。这将模型准确率从78.8%提升到79.4%。值得注意的是,有一些研究充分讨论计算分布,似乎存在更优化的设计。作者将使用这个比例运算。

(2) 将主干Patchify。
通常,主干细胞设计关注的是在网络开始时如何处理输入图像。由于自然图像固有的冗余性,一个常见的干细胞在标准的ConvNet和ViT中积极地将输入图像下采样到合适的特征图大小。标准ResNet模型中的干细胞包含有一个 7 × 7 7 \times 7 7×7步长为2的卷积层,然后跟着一个最大池化层,这导致了输入图像的4倍下采样。在ViT中,干细胞采用了更激进的“patchify”策略,相当于对应较大的内核大小(核大小为14或16)和非重叠卷积。Swin Transformer采用类似的patchify层,但使用了更小的 4 × 4 4\times 4 4×4补丁大小来适应架构的多阶段设计。作者将ResNet风格的干细胞替换为使用 4 × 4 4\times 4 4×4、步长为4的卷积层实现补丁化层。准确率从79.4提升到79.5,表明ResNet中的干细胞可以使用更简单的patchify层来替代,产生相似的性能。
作者将在网络中采用补丁化干细胞( 4 × 4 4\times 4 4×4、步长为4的卷积层)。

2.3 ResNeXt-ify

本部分作者尝试采用ResNeXt的思想,它比原始的ResNet取得了更好的FLOPs/Accuracy均衡。核心组件是分组卷积,其中卷积滤波器被分为不同的组。在较高的层面上,ResNeXt的指导原则是“使用更多的组,扩大宽度”。更精确地说,ResNeXt对BottleNeck中的 3 × 3\times 3×卷积采用分组卷积。这显著降低FLOPs,因此扩展了网络宽度以补偿容量损失。
在作者的案例中,使用深度卷积DW-CNN,这是分组卷积的一种特殊情况,每一组只有一个通道。DW-CNN已经被MobileNet和Xception推广。作者注意到,DW-CNN类似于self-attention中的加权求和操作,它在每个通道的基础上操作,即仅在空间维度上融合信息。DW-CNN和Point-wise CNN的组合导致了空间与通道混合的分离,这是ViT共享的属性,其中每个操作要么混合空间维度或通道维度的信息,而不能同时混合两者。DW-CNN的使用有效地降低了FLOPs,预期地一样,和准确度。按照ResNeXt提到的策略,作者将网络宽度增加到Swin-Tiny相同的通道数(从64到96),FLOPs增加到5.3G,识别率也达到了了80.5%。

2.4 倒置BottleNeck

每个Transformer块的重要设计是它创造了一个倒置的BottleNeck,即MLP块的隐藏维度是输入维度的四倍。有趣的是,Transformer这种设计与ConvNets中使用的扩展比为4的倒置BottleNeck设计有关联。这个想法被MobileNet-v2推广,随后在几个先进的ConvNets网络中获得关注。


模块修改和对应的规格。(a) ResNeXt的一个块;(b) 作者创建的反转维度后的BottleNeck块;(c)将DW-CNN层上移后的模块。

作者探索了倒置BottleNeck的设计。比较有意思的是,网络的FLOPs减少到4.6G,但精度从80.5提升到80.6,在ResNet200和Swin-Base中,这一步带来了更大的收益,从81.9增加到82.6,运算量反而减低。

2.5 大核的尺寸

在这部分,作者关注大卷积核的行为。ViT最显著的方面之一是它们的非局部注意力,它使每一层都具有全局感受野。虽然过去ConvNets也使用大卷积核,但黄金标准(VGG普及)是堆叠小卷积核( 3 × 3 3\times 3 3×3)的卷积层,在现代GPU上具有高效的硬件实现。尽管Swin Transformer将局部窗口重新引入自注意力模块中,但窗口大小至少为 7 × 7 7 \times 7 7×7,明显大于 3 × 3 3\times 3 3×3的ResNe(X)t等。

(1) 上移DW-CNN层
为了探索大内核,一个先决条件是向上移动DW-CNN的位置,上图c。这在ViT设计中也很明显:MSA模块放置在MLP层前。这是一个自然的设计选择:即复杂而低效率的模块(如MSA、大内核)具有更少的通道,而高效率的 1 × 1 1\times 1 1×1将完成繁重的工作。这个中间步骤将FLOPs降低到4.1G,性能也暂时下降到79.9%。

(2) 扩大卷积核尺寸

通过所有这些准备,采用更大内核的好处是明显的。作者尝试了几个内核大小,包括 3 , 5 , 7 , 9 , 11 {3,5,7,9,11} 3,5,7,9,11。网络的性能从79.9(3×3)增加到80.6(7×7),而网络的FLOPs大致保持不变。此外,作者观察到大核的好处在(7×7)出达到饱和。因此,默认采用核大小为7的卷积层。
至此,作者完成了对宏观网络架构的检查。有趣的是,Transformer中的很大一部分设计选择可能会映射到ConvNet的实例化中。

2.6 微观设计

本节作者在微观尺度上研究其他几个架构差异:这里大部分探索都是在层级完成的,重点关注激活函数和归一化层的选择。

(1) 使用GELU替代ReLU
NLP和视觉架构之间的一个差异是使用哪些激活函数的细节。随着时间的推移有不少激活函数被开发出来,但是ReLUctant即整流线性单元由于其简单性和效率,仍然在ConvNets中广泛使用。ReLU也被用在原始Transformer论文中。高斯误差线性单元GELU,可以看作是ReLU的一个平滑变体,被用于最先进的Transformer中,包括谷歌的BERT,OpenAI的GPT2,和大多数最近的ViT中。作者发现ReLU可以用GELU代替,尽管精度保持不变,都为80.6%。

(2) 更少的激活函数
Transformer和ResNet块之间的一个小区别是Transformer的激活层更少。考虑一个带有QKV的线性嵌入层、投影层和MLP块中的两个线性层的Transformer块,在MLP块中只有一个激活函数。相比之下,通常的做法是在每个卷积层(包括1×1)后附件一个激活函数。这里,作者研究了当坚持相同的策略时,性能如何变化。如图,作者从残差块中消除了所有的GELU层,除了两个 1 × 1 1\times 1 1×1层之间的一个,复制了Transformer块的样式。这个过程将结果提高了0.7%到81.3%,与Swin-Tiny性能相当。因此,作者在每个模块中使用单个GELU激活。

(3) 更少的归一化层
Transformer块通常具有更少的归一化层。这里,作者删除了两个BN层,在conv 1 × 1 1\times 1 1×1层之前只留有一个BN层。这进一步将性能提升到81.4%,超过Swin-Tiny的效果。注意,作者设计的模块的归一化层比Transformer还要少,因为根据经验作者发现在模块的开头添加一个额外的BN层并不能提高性能。

(4) 用LN替代BN
BatchNorm是ConvNets的重要组成部分,因为它提高了收敛性并减少过拟合。但是,BN可能会对模型的性能产生一些不利的影响。尽管有很多尝试去开发可替代的归一化技术,但BN在多数视觉任务中仍然是首先。另一方面,Transformer中更简单的层归一化即Layer Norm,在不同的应用场景中实现良好的性能。

在原始的ResNet中直接用LN替换BN,将导致性能欠佳。随着网络架构和训练技术的修改,作者重新审视了使用LN替代BN的影响。观察到,作者的ConvNet模型使用LN训练没有任何困难;实际上,性能稍好一点,达到了81.5%。因此,作者在每个残差块中采用LN作为归一化。

(5) 单独的下采样层
ResNet中下采样是在每一层中通过残差块来实现的,即使用 3 × 3 3\times 3 3×3、步长为2的卷积(在shortcut中是 1 × 1 1\times 1 1×1、步长为2的卷积)。在Swin Transformer中,一个单独的下采样层被添加到各个阶段之间。作者探索了一个类似的策略,采用使用 2 × 2 2\times 2 2×2、步长为2的卷积进行空间下采样。这种修改,出乎意料地导致了不同的训练。进一步调查表明,在空间分辨率发生变化的地方,添加归一化层有利于稳定训练。其中包括Swin Transformer中也使用的几个LN层:每个下采样层前有一个,主干细胞之后有一个,和全局池化层之后的一个。作者将性能提升到82.0%,明显超过了Swin-Tiny的81.3%。

至此,作者已经完成了第一次“演练”,并发现了 ConvNeXt,一个纯 ConvNet,它在这个计算机制中的 ImageNet-1K 分类性能优于 Swin Transformer。值得注意的是,到目前为止讨论的所有设计选择都改编自ViT。此外,即使在 ConvNet 文献中,这些设计也并不新颖——在过去十年中,它们都是单独研究的,但不是集体研究的。作者提出的 ConvNeXt 模型具有与 Swin Transformer 大致相同的 FLOP、#params.、吞吐量和内存使用,但不需要专门的模块,例如移位窗口注意力或相对位置偏差。

这些发现令人鼓舞,但尚未完全令人信服——迄今为止,作者的探索仅限于小规模,但ViT的可扩展性才是真正让它们与众不同的地方。此外,ConvNet 能否在对象检测和语义分割等下游任务上与 Swin Transformers 竞争的问题是计算机视觉从业者关注的核心问题。在下一节中,作者将在数据和模型大小方面扩展 ConvNeXt 模型,并在一组不同的视觉识别任务上评估它们。

三、实验结果


在ImageNet-1K上,与各大深度网络的性能对比。不难发现,ConvNeXt-Tiny相比较于同等运算量的Swin-Tiny,取得了超过0.8%到82.1%的Top1 acc。在更大输入图像分辨率即384下,更大容量的ConvNext-Base也比Swin-Base取得更好的性能。

四、核心代码

ConvNeXt 基本构造块

class Block(nn.Module):    r""" ConvNeXt Block. There are two equivalent implementations:    (1) DwConv -> LayerNorm (channels_first) -> 1x1 Conv -> GELU -> 1x1 Conv; all in (N, C, H, W)    (2) DwConv -> Permute to (N, H, W, C); LayerNorm (channels_last) -> Linear -> GELU -> Linear; Permute back    We use (2) as we find it slightly faster in PyTorch        Args:        dim (int): Number of input channels.        drop_path (float): Stochastic depth rate. Default: 0.0        layer_scale_init_value (float): Init value for Layer Scale. Default: 1e-6.    """    def __init__(self, dim, drop_path=0., layer_scale_init_value=1e-6):        super().__init__()        self.dwconv = nn.Conv2d(dim, dim, kernel_size=7, padding=3, groups=dim) # depthwise conv        self.norm = LayerNorm(dim, eps=1e-6)        self.pwconv1 = nn.Linear(dim, 4 * dim) # pointwise/1x1 convs, implemented with linear layers        self.act = nn.GELU()        self.pwconv2 = nn.Linear(4 * dim, dim)        self.gamma = nn.Parameter(layer_scale_init_value * torch.ones((dim)),                                     requires_grad=True) if layer_scale_init_value > 0 else None        self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()    def forward(self, x):        input = x        x = self.dwconv(x)        x = x.permute(0, 2, 3, 1) # (N, C, H, W) -> (N, H, W, C)        x = self.norm(x)        x = self.pwconv1(x)        x = self.act(x)        x = self.pwconv2(x)        if self.gamma is not None:            x = self.gamma * x        x = x.permute(0, 3, 1, 2) # (N, H, W, C) -> (N, C, H, W)        x = input + self.drop_path(x)        return 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

ConvNeXt整体结构:

  • stem:将图像分块
  • downsample_layers:单独从BottleNeck中剥离,在分辨率发生变化后添加归一化层
class ConvNeXt(nn.Module):    r""" ConvNeXt        A PyTorch impl of : `A ConvNet for the 2020s`  -          https://arxiv.org/pdf/2201.03545.pdf    Args:        in_chans (int): Number of input image channels. Default: 3        num_classes (int): Number of classes for classification head. Default: 1000        depths (tuple(int)): Number of blocks at each stage. Default: [3, 3, 9, 3]        dims (int): Feature dimension at each stage. Default: [96, 192, 384, 768]        drop_path_rate (float): Stochastic depth rate. Default: 0.        layer_scale_init_value (float): Init value for Layer Scale. Default: 1e-6.        head_init_scale (float): Init scaling value for classifier weights and biases. Default: 1.    """    def __init__(self, in_chans=3, num_classes=1000,                  depths=[3, 3, 9, 3], dims=[96, 192, 384, 768], drop_path_rate=0.,                  layer_scale_init_value=1e-6, head_init_scale=1.,                 ):        super().__init__()        self.downsample_layers = nn.ModuleList() # stem and 3 intermediate downsampling conv layers        stem = nn.Sequential(            nn.Conv2d(in_chans, dims[0], kernel_size=4, stride=4),            LayerNorm(dims[0], eps=1e-6, data_format="channels_first")        )        self.downsample_layers.append(stem)        for i in range(3):            downsample_layer = nn.Sequential(                    LayerNorm(dims[i], eps=1e-6, data_format="channels_first"),                    nn.Conv2d(dims[i], dims[i+1], kernel_size=2, stride=2),            )            self.downsample_layers.append(downsample_layer)        self.stages = nn.ModuleList() # 4 feature resolution stages, each consisting of multiple residual blocks        dp_rates=[x.item() for x in torch.linspace(0, drop_path_rate, sum(depths))]         cur = 0        for i in range(4):            stage = nn.Sequential(                *[Block(dim=dims[i], drop_path=dp_rates[cur + j],                 layer_scale_init_value=layer_scale_init_value) for j in range(depths[i])]            )            self.stages.append(stage)            cur += depths[i]        self.norm = nn.LayerNorm(dims[-1], eps=1e-6) # final norm layer        self.head = nn.Linear(dims[-1], num_classes)        self.apply(self._init_weights)        self.head.weight.data.mul_(head_init_scale)        self.head.bias.data.mul_(head_init_scale)    def _init_weights(self, m):        if isinstance(m, (nn.Conv2d, nn.Linear)):            trunc_normal_(m.weight, std=.02)            nn.init.constant_(m.bias, 0)    def forward_features(self, x):        for i in range(4):            x = self.downsample_layers[i](x)            x = self.stages[i](x)        return self.norm(x.mean([-2, -1])) # global average pooling, (N, C, H, W) -> (N, C)    def forward(self, x):        x = self.forward_features(x)        x = self.head(x)        return x
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66

结论:纯CNN架构,也能取得超过同等规模的Swin Transformer的识别性能。Transformer出色的可扩展性,在该ConvNext上也能体现出来;此外,在下游任务如目标检测、语义分割等,ConvNeXt也能取得出色的性能。这一局与Transformer较量,ConvNeXt为CNN扳回一局。

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发