YoloV9改进策略:主干网络篇|MobileNetV4主干替换YoloV9的BackBone(独家原创)

摘要

今年,轻量级王者MobileNetV4闪亮登场!在我们这篇文章里,我们把MobileNetV4加入到了YoloV9中,对MobileNetV4的层数和卷积层核做了适当的修改,然后替换原有的BackBone。哈哈,你猜怎么着?效果超赞!
在这里插入图片描述

文章里详细记录了改进过程,给那些正在为创新点子发愁的小伙伴们提供了满满的灵感。嘿,想要发表关于轻量级改进的论文?这篇文章绝对是你的首选参考!

论文翻译:《MobileNetV4——移动生态系统的通用模型》

论文链接:https://arxiv.org/pdf/2404.10518
我们推出了最新一代的MobileNets,称为MobileNetV4(MNv4),其特点是为移动设备提供普遍高效的架构设计。在核心部分,我们引入了通用倒置瓶颈(UIB)搜索块,这是一种统一且灵活的结构,融合了倒置瓶颈(IB)、ConvNext、前馈网络(FFN)以及新型Extra Depthwise(ExtraDW)变体。除了UIB之外,我们还推出了Mobile MQA,这是一种专为移动加速器设计的注意力块,可带来高达39%的速度提升。我们还引入了一种优化的神经架构搜索(NAS)配方,提高了MNv4搜索的有效性。UIB、Mobile MQA和精炼的NAS配方的集成,产生了一系列新的MNv4模型,这些模型在移动CPU、DSP、GPU以及像Apple Neural Engine和Google Pixel EdgeTPU这样的专用加速器上大多是帕累托最优的——这是在其他测试模型中找不到的特性。最后,为了进一步提高准确性,我们引入了一种新型的知识蒸馏技术。通过这种技术的增强,我们的MNv4-Hybrid-Large模型在ImageNet-1K上达到了87%的准确率,同时在Pixel 8 EdgeTPU上的运行时间仅为3.8毫秒。

代码链接:https://github.com/tensorflow/models/blob/master/official/vision/modeling/backbones/mobilenet.py

1、引言

高效的设备端神经网络不仅能实现快速、实时和交互式的体验,还能避免将私人数据通过公共互联网进行传输。然而,移动设备的计算约束给在准确性和效率之间取得平衡带来了重大挑战。为此,我们引入了UIB和Mobile MQA这两个创新性的构建块,并通过精炼的NAS配置将它们集成在一起,创建了一系列在移动设备上普遍最优的模型。此外,我们还提出了一种蒸馏技术,以进一步提高准确性。
在这里插入图片描述

我们的通用倒置瓶颈(UIB)块通过融入两个可选的深度卷积操作,改进了倒置瓶颈块[36]。尽管其设计简单,但UIB统一了突出的微架构——逆置瓶颈(IB)、ConvNext[32]和前馈网络(FFN)[12],并引入了Extra Depthwise(ExtraDW)IB块。UIB在空间和通道混合方面提供了灵活性,可以选择扩展感受野,并提高计算效率。

我们的优化Mobile MQA块相对于多头注意力[44]在移动加速器上实现了超过39%的推理加速。

我们的两阶段NAS方法通过分离粗粒度搜索和细粒度搜索,显著提高了搜索效率,并有助于创建比先前最先进的模型[41]大得多的模型。此外,通过纳入一个离线的蒸馏数据集,我们减少了NAS奖励测量中的噪声,从而提高了模型质量。

通过集成UIB、MQA和改进的NAS配置,我们推出了MNv4模型套件,它在包括CPU、DSP、GPU和专用加速器在内的多种硬件平台上实现了大多数帕累托最优性能。我们的模型系列涵盖了一个广泛的计算谱系,从极其紧凑的MNv4-Conv-S设计开始,该设计具有3.8M参数和0.2G MACs,在Pixel 6 CPU上以2.4毫秒的速度实现了73.8%的ImageNet-1K top-1准确率,一直到MNv4-Hybrid-L高端变体,它建立了移动模型准确性的新基准,在Pixel 8 EdgeTPU上以3.8毫秒的速度运行。我们新颖的蒸馏配方混合了具有不同增强的数据集,并添加了平衡的同类数据,增强了泛化能力,并进一步提高了准确性。通过这种技术,MNv4-Hybrid-L在ImageNet-1K上实现了令人印象深刻的87% top-1准确率:与其教师模型相比,仅下降了0.5%,尽管其MACs减少了39倍。

2、相关工作

在准确性和效率方面优化模型是一个经过深入研究的问题。

移动卷积网络:关键工作包括MobileNetV1[20],它使用深度可分离卷积来提高效率;MobileNetV2[36]引入了线性瓶颈和倒置残差;MnasNet[40]在瓶颈中集成了轻量级注意力;MobileOne[43]在推理时添加并重新参数化倒置瓶颈中的线性分支。

高效混合网络:这一研究方向结合了卷积和注意力机制。MobileViT[33]通过全局注意力块将CNN的优势与ViT[12]相结合。MobileFormer[6]并行化了一个MobileNet和一个Transformer,并在它们之间建立了一个双向桥以进行特征融合。FastViT[42]在最后阶段添加了注意力,并在早期阶段使用大卷积核作为自注意力的替代。

高效注意力:研究集中在提高MHSA[44]的效率上。EfficientViT[13]和MobileViTv2[34]引入了具有线性复杂度的自注意力近似,对准确性影响较小。EfficientFormerV2[27]通过下采样Q、K、V来提高效率,而CMT[15]和NextViT[26]仅下采样K和V。

硬件感知的神经架构搜索(NAS):另一种常见的技术是使用硬件感知的神经架构搜索(NAS)来自动化模型设计过程。NetAdapt[49]使用经验延迟表来优化模型在目标延迟约束下的准确性。MnasNet[40]也使用延迟表,但应用强化学习来进行硬件感知的NAS。FBNet[47]通过可微分的NAS加速多任务硬件感知搜索。MobileNetV3[18]通过结合硬件感知的NAS、NetAdapt算法和架构进步,针对手机CPU进行调整。MobileNet MultiHardware[8]优化单个模型以适应多个硬件目标。Once-for-all[5]为了效率而分离训练和搜索。

3、硬件无关的帕累托效率

Roofline模型:要使模型具有普遍的效率,它必须在具有截然不同瓶颈的硬件目标上表现良好,这些瓶颈在很大程度上限制了模型的性能。这些瓶颈主要由硬件的峰值计算吞吐量和峰值内存带宽决定。

为此,我们使用Roofline模型[46],该模型可以估算给定工作负载的性能,并预测它是否受到内存瓶颈或计算瓶颈的限制。简而言之,它抽象掉了特定的硬件细节,只考虑工作负载的操作强度( L a y e r M A C s i / ( W e i g h t B y t e s i + A c t i v a t i o n B y t e s i ) LayerMACs_{i} / (WeightBytes_{i} + ActivationBytes_{i}) LayerMACsi/(WeightBytesi+ActivationBytesi))与硬件处理器和内存系统的理论限制之间的关系。内存和计算操作大致是并行发生的,因此两者中较慢的一个大致决定了延迟瓶颈。为了将Roofline模型应用于具有层索引 i 的神经网络,我们可以按如下方式计算模型推理延迟 ModelTime:
 ModelTime  = ∑ i max ⁡ (  MACTime  i ,  MemTime  i )  MACTime  i =  LayerMACs  i  PeakMACs  ,  MemTime  i =  WeightBytes  i +  ActivationBytes  i  PeakMemBW  \begin{array}{l} \text { ModelTime }=\sum_{i} \max \left(\text { MACTime }_{i}, \text { MemTime }_{i}\right) \\ \text { MACTime }_{i}=\frac{\text { LayerMACs }_{i}}{\text { PeakMACs }}, \quad \text { MemTime }_{i}=\frac{\text { WeightBytes }_{i}+\text { ActivationBytes }_{i}}{\text { PeakMemBW }} \\ \end{array}  ModelTime =imax( MACTime i, MemTime i) MACTime i= PeakMACs  LayerMACs i, MemTime i= PeakMemBW  WeightBytes i+ ActivationBytes i

在Roofline模型中,硬件行为由脊点(Ridge Point,RP)来概括——即硬件的峰值MACs与峰值MemBW之比。换句话说,这是实现最大性能所需的最小操作强度。为了针对具有广泛瓶颈的硬件进行优化,如图2和图3所示,我们分析了算法在RP从最低预期值(0 MAC/byte)到最高预期值( 500 M A C s / b y t e 500 MACs/byte 500MACs/byte)的延迟情况。更多细节见附录F。屋顶线模型只依赖于数据传输与计算的比率,因此所有具有相同RP的硬件都会按延迟对工作负载进行相同的排名。这意味着,如果新目标的RP包含在扫描范围内,那么扫描RP的屋顶线分析(见下一段)将适用于未来的硬件和软件。

在这里插入图片描述

脊点扫描分析:如图2和图3所示,屋顶线模型揭示了MobileNetV4模型如何相对于其他卷积MobileNets实现硬件无关的、主要是帕累托最优的性能。在低RP硬件(例如CPU)上,模型更可能受到计算限制而不是内存限制。因此,为了改进延迟,你会减少总MACs数量,即使这会增加内存复杂性(如MobileNetV3Large-1.5x)。在高RP硬件上,数据移动是瓶颈,因此MACs不会显著减慢模型速度,但可以增加模型容量(如MobileNetV1-1.5x)。因此,针对低RP优化的模型在高RP上运行缓慢,因为内存密集型且MACs较少的全连接(FC)层在内存带宽上成为瓶颈,无法利用高可用的PeakMACs。

MobileNetV4设计:MobileNetV4在MACs和内存带宽方面进行平衡投资,以在成本上获得最大回报,特别关注网络的开始和结束部分。在网络开始时,MobileNetV4使用大型且昂贵的初始层来显著提高模型的容量和下游准确性。这些初始层由大量的MACs主导,因此它们仅在低RP硬件上成本较高。在网络的末尾,所有MobileNetV4变体都使用相同大小的最终FC层以最大化准确性,尽管这会导致较小的MNV4变体在高RP硬件上遭受更高的FC延迟。由于大型初始Conv层在低RP硬件上昂贵,但在高RP硬件上并不昂贵,而最终FC层在高RP硬件上昂贵,但在低RP硬件上并不昂贵,因此MobileNetV4模型永远不会同时遇到两种减速情况。换句话说,MNv4模型能够使用不成比例地提高准确性的昂贵层,而不会同时遭受这些层的组合成本,从而在所有脊点上实现主要是帕累托最优的性能。

4、通用反向瓶颈

我们提出了通用反向瓶颈(UIB)块,这是一个高效网络设计的自适应构建块,具有适应各种优化目标而不增加搜索复杂性的灵活性。UIB扩展了MobileNetV2 [36]引入的反向瓶颈(IB)块,它已成为高效网络的标准构建块[12,18,32,41]。

在MobileNet最成功的元素——可分离的深度卷积(DW)、逐点(PW)扩展和投影的反向瓶颈结构的基础上,本文引入了一个新的构建块——通用反向瓶颈(UIB)块,如图4所示。其结构相当简单。我们在反向瓶颈块中引入了两个可选的DW层,一个在扩展层之前,一个在扩展层和投影层之间。这些DW层的存在与否是NAS优化程序的一部分,会产生新颖的网络架构。尽管这一修改很简单,但我们新的构建块很好地统一了几个重要的现有块,包括原始IB块、ConvNext块和ViT中的FFN块。此外,UIB还引入了一个新的变体:Extra深度卷积IB(ExtraDW)块。
在这里插入图片描述

除了允许在NAS期间使用灵活的IB结构外,我们还避免了任何人为制定的缩放规则,如EfficientNet中使用的规则,而是针对每个模型大小单独优化结构。为了避免NAS SuperNet的大小爆炸,我们共享了公共组件(逐点扩展和投影),并简单地将DW作为额外的搜索选项添加进去。与基于SuperNet的网络架构搜索算法相结合,这种方法使不同实例化之间的大部分参数(>95%)得以共享,从而使NAS极其高效。
在这里插入图片描述

UIB实例化 UIB块中的两个可选深度卷积有四种可能的实例化(如图4所示),导致不同的权衡。

反向瓶颈(IB)——在扩展特征激活上进行空间混合,以更高的成本提供更大的模型容量。

ConvNext通过在扩展之前进行空间混合,允许使用更大内核尺寸进行更便宜的空间混合。

ExtraDW是本文中引入的一个新变体,它允许以较低的成本增加网络深度和感受野。它结合了ConvNext和IB的优点。

FFN是两个1x1逐点卷积(PW)的堆叠,中间带有激活和归一化层。PW是最有利于加速器的操作之一,但与其他块一起使用时效果最佳。

在每个网络阶段,UIB提供了灵活性,以便(1)实现即时的空间和通道混合权衡;(2)根据需要扩大感受野;(3)最大化计算利用率。

5、Mobile MQA

在本节中,我们介绍Mobile MQA,这是一个专为加速器优化的新型注意力块,可提供超过39%的推理速度提升。

操作强度的重要性:最近关于视觉模型的研究主要集中在减少算术运算(MACs)以提高效率。然而,在移动加速器上,真正的性能瓶颈往往不是计算,而是内存访问。这是因为加速器提供的计算能力远远超过内存带宽。因此,仅仅减少MACs可能不会带来更好的性能。相反,我们需要考虑操作强度,即算术运算与内存访问的比率。MQA在混合模型中表现出色:MHSA [44]将查询、键和值投影到多个空间以捕获信息的不同方面。多查询注意力(MQA) [37]通过在所有头部之间共享键和值来简化这一点。虽然多个查询头是必要的,但大型语言模型可以有效地共享用于键和值的单个头,而不会牺牲准确性 [7] [25]。当批处理令牌的数量与特征维度相比相对较小时,一个共享的键和值头可以大大减少内存访问需求,从而显著提高操作强度。这通常是移动应用混合视觉模型的情况,其中注意力仅在具有高特征维度的低分辨率后期阶段中使用,并且批处理大小通常为一个。我们的实验证实了MQA在混合模型中的优势。如表1所示,与MHSA相比,MQA在EdgeTPU和Samsung S23 GPU上实现了超过39%的加速,且质量损失可忽略不计(-0.03%)。MQA还减少了超过25%的MACs和模型参数。据我们所知,我们是第一个将MQA用于移动视觉的。
在这里插入图片描述

引入不对称空间下采样:受到MQA的启发,MQA在查询、键和值之间利用不对称计算,我们在优化后的MQA块中引入了空间减少注意力(SRA) [45],以降低键和值的分辨率,同时保持高分辨率的查询。这一策略受到混合模型中空间相邻令牌之间观察到的相关性的启发,这归因于早期层中的空间混合卷积滤波器。通过不对称空间下采样,我们保持输入和输出之间的令牌数量相同,从而保持注意力的高分辨率并显著提高效率。与[45]不同,我们的方法使用步长为2的 3 × 3 3 \times 3 3×3深度卷积替换AvgPooling进行空间减少,这是一种提高模型容量的经济高效方法。

Mobile MQA。在这里,我们介绍我们的Mobile MQA块:

 MobileMQA  ( X ) = Concat ( attention  1 , … ,  attention  n ) W O  where attention  j = softmax ( ( X W Q j ) ( S R ( X ) W K ) T d k ) ( S R ( X ) W V ) \begin{aligned} \text { MobileMQA }(\mathbf{X}) & =\text{Concat}\left(\text {attention }_{1}, \ldots, \text { attention }_{n}\right) \mathbf{W}^{O} \\ \text { where attention }_{j} & =\text{softmax}\left(\frac{\left(\mathbf{X W}^{Q_{j}}\right)\left(S R(\mathbf{X}) \mathbf{W}^{K}\right)^{T}}{\sqrt{d_{k}}}\right)\left(S R(\mathbf{X}) \mathbf{W}^{V}\right) \end{aligned}  MobileMQA (X) where attention j=Concat(attention 1,, attention n)WO=softmax dk (XWQj)(SR(X)WK)T (SR(X)WV)

其中, S R SR SR表示空间减少,在我们的设计中是一个步长为2的深度卷积,或者在不使用空间减少的情况下是恒等函数。如表2所示,引入不对称空间下采样带来了超过20%的效率提升,同时精度损失极小(-0.06%)。这种设计使得Mobile MQA成为移动视觉任务中高效且准确的注意力机制。

6、MNv4模型设计

我们的设计理念:简洁与效率并存。在开发最新版的MobileNets时,我们的核心目标是实现跨多种移动平台的帕累托最优。为了实现这一目标,我们首先对现有的模型和硬件进行了广泛的相关性分析。通过实证考察,我们找到了一组组件和参数,它们既能确保在不同设备上的成本模型(预测延迟成本)之间具有高度相关性,又能接近性能上的帕累托前沿。

我们的调查揭示了以下关键见解:

多路径效率问题:尽管组卷积[52]和类似的多路径设计具有较低的浮点运算次数,但由于内存访问的复杂性,它们可能效率较低。

硬件支持的重要性:在DSP上,像Squeeze and Excite (SE)[21]、GELU[16]、LayerNorm[1]等高级模块的支持并不完善。LayerNorm在性能上也落后于BatchNorm[23],而SE在加速器上的运行速度较慢。

简洁的力量:传统的组件——深度卷积、逐点卷积、ReLU [35]、BatchNorm以及简单的注意力机制(如MHSA)展现了卓越的效率和硬件兼容性。

基于这些发现,我们确立了一系列设计原则:

  • 标准组件:我们优先考虑广泛支持的元素,以实现无缝部署和硬件效率。

  • 灵活的UIB块:我们创新的可搜索UIB构建块允许灵活的空间和通道混合、感受野调整以及最大化计算利用率,通过网络架构搜索(NAS)在效率和准确性之间实现平衡妥协。

  • 采用直观的注意力机制:我们的Mobile MQA机制以简洁性为优先,以实现最佳性能。

这些原则使得MobileNetV4在所有评估的硬件上都能实现大部分的帕累托最优。接下来,我们将详细阐述我们针对UIB模型搜索的精炼NAS方法,概述各种MNv4-Conv模型尺寸的具体搜索配置,并解释混合模型的构建过程。

6.1、精炼NAS以增强架构

为了有效地实例化UIB块,我们采用TuNAS[3]并进行定制增强以提高性能。

增强的搜索策略:我们的方法通过实施两阶段搜索,缓解了TuNAS由于参数共享而偏向较小滤波器和扩展因子的倾向。这种策略解决了UIB的深度卷积层与其他搜索选项之间参数数量的差异。

粗粒度搜索:首先,我们专注于确定最优滤波器大小,同时保持参数固定:采用具有默认扩展因子为4和3x3深度卷积核的反转瓶颈块。

细粒度搜索:基于初步搜索的结果,我们搜索UIB的两个深度卷积层的配置(包括它们的存在与否以及3x3或5x5的卷积核大小),同时将扩展因子保持在4。
在这里插入图片描述

表3展示了与传统单阶段搜索相比,通过我们的两阶段搜索实现的增强效率和模型质量提升。在单阶段搜索中,使用一个TuNAS过程探索统一的搜索空间。

使用鲁棒训练增强TuNAS:TuNAS的成功取决于准确评估架构质量,这对于奖励计算和策略学习至关重要。最初,TuNAS利用ImageNet-1k来训练SuperNet,但ImageNet上的模型性能明显受到数据增强、正则化和超参数选择的影响。鉴于TuNAS不断演变的架构样本,找到一组稳定的超参数是具有挑战性的。

在这里插入图片描述

我们通过使用离线蒸馏数据集来解决这个问题,从而消除了对额外增强的需求,并降低了对正则化和优化设置的敏感性。JFT蒸馏数据集(详见第8节)作为我们TuNAS的训练集,在表4中展示了显著的改进。我们承认,在长时间的训练过程中,深度扩展的模型通常优于宽度扩展的模型[2],因此我们将TuNAS的训练周期延长至750个周期,从而得到更深、质量更高的模型。

6.2、MNv4模型的优化

我们使用NAS优化的UIB块构建了MNv4-Conv模型,并根据特定的资源约束进行了定制。更多细节见附录A。与其他混合模型一致,我们发现将注意力添加到卷积模型的最后阶段最为有效。在MNv4-Hybrid模型中,我们将Mobile MQA块与UIB块交错使用,以增强性能。有关模型的全面规格,请参阅附录D。

7、结果

在本节中,我们展示了MobileNet V4(MNv4)模型在ImageNet-1K分类和COCO目标检测任务上的大多数Pareto最优性能。

7.1、ImageNet分类

实验设置:为了评估模型架构的性能,我们遵循标准协议,仅使用ImageNet-1k [11]的训练集进行训练,并在其验证集上测量Top-1准确率。我们的延迟分析涵盖了多种具有代表性的移动硬件设备,包括ARM Cortex CPU(Pixel 6,Samsung S23)、Qualcomm Hexagon DSP(Pixel 4)、ARM Mali GPU(Pixel 7)、Qualcomm Snapdragon(S23 GPU)、Apple Neural Engine和Google EdgeTPU。我们的完整训练设置详见附录C。

在基准测试中,我们将我们的模型与领先的高效模型进行比较,包括混合模型(MiT-EfficientViT [13]、FastViT [42]、NextViT [26])和卷积模型(MobileOne [43]、ConvNext [32]以及之前的MobileNet版本[19]、[36]、[18]),比较依据是它们报告的Top-1准确率和我们的延迟评估。值得注意的是,我们采用现代训练策略对MobileNet系列(V1、V2、V3)进行了增强,实现了显著的准确率提升:MobileNet V1提升了3.4%至74.0%,V2提升了1.4%至73.4%,V3提升了0.3%至75.5%。这些增强的MobileNet基线模型在整篇论文中用于隔离架构上的进步。
结果:
在这里插入图片描述

如图1所示并在表5中详细列出,我们的结果证明,MNv4模型在各种准确率目标和移动硬件(包括CPU、DSP、GPU以及像Apple Neural Engine和Google EdgeTPU这样的专用加速器)上大多达到了Pareto最优。

在CPU上,MNv4模型的表现尤为出色,其速度大约是MobileNetV3的两倍,并且在相同准确率目标下,与其他模型相比速度要快几倍。在EdgeTPU上,MNv4模型在相同准确率水平下的速度是MobileNet V3的两倍。具体来说,MNv4-Conv-M模型比MobileOne-S4和FastViT-S12快超过50%,同时在可比延迟下比MobileNet V2的Top-1准确率提高了1.5%。在S23 GPU和iPhone 13 CoreML(ANE)上,MNv4模型大多位于Pareto前沿。MIT-EfficientViT是S23 GPU上最接近的竞争对手,但在CoreML上,MNv4的延迟是其一半,而准确率相同。FastViT针对Apple Neural Engine进行了优化,在CoreML上排名第二,但在S23 GPU上的延迟是MNv4的5倍以上。与许多混合模型一样,MNv4-Hybrid模型与DSP不兼容。然而,MNv4-Conv模型在DSP上仍然是表现最佳的,这强调了它们在不同硬件平台上的卓越兼容性和效率。MNv4-Conv模型提供了出色的硬件兼容性和效率。这一成功凸显了我们UIB块的强大、增强的NAS策略以及精心设计的搜索空间的优点。MNv4-Hybrid在CPU和加速器上实现了卓越性能,证明了我们Mobile MQA设计的跨平台效率。

通用性对于移动模型至关重要,要求它们能够在各种硬件平台上实现最佳性能。我们的评估强调了现有模型在实现这一目标时面临的挑战。MobileNet V3 在 CPU 上表现出色,但在 EdgeTPU、DSP 和 GPU 上表现不佳。FastViT 在 Apple Neural Engine 上表现良好,但在 CPU 和 GPU 上表现不佳。EfficientViT 在 GPU 上表现良好,但在 Apple Neural Engine 上表现不佳。相比之下,MNv4-Conv 模型表现出出色的兼容性,并在包括 CPU、GPU、Apple Neural Engine 和 Google EdgeTPU 在内的各种硬件上实现了普遍的帕累托最优性能。这种多功能性确保了 MNv4-Conv 模型可以在移动生态系统中无缝部署,而无需进行任何针对平台的调整,从而为移动模型通用性设定了新的基准。
7.2 COCO 目标检测

实验设置:我们在COCO 17 [31] 数据集上评估了MNv4骨干网络在目标检测任务上的有效性。我们将M尺寸的MNv4骨干网络与具有相似MAC(乘法累加操作数)数量的当前最先进(SOTA)高效骨干网络进行了比较。对于每个骨干网络,我们使用RetinaNet [30] 框架构建了一个目标检测器。我们在P3到P7的端点上附加了一个256维的FPN [29] 解码器,以及一个具有4个卷积层的256维预测头。与移动检测器一样,我们采用深度可分离卷积来降低FPN解码器和边界框预测头的计算复杂度。我们在COCO 17 [31] 训练集上对所有模型进行了600个周期的训练。所有图像都被调整为384像素×384像素的大小,并使用随机水平翻转、随机缩放以及Randaug [9] 进行增强。我们从Randaug中排除了剪切和旋转增强,因为这些变形会损害小物体的检测精度。训练使用了2048的批次大小、Adam优化器 [24] 和0.00003的L2权重衰减。我们采用了带有24个周期预热期的余弦学习率调度,并为每个模型单独调整学习率。对于所有基线,我们设置了滤波器乘数,以便MACs大致相当。按照分类实验的做法,我们使用0.2的随机丢弃率 [22] 来训练MobileNet V4骨干网络。所有MobileNet基线都是使用官方的Tensorflow Model Garden [17] 实现进行训练的。我们在Tensorflow中重新实现了EfficientFormer。
在这里插入图片描述

结果:实验结果如表6所示。参数、MAC(乘法累加操作数)和基准测试是使用整个检测器在384像素×384像素输入分辨率下计算的。中等尺寸的仅包含卷积层的MNv4-Conv-M检测器达到了32.6%的AP(平均精度),这与MobileNet Multi-AVG和MobileNet v2相近。然而,该模型在Pixel 6 CPU上的延迟比MobileNet Multi-AVG低12%,比MobileNet v2低23%。在Pixel 6 CPU上延迟增加18%的情况下,添加Mobile MQA块使MNv4-Hybrid-M检测器的AP比MNv4-Conv-M提高了+1.6%,这证明了MNv4在混合形式下对于像目标检测这样的任务的有效性和效率。

8、增强蒸馏方案

除了架构创新外,蒸馏是提升机器学习效率的强大工具。对于移动模型来说,其优势尤为显著,在严格的部署约束条件下,可能带来数倍的效率提升。在强大的Patient Teacher蒸馏基线$ [4] $的基础上,我们引入了两项新技术来进一步提升性能。

动态数据集混合:数据增强对于蒸馏性能至关重要。尽管先前的方法依赖于固定的增强序列,但我们发现,在训练过程中动态混合具有不同增强策略的多个数据集,可以带来更好的蒸馏效果。我们尝试了以下三个关键的蒸馏数据集:

  • D 1 \mathcal{D}_{1} D1:对500个ImageNet-1k副本应用Inception Crop$ [39] ,然后应用 R a n d A u g m e n t ,然后应用RandAugment ,然后应用RandAugment [10] $ 12m9。
  • D 2 \mathcal{D}_{2} D2:对1000个ImageNet 1k副本应用Inception Crop,然后应用极端Mixup$ [51] $(镜像Patient Teacher方法)。
  • D 1 + D 2 \mathcal{D}_{1}+\mathcal{D}_{2} D1+D2:在训练过程中动态混合 D 1 \mathcal{D}_{1} D1 D 2 \mathcal{D}_{2} D2

我们的表7中的结果显示, D 2 \mathcal{D}_{2} D2在学生模型准确率方面优于 D 1 \mathcal{D}_{1} D1 84.1 % 84.1\% 84.1%对比 83.8 % 83.8\% 83.8%)。然而,动态混合数据集 ( D 1 + D 2 ) \left(\mathcal{D}_{1}+\mathcal{D}_{2}\right) (D1+D2)将准确率提升至 84.4 % 84.4\% 84.4%(提升 + 0.3 % +0.3\% +0.3%)。这一发现表明,数据集混合扩展了增强图像空间,增加了难度和多样性,最终提高了学生模型的性能。

JFT数据增强:为了增加训练数据量,我们通过重新采样JFT-300M[38]数据集,为每个类别增加13万个域内、类别平衡的数据(总计1.3亿张图片)。遵循Noisy Student[48]协议,并使用在ImageNet-1K上训练的EfficientNet-B0,我们选择了相关性阈值高于0.3的图像。对于数据丰富的类别,我们选择前13万个图像;对于稀有类别,我们复制图像以保持平衡。这个数据集被复制了10次。由于JFT的复杂性,我们采用了较弱的数据增强方法(Inception Crop + RandAugment 12m5)。这构成了蒸馏数据集 D 3 \mathcal{D}_{3} D3。表7显示,仅使用JFT( D 3 \mathcal{D}_{3} D3)会导致准确率下降 2 % 2\% 2%。然而,将JFT与ImageNet数据结合使用,准确率提升了 0.6 % 0.6\% 0.6%,这证明了额外数据对于泛化能力的价值。
在这里插入图片描述

我们的蒸馏方案:我们的综合蒸馏方案动态混合了 D 1 \mathcal{D}_{1} D1 D 2 \mathcal{D}_{2} D2 D 3 \mathcal{D}_{3} D3数据集,以实现多样化的增强,并利用类别平衡的JFT数据。如表7和表8所示,我们的方法相较于先前的SOTA[4]方法,实现了超过 0.8 % 0.8\% 0.8%的top-1准确率的一致提升。训练一个MNv4-Conv-L学生模型,经过2000个周期,达到了 85.9 % 85.9\% 85.9%的top-1准确率。这证明了我们方法的有效性:学生模型的参数仅为教师模型EfficientNet-L2的 1 / 15 1/15 1/15,计算量(MACs)也仅为教师模型的 1 / 48 1/48 1/48,但准确率仅下降了 1.6 % 1.6\% 1.6%。当将蒸馏与JFT预训练结合时,MNv4-Conv-Hybrid达到了 87.0 % 87.0\% 87.0%的top-1准确率。

9、结论

在本文中,我们提出了MobileNetV4,一系列通用且高效的模型,经过调优,可在移动生态系统上高效运行。我们利用多项技术进展,使MobileNetV4在所有移动CPU、GPU、DSP和专用加速器上实现了近似最优的性能,这是其他测试过的模型所不具备的特点。我们引入了新的通用反转瓶颈和Mobile MQA层,并与改进的NAS方案相结合。结合这些技术与新颖的、最先进的蒸馏方法,我们在Pixel 8 EdgeTPU上实现了 87 % 87\% 87%的ImageNet-1K准确率,延迟仅为 3.8   m s 3.8\mathrm{~ms} 3.8 ms,从而推动了移动计算机视觉技术的最新进展。此外,我们还引入了一个理论框架和分析,以理解是什么使模型在异构设备上具有通用性,为未来的设计指明了方向。我们希望这些新颖的贡献和分析框架能够进一步推动移动计算机视觉领域的发展。

10、致谢

我们要感谢Tammo Spalink、Yeqing Li、Bob Muniz、David Wood和Lynn Nguyen在开发这项工作过程中的支持。

A、搜索空间细节

在构建NAS(神经网络架构搜索)的搜索空间时,以下是一些具体的步骤和细节:

首先,构建搜索空间需要确定网络架构的初始层和头部层。在初始阶段,我们采用一个Conv2D层(3x3卷积核,步长为2)来快速降低分辨率。接着,在第二阶段,我们使用NAS优化的FusedIB块(步长为2)来平衡效率和准确性。

在NAS驱动的优化过程中,NAS算法会精确地确定剩余四个阶段中UIB块的数量和参数实例化,以确保网络结构的性能达到最优。

至于头部层,我们采用与MobileNet V3相同的配置。

我们观察到,在UIB块内的逐点卷积在高分辨率下往往表现出较低的操作强度,因此我们在初始层中优先使用计算密度较高的操作,以平衡效率和准确性。

我们的优化目标包括:

  • MNv4-Conv-S:双目标——285M MACs和0.2ms延迟(Pixel 6 EdgeTPU,224px输入)。
  • MNv4-Conv-M:0.6ms延迟(Pixel 6 EdgeTPU,256px输入)。
  • MNv4-Conv-L:双延迟目标——2.3ms(Pixel 6 EdgeTPU)和2.0ms(Pixel 7 EdgeTPU),使用384px输入。

值得注意的是,通过将搜索空间限制为在设备上具有良好相关成本模型的组件,我们发现EdgeTPU延迟优化直接产生了普遍高效的模型,这在后续部分中得到了证明。

B、基准测试方法论

我们在各种移动平台上采用了一致的基准测试策略,苹果神经网络引擎(Apple Neural Engine)除外。为了提高效率,模型被转换为TensorFlow Lite格式,并对移动CPU、Hexagon和EdgeTPU进行了INT8量化,而移动GPU则使用了FP16。我们每个模型运行1000次,并取这些运行结果的平均延迟。然后,我们对每个模型重复这个过程5次,并报告平均值的中位数。为了优化性能,我们将CPU亲和性设置为最快的核心,并使用XNNPACK后端进行CPU评估。相比之下,在苹果神经网络引擎上的基准测试(在装有iOS 16.6.1、CoreMLTools 7.1和Xcode 15.0.1的iPhone 13上进行,用于性能分析)中,我们将PyTorch模型转换为CoreML的MLProgram格式,并使用float16精度和float16 MultiArray输入,以最小化输入复制。

C、ImageNet-1k分类任务的训练设置

为了提升模型性能,我们的训练方案采用了广泛采用的数据增强技术和正则化方法。在数据增强方面,我们使用了Inception Crop[39]、水平翻转、RandAugment[9]、Mixup[51]和CutMix[50]。在正则化方面,我们应用了L2归一化和随机深度丢弃[22]。根据模型大小,我们对增强和正则化的强度进行了调整,具体细节如表9所示。

在这里插入图片描述

D、模型细节

我们的MNv4模型架构细节从表10至表14进行了描述。

现在,让我们详细探讨TuNAS优化后的MNv4-Conv模型的细节。TuNAS优化后的宏观架构策略性地结合了四种UIB实例化:Extra DW、ConvNext、IB和FFN。这种组合展示了UIB的灵活性以及在网络不同阶段使用不同实例化块的重要性。具体来说,在每个可搜索阶段的开始,当空间分辨率显著下降时,Extra DW成为首选。Extra DW中双深度卷积层的设计有助于扩大感受野,增强空间混合,并有效缓解分辨率损失。类似地,出于相同的原因,Extra DW在MNv4Conv模型的早期阶段也经常被选择。对于最终层,由于前面的层已经进行了大量的空间混合,因此选择FFN和ConvNext,因为通道混合提供了更大的增量增益。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

E、更大的帕累托曲线

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

F、额外的屋顶线分析

这部分将图3的分析扩展到包括MobileNetV4-Conv-Small(图7)、MobileNetV4-Conv-Medium(图8)和MobileNetV4-Conv-Large(图9)。这些图还从0.0 MACs/byte脊点(仅MACs,无限内存带宽)到500.0 MACs/byte脊点(类似加速器,内存带宽瓶颈)的扫描中分解了每个数量级。此外,还包括了测量延迟、经验拟合屋顶线模型和MACs计数之间的相关性分析(表15和图6)。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码

"""
Creates a MobileNetV4 Model as defined in:
Danfeng Qin, Chas Leichner, Manolis Delakis, Marco Fornoni, Shixin Luo, Fan Yang, Weijun Wang, Colby Banbury, Chengxi Ye, Berkin Akin, Vaibhav Aggarwal, Tenghui Zhu, Daniele Moro, Andrew Howard. (2024).
MobileNetV4 - Universal Models for the Mobile Ecosystem
arXiv preprint arXiv:2404.10518.
"""

import torch
import torch.nn as nn
import math

__all__ = ['mobilenetv4_conv_small', 'mobilenetv4_conv_medium', 'mobilenetv4_conv_large']


def make_divisible(value, divisor, min_value=None, round_down_protect=True):
    if min_value is None:
        min_value = divisor
    new_value = max(min_value, int(value + divisor / 2) // divisor * divisor)
    # Make sure that round down does not go down by more than 10%.
    if round_down_protect and new_value < 0.9 * value:
        new_value += divisor
    return new_value


class ConvBN(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, stride=1):
        super(ConvBN, self).__init__()
        self.block = nn.Sequential(
            nn.Conv2d(in_channels, out_channels, kernel_size, stride, (kernel_size - 1) // 2, bias=False),
            nn.BatchNorm2d(out_channels),
            nn.ReLU(inplace=True),
        )

    def forward(self, x):
        return self.block(x)


class UniversalInvertedBottleneck(nn.Module):
    def __init__(self,
                 in_channels,
                 out_channels,
                 expand_ratio,
                 start_dw_kernel_size,
                 middle_dw_kernel_size,
                 stride,
                 middle_dw_downsample: bool = True,
                 use_layer_scale: bool = False,
                 layer_scale_init_value: float = 1e-5):
        super(UniversalInvertedBottleneck, self).__init__()
        self.start_dw_kernel_size = start_dw_kernel_size
        self.middle_dw_kernel_size = middle_dw_kernel_size

        if start_dw_kernel_size:
            self.start_dw_conv = nn.Conv2d(in_channels, in_channels, start_dw_kernel_size,
                                           stride if not middle_dw_downsample else 1,
                                           (start_dw_kernel_size - 1) // 2,
                                           groups=in_channels, bias=False)
            self.start_dw_norm = nn.BatchNorm2d(in_channels)

        expand_channels = make_divisible(in_channels * expand_ratio, 8)
        self.expand_conv = nn.Conv2d(in_channels, expand_channels, 1, 1, bias=False)
        self.expand_norm = nn.BatchNorm2d(expand_channels)
        self.expand_act = nn.ReLU(inplace=True)

        if middle_dw_kernel_size:
            self.middle_dw_conv = nn.Conv2d(expand_channels, expand_channels, middle_dw_kernel_size,
                                            stride if middle_dw_downsample else 1,
                                            (middle_dw_kernel_size - 1) // 2,
                                            groups=expand_channels, bias=False)
            self.middle_dw_norm = nn.BatchNorm2d(expand_channels)
            self.middle_dw_act = nn.ReLU(inplace=True)

        self.proj_conv = nn.Conv2d(expand_channels, out_channels, 1, 1, bias=False)
        self.proj_norm = nn.BatchNorm2d(out_channels)

        if use_layer_scale:
            self.gamma = nn.Parameter(layer_scale_init_value * torch.ones((out_channels)), requires_grad=True)

        self.use_layer_scale = use_layer_scale
        self.identity = stride == 1 and in_channels == out_channels

    def forward(self, x):
        shortcut = x

        if self.start_dw_kernel_size:
            x = self.start_dw_conv(x)
            x = self.start_dw_norm(x)

        x = self.expand_conv(x)
        x = self.expand_norm(x)
        x = self.expand_act(x)

        if self.middle_dw_kernel_size:
            x = self.middle_dw_conv(x)
            x = self.middle_dw_norm(x)
            x = self.middle_dw_act(x)

        x = self.proj_conv(x)
        x = self.proj_norm(x)

        if self.use_layer_scale:
            x = self.gamma * x

        return x + shortcut if self.identity else x


class MobileNetV4(nn.Module):
    def __init__(self, block_specs, num_classes=1000):
        super(MobileNetV4, self).__init__()

        c = 3
        layers = []
        for block_type, *block_cfg in block_specs:
            if block_type == 'conv_bn':
                block = ConvBN
                k, s, f = block_cfg
                layers.append(block(c, f, k, s))
            elif block_type == 'uib':
                block = UniversalInvertedBottleneck
                start_k, middle_k, s, f, e = block_cfg
                layers.append(block(c, f, e, start_k, middle_k, s))
            else:
                raise NotImplementedError
            c = f
        self.features = nn.Sequential(*layers)
        self.channels = [64, 128, 256, 512]
        self.indexs=[2,4,15,28]
        self._initialize_weights()

    def forward(self, x):
        out=[]
        for i in range(len(self.features)):
            x = self.features[i](x)
            if i in self.indexs:
                out.append(x)
            # print(x.shape)
        return out

    def _initialize_weights(self):
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
                m.weight.data.normal_(0, math.sqrt(2. / n))
                if m.bias is not None:
                    m.bias.data.zero_()
            elif isinstance(m, nn.BatchNorm2d):
                m.weight.data.fill_(1)
                m.bias.data.zero_()


def mobilenetv4_conv_small(**kwargs):
    """
    Constructs a MobileNetV4-Conv-Small model
    """
    block_specs = [
        # conv_bn, kernel_size, stride, out_channels
        # uib, start_dw_kernel_size, middle_dw_kernel_size, stride, out_channels, expand_ratio
        # 112px
        ('conv_bn', 3, 2, 32),
        # 56px
        ('conv_bn', 3, 2, 32),
        ('conv_bn', 1, 1, 32),
        # 28px
        ('conv_bn', 96, 3, 2),
        ('conv_bn', 64, 1, 1),
        # 14px
        ('uib', 5, 5, 2, 96, 3.0),  # ExtraDW
        ('uib', 0, 3, 1, 96, 2.0),  # IB
        ('uib', 0, 3, 1, 96, 2.0),  # IB
        ('uib', 0, 3, 1, 96, 2.0),  # IB
        ('uib', 0, 3, 1, 96, 2.0),  # IB
        ('uib', 3, 0, 1, 96, 4.0),  # ConvNext
        # 7px
        ('uib', 3, 3, 2, 128, 6.0),  # ExtraDW
        ('uib', 5, 5, 1, 128, 4.0),  # ExtraDW
        ('uib', 0, 5, 1, 128, 4.0),  # IB
        ('uib', 0, 5, 1, 128, 3.0),  # IB
        ('uib', 0, 3, 1, 128, 4.0),  # IB
        ('uib', 0, 3, 1, 128, 4.0),  # IB
        ('conv_bn', 1, 1, 960),  # Conv
    ]
    return MobileNetV4(block_specs, **kwargs)


def mobilenetv4_conv_medium(**kwargs):
    """
    Constructs a MobileNetV4-Conv-Medium model
    """
    block_specs = [
        ('conv_bn', 3, 2, 32),
        ('conv_bn', 3, 2, 128),
        ('conv_bn', 1, 1, 48),
        # 3rd stage
        ('uib', 3, 5, 2, 80, 4.0),
        ('uib', 3, 3, 1, 80, 2.0),
        # 4th stage
        ('uib', 3, 5, 2, 160, 6.0),
        ('uib', 3, 3, 1, 160, 4.0),
        ('uib', 3, 3, 1, 160, 4.0),
        ('uib', 3, 5, 1, 160, 4.0),
        ('uib', 3, 3, 1, 160, 4.0),
        ('uib', 3, 0, 1, 160, 4.0),
        ('uib', 0, 0, 1, 160, 2.0),
        ('uib', 3, 0, 1, 160, 4.0),
        # 5th stage
        ('uib', 5, 5, 2, 256, 6.0),
        ('uib', 5, 5, 1, 256, 4.0),
        ('uib', 3, 5, 1, 256, 4.0),
        ('uib', 3, 5, 1, 256, 4.0),
        ('uib', 0, 0, 1, 256, 4.0),
        ('uib', 3, 0, 1, 256, 4.0),
        ('uib', 3, 5, 1, 256, 2.0),
        ('uib', 5, 5, 1, 256, 4.0),
        ('uib', 0, 0, 1, 256, 4.0),
        ('uib', 0, 0, 1, 256, 4.0),
        ('uib', 5, 0, 1, 256, 2.0),
    ]

    return MobileNetV4(block_specs, **kwargs)


def mobilenetv4_conv_large(**kwargs):
    """
    Constructs a MobileNetV4-Conv-Large model
    """
    block_specs = [
        ('conv_bn', 3, 2, 24),
        ('conv_bn', 3, 2, 96),
        ('conv_bn', 1, 1, 64),
        ('uib', 3, 5, 2, 128, 4.0),
        ('uib', 3, 3, 1, 128, 4.0),
        ('uib', 3, 5, 2, 256, 4.0),
        ('uib', 3, 3, 1, 256, 4.0),
        ('uib', 3, 3, 1, 256, 4.0),
        ('uib', 3, 3, 1, 256, 4.0),
        ('uib', 3, 5, 1, 256, 4.0),
        ('uib', 5, 3, 1, 256, 4.0),
        ('uib', 5, 3, 1, 256, 4.0),
        ('uib', 5, 3, 1, 256, 4.0),
        ('uib', 5, 3, 1, 256, 4.0),
        ('uib', 5, 3, 1, 256, 4.0),
        ('uib', 3, 0, 1, 256, 4.0),
        ('uib', 5, 5, 2, 512, 4.0),
        ('uib', 5, 5, 1, 512, 4.0),
        ('uib', 5, 5, 1, 512, 4.0),
        ('uib', 5, 5, 1, 512, 4.0),
        ('uib', 5, 0, 1, 512, 4.0),
        ('uib', 5, 3, 1, 512, 4.0),
        ('uib', 5, 0, 1, 512, 4.0),
        ('uib', 5, 0, 1, 512, 4.0),
        ('uib', 5, 3, 1, 512, 4.0),
        ('uib', 5, 5, 1, 512, 4.0),
        ('uib', 5, 0, 1, 512, 4.0),
        ('uib', 5, 0, 1, 512, 4.0),
        ('uib', 5, 0, 1, 512, 4.0),
    ]

    return MobileNetV4(block_specs, **kwargs)


if __name__ == "__main__":
    init = torch.randn(1, 3, 640, 640).cuda()
    models = mobilenetv4_conv_large().cuda()
    print(models)
    out = models(init)
    for i in out:
        print(i.shape)

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-10 00:28:02       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-10 00:28:02       100 阅读
  3. 在Django里面运行非项目文件

    2024-06-10 00:28:02       82 阅读
  4. Python语言-面向对象

    2024-06-10 00:28:02       91 阅读

热门阅读

  1. C++ 标准库string

    2024-06-10 00:28:02       30 阅读
  2. Flask 实现增改及分页查询的完整 Demo

    2024-06-10 00:28:02       30 阅读
  3. LeetCode110. 平衡二叉树

    2024-06-10 00:28:02       32 阅读
  4. 【risc-v】arm和riscv有什么关系或者联系?

    2024-06-10 00:28:02       41 阅读
  5. 防火墙端口定时开放工具v2

    2024-06-10 00:28:02       44 阅读
  6. Python有什么功能:探索Python的无限可能

    2024-06-10 00:28:02       33 阅读
  7. 结构体构造函数

    2024-06-10 00:28:02       38 阅读
  8. Cweek4+5

    Cweek4+5

    2024-06-10 00:28:02      26 阅读
  9. C++查看编译后的代码

    2024-06-10 00:28:02       38 阅读
  10. C++迈向精通:STL的Deque复现

    2024-06-10 00:28:02       29 阅读
  11. 【DevOps】OpenVPN 实现分流的几种方法和实战

    2024-06-10 00:28:02       56 阅读