【轻量化网络系列(7)】EfficientNetV2论文超详细解读(翻译 +学习笔记+代码实现)

【轻量化网络系列(7)】EfficientNetV2论文超详细解读(翻译 +学习笔记+代码实现)_第1张图片

前言

今天我们要学习的是EfficientNetV2 ,该网络主要使用训练感知神经结构搜索缩放的组合;在EfficientNetV1的基础上,引入了Fused-MBConv到搜索空间中;引入渐进式学习策略自适应正则强度调整机制使得训练更快;进一步关注模型的推理速度训练速度

学习资料:

  • 论文题目:《EfficientNetV2: Smaller Models and Faster Training》(《EfficientNetV2:更小的模型和更快的训练》)
  • 原文地址:EfficientNetV2: Smaller Models and Faster Training
  • 论文提供代码地址:https://github.com/google/automl/tree/master/efficientnetv2

前期回顾: 

【轻量化网络系列(1)】MobileNetV1论文超详细解读(翻译 +学习笔记+代码实现)

【轻量化网络系列(2)】MobileNetV2论文超详细解读(翻译 +学习笔记+代码实现)

【轻量化网络系列(3)】MobileNetV3论文超详细解读(翻译 +学习笔记+代码实现)

【轻量化网络系列(4)】ShuffleNetV1论文超详细解读(翻译 +学习笔记+代码实现)

【轻量化网络系列(5)】ShuffleNetV2论文超详细解读(翻译 +学习笔记+代码实现)


目录

前言

Abstract—摘要

 一、Introduction—简介

二、Related work—相关工作

三、EfficientNetV2 Architecture Design—高效EfficientNetV2架构设计

3.1 Review of EfficientNet—回顾EfficientNet

3.2 Understanding Training Efficiency—了解训练效率

Training with very large image sizes is slow—使用非常大的图像大小进行训练的速度很慢

Depthwise convolutions are slow in early layers but ef- fective in later stages—深度卷积在早期阶段较慢,但在后期阶段有效

Equally scaling up every stage is sub-optimal—对每个阶段做相同的扩展是次优的

3.3 Training-Aware NAS and Scaling—训练感知NAS和缩放

NAS Search—NAS搜索

EfficientNetV2 Architecture—EfficientNetV2 体系结构

EfficientNetV2 Scaling—EfficientNetV2缩放

Training Speed Comparison—训练速度比较

四、Progressive Learning—渐进式学习

4.1 Motivation—动机

4.2 Progressive Learning with adaptive Regularization—自适应正则化的渐进学习

五、Main Results—主要结果

5.1 ImageNet ILSVRC2012

5.2 ImageNet21k

5.3 Transfer Learning Datasets—迁移学习数据集

六、Ablation Studies—消融研究

6.1 Comparison to EfficientNet—与EfficientNet的比较

6.2 Progressive Learning for Different Networks—针对不同网络的渐进式学习

6.3 Importance of Adaptive Regularization—自适应正则化的重要性

七、Conclusion—结论

代码实现

【轻量化网络系列(7)】EfficientNetV2论文超详细解读(翻译 +学习笔记+代码实现)_第2张图片

Abstract—摘要

翻译

本文介绍了一类新的卷积网络EfficientNetV2,它比以前的模型具有更快的训练速度和更好的参数效率。为了开发这一系列模型,我们结合训练感知神经结构搜索(training-aware NAS)和缩放,共同优化训练速度和参数效率。这些模型是从搜索空间中搜索出来的,搜索空间中包含了新的操作,如Fused MBConv。我们的实验表明,EfficientNetV2模型的训练速度比最先进的模型快得多,但要小6.8倍。

我们可以通过在训练过程中逐渐增大图像大小来进一步加快训练速度,但这通常会导致精确度下降。为了补偿这种精度下降,我们还提出一种渐进式学习的方法以自适应调整正则化(例如数据增强),这样我们可以实现快速训练和良好的精度。

通过渐进式学习,我们的EfficientNetV2在ImageNet和CIFAR/Cars/Flowers数据集上的性能明显优于以前的模型。通过在相同的ImageNet 21k上进行预训练,我们的EfficientNetV2在ImageNet ILSVRC2012上实现了87.3%的top-1精度,比最近的ViT提高了2.0%的精度,同时使用相同的计算资源训练速度加快了5-11倍。


精读

本文主要工作

(1)本文使用训练感知神经结构搜索(training-aware NAS)缩放的组合,以共同优化训练速度和参数效率

(2)从空间搜索领域引入新的操作:Fused-MBConv优化模型

(3)提出了一种改进的渐进式学习方法,它自适应地调整正则化(如dropout和数据增强)以及图像大小,用来加速训练过程

(4)实验表明,EfficientNetV2模型的训练速度比最先进的模型快得多,但参数量小6.8倍


 一、Introduction—简介

翻译

随着模型规模和训练数据规模越来越大,训练效率对于深度学习非常重要。例如,GPT-3(Brown et al.,2020)具有更大的模型和更多的训练数据,证明了其在少样本学习中的卓越能力,但它需要数周的数千GPU训练,因此很难再训练或提高。

最近,训练效率受到了广泛关注。例如,NFNET(Brock et al.,2021)旨在通过消除昂贵的批量归一化来提高训练效率;最近的几项工作(Srinivas等人,2021年)侧重于通过向卷积网络(ConvNet)中添加注意层来提高训练速度;Vision Transformers(Dosovitskiy等人,2021年)通过使用Transformer块提高了大规模数据集的训练效率。然而,如图1(b)所示,这些方法在较大的参数大小上通常会带来昂贵的开销。

在本文中,我们使用训练感知神经结构搜索(training-aware NAS)和缩放相结合的方法来提高训练速度和参数效率。鉴于EfficientNet的参数效率(Tan&Le,2019a),我们首先系统地研究EfficientNet中的训练瓶颈。我们的研究表明,在EfficientNet中:(1)图像尺寸过大的训练速度较慢(2)深度卷积在早期层中很慢(3)对每个阶段做相同扩展是次优的。基于这些观察结果,我们设计了一个搜索空间,其还包含了额外的操作,如Fused MBConv,并应用训练感知NAS和缩放来联合优化模型精度、训练速度和参数量。我们发现的名为EfficientNetV2的网络训练速度比以前的型号快4倍(图3),而参数量则小6.8倍。

通过在训练过程中逐步增大图像大小,可以进一步加快我们的训练速度。许多以前的作品,如渐进式调整大小(progressive resizing,Howard,2018)、FixRes(Touvron等人,2019)和Mix&Match(Hoffer等人,2019),在训练中使用了较小的图像尺寸;但是,它们在训练图像尺寸不同的时候使用相同的正则化,导致精度下降。我们认为,对于不同的图像尺寸保持相同的正则化并不理想:对于相同的网络,较小的图像大小导致较小的网络容量,因此需要弱正则化;反之亦然,较大的图像尺寸需要更强的正则化来防止过度拟合(见第4.1节)。基于这一认识,我们提出了一种改进的渐进式学习方法:在早期的训练阶段,我们用较小的图像大小和弱正则化(例如,dropout和数据增强)训练网络,然后逐渐增加图像大小并添加更强的正则化。基于渐进式调整(Howard,2018),但通过动态调整正则化,我们的方法可以加快训练速度,而不会导致精度下降。

通过改进的渐进式学习,我们的EfficientNetV2在ImageNet、CIFAR-10、CIFAR100、Cars和Flowers数据集上取得了优异的成绩。在ImageNet上,我们实现了85.7%的top-1精度,同时训练速度比以前的模型快3-9倍,比以前的模型小6.8倍(图1)。我们的EfficientNetV2和渐进式学习也使得在更大的数据集上训练模型变得更容易。例如,ImageNet21k(Russakovsky et al.,2015)大约是ImageNet ILSVRC2012的10倍,但我们的EfficientNetV2可以使用32 TPUv3核的中等计算资源在两天内完成训练。通过在公共ImageNet 21K上进行预训练,我们的EfficientNetV2在ImageNet ILSVRC2012上实现了87.3%的top-1精度,比最近的ViT-L/16提高了2.0%的精度,同时训练速度加快了5-11倍(图1)。

我们的贡献有三方面:

•    我们推出EfficientNetV2,这是一个新的更小更快的系列。通过我们的训练感知NAS和扩展发现,EfficientNetV2在训练速度和参数效率方面都优于以前的模型。

•    我们提出了一种改进的渐进学习方法,该方法随图像大小自适应调整正则化。我们表明,它加快了训练,同时提高了准确性。

•    与现有技术相比,我们在ImageNet、CIFAR、Cars和Flowers数据集上的训练速度提高了11倍,参数效率提高了6.8倍。


精读

之前有关训练效率的工作

  • NFNets: 去除批量归一化
  • 添加注意力机制
  • Vision Transformers: 使用Transformer块

之前的不足

这些方法在大参数规模上往往伴随着大量的参数计算

EfficientNet v1的不足

(1)输入分辨率大时训练比较慢

(2)深度depthwise卷积在网络浅层中比较慢

(3)用同样的缩放系数缩放网络的每个stage是次优的

本文采用的方法

(1)作者设计了一个包含额外算子ops如Fused-MBConv的搜索空间,并应用训练感知training-aware的NAS和缩放scaling来联合优化模型精度、训练速度和参数大小。

(2)本文还提出了一种改进的渐进式训练progressive learning方法:在训练的早期用较小的输入和较弱的正则化,随着训练的进行,逐渐增大输入分辨率和正则化的强度。

本文主要贡献

(1)本文提出了EfficientNet V2,一个更小更快的模型,基于training-aware NAS和scaling,EfficientNetV2在训练速度和参数效率方面都优于之前的模型。

(2)本文提出了一种改进的渐进式训练方法它自适应的调整正则化和输入大小,通过实验证明该方法既加快了训练速度,同时也提高了准确性。

(3)EfficientNetV2结合改进的渐进式训练方法,在ImageNet、CIFAR、Cars、Flowers数据集上,比之前的模型训练速度最高提升了11倍,参数效率最高提升了6.8倍。


二、Related work—相关工作

翻译

训练和参数效率:

许多工作,如DenseNet(Huang et al.,2017)和EfficientNet(Tan&Le,2019a),都专注于参数效率,旨在以较少的参数实现更高的精度。最近的一些工作旨在提高训练或推理速度,而不是参数效率。例如,RegNet(Radosavovic et al.,2020)、ResNeSt(Zhang et al.,2020)、TResNet(Ridnik et al.,2020)和EfficientNet-X(Li et al.,2021)侧重于GPU和/或TPU推理速度;NFNET(Brock等人,2021年)和BoTNets(Srinivas等人,2021年)专注于提高训练速度。然而,他们的训练或推理速度往往伴随着更多参数的代价。本文旨在比现有技术显著提高训练速度和参数效率。

渐进式训练:

先前的研究已经提出了不同类型的渐进式训练,动态地改变训练设置或网络,用于GANs(Karras等人,2018年)、迁移学习(Karras等人,2018年)、对抗性学习(Yu等人,2019年)和语言模型(Press等人,2021年)。渐进式调整(progressive resizing,Howard,2018)主要与我们旨在提高训练速度的方法有关。然而,它通常伴随着精度下降的成本。另一项密切相关的工作是Mix&Match(Hoffer等人,2019年),它为每批随机抽取不同大小的图像。渐进式调整大小和Mix&Match对所有图像大小使用相同的正则化,导致精度下降。在本文中,我们的主要区别是自适应地调整正则化,以便提高训练速度和精度。我们的方法也部分受到 curriculum learning的启发(Bengio et al.,2009), curriculum learning从简单到困难安排训练样本。我们的方法也通过增加更多的正则化来逐渐增加学习难度,但我们没有选择性地选择训练示例。

神经架构搜索(NAS):

通过自动化网络设计过程,NAS被用于优化图像分类(Zoph等人,2018年)、目标检测(Chen等人,2019年;Tan等人,2020)、分割(Liu等人,2019)、超参数(Dong等人,2020)和其他应用(Elsken等人,2019)。以前的NAS工作主要集中于提高FLOPs效率(Tan&Le,2019b;a) 或推理效率(Tan等人,2019年;蔡等人,2019年;吴等,2019年;李等人,2021年)。与以前的工作不同,本文使用NAS优化训练效率和参数效率。


精读

Training and parameter efficiency—训练和参数效率

  • 以较少的参数实现更高的精度: DenseNet和EfficientNet
  • 侧重于GPU和/或TPU推理速度: RegNet、ResNeSt、TResNet和EfficientNet-X
  • 专注于提高训练速度: NFNET和BoTNets

Progressive training—渐进式训练

先前研究的渐进式训练:GANs、迁移学习、对抗性学习和语言模型

本文方法:本文主要通过自适应地调整正则化,提高训练速度和精度。同时也通过增加更多的正则化来逐渐增加学习难度,但没有选择性地选择训练示例。

Neural architecture search (NAS)—神经架构搜索

本文使用NAS优化训练效率和参数效率


三、EfficientNetV2 Architecture Design—高效EfficientNetV2架构设计

3.1 Review of EfficientNet—回顾EfficientNet

翻译

EfficientNet(Tan&Le,2019a)是一系列针对FLOPs和参数效率进行优化的模型。它利用NAS搜索基线EfficientNet-B0,该基线在准确性和FLOPs方面具有更好的权衡。然后使用复合缩放策略扩展基线模型,以获得模型B1-B7族。虽然最近的工作在训练或推理速度方面取得了巨大的进步,但在参数和FLOPs效率方面,它们往往比EfficientNet差(表1)。在本文中,我们的目标是在保持参数效率的同时提高训练速度。

【轻量化网络系列(7)】EfficientNetV2论文超详细解读(翻译 +学习笔记+代码实现)_第3张图片


精读

EfficientNet V1就不再过多介绍了,大家可以看我的上一篇:

【轻量化网络系列(6)】EfficientNetV1论文超详细解读(翻译 +学习笔记+代码实现)


3.2 Understanding Training Efficiency—了解训练效率

翻译

我们研究了EfficientNet的训练瓶颈(Tan&Le,2019a),此后也称为EfficientNet v1,以及一些提高训练速度的简单技术。

使用非常大的图像大小进行训练的速度很慢:

正如之前的工作(Radosavovic et al.,2020)所指出的,EfficientNet的大图像大小导致了显著的内存使用。由于GPU/TPU上的总内存是固定的,我们必须以较小的批量来训练这些模型,这大大降低了训练速度。一个简单的改进是应用FixRes(Touvron et al.,2019),使用较小的图像大小进行训练,而不是进行推理。如表2所示,图像尺寸越小,计算量越少,批量越大,因此训练速度提高了2.2倍。值得注意的是,正如(Touvron等人,2020年;Brock等人,2021年),使用较小的图像大小进行训练也会带来稍好的准确性。但与(Touvron et al.,2019)不同,我们在训练后不会对任何层进行微调。

在第4节中,我们将探索一种更先进的训练方法,在训练过程中逐步调整图像大小和正则化。

深度卷积在早期阶段较慢,但在后期阶段有效(effective):

EfficientNet的另一个训练瓶颈来自大量的深度卷积(Sifre,2014)。深度卷积比常规卷积具有更少的参数和FLOPs,但它们通常不能充分利用现代加速器。最近,Fused MBConv在(Gupta&Tan,2019年)中提出,随后在(Gupta&Akin,2020年;熊等,2020年;Li等人,2021),以更好地利用移动或服务器加速器。它使用一个常规的conv3x3取代了MBConv中的深度conv3x3和扩展conv1x1(Sandler等人,2018;Tan&Le,2019a),如图2所示。为了系统地比较这两个构建块,我们逐渐用FusedMBConv替换EfficientNet-B4中的原始MBConv(表3)。当在早期阶段1-3中应用时,FusedMBConv可以在参数和FLOPs上以较小的开销提高训练速度,但如果我们用FusedMBConv(阶段1-7)替换所有块,则它会显著增加参数和FLOPs,同时也会减慢训练速度。找到这两个构建块MBConv和Fused MBConv的正确组合并非易事,这促使我们利用神经架构搜索来自动搜索最佳组合。

对每个阶段做相同的扩展是次优的:

EfficientNet使用简单的复合缩放规则均匀扩展所有阶段。例如,当深度系数(depth coefficient )为2时,网络中的所有阶段的层数将加倍。然而,这些阶段对训练速度和参数效率的贡献并不均等。在本文中,我们将使用一种非均匀缩放策略来逐渐向后期添加更多层。此外,EfficientNets激进地扩大图像大小,导致大量内存消耗和缓慢的训练。为了解决这个问题,我们稍微修改了缩放规则,并将最大图像大小限制为较小的值。


精读

Training with very large image sizes is slow—使用非常大的图像大小进行训练的速度很慢

存在的问题: 训练图像的尺寸很大时,训练速度非常慢

本文方法: 降低训练图片尺寸,加快训练速度的同时还可以使用更大的 batch_size

表2采用较小的图像块会有更小的计算量,实现更大的batch size,从而将训练速度提高2.2倍

【轻量化网络系列(7)】EfficientNetV2论文超详细解读(翻译 +学习笔记+代码实现)_第4张图片

Depthwise convolutions are slow in early layers but ef- fective in later stages—深度卷积在早期阶段较慢,但在后期阶段有效

存在的问题:DW 卷积在现有的硬件下是无法利用很多加速器的,所以实际使用起来并没有想象中那么快。所以引入了Fused-MBConv。

但如果用Fused-MBConv(第1-7阶段)取代所有的模块(其实就是将 MBConv 模块的1×1 和 DW conv 融合为了一个 3×3 卷积。),参数和FLOPs会增加,同时训练速度也会降低。

【轻量化网络系列(7)】EfficientNetV2论文超详细解读(翻译 +学习笔记+代码实现)_第5张图片

表3表现了基于EfficientNet-B4,采用Fused-MBConv替换原始的MBConv的性能对比

【轻量化网络系列(7)】EfficientNetV2论文超详细解读(翻译 +学习笔记+代码实现)_第6张图片

本文目标: 找到MBConv和Fused-MBConv这两个模块的正确组合

本文方法: 使用 NAS 技术进行搜索,将前三个 MBConv 进行替换

Equally scaling up every stage is sub-optimal—对每个阶段做相同的扩展是次优的

之前的问题:

(1)在 EfficientNetV1 中每个 stage 的深度和宽度都是同等放大的。也就是直接简单粗暴的乘上宽度和深度缩放因子就行了,但是不同 stage 对于网络的训练速度,参数量等贡献并不相同。

(2)EfficientNet的采用大尺寸图像导致大计算量、训练速度降低问题。

本文方法:

(1)采用非均匀缩放策略对后面的stage添加更多的层。

(2)对缩放规则进行了轻微调整并将最大图像尺寸限制在一个较小的数值。


3.3 Training-Aware NAS and Scaling—训练感知NAS和缩放

翻译

为此,我们学习了多种提高训练速度的设计选择。为了寻找这些选择的最佳组合,我们现在提出一种训练感知NAS。

NAS搜索:

我们的训练感知NAS框架主要基于以前的NAS工作(Tan等人,2019年;Tan&Le,2019a),但旨在联合优化精度、参数效率和现代加速器的训练效率。具体来说,我们使用EfficientNet作为主干。我们的搜索空间是一个类似于(EfficientNet v1,Tan等人,2019)的基于阶段的因式分解空间(stage-based factorized space),包括卷积运算类型{MBConv,Fused MBConv},层数,核大小{3x3,5x5},扩展比{1,4,6}的设计选择。另一方面,我们通过2点来减小搜索空间大小:(1)删除不必要的搜索选项(如 pooling skip ops),因为它们从未在原始效率集中使用;(2)重用主干中已经搜索到的相同通道大小(Tan&Le,2019a)。由于搜索空间较小,我们可以应用强化学习(Tan et al.,2019)或简单地在更大的网络上进行随机搜索,这些网络的大小与EfficientNetB4相当。具体来说,我们对多达1000个模型进行了采样,并对每个模型进行了约10个epoch的训练,减少了图像大小,以便进行训练。我们的搜索奖励结合了模型精度A、归一化的训练步时间S和参数量P,使用简单的加权积A\cdot S^{w}\cdot P^{v},其中和根据经验确定w = -0.07v = -0.05,以平衡类似于(Tan等人,2019年)的权衡。

EfficientNetV2体系结构:

表4显示了我们搜索的模型EfficientNetV2-S的体系结构。与EfficientNet主干相比,我们搜索的EfficientNetV2有几个主要区别:

(1)第一个区别是EfficientNetV2大量使用MBConv(Sandler等人,2018;Tan&Le,2019a)和新添加的Fused MBConv(Gupta&Tan,2019)在早期的层中;

(2) 其次,EfficientNetV2更喜欢MBConv的较小扩展比,因为较小的扩展比往往具有较少的内存访问开销;

(3)第三,EfficientNetV2更喜欢较小的3x3核大小,但它增加了更多的层来补偿较小核大小导致的感受野减小;

(4) 最后,EfficientNetV2完全删除了原始EfficientNet中的最后一个stride-1阶段,这可能是由于其较大的参数大小和内存访问开销。


精读

NAS Search—NAS搜索

目的:联合优化精度、参数效率和现代加速器的训练效率

本文使用的方法:

(1)使用EfficientNet作为主干。搜索空间是一个类似于EfficientNet v1的基于阶段的因式分解空间(stage-based factorized space),

(2)这里进行网络搜索的单元是stage,其中的搜索空间包括:卷积模块的类型(MBConv或Fused-MBConv),stage中layer的数量,卷积kernel的大小3或5,膨胀系数[1,4,6]。

减少了搜索空间的大小的方法:

(1)移除了诸如pooling skip这类非必要的op,因为这类op在EfficientNet中就没有存在

(2)重用EfficientNet中搜索的到的channel数

公式:

A是模型精度、S是归一化训练时长、P是参数量

A\cdot S^{w}\cdot P^{v}

其中,w = -0.07和v = -0.05(经验所得)

EfficientNetV2 Architecture—EfficientNetV2 体系结构

表4显示了我们搜索的模型EfficientNetV2-S的体系结构

【轻量化网络系列(7)】EfficientNetV2论文超详细解读(翻译 +学习笔记+代码实现)_第7张图片

与V1的不同:

(1)除了使用 MBConv 之外还使用了 Fused-MBConv 模块,加快训练速度与提升性能

(2)使用较小的 expansion ratio (之前是6),从而减少内存的访问量

(3)趋向于选择kernel大小为3的卷积核,但是会增加多个卷积用以提升感受野,( V1 中有 5 × 5 )

(4)移除了最后一个stride为1的stage,从而减少部分参数和内存访问

EfficientNetV2 Scaling—EfficientNetV2缩放

作者在EfficientNetV2-S的基础上采用类似EfficientNet的复合缩放,并添加几个额外的优化,得到EfficientNetV2-M/L。

额外的优化描述如下:

(1)限制最大推理图像尺寸为480

(2)在网络的后期添加更多的层提升模型容量且不引入过多耗时

Training Speed Comparison—训练速度比较

图3比较了新的EfficientNetV2的训练步骤时间

【轻量化网络系列(7)】EfficientNetV2论文超详细解读(翻译 +学习笔记+代码实现)_第8张图片

如图所示,EfficientNetV2模型在ImageNet上top-1 acc和train step time,这里的训练采用固定的图像大小,不过比推理时图像大小降低30%,而图中的EffNet(reprod)也是采用这样的训练策略,可以看到比baseline训练速度和效果均有明显提升,而EfficientNetV2在训练速度和效果上有进一步地提升。


四、Progressive Learning—渐进式学习

4.1 Motivation—动机

翻译

如第3节所述,图像大小对训练效率起着重要作用。除了FixRes(Touvron et al.,2019),许多其他作品在训练期间动态改变图像大小(Howard,2018;Hoffer等人,2019),但它们通常会导致精度下降。

我们假设精度下降来自不平衡正则化:当使用不同图像大小进行训练时,我们还应该相应地调整正则化强度(而不是像以前的工作那样使用固定的正则化)。事实上,大型模型通常需要更强的正则化来对抗过拟合:例如,EfficientNet-B7使用比B0更大的衰减和更强的数据增强。在本文中,我们认为,即使对于相同的网络,较小的图像大小也会导致较小的网络容量,因此需要较弱的正则化;反之亦然,图像尺寸越大,计算量越大,越容易过度拟合。为了验证我们的假设,我们训练了一个从我们的搜索空间取样的模型,该模型具有不同的图像大小和数据增强(表5)。当图像尺寸较小时,在增强较弱的情况下,其精度最好;但对于更大的图像,使用更强的数据增强效果更好。这种观察促使我们在训练期间自适应调整正则化和图像大小,从而改进了渐进式学习方法。


精读

之前的问题

当用不同的图像尺寸进行训练时,也应该相应地调整正则化强度(而不是像以前的工作那样使用固定的正则化)

表5表现了用同一网络,以不同的输入大小和不同的正则强度进行训练的结果

【轻量化网络系列(7)】EfficientNetV2论文超详细解读(翻译 +学习笔记+代码实现)_第9张图片

结论:

(1)即使是相同的网络,较小的图像尺寸会导致较小的网络容量,因此需要较弱的正则化

(2)反之,较大的图像尺寸会导致更多的计算,而容量较大,因此更容易出现过拟合

(3)当图像大小较小时,弱增强的精度最好;但对于较大的图像,更强的增强效果更好


4.2 Progressive Learning with adaptive Regularization—自适应正则化的渐进学习

翻译

图4展示了我们改进的渐进式学习的训练过程:在早期训练阶段,我们使用较小的图像和弱正则化训练网络,这样网络可以轻松快速地学习简单的表示。然后,我们逐渐增加图像大小,但也通过添加更强的正则化使学习更加困难。我们的方法基于(Howard,2018)逐步改变图像大小,但这里我们也自适应调整正则化。

形式上,假设整个训练有N个总步骤,目标图像大小为S_{e},目标正则化幅度为一个列表\Phi _{e}=\left \{ \phi _{e}^{k} \right \},其中表示一种正则化,例如dropout率或mixup率。我们将训练分为M个阶段:每个阶段1\leq i\leq M、 该模型采用图像大小S_{i}和正则化幅度\Phi _{e}=\left \{ \phi _{i}^{k} \right \}进行训练。最后阶段M将使用目标图像大小S_{e}和正则化\Phi _{e}。为了简单起见,我们启发式地选取初始图像大小和正则化,然后使用线性插值来确定每个阶段的值。算法1总结了该过程。在每个阶段开始时,网络将继承前一阶段的所有权重。与transformers不同,transformers的权重(例如, position embedding)可能取决于输入长度,而卷积网络权重与图像大小无关,因此很容易继承。

我们改进的渐进式学习通常与现有的正规化相兼容。为简单起见,本文主要研究以下三种正则化:

•    dropout(Srivastava et al.,2014):一种网络级的正规化,通过随机丢弃通道来减少共同适应(co-adaptation)。我们将调整dropout率。

•    RandAugment(Cubuk等人,2020):对每幅图像分别做幅度可调的数据增强。

•    Mixup(Zhang等人,2018):图像与图像相互作用的数据增强。给定带有标签的两幅图像\left ( x_{i}, y_{i}\right )\left ( x_{j}, y_{j}\right ),Mixup根据混合比将两者混合:\widetilde{x_{i}}=\lambda x_{j}+(1-\lambda )x_{i}\widetilde{y_{i}}=\lambda y_{j}+(1-\lambda )y_{j}。我们将在训练期间调整混合比\lambda


精读

图4展示了本文改进的渐进学习的训练过程

【轻量化网络系列(7)】EfficientNetV2论文超详细解读(翻译 +学习笔记+代码实现)_第10张图片

它从较小的图像大小和弱正则化(epoch=1)开始,然后随着图像大小和强正则化逐渐增加学习难度:dropout rate较大,RandAugment幅度较大,mixup ratio(如epoch=300)较大

作者将渐进式学习策略抽象成了一个公式来设置不同训练阶段使用的训练尺寸以及正则化强度。算法1总结了过程:

【轻量化网络系列(7)】EfficientNetV2论文超详细解读(翻译 +学习笔记+代码实现)_第11张图片

【轻量化网络系列(7)】EfficientNetV2论文超详细解读(翻译 +学习笔记+代码实现)_第12张图片


五、Main Results—主要结果

5.1 ImageNet ILSVRC2012

翻译

ImageNet ILSVRC2012(Russakovsky et al.,2015)包含约128万张训练图像和50000张验证图像,包含1000个类。在架构搜索或超参数优化过程中,我们从训练集中保留25000张图像(约2%),作为minival用于精度评估。我们还使用minival执行提前停止。我们的ImageNet训练设置主要遵循EfficientNets(Tan&Le,2019a):衰减为0.9、动量为0.9的RMSProp优化器;批次标准动量0.99;重量衰减1e-5。每个模型训练350个时期,总批量为4096。学习率首先从0上升到0.256,然后每2.4个时期衰减0.97。我们使用衰减率为0.9999的指数移动平均、RandAugment(Cubuk等人,2020)、Mixup(Zhang等人,2018)、Dropout(Srivastava等人,2014)和随机深度(Huang等人,2016),生存概率为0.8。

对于渐进式学习,我们将训练过程分为四个阶段,每个阶段大约87个时代:早期阶段使用较小的图像大小,但正则性较弱,而后期阶段使用较大的图像大小,正则性较强,如算法1所述。表6显示了图像大小和正则化的最小值(第一阶段)和最大值(最后阶段)。为简单起见,所有模型都使用相同的图像尺寸最小值和正则化最小值,但它们采用不同的最大值,因为较大的模型通常需要更多的正则化来防止过度拟合。按照(Touvron et al.,2020),我们训练的最大图像尺寸比推理的图像尺寸小约20%,但训练后我们不会微调任何层。

结果:

如表7所示,我们的EfficientNetV2模型比ImageNet上以前的ConvNet和Transformers速度更快,精度和参数效率更高。特别是,我们的EfficientNet V2-M在使用相同的计算资源进行训练的同时,实现了与EfficientNet-B7相当的精度,训练速度提高了11倍。我们的EfficientNetV2模型在准确性和推理速度方面也显著优于所有最近的RegNet和ResNeSt。图1进一步显示了训练速度和参数效率的比较。值得注意的是,这种加速结合了渐进式训练和更好的网络,我们将在消融研究中研究它们各自的影响。

最近,Vision Transformers在ImageNet准确性和训练速度方面取得了令人印象深刻的成果。然而,在这里,我们表明,适当设计的卷积网络和改进的训练方法仍然可以在精度和训练效率方面大大优于Vision Transformers。特别是,我们的EfficientNetV2-L达到了85.7%的top-1精度,超过了ViT-L/16(21k),ViT-L/16(21k)是在更大的ImageNet21k数据集上预训练的更大的Transformers模型。这里,VIT在ImageNet ILSVRC2012上没有得到很好的微调;DEIT使用与VIT相同的体系结构,但通过添加更多正则化来实现更好的结果。

尽管我们的EfficientNetV2模型针对训练进行了优化,但它们在推理方面也表现良好,因为训练速度通常与推理速度相关。图5显示了基于表7的模型大小、FLOPs和推断延迟。由于延迟通常取决于硬件和软件,因此我们在这里使用相同的PyTorch图像模型代码库(Wightman,2021),并使用批大小16在同一台机器上运行所有模型。通常,我们的模型的参数/FLOPs效率只比EfficientNets略高,但我们的推理延迟比EfficientNets快3倍。与最近专门为GPU优化的ResNeSt相比,我们的EfficientNetV2-M的精度提高了0.6%,推理速度加快了2.8倍。


精读

设置

  • 数据集: ImageNet ILSVRC2012
  • 衰减率: 0.9
  • 动量: 0.9
  • 优化器: RMSProp
  • 批次标准动量: 0.99
  • 重量衰减: 1e-5
  • epoch: 350

表6给出了EfficientNetV2(S,M,L)三个模型的渐进学习策略参数

【轻量化网络系列(7)】EfficientNetV2论文超详细解读(翻译 +学习笔记+代码实现)_第13张图片

表7给出了所提方法与其他方案在精度、参数量、FLOPs以及耗时方面的对比

【轻量化网络系列(7)】EfficientNetV2论文超详细解读(翻译 +学习笔记+代码实现)_第14张图片

图5显示了基于表7的模型大小、FLOPs和推断延迟

【轻量化网络系列(7)】EfficientNetV2论文超详细解读(翻译 +学习笔记+代码实现)_第15张图片

结论: 相比其他方法,所提EfficientNetV2训练速度更快、精度更高、参数量更少。


5.2 ImageNet21k

翻译

设置:

ImageNet21k(Russakovsky et al.,2015)包含约1300万张训练图像,共21841类。原始ImageNet21k没有train/eval划分,因此我们保留随机选取的100000张图像作为验证集,并使用剩余的图像作为训练集。我们在很大程度上重复使用与ImageNet ILSVRC2012相同的训练设置,但做了一些更改:(1)我们将训练epochs更改为60或30以减少训练时间,并使用余弦学习速率衰减,可以适应不同的步骤而无需额外调整(2) 由于每个图像都有多个标签,因此在计算softmax损失之前,我们将标签归一化为总和为1。在ImageNet21k上预训练后,使用余弦学习率衰减在ILSVRC2012上对每个模型进行15个epoch的微调。

结果:

表7显示了性能比较,其中使用21k标记的模型在ImageNet21k上进行了预训练,并在ImageNet ILSVRC2012上进行了微调。与最新的ViT-L/16(21k)相比,我们的EfficientNetV2-L(21k)将top-1的准确度提高了1.5%(85.3%对86.8%),使用的参数减少了2.5倍,FLOPs次数减少了3.6倍,同时训练和推理速度加快了6倍至7倍。

我们想强调几个有趣的观察结果:

•    在高精度情况下,放大数据大小(data size,编者注:这里应该指数据集样本规模,而不是指图像的尺寸)比简单地放大模型大小更有效:当top-1精度超过85%时,由于严重的过拟合,很难通过简单地增加模型大小来进一步改进。然而,额外的ImageNet21K预训练可以显著提高准确性。在以前的工作中也观察到了大型数据集的有效性(Mahajan等人,2018年;谢等,2020年;多索维茨基等人,2021年)。

•    在ImageNet21k上进行预训练可能非常有效。

尽管ImageNet21k的数据量是前者的10倍,但我们的训练方法使我们能够使用32个TPU核在两天内完成EfficientNetV2的预训练(而不是ViT的几周(Dosovitskiy et al.,2021))。这比在ImageNet上训练更大的模型更有效。我们建议未来对大规模模型的研究使用公共ImageNet21k作为默认数据集。


精读

设置

  • 数据集: ImageNet21k
  • 训练图像数量: 1300万张训练图像
  • 类别: 共21841类

与ImageNet ILSVRC2012的区别

(1)将训练epochs更改为60或30以减少训练时间,并使用余弦学习速率衰减,可以适应不同的步骤而无需额外调整

(2)由于每个图像都有多个标签,因此在计算softmax损失之前,将标签归一化为总和为1

结论:

(1)EfficientNetV2-L(21k)将top-1的准确度提高了1.5%,使用的参数减少了2.5倍,FLOPs次数减少了3.6倍,同时训练和推理速度加快了6倍至7倍

(2)在高精度情况下,放大数据集样本规模比简单地放大模型大小更有效

(3)在ImageNet21k上进行预训练可能非常有效


5.3 Transfer Learning Datasets—迁移学习数据集

翻译

设置:

我们在四个迁移学习数据集上评估了我们的模型:CIFAR-10、CIFAR-100、Flowers和Cars。表9包括这些数据集的统计数据。

对于这个实验,我们使用在ImageNet ILSVRC2012上训练的检查点。为了公平比较,此处不使用ImageNet21k图像。我们的微调设置基本上与ImageNet训练相同,但有一些修改类似于(Dosovitskiy等人,2021;Touvron等人,2021):我们使用更小的批量512,更小的初始学习率0.001和余弦衰减。对于所有数据集,我们对每个模型进行固定10000步的训练。由于每个模型都只微调很少步,因此我们禁用了权重衰减,并使用了一个简单的cutou数据增强。

结果:

表8比较了迁移学习性能。总的来说,我们的模型在所有这些数据集上都优于以前的ConvNet和Vision Transformers,有时甚至有一个不小的差距:例如,在CIFAR-100上,EfficientNetV2-L的精度比以前的GPipe/EfficientNets高0.6%,比以前的ViT/DeiT模型高1.5%。这些结果表明,我们的模型可以从ImageNet右很好的泛化(our models also generalize well beyond ImageNet. )。


精读

设置

四个迁移学习数据集: CIFAR-10、CIFAR-100、Flowers和Cars

表9包括这些数据集的统计数据

【轻量化网络系列(7)】EfficientNetV2论文超详细解读(翻译 +学习笔记+代码实现)_第16张图片

表8比较了迁移学习性能 【轻量化网络系列(7)】EfficientNetV2论文超详细解读(翻译 +学习笔记+代码实现)_第17张图片


六、Ablation Studies—消融研究

6.1 Comparison to EfficientNet—与EfficientNet的比较

翻译

在本节中,我们将在相同的训练和推理设置下,比较我们的EfficientNetV2(简称V2)与EfficientNet(Tan&Le,2019a)(简称V1)。

在相同训练中的表现:

表10显示了使用相同渐进式学习设置的性能比较。由于我们在EfficientNet中采用了相同的渐进式学习,其训练速度(从139h降低到54h)和准确性(从84.7%提高到85.0%)都优于原始论文(Tan&Le,2019a)。然而,如表10所示,我们的EfficientNetV2模型仍然大大优于EfficientNets:EfficientNetV2-M将参数减少了17%,FLOPs率减少了37%,同时训练速度比EfficientNet-B7快4.1倍,推理速度比EfficientNet7快3.1倍。由于我们在这里使用相同的训练设置,因此我们将收益归因于EfficientNetV2体系结构。

向下扩展:

前几节主要关注大型模型。在这里,我们通过使用EfficientNet复合扩展缩小方法来向下扩展EfficientNet V2-S,以比较小模型。为了便于比较,所有模型都没有使用渐进式训练。与小型EfficientNets(V1)相比,我们的新EfficientNetV2(V2)模型通常更快,同时保持可比的参数效率。


精读

(1)在相同训练中的表现

表10显示了使用相同渐进式学习设置的性能比较

【轻量化网络系列(7)】EfficientNetV2论文超详细解读(翻译 +学习笔记+代码实现)_第18张图片

(2)向下扩展

表11通过使用EfficientNet复合扩展缩小方法来向下扩展EfficientNet V2-S

【轻量化网络系列(7)】EfficientNetV2论文超详细解读(翻译 +学习笔记+代码实现)_第19张图片

结论: 与小型EfficientNetV1相比,EfficientNetV2模型通常更快,同时保持可比的参数效率。


6.2 Progressive Learning for Different Networks—针对不同网络的渐进式学习

翻译

我们消冗不同网络的渐进式学习的表现。表12显示了使用了相同的ResNet和EfficientNet模型,我们的渐进式训练和基线训练之间的性能比较。在这里,基线ResNet比原始论文(He等人,2016年)具有更高的准确性,因为它们是使用我们改进的训练设置(见第5节)进行训练的,使用了更多的epochs和更好的优化器。我们还将ResNet的图像大小从224增加到380,以进一步提高网络容量和准确性。

如表12所示,我们的渐进式学习通常减少了训练时间,同时提高了所有不同网络的准确性。毫不奇怪,当默认图像大小非常小时,例如大小为224x224的ResNet50(224),训练加速比是有限的(1.4x加速比);然而,当默认图像大小更大且模型更复杂时,我们的方法在精确度和训练效率方面获得了更大的收益:对于ResNet152(380),我们的方法将训练速度提高了2.1倍,精确度略高;对于EfficientNet-B4,我们的方法将训练速度提高了2.2倍。


精读

表12显示了使用了相同的ResNet和EfficientNet模型,渐进式训练和基线训练之间的性能比较

【轻量化网络系列(7)】EfficientNetV2论文超详细解读(翻译 +学习笔记+代码实现)_第20张图片

结论: 渐进式学习减少了训练时间,同时提高了所有不同网络的准确性


6.3 Importance of Adaptive Regularization—自适应正则化的重要性

翻译

我们的训练方法的一个关键洞察是自适应正则化,它根据图像大小动态调整正则化。本文选择了一种简单渐进的方法,因为它的简单性,但它也是一种可以与其他方法相结合的通用方法。

表13研究了我们在两种训练设置下的自适应正则化:一种是将图像大小逐渐增大(Howard,2018),另一种是为每个批次随机采样不同的图像大小(Hoffer et al.,2019)。因为TPU需要为每个新的大小重新编译图形(recompile the graph),所以这里我们每8个epoch而不是每个batch随机采样一个图像大小。与对所有图像大小使用相同正则化的渐进式或随机调整大小的普通方法相比,我们的自适应正则化将精度提高了0.7%。图6进一步比较了渐进式方法的训练曲线。我们的自适应正则化在早期训练阶段对小图像使用更小的正则化,允许模型更快地收敛并获得更好的最终精度。


精读

表13研究了我们在两种训练设置下的自适应正则化:一种是将图像大小逐渐增大,另一种是为每个批次随机采样不同的图像大小

【轻量化网络系列(7)】EfficientNetV2论文超详细解读(翻译 +学习笔记+代码实现)_第21张图片

图6进一步比较了渐进式方法的训练曲线

【轻量化网络系列(7)】EfficientNetV2论文超详细解读(翻译 +学习笔记+代码实现)_第22张图片

结论: 自适应正则化在早期训练阶段对小图像使用更小的正则化,允许模型更快地收敛并获得更好的最终精度。


七、Conclusion—结论

翻译

本文介绍了EfficientNetV2,这是一个用于图像识别的小型快速神经网络新家族。我们的EfficientNetV2通过训练感知NAS和模型扩展进行了优化,大大优于以前的模型,同时在参数方面速度更快、效率更高。为了进一步加快训练速度,我们提出了一种改进的渐进式学习方法,即在训练期间联合增加图像大小和正则化。大量实验表明,我们的EfficientNetV2在ImageNet和CIFAR/Flowers/Cars上取得了很好的效果。与EfficientNet和最近的作品相比,我们的EfficientNet V2的训练速度快11倍,而体积小6.8倍。


精读

本文是EfficientNet原作者对其进行的一次升级,旨在保持参数量高效利用的同时尽可能提升训练速度。

作者系统性的研究了EfficientNet的训练过程,并总结出了三个问题:

  • 1.训练图像的尺寸很大时,训练速度非常慢
  • 2.在网络浅层中使用Depthwise convolutions速度会很慢
  • 3.同等的放大每个阶段是次优的

在EfficientNet的基础上,引入了Fused-MBConv到搜索空间中;同时为渐进式学习引入了自适应正则强度调整机制,两种改进的组合得到了EfficientNetV2。


代码实现

from collections import OrderedDict
from functools import partial
from typing import Callable, Optional

import torch.nn as nn
import torch
from torch import Tensor


def drop_path(x, drop_prob: float = 0., training: bool = False):
    """
    Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks).
    "Deep Networks with Stochastic Depth", https://arxiv.org/pdf/1603.09382.pdf
    This function is taken from the rwightman.
    It can be seen here:
    https://github.com/rwightman/pytorch-image-models/blob/master/timm/models/layers/drop.py#L140
    """
    if drop_prob == 0. or not training:
        return x
    keep_prob = 1 - drop_prob
    shape = (x.shape[0],) + (1,) * (x.ndim - 1)  # work with diff dim tensors, not just 2D ConvNets
    random_tensor = keep_prob + torch.rand(shape, dtype=x.dtype, device=x.device)
    random_tensor.floor_()  # binarize
    output = x.div(keep_prob) * random_tensor
    return output


class DropPath(nn.Module):
    """
    Drop paths (Stochastic Depth) per sample  (when applied in main path of residual blocks).
    "Deep Networks with Stochastic Depth", https://arxiv.org/pdf/1603.09382.pdf
    """
    def __init__(self, drop_prob=None):
        super(DropPath, self).__init__()
        self.drop_prob = drop_prob

    def forward(self, x):
        return drop_path(x, self.drop_prob, self.training)


class ConvBNAct(nn.Module):
    def __init__(self,
                 in_planes: int,
                 out_planes: int,
                 kernel_size: int = 3,
                 stride: int = 1,
                 groups: int = 1,
                 norm_layer: Optional[Callable[..., nn.Module]] = None,
                 activation_layer: Optional[Callable[..., nn.Module]] = None):
        super(ConvBNAct, self).__init__()

        padding = (kernel_size - 1) // 2
        if norm_layer is None:
            norm_layer = nn.BatchNorm2d
        if activation_layer is None:
            activation_layer = nn.SiLU  # alias Swish  (torch>=1.7)

        self.conv = nn.Conv2d(in_channels=in_planes,
                              out_channels=out_planes,
                              kernel_size=kernel_size,
                              stride=stride,
                              padding=padding,
                              groups=groups,
                              bias=False)

        self.bn = norm_layer(out_planes)
        self.act = activation_layer()

    def forward(self, x):
        result = self.conv(x)
        result = self.bn(result)
        result = self.act(result)

        return result


class SqueezeExcite(nn.Module):
    def __init__(self,
                 input_c: int,   # block input channel
                 expand_c: int,  # block expand channel
                 se_ratio: float = 0.25):
        super(SqueezeExcite, self).__init__()
        squeeze_c = int(input_c * se_ratio)
        self.conv_reduce = nn.Conv2d(expand_c, squeeze_c, 1)
        self.act1 = nn.SiLU()  # alias Swish
        self.conv_expand = nn.Conv2d(squeeze_c, expand_c, 1)
        self.act2 = nn.Sigmoid()

    def forward(self, x: Tensor) -> Tensor:
        scale = x.mean((2, 3), keepdim=True)
        scale = self.conv_reduce(scale)
        scale = self.act1(scale)
        scale = self.conv_expand(scale)
        scale = self.act2(scale)
        return scale * x


class MBConv(nn.Module):
    def __init__(self,
                 kernel_size: int,
                 input_c: int,
                 out_c: int,
                 expand_ratio: int,
                 stride: int,
                 se_ratio: float,
                 drop_rate: float,
                 norm_layer: Callable[..., nn.Module]):
        super(MBConv, self).__init__()

        if stride not in [1, 2]:
            raise ValueError("illegal stride value.")

        self.has_shortcut = (stride == 1 and input_c == out_c)

        activation_layer = nn.SiLU  # alias Swish
        expanded_c = input_c * expand_ratio

        # 在EfficientNetV2中,MBConv中不存在expansion=1的情况所以conv_pw肯定存在
        assert expand_ratio != 1
        # Point-wise expansion
        self.expand_conv = ConvBNAct(input_c,
                                     expanded_c,
                                     kernel_size=1,
                                     norm_layer=norm_layer,
                                     activation_layer=activation_layer)

        # Depth-wise convolution
        self.dwconv = ConvBNAct(expanded_c,
                                expanded_c,
                                kernel_size=kernel_size,
                                stride=stride,
                                groups=expanded_c,
                                norm_layer=norm_layer,
                                activation_layer=activation_layer)

        self.se = SqueezeExcite(input_c, expanded_c, se_ratio) if se_ratio > 0 else nn.Identity()

        # Point-wise linear projection
        self.project_conv = ConvBNAct(expanded_c,
                                      out_planes=out_c,
                                      kernel_size=1,
                                      norm_layer=norm_layer,
                                      activation_layer=nn.Identity)  # 注意这里没有激活函数,所有传入Identity

        self.out_channels = out_c

        # 只有在使用shortcut连接时才使用dropout层
        self.drop_rate = drop_rate
        if self.has_shortcut and drop_rate > 0:
            self.dropout = DropPath(drop_rate)

    def forward(self, x: Tensor) -> Tensor:
        result = self.expand_conv(x)
        result = self.dwconv(result)
        result = self.se(result)
        result = self.project_conv(result)

        if self.has_shortcut:
            if self.drop_rate > 0:
                result = self.dropout(result)
            result += x

        return result


class FusedMBConv(nn.Module):
    def __init__(self,
                 kernel_size: int,
                 input_c: int,
                 out_c: int,
                 expand_ratio: int,
                 stride: int,
                 se_ratio: float,
                 drop_rate: float,
                 norm_layer: Callable[..., nn.Module]):
        super(FusedMBConv, self).__init__()

        assert stride in [1, 2]
        assert se_ratio == 0

        self.has_shortcut = stride == 1 and input_c == out_c
        self.drop_rate = drop_rate

        self.has_expansion = expand_ratio != 1

        activation_layer = nn.SiLU  # alias Swish
        expanded_c = input_c * expand_ratio

        # 只有当expand ratio不等于1时才有expand conv
        if self.has_expansion:
            # Expansion convolution
            self.expand_conv = ConvBNAct(input_c,
                                         expanded_c,
                                         kernel_size=kernel_size,
                                         stride=stride,
                                         norm_layer=norm_layer,
                                         activation_layer=activation_layer)

            self.project_conv = ConvBNAct(expanded_c,
                                          out_c,
                                          kernel_size=1,
                                          norm_layer=norm_layer,
                                          activation_layer=nn.Identity)  # 注意没有激活函数
        else:
            # 当只有project_conv时的情况
            self.project_conv = ConvBNAct(input_c,
                                          out_c,
                                          kernel_size=kernel_size,
                                          stride=stride,
                                          norm_layer=norm_layer,
                                          activation_layer=activation_layer)  # 注意有激活函数

        self.out_channels = out_c

        # 只有在使用shortcut连接时才使用dropout层
        self.drop_rate = drop_rate
        if self.has_shortcut and drop_rate > 0:
            self.dropout = DropPath(drop_rate)

    def forward(self, x: Tensor) -> Tensor:
        if self.has_expansion:
            result = self.expand_conv(x)
            result = self.project_conv(result)
        else:
            result = self.project_conv(x)

        if self.has_shortcut:
            if self.drop_rate > 0:
                result = self.dropout(result)

            result += x

        return result


class EfficientNetV2(nn.Module):
    def __init__(self,
                 model_cnf: list,
                 num_classes: int = 1000,
                 num_features: int = 1280,
                 dropout_rate: float = 0.2,
                 drop_connect_rate: float = 0.2):
        super(EfficientNetV2, self).__init__()

        for cnf in model_cnf:
            assert len(cnf) == 8

        norm_layer = partial(nn.BatchNorm2d, eps=1e-3, momentum=0.1)

        stem_filter_num = model_cnf[0][4]

        self.stem = ConvBNAct(3,
                              stem_filter_num,
                              kernel_size=3,
                              stride=2,
                              norm_layer=norm_layer)  # 激活函数默认是SiLU

        total_blocks = sum([i[0] for i in model_cnf])
        block_id = 0
        blocks = []
        for cnf in model_cnf:
            repeats = cnf[0]
            op = FusedMBConv if cnf[-2] == 0 else MBConv
            for i in range(repeats):
                blocks.append(op(kernel_size=cnf[1],
                                 input_c=cnf[4] if i == 0 else cnf[5],
                                 out_c=cnf[5],
                                 expand_ratio=cnf[3],
                                 stride=cnf[2] if i == 0 else 1,
                                 se_ratio=cnf[-1],
                                 drop_rate=drop_connect_rate * block_id / total_blocks,
                                 norm_layer=norm_layer))
                block_id += 1
        self.blocks = nn.Sequential(*blocks)

        head_input_c = model_cnf[-1][-3]
        head = OrderedDict()

        head.update({"project_conv": ConvBNAct(head_input_c,
                                               num_features,
                                               kernel_size=1,
                                               norm_layer=norm_layer)})  # 激活函数默认是SiLU

        head.update({"avgpool": nn.AdaptiveAvgPool2d(1)})
        head.update({"flatten": nn.Flatten()})

        if dropout_rate > 0:
            head.update({"dropout": nn.Dropout(p=dropout_rate, inplace=True)})
        head.update({"classifier": nn.Linear(num_features, num_classes)})

        self.head = nn.Sequential(head)

        # initial weights
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight, mode="fan_out")
                if m.bias is not None:
                    nn.init.zeros_(m.bias)
            elif isinstance(m, nn.BatchNorm2d):
                nn.init.ones_(m.weight)
                nn.init.zeros_(m.bias)
            elif isinstance(m, nn.Linear):
                nn.init.normal_(m.weight, 0, 0.01)
                nn.init.zeros_(m.bias)

    def forward(self, x: Tensor) -> Tensor:
        x = self.stem(x)
        x = self.blocks(x)
        x = self.head(x)

        return x


def efficientnetv2_s(num_classes: int = 1000):
    """
    EfficientNetV2
    https://arxiv.org/abs/2104.00298
    """
    # train_size: 300, eval_size: 384

    # repeat, kernel, stride, expansion, in_c, out_c, operator, se_ratio
    model_config = [[2, 3, 1, 1, 24, 24, 0, 0],
                    [4, 3, 2, 4, 24, 48, 0, 0],
                    [4, 3, 2, 4, 48, 64, 0, 0],
                    [6, 3, 2, 4, 64, 128, 1, 0.25],
                    [9, 3, 1, 6, 128, 160, 1, 0.25],
                    [15, 3, 2, 6, 160, 256, 1, 0.25]]

    model = EfficientNetV2(model_cnf=model_config,
                           num_classes=num_classes,
                           dropout_rate=0.2)
    return model


def efficientnetv2_m(num_classes: int = 1000):
    """
    EfficientNetV2
    https://arxiv.org/abs/2104.00298
    """
    # train_size: 384, eval_size: 480

    # repeat, kernel, stride, expansion, in_c, out_c, operator, se_ratio
    model_config = [[3, 3, 1, 1, 24, 24, 0, 0],
                    [5, 3, 2, 4, 24, 48, 0, 0],
                    [5, 3, 2, 4, 48, 80, 0, 0],
                    [7, 3, 2, 4, 80, 160, 1, 0.25],
                    [14, 3, 1, 6, 160, 176, 1, 0.25],
                    [18, 3, 2, 6, 176, 304, 1, 0.25],
                    [5, 3, 1, 6, 304, 512, 1, 0.25]]

    model = EfficientNetV2(model_cnf=model_config,
                           num_classes=num_classes,
                           dropout_rate=0.3)
    return model


def efficientnetv2_l(num_classes: int = 1000):
    """
    EfficientNetV2
    https://arxiv.org/abs/2104.00298
    """
    # train_size: 384, eval_size: 480

    # repeat, kernel, stride, expansion, in_c, out_c, operator, se_ratio
    model_config = [[4, 3, 1, 1, 32, 32, 0, 0],
                    [7, 3, 2, 4, 32, 64, 0, 0],
                    [7, 3, 2, 4, 64, 96, 0, 0],
                    [10, 3, 2, 4, 96, 192, 1, 0.25],
                    [19, 3, 1, 6, 192, 224, 1, 0.25],
                    [25, 3, 2, 6, 224, 384, 1, 0.25],
                    [7, 3, 1, 6, 384, 640, 1, 0.25]]

    model = EfficientNetV2(model_cnf=model_config,
                           num_classes=num_classes,
                           dropout_rate=0.4)
    return model

你可能感兴趣的:(目标检测论文,轻量化网络,目标检测,人工智能,计算机视觉)