图像分类(六) 全面解读复现MobileNetV1-V3

MobileNetV1

前言

MobileNetV1网络是谷歌团队在2017年提出的,专注于移动端和嵌入设备的轻量级CNN网络,相比于传统的神经网络,在准确率小幅度降低的前提下大大减少模型的参数与运算量。相比于VGG16准确率减少0.9%,但模型的参数只有VGG1/32。

其实简单来说,就是把VGG中的标准卷积层换成深度可分离卷积。不过这个深度可分离卷积刚开始接触比较抽象难理解,建议大家看看文末链接里大佬的讲解视频噢!也欢迎大家在评论区讨论 (ฅ´ω`ฅ)~

学习资料:

  • 论文题目:《MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications》(《MobileNets:用于移动视觉应用的高效卷积神经网络》)
  • **原文地址:**https://arxiv.org/abs/1704.04861
  • **项目地址:**https://github.com/Zehaos/MobileNet

Abstract—摘要

翻译

我们提出了一类有效的模型称为移动和嵌入式视觉应用的移动网络。MobileNets是基于流线型架构,使用深度可分卷积来建立轻量级深度神经网络。我们介绍了两个简单的全局超参数,它们可以有效地在延迟和准确性之间进行权衡。这些超参数允许模型构建者根据问题的约束为其应用程序选择适当大小的模型。我们在资源和精度权衡方面进行了大量的实验,并与其他流行的ImageNet分类模型相比,显示了较强的性能。然后,我们演示了MobileNets在广泛的应用和用例中的有效性,包括目标检测、细粒度分类、人脸属性和大规模地理定位。

精读

本文主要工作

(1)提出了一个可在移动端应用的高效网络MobileNets,其使用深度可分类卷积使网络轻量化同时保证精度。

(2)设计了两个控制网络大小全局超参数,通过这两个超参数来进行速度 (时间延迟)和准确率的权衡,使用者可以根据设备的限制调整网络。

(3)在ImageNet分类集上与其他模型进行了广泛对比,验证了MobileNets的有效性。

Introduction—简介

翻译

自从AlexNet通过赢得ImageNet挑战赛:ILSVRC 2012普及了深度卷积神经网络以来,卷积神经网络在计算机视觉中变得无处不在。为了获得更高的精度,一般的趋势是构建更深更复杂的网络。然而,这些提高准确性的进步并不一定使网络在规模和速度方面更有效率。在机器人、自动驾驶汽车和增强现实等许多现实应用中,识别任务需要在一个计算能力有限的平台上及时执行。

本文描述了一种高效的网络架构和两个超参数,以便构建非常小的、低延迟的模型,可以很容易地满足移动和嵌入式视觉应用程序的设计要求。第2节回顾了以前在构建小模型方面的工作。第3节描述了MobileNet架构和两个超参数宽度乘法器和分辨率乘法器,以定义更小和更有效的MobileNet。第4节描述了在ImageNet上的实验以及各种不同的应用程序和用例。第5节以总结和结论结束。

精读

文章这一部分主要是简要介绍了一下卷积神经网络的发展和应用,然后引出自己提出的MobileNets网络,指出其在移动端应用方面的有效性,最后介绍本篇论文的写作框架。

img

Prior Work—先前的工作

翻译

在最近的文献中,人们对构建小型而高效的神经网络的兴趣越来越大。许多不同的方法可以大致分为压缩预训练网络和直接训练小型网络。本文提出了一类网络体系结构,它允许模型开发人员为其应用程序选择与资源限制(延迟、大小)匹配的小型网络。MobileNets主要关注于优化延迟,但也产生小的网络。许多关于小型网络的论文只关注规模而不考虑速度。mobilenet最初是由[26]中引入的深度可分卷积构建的,随后在Inception模型[13]中使用,以减少前几层的计算。扁平网络[16]构建了一个完全因数分解卷积的网络,并展示了高度因数分解网络的潜力。与本文无关,分解网络[34]引入了一个类似的分解卷积以及拓扑连接的使用。随后,Xception网络[3]演示了如何向上扩展深度可分离的过滤器,以执行Inception V3网络。另一个小型网络是Squeezenet[12],它使用瓶颈方法来设计一个非常小的网络。其他简化计算网络包括结构变换网络[28]和油炸卷积网络[37]。

另一种获得小型网络的方法是缩小、分解或压缩预先训练好的网络。文献中提出了基于产品量化[36]、哈希[2]、剪枝、矢量量化和霍夫曼编码[5]的压缩方法。此外,还提出了各种因数分解方法来加速预先训练好的网络[14,20]。另一种训练小网络的方法是蒸馏[9],它使用一个更大的网络来教一个更小的网络。它是对我们的方法的补充,并在第4节中介绍了我们的一些用例。另一种新兴的方法是低比特网络[4,22,11]。

精读

以前的方法

  • 压缩预训练网络
  • 直接训练小网络

相关轻量化网络

  • **Inception网络:**使用深度可分离卷积减少前几层的计算量。
  • **Flattened网络:**利用完全的因式分解的卷积网络构建模型,显示出完全分解网络的潜力。
  • **Factorized Networks :**引入了类似的分解卷积以及拓扑连接的使用。
  • **Xception网络:**演示了如何按比例扩展深度可分离卷积核。
  • **Squeezenet网络:**使用一个bottleneck用于构建小型网络。

建立小型高效的神经网络两种方法

(1)压缩预训练模型:

  • ①减小、分解或压缩预训练网络,例如量化压缩(product quantization)、哈希(hashing )、剪枝(pruning)、矢量编码( vector quantization)和霍夫曼编码(Huffman coding)等
  • ②各种分解因子,用来加速预训练网络

(2)蒸馏:

使用大型网络指导小型网络

MobileNet Architecture— MobileNet结构

Depthwise Separable Convolution—深度可分离卷积

翻译

标准的卷积层将作为输入DF×DF×M功能映射F和产生一个DF×DF×N特性图G, DF是输入特征图的高度和宽度,M是输入通道的数量(输入深度),DG是一个正方形的空间宽度和高度输出特性图和N是输出通道输出(深度)的数量。标准卷积层由大小为DK×DK×M×N的卷积核K参数化,其中DK为假设为平方的核的空间维数,M为输入通道数,N为前面定义的输出通道数。假设stride为1,padding为1,计算标准卷积的输出特征图为:

img

标准卷积的计算成本为:

img

其中,计算代价乘上输入通道M的数量,输出通道N的数量,核大小Dk×Dk, feature map大小DF×DF。MobileNet模型解决了这些术语及其相互作用。首先,它使用深度可分卷积来打破输出通道数量和内核大小之间的交互。标准卷积运算的作用是基于卷积核对特征进行滤波,并结合特征得到新的表示。滤波和组合步骤可分为两个步骤,通过使用分解卷积称为深度可分卷积,以大幅降低计算成本。深度可分卷积由两层构成:深度卷积和点卷积。我们使用深度卷积为每个输入通道应用一个过滤器(输入深度)。点态卷积,一个简单的1×1卷积,然后用来创建一个线性组合的输出的深度层。MobileNets对两个层都使用batchnorm和ReLU非线性。每个输入通道一个滤波器的深度卷积(输入深度)可表示为:

img

其中K为大小为DK×DK×M的深度卷积核,其中K中的第M个滤波器应用于F中的第M个信道,得到滤波后的输出特征映射G^的第M个信道。深度卷积的计算代价为:

img

深度卷积相对于标准卷积是非常有效的。但是,它只过滤输入通道,而不将它们组合起来创建新特性。因此,需要通过1×1的卷积来计算深度卷积输出的线性组合,以生成这些新特性。深度卷积和1×1(点态)卷积的组合称为深度可分离卷积,最早是在[26]中引入的。深度可分卷积的代价:

img

它是深度卷积和1×1点卷积的和。将卷积表示为滤波和组合的两步过程,计算量减少为:

img

MobileNet使用3×3深度可分卷积,它使用的计算量是标准卷积的8到9倍,仅在精度上略有降低,如第4节所示。空间维度上的额外因式分解,并没有节省很多额外的计算,因为深度卷积的计算量很少。

精读

标准卷积

标准卷积我们已经很熟悉了,直接看下图吧:

img

方法

img

Dk×Dk×M×Df×Df

其中Dk为卷积核尺寸,Df为特征图尺寸,M为输入通道数,输出通道数为1。


pointwise convolution:逐点卷积

逐点卷积负责转换通道,是1x1卷积进行跨通道信息融合,可以大大减少参数量。

img

方法

Pointwise Convolution的运算与标准卷积运算非常相似,它的卷积核的尺寸为1×1×M,( M为上一层的通道数)。所以这里的卷积运算会将上一步的map在深度方向上进行加权组合,生成新的Feature map。有几个卷积核就有几个输出Feature map。

参数量

1 x 1 x M x N

计算量

1x 1 x M x N x Df x Df

其中卷积核尺寸是1×1,Df为特征图尺寸,M为输入通道数,N为输出通道数。


因此计算一次深度可分离卷积的总体计算量为:

img

它们减少计算量的比例(参数量比例同计算量)为:

img

  • 深度卷积其实就是g=M=N的分组卷积,但没有将g组concate起来,所以参数量为标准卷积的1/N
  • 逐点卷积其实就是g组卷积用con1×1拼接起来,所以参数量是标准卷积的1/Dk^2

Network Structure and Training— 网络结构和训练

翻译

MobileNet结构是建立在前一节提到的深度可分卷积,除了第一层是一个完整的卷积。通过用如此简单的术语定义网络,我们可以很容易地探索网络拓扑以找到一个好的网络。MobileNet体系结构定义在表1中。除了最后的全连接层不存在非线性,并输入softmax层进行分类之外,所有层都遵循batchnorm和ReLU非线性。图3对比了一层与正则卷积、batchnorm和ReLU的卷积后的深度卷积、1×1点卷积的分解层和每一层卷积后的batchnorm和ReLU的非线性关系。下行采样在深度卷积和第一层卷积中都使用了strided convolution。最终的平均池将空间分辨率降低到全连接层之前的1。将深度卷积和点卷积计算为独立的层,MobileNet有28层。

仅仅用少量的多添加来定义网络是不够的。确保这些操作能够有效地实现也很重要。例如,非结构化的稀疏矩阵操作通常不会比密集矩阵操作快,直到非常高的稀疏程度。我们的模型结构将几乎所有的计算都放在密集的1×1个卷积中。这可以通过高度优化的通用矩阵乘法(GEMM)函数来实现。通常,卷积是由GEMM实现的,但是需要在内存中进行名为im2col的初始重新排序才能将其映射到GEMM。例如,在流行的Caffe包[15]中使用了这种方法。1×1卷积不需要在内存中重新排序,可以直接使用GEMM实现,GEMM是最优化的数值线性代数算法之一。MobileNet将95%的计算时间花费在1×1个卷积上,其中75%的参数如表2所示。几乎所有的附加参数都在全连接层中。

MobileNet模型在TensorFlow[1]中使用RMSprop[33]进行训练,其异步梯度下降类似于Inception V3[31]。然而,与训练大型模型相反,我们使用较少的正则化和数据扩充技术,因为小型模型的过拟合问题较少。当训练MobileNets时,我们不使用侧头或标签平滑,并通过限制在大型初始训练[31]中使用的小型作物的大小来减少图像失真的数量。此外,我们发现在深度方向的滤波器上放很少或没有权值衰减(l2正则化)是很重要的,因为它们的参数很少。对于下一节中的ImageNet基准测试,所有模型都使用相同的训练参数进行训练,而不考虑模型的大小。

精读

(1)核心层(深度可分离卷积层)

深度可分离卷积结合BN和ReLU,与标准卷积模型的对比如下

img


(2)整体网络结构

img

整个MobileNetV1网络除了平均池化层和softmax输出层外,共28层。

第1层为标准卷积,接下来26层为核心层结构(深度可分离卷积层),最后是平均池化层,全连接层加softmax层输出。

除全连接层不使用激活函数,而使用softmax进行分类之外,其他所有层都使用BN和ReLU。


(3)训练设置

计算复杂度设计

深度可分离卷积结构几乎把全部的计算复杂度放到了1×1卷积中,在MobileNet中有95%的时间花费在1×1卷积上,这部分也占了75%的参数。

img

原因:

  • ①1x1卷积核是一个比较密集的矩阵,所以在卷积计算时速度较快
  • ②1x1卷积可以直接通过GEMM (general matrix multiply)进行加速,其他类型的卷积在使用GEMM之前需要先经过Im2co

训练配置参数

使用Tensorflow框架训练,使用RMSprop优化器,异步梯度下降(并行数据),需要“钞能力”才可以搞定整个结构。

注意事项: 由于小网络不易过拟合,MobileNet较少使用正则化和数据增强技术(如没有使用side heads或者label smoothing)。


Width Multiplier: Thinner Models—宽度超参数α

翻译

尽管基本的MobileNet体系结构已经很小而且延迟很低,但是很多时候一个特定的用例或应用程序可能需要模型更小和更快。为了构建这些较小和较昂贵的模型计算我们介绍一个非常简单的参数α称为宽度乘数。宽度乘数α的作用是在每一层薄网络统一。对于一个给定的乘数α层和宽度的输入通道数M变成αM和输出通道的数目N变成αN。切除分离卷积的计算成本与宽度乘数α是:

img

α2 (0;1]典型设置为1、0.75、0.5、0.25。α= 1基线MobileNet和α< 1 MobileNets减少。宽度乘数降低计算成本的影响,参数的数量大约α2平方。宽度乘法器可以应用于任何模型结构,以定义一个新的更小的模型,具有合理的准确性、延迟和大小权衡。它用于定义一个新的简化结构,需要从零开始训练。


精读

目的

为了构造这些更小、计算成本更低的模型,引入了一个非常简单的参数α称为宽度乘数

作用

统一让网络中的每一层都更瘦

方法

比如针对某一层网络和α ,输入通道从M变成αM ,输出通道从N变成αN,该层计算量变成了:

img

**举个栗子:**如果把α设置成0.8,那么网络结构中的每一个卷积层中的卷积核个数都变为0.8倍。

α=1时是基准的MobileNet,而α < 1时是减小的MobileNet。

计算量减少了

img

Resolution Multiplier: Reduced Representation—分辨率超参数ρ

翻译

第二个hyper-parameter减少神经网络的计算成本是一项决议乘数ρ。我们将其应用于输入图像,每一层的内部表示随后被相同的乘法器缩减。在实践中我们隐式地设置ρ通过设置输入分辨率。我们现在可以表达我们的网络的核心层次的计算成本与宽度切除可分离旋转乘数乘数ρα和解决:

img

img

通常隐式设置,因此网络的输入分辨率为224、192、160或128。ρ= 1基线MobileNet和ρ< 1计算MobileNets减少。决议乘数的影响由ρ2降低计算成本。作为一个例子,我们可以看看一个典型的层在MobileNet和看到如何深度可分卷积,宽度乘子和分辨率乘子降低成本和参数。表3显示了一个层的计算和参数的数量,因为架构收缩方法依次应用于该层。第一行显示全卷积层的多加和参数,输入feature map大小为14×14×512,内核K大小为3×3×512×512。我们将在下一节详细讨论资源和准确性之间的权衡。

精读

作用

分辨率超参数ρ用来减少每一层输出的特征图大小的,通过减小特征图的分辨率来降低模型所需要的计算量

方法

ρ负责控制输入图像的尺寸,间接控制中间层feature map的大小。输入的尺寸大,中间层的feature map就大,feature map大卷积的次数就会变多,次数变多运算量变大。

img

计算量减少了

img

文中给出了标准卷积、深度可分离卷积以及添加了两种超参数深度可分离卷积的参数量对比例子,输入的feature map 为14x14x512,卷积核大小为3x3x512x512,乘法和加法的计算量如下图:

img

结论

  • 通过对比看可以看到添加了两张超参数的网络计算量和权重参数量都相应减少
  • 添加分辨率超参数ρ不影响权重的参数量(两个都是0.15)

Experiments—实验

Model Choices—模型的选择

翻译

首先,我们展示了深度可分卷积的MobileNet与全卷积模型的比较结果。在表4中我们可以看到,使用深度可分卷积与全卷积相比,在ImageNet上只降低了1%的精度,这在多加和参数上节省了很多。接下来,我们将展示使用宽度倍增器的较薄模型与使用较少层的较浅模型的比较结果。为了使MobileNet更浅,删除了表1中的5层可分离滤波器,其特征尺寸为14×14×512。表5显示,在相似的计算和参数数量下,使MobileNets变薄比变浅好3%。

精读

实验1:对比标准卷积和深度可分离卷积的效果

表4展示使用标准卷积和深度可分离卷积网络的效果对比

img

**结论:**虽然精读略有下降,但是使用深度可分离卷积的MobileNets计算量和参数小了很多。

实验2:在计算量恒定情况下,MobileNet是选择更瘦还是更浅的网络

表5展示一个浅层MobileNet (删除了5层卷积层)和一个使用α等于0.75的MobileNet网络结构的对比

img

**结论:**可以看到二者的参数量和计算量差不多,但是深度减少之后的浅网络精度相对降低,所以超参数比减少网络层数有用。

Model Shrinking Hyperparameters—模型收缩参数

翻译

表6显示了精度,计算和尺寸缩小MobileNet架构的权衡宽度乘数α。精度下降平稳,直到架构是由25α=太小。

表7显示了通过训练具有降低输入分辨率的MobileNets,不同分辨率乘子的准确性、计算和大小权衡。精度随着分辨率的提高而平稳下降。

图4显示了之间的权衡ImageNet 16模型的准确性和计算由宽乘数α2 f1的叉积;0:75;0:5;0:25g和决议f224;192;160;128g。

图5显示之间的权衡ImageNet准确性和参数的数量为16模型由宽乘数α2 f1的叉积;0:75;0:5;0:25g和决议f224;192;160;128 g。

表8将完整的MobileNet与原始的GoogleNet[30]和VGG16[27]进行了比较。MobileNet几乎与VGG16一样精确,但它比VGG16小32倍,计算强度低27倍。它比GoogleNet更精确,但体积更小,计算量是后者的2.5倍。表9比较与宽度减少MobileNet乘数α= 0:5和降低分辨率160×160。简化的MobileNet比AlexNet[19]好4%,同时比AlexNet小45倍和少9:4倍的计算。在相同的尺寸和22倍的计算量下,它也比Squeezenet[12]好4%。

精读

实验3:不同宽度的MobileNet效果对比

表6展示了不同width缩放因子α对准确率的影响

img

结论: 当α=0.25时才有显著下降。

实验4:不同分辨率的MobileNet效果对比

表7展示了不同分辨率ρ对准确率的影响

img

**结论:**准确度随着分辨率变低而下降。


实验5:精度和MAdds、参数量的关系

图4展示MAdds和精度的关系

img

**结论:**当模型越来越小时,精度可近似看成对数跳跃形式的。

图5展示了精度和参数量的关系

img

结论: 参数量高的精度对应也高。


实验6:和先进网络模型对比

表8比较了MobileNet与GoogleNet和VGG16的效果(大网络)

img

结论:

  • MobileNet和VGG16准确度相似,但是小了32倍,计算量少了27倍。
  • MobileNet比GoogleNet准确率更高,但是更小,计算量少了2.5倍。

表9比较了用width multiplier α=0.5和resolution160*160减少后的MobileNet

img

结论:

  • Reduced MobileNet比AlexNet准确度高4%,但是小了45倍,计算量少了9.4倍。
  • MobileNet比同等大小的SqueezeNet准确度高了4%,计算量少了22倍。

Fine Grained Recognition—细粒度图像分类

翻译

我们训练MobileNet在斯坦福狗数据集[17]上进行细粒度识别。我们扩展了[18]的方法,并从web上收集了比[18]更大但更嘈杂的训练集。我们使用带噪声的web数据预训练细粒度的犬类识别模型,然后在Stanford Dogs training set上对模型进行微调。Stanford Dogs test set的结果如表10所示。MobileNet几乎可以实现[18]的最先进的结果,大大减少了计算和大小。

精读

实验7:在Stanford Dogs数据集上训练MobileNet

表10用网络噪声数据来预训练一个细粒度狗的识别模型,在Stanford Dogs训练集上进行微调

img

结论: 和Inception v3对比,MobileNet在计算量和参数量降低一个数量级的同时几乎保持相同的精度。


Large Scale Geolocalizaton—以图搜地

翻译

行星[35]把确定照片拍摄地点的任务作为一个分类问题。该方法将地球划分成网格状的地理单元,这些单元作为目标类,并在数百万张带有地理标记的照片上训练一个卷积神经网络。PlaNet已经被证明能够成功地定位大量的照片,并且在处理相同任务方面表现得比Im2GPS更出色[6,7]。我们在相同的数据上使用MobileNet架构对PlaNet进行再培训。而基于Inception V3架构[31]的完整行星模型有5200万个参数和57.4亿个mult-add。MobileNet模型只有1300万个参数,通常是300万个参数用于车身,1000万个参数用于最后一层,58万个多附加参数。如表11所示,MobileNet版本虽然更紧凑,但与PlaNet相比,其性能仅略有下降。此外,它的表现仍然远远好于Im2GPS。

精读

实验8:基于以图搜地,对比不同网络结构进行对比

表11在相同的数据上使用MobileNet架构重新训练PlaNet,然后进行对比

img

结论: MobileNet版本与PlaNet相比,虽然更紧凑,但性能仅略有下降。但它的性能仍然大大优于Im2GPS。


Face Attributes—人脸属性

翻译

MobileNet的另一个用例是压缩大型系统,有未知或深奥的培训程序。在人脸属性分类任务中,我们展示了MobileNet与蒸馏之间的协同关系,这是一种深度网络的知识传递技术。我们寻求通过7500万的参数和1600万的mult补充来减少一个大的面部属性分类器。分类器在一个与YFCC100M[32]相似的多属性数据集上进行了训练。我们使用MobileNet架构进行人脸属性分类器。通过训练分类器来模拟更大的模型2的输出,而不是地面真理标签,因此可以通过培训分类器来模拟大模型的输出,从而使从大型(以及潜在的无限)未标记的数据集进行培训。结合蒸馏训练的可扩展性和MobileNet的无偏性参数化,最终系统不仅不需要正规化(例如重量衰变和早期停止),而且还演示了增强的性能。从表12中可以看出,mobilenetbased的分类器对攻击性模型的收缩很有弹性:它在跨属性(指AP)中达到了类似的平均精度(指AP),但仅消耗1%的多值。

精读

实验9:人脸属性分类任务

表12演示了在MobileNet和蒸馏法之间的协同关系

img

结论: 基础MobileNet分类器具有积极的模型缩小的弹性:它在人脸属性上实现了一个相似的平均精度却只消耗了Mult-Adds的 1%。

Object Detection— 目标检测

翻译

MobileNet也可以作为一个有效的基础网络部署在现代目标检测系统。我们报告的结果,MobileNet训练的目标检测基于COCO数据基于最近的工作,赢得了2016年COCO挑战[10]。在表13中,MobileNet在fast - rcnn和SSD框架下与VGG和Inception V2进行了比较。在我们的实验中,SSD被评估为300输入分辨率(SSD 300), fast - rcnn被评估为300和600输入分辨率(FasterRCNN 300, fast - rcnn 600)。快速rcnn模型对每个图像评估300个RPN建议框。模型在COCO训练+val上进行训练,排除8k minival图像,在minival上进行评估。对于这两个框架,MobileNet实现了与其他网络的可比较的结果,只有一小部分的计算复杂性和模型大小。

精读

实验10:COCO数据目标检测训练

表13演示了MobileNet与VGG和Faster-RCNN和SSD框架的比较

img

结论: MobileNet和另外两个网络相比计算复杂度和模型大小都相对更小


Face Embeddings—人脸识别

翻译

FaceNet模型是目前最先进的人脸识别模型。它建立基于三重损耗的面嵌入。为了建立一个移动的FaceNet模型,我们使用蒸馏来最小化FaceNet和MobileNet输出在训练数据上的平方差异。非常小的MobileNet模型的结果可以在表14中找到。

精读

实验11:人脸识别检测

表14显示了基于MobileNet和蒸馏技术训练出结果

img

结论: 精读略有下降但计算量和参数大幅度减少

Conclusion—结论

翻译

提出了一种基于深度可分卷积的移动网络模型结构。我们研究了一些导致有效模型的重要设计决策。然后,我们演示了如何使用宽度倍增器和分辨率倍增器构建更小、更快的mobilenet,通过权衡一定的精度来减少大小和延迟。然后,我们比较了不同的移动网络和流行的模型,显示出更大的尺寸,速度和准确性的特点。最后,我们展示了MobileNet在广泛应用于各种任务时的有效性。作为帮助采用和探索MobileNets的下一步,我们计划在张量流中发布模型。

精读

(1)提出了一种基于深度可分离卷积构建了轻量级网络— MobileNet,并设置宽度乘子和分辨率乘子以调整网络大小达到在不同设备上适配的 目的。

(2)通过实验其在大幅度降低MAdds和参数量时,没有出现精度显著下降。

(3)在实验部分展示了MobileNet在分类、检测、人脸识别等各种图像任务上的效果,并且将MobileNets与其他先进的模型进行对比,凸显了 MobileNets良好的尺寸和性能。


代码实现

import torch
import torch.nn as nn
import torch.nn.functional as F
from torchsummary import summary# 定义DSC结构:DW+PW操作
def BottleneckV1(in_channels, out_channels, stride):# 深度可分卷积操作模块: DSC卷积 = DW卷积 + PW卷积return nn.Sequential(# dw卷积,也是RexNeXt中的组卷积,当分组个数等于输入通道数时,输出矩阵的通道输也变成了输入通道数时,组卷积就是dw卷积nn.Conv2d(in_channels=in_channels, out_channels=in_channels, kernel_size=3, stride=stride, padding=1,groups=in_channels),nn.BatchNorm2d(in_channels),nn.ReLU6(inplace=True),# pw卷积,与普通的卷积一样,只是使用了1x1的卷积核nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=1, stride=1),nn.BatchNorm2d(out_channels),nn.ReLU6(inplace=True))# 定义MobileNetV1结构
class MobileNetV1(nn.Module):def __init__(self, num_classes=5):super(MobileNetV1, self).__init__()# torch.Size([1, 3, 224, 224])self.first_conv = nn.Sequential(nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, stride=2, padding=1),nn.BatchNorm2d(32),nn.ReLU6(inplace=True),)# torch.Size([1, 32, 112, 112])# 叠加的基本结构是: DW+PW(DW用来减小尺寸stride=2实现,PW用来增加通道out_channels增加实现)self.bottleneck = nn.Sequential(BottleneckV1(32, 64, stride=1),  # torch.Size([1, 64, 112, 112]), stride=1BottleneckV1(64, 128, stride=2),  # torch.Size([1, 128, 56, 56]), stride=2BottleneckV1(128, 128, stride=1),  # torch.Size([1, 128, 56, 56]), stride=1BottleneckV1(128, 256, stride=2),  # torch.Size([1, 256, 28, 28]), stride=2BottleneckV1(256, 256, stride=1),  # torch.Size([1, 256, 28, 28]), stride=1BottleneckV1(256, 512, stride=2),  # torch.Size([1, 512, 14, 14]), stride=2BottleneckV1(512, 512, stride=1),  # torch.Size([1, 512, 14, 14]), stride=1BottleneckV1(512, 512, stride=1),  # torch.Size([1, 512, 14, 14]), stride=1BottleneckV1(512, 512, stride=1),  # torch.Size([1, 512, 14, 14]), stride=1BottleneckV1(512, 512, stride=1),  # torch.Size([1, 512, 14, 14]), stride=1BottleneckV1(512, 512, stride=1),  # torch.Size([1, 512, 14, 14]), stride=1BottleneckV1(512, 1024, stride=2),  # torch.Size([1, 1024, 7, 7]), stride=2BottleneckV1(1024, 1024, stride=1),  # torch.Size([1, 1024, 7, 7]), stride=1)# torch.Size([1, 1024, 7, 7])self.avg_pool = nn.AvgPool2d(kernel_size=7, stride=1)  # torch.Size([1, 1024, 1, 1])self.linear = nn.Linear(in_features=1024, out_features=num_classes)self.dropout = nn.Dropout(p=0.2)self.softmax = nn.Softmax(dim=1)self.init_params()# 初始化操作def init_params(self):for m in self.modules():if isinstance(m, nn.Conv2d):nn.init.kaiming_normal_(m.weight)nn.init.constant_(m.bias, 0)elif isinstance(m, nn.Linear) or isinstance(m, nn.BatchNorm2d):nn.init.constant_(m.weight, 1)nn.init.constant_(m.bias, 0)def forward(self, x):x = self.first_conv(x)  # torch.Size([1, 32, 112, 112])x = self.bottleneck(x)  # torch.Size([1, 1024, 7, 7])x = self.avg_pool(x)  # torch.Size([1, 1024, 1, 1])x = x.view(x.size(0), -1)  # torch.Size([1, 1024])x = self.dropout(x)x = self.linear(x)  # torch.Size([1, 5])out = self.softmax(x)  # 概率化return x# if __name__ == '__main__':
#     model = MobileNetV1()
#     # print(model)
#
#     input = torch.randn(1, 3, 224, 224)
#     out = model(input)
#     print(out.shape)
if __name__ == '__main__':net = MobileNetV1().cuda()summary(net, (3, 224, 224))

网络结构打印如下:

----------------------------------------------------------------Layer (type)               Output Shape         Param #
================================================================Conv2d-1         [-1, 32, 112, 112]             896BatchNorm2d-2         [-1, 32, 112, 112]              64ReLU6-3         [-1, 32, 112, 112]               0Conv2d-4         [-1, 32, 112, 112]             320BatchNorm2d-5         [-1, 32, 112, 112]              64ReLU6-6         [-1, 32, 112, 112]               0Conv2d-7         [-1, 64, 112, 112]           2,112BatchNorm2d-8         [-1, 64, 112, 112]             128ReLU6-9         [-1, 64, 112, 112]               0Conv2d-10           [-1, 64, 56, 56]             640BatchNorm2d-11           [-1, 64, 56, 56]             128ReLU6-12           [-1, 64, 56, 56]               0Conv2d-13          [-1, 128, 56, 56]           8,320BatchNorm2d-14          [-1, 128, 56, 56]             256ReLU6-15          [-1, 128, 56, 56]               0Conv2d-16          [-1, 128, 56, 56]           1,280BatchNorm2d-17          [-1, 128, 56, 56]             256ReLU6-18          [-1, 128, 56, 56]               0Conv2d-19          [-1, 128, 56, 56]          16,512BatchNorm2d-20          [-1, 128, 56, 56]             256ReLU6-21          [-1, 128, 56, 56]               0Conv2d-22          [-1, 128, 28, 28]           1,280BatchNorm2d-23          [-1, 128, 28, 28]             256ReLU6-24          [-1, 128, 28, 28]               0Conv2d-25          [-1, 256, 28, 28]          33,024BatchNorm2d-26          [-1, 256, 28, 28]             512ReLU6-27          [-1, 256, 28, 28]               0Conv2d-28          [-1, 256, 28, 28]           2,560BatchNorm2d-29          [-1, 256, 28, 28]             512ReLU6-30          [-1, 256, 28, 28]               0Conv2d-31          [-1, 256, 28, 28]          65,792BatchNorm2d-32          [-1, 256, 28, 28]             512ReLU6-33          [-1, 256, 28, 28]               0Conv2d-34          [-1, 256, 14, 14]           2,560BatchNorm2d-35          [-1, 256, 14, 14]             512ReLU6-36          [-1, 256, 14, 14]               0Conv2d-37          [-1, 512, 14, 14]         131,584BatchNorm2d-38          [-1, 512, 14, 14]           1,024ReLU6-39          [-1, 512, 14, 14]               0Conv2d-40          [-1, 512, 14, 14]           5,120BatchNorm2d-41          [-1, 512, 14, 14]           1,024ReLU6-42          [-1, 512, 14, 14]               0Conv2d-43          [-1, 512, 14, 14]         262,656BatchNorm2d-44          [-1, 512, 14, 14]           1,024ReLU6-45          [-1, 512, 14, 14]               0Conv2d-46          [-1, 512, 14, 14]           5,120BatchNorm2d-47          [-1, 512, 14, 14]           1,024ReLU6-48          [-1, 512, 14, 14]               0Conv2d-49          [-1, 512, 14, 14]         262,656BatchNorm2d-50          [-1, 512, 14, 14]           1,024ReLU6-51          [-1, 512, 14, 14]               0Conv2d-52          [-1, 512, 14, 14]           5,120BatchNorm2d-53          [-1, 512, 14, 14]           1,024ReLU6-54          [-1, 512, 14, 14]               0Conv2d-55          [-1, 512, 14, 14]         262,656BatchNorm2d-56          [-1, 512, 14, 14]           1,024ReLU6-57          [-1, 512, 14, 14]               0Conv2d-58          [-1, 512, 14, 14]           5,120BatchNorm2d-59          [-1, 512, 14, 14]           1,024ReLU6-60          [-1, 512, 14, 14]               0Conv2d-61          [-1, 512, 14, 14]         262,656BatchNorm2d-62          [-1, 512, 14, 14]           1,024ReLU6-63          [-1, 512, 14, 14]               0Conv2d-64          [-1, 512, 14, 14]           5,120BatchNorm2d-65          [-1, 512, 14, 14]           1,024ReLU6-66          [-1, 512, 14, 14]               0Conv2d-67          [-1, 512, 14, 14]         262,656BatchNorm2d-68          [-1, 512, 14, 14]           1,024ReLU6-69          [-1, 512, 14, 14]               0Conv2d-70            [-1, 512, 7, 7]           5,120BatchNorm2d-71            [-1, 512, 7, 7]           1,024ReLU6-72            [-1, 512, 7, 7]               0Conv2d-73           [-1, 1024, 7, 7]         525,312BatchNorm2d-74           [-1, 1024, 7, 7]           2,048ReLU6-75           [-1, 1024, 7, 7]               0Conv2d-76           [-1, 1024, 7, 7]          10,240BatchNorm2d-77           [-1, 1024, 7, 7]           2,048ReLU6-78           [-1, 1024, 7, 7]               0Conv2d-79           [-1, 1024, 7, 7]       1,049,600BatchNorm2d-80           [-1, 1024, 7, 7]           2,048ReLU6-81           [-1, 1024, 7, 7]               0AvgPool2d-82           [-1, 1024, 1, 1]               0Dropout-83                 [-1, 1024]               0Linear-84                    [-1, 5]           5,125Softmax-85                    [-1, 5]               0
================================================================
Total params: 3,223,045
Trainable params: 3,223,045
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.57
Forward/backward pass size (MB): 115.43
Params size (MB): 12.29
Estimated Total Size (MB): 128.30
----------------------------------------------------------------Process finished with exit code 0

MobileNetV2

前言

上一篇介绍了MobileNetV1,主要是将普通Conv转换为dw和pw,但是在dw中训练出来可能会很多0,也就是depthwise部分得到卷积核会废掉,即卷积核参数大部分为0,因为权重数量可能过少,再加上Relu激活函数的原因。

后来作者大大又做了修改,MobileNetV2使用了深度可分离卷积+先升维+倒残差+低维不使用ReLU的策略构建了比V1效果更好更轻量的网络。

Abstract—摘要

翻译

在本文中,我们描述了一种新的移动架构MobileNetV2,该架构提高了移动模型在多个任务和多个基准数据集上以及在不同模型尺寸范围内的最佳性能。我们还描述了在我们称之为SSDLite的新框架中将这些移动模型应用于目标检测的有效方法。此外,我们还演示了如何通过DeepLabv3的简化形式,我们称之为Mobile DeepLabv3来构建移动语义分割模型。

MobileNetV2架构基于倒置的残差结构,其中快捷连接位于窄的瓶颈层之间。中间展开层使用轻量级的深度卷积作为非线性源来过滤特征。此外,我们发现为了保持表示能力,去除窄层中的非线性是非常重要的。我们证实了这可以提高性能并提供了产生此设计的直觉。

最后,我们的方法允许将输入/输出域与变换的表现力解耦,这为进一步分析提供了便利的框架。我们在ImageNet[1]分类,COCO目标检测[2],VOC图像分割[3]上评估了我们的性能。我们评估了在精度、通过乘加(MAdd)度量的操作次数,以及实际的延迟和参数的数量之间的权衡。


精读

本文主要工作

(1)本文提出了一种新的移动端架构MobileNet V2,在当前移动端模型中最优

(2)本文介绍了一种新框架:SSDLite,描述了如何通过SSDLite将这些移动模型应用于对象检测

(3)本文还演示了如何通过简化形式的DeepLabv3(称之为mobile DeepLabv3)构建移动端的语义分割模型


Introduction—介绍

翻译

神经网络已经彻底改变了机器智能的许多领域,使具有挑战性的图像识别任务获得了超过常人的准确性。然而,提高准确性的驱动力往往需要付出代价:现代先进网络需要超出许多移动和嵌入式应用能力之外的高计算资源。

本文介绍了一种专为移动和资源受限环境量身定制的新型神经网络架构。我们的网络通过显著减少所需操作和内存的数量,同时保持相同的精度推进了移动定制计算机视觉模型的最新水平。

我们的主要贡献是一个新的层模块:具有线性瓶颈的倒置残差。该模块将输入的低维压缩表示首先扩展到高维并用轻量级深度卷积进行过滤。随后用线性卷积将特征投影回低维表示。官方实现可作为[4]中TensorFlow-Slim模型库的一部分。

这个模块可以使用任何现代框架中的标准操作来高效地实现,并允许我们的模型使用标准基线沿多个性能点击败最先进的技术。此外,这种卷积模块特别适用于移动设计,因为它可以通过从不完全实现大型中间张量来显著减少推断过程中所需的内存占用。这减少了许多嵌入式硬件设计中对主存储器访问的需求,这些设计提供了少量高速软件控制缓存。

精读

本文主要贡献

  • **Inverted Residuals :**倒残差结构
  • **Linear Bottlenecks:**结构的最后一层采用线性层

该模块将低维压缩表示作为输入,首先将其扩展到高维,并使用轻型深度卷积进行过滤。特征随后通过线性卷积投影回低维表示。

该模块的优点

(1)该模块可以在任何现代框架中高性能实现。

(2)适合于移动设计。减少了许多嵌入式硬件设计中对主内存访问的需求,提供了少量非常快速的软件控制高速缓存。


Related Work—相关工作

翻译

调整深层神经架构以在精确性和性能之间达到最佳平衡已成为过去几年研究活跃的一个领域。由许多团队进行的手动架构搜索和训练算法的改进,已经比早期的设计(如AlexNet[5],VGGNet [6],GoogLeNet[7]和ResNet[8])有了显著的改进。最近在算法架构探索方面取得了很多进展,包括超参数优化[9,10,11]、各种网络修剪方法[12,13,14,15,16,17]和连接学习[18,19]。 也有大量的工作致力于改变内部卷积块的连接结构如ShuffleNet[20]或引入稀疏性[21]和其他[22]。

最近,[23,24,25,26]开辟了了一个新的方向,将遗传算法和强化学习等优化方法带入架构搜索。然而,一个缺点是最终所得到的网络非常复杂。在本文中,我们追求的目标是发展了解神经网络如何运行的更好直觉,并使用它来指导最简单可能的网络设计。我们的方法应该被视为[23]中描述的方法和相关工作的补充。在这种情况下,我们的方法与[20,22]所采用的方法类似,并且可以进一步提高性能,同时可以一睹其内部的运行。我们的网络设计基于MobileNetV1[27]。它保留了其简单性,并且不需要任何特殊的运算符,同时显著提高了它的准确性,为移动应用实现了在多种图像分类和检测任务上的最新技术。

精读

以前的相关工作

  • 调整深度神经架构以在准确性和性能之间取得最佳平衡
  • 超参数优化以及各种网络修剪方法和连通性学习
  • 改变内部卷积块的连接结构(ShuffleNet或引入稀疏性等)

本文的目标

开发关于神经网络如何操作的更好的直觉,并使用它来指导最简单的网络设计。


Preliminaries, discussion and intuition—准备、讨论和直觉

Depthwise Separable Convolutions—深度可分离卷积

翻译

深度可分卷积是许多高效神经网络架构的关键组成部分[27,28,20],我们在目前的工作中也使用它们。其基本思想是用分解版本替换完整的卷积运算符,将卷积拆分为两个单独的层。第一层称为深度卷积,它通过对每个输入通道应用单个卷积滤波器来执行轻量级滤波。第二层是1×1卷积,称为逐点卷积,它负责通过计算输入通道的线性组合来构建新特征。

标准卷积使用K∈Rk×k×di×dj维的输入张量Li,并对其应用卷积核K∈Rk×k×di×dj来产生hi×wi×dj维的输出张量Lj。标准卷积层的计算代价为hi⋅wi⋅di⋅dj⋅k⋅k。

深度可分卷积是标准卷积层的直接替换。经验上,它们几乎与常规卷积一样工作,但其成本为:

hi⋅wi⋅di(k2+dj) (1)

它是深度方向和1×1逐点卷积的总和。深度可分卷积与传统卷积层相比有效地减少了几乎k^2倍的计算量。MobileNetV2使用k=3(3×3的深度可分卷积),因此计算成本比标准卷积小88到99倍,但精度只有很小的降低[27]。


精读

这个在MobileNetV1(点这里复习一下)时我们就见过了:

  • 第一层是深度卷积,它通过对每个输入通道应用单个卷积核来执行轻量级卷积。
  • 第二层是逐点卷积,也就是1×1卷积,负责通过计算输入通道的线性组合来构建新特征。

虽然精读略有降低,但计算量比标准卷积低8到9倍。

Linear Bottlenecks—线性瓶颈层

翻译

考虑一个由n层Li组成的深度神经网络,每层都有一个hi×wi×di维的激活张量。在本节中,我们将讨论这些激活张量的基本属性,我们将把它们看作hi×wi个具有di维的“pixels”。非正式地,对于输入的一组真实图像,我们说层激活的集合(对于任何层Li)形成一个“感兴趣的流形”。长久以来,人们一直认为神经网络中的流形可以嵌入到低维子空间中。换句话说,当我们查看深层卷积层的所有单独的d通道像素时,在这些值中编码的信息实际上位于某个流形中,这反过来又可嵌入到低维子空间中。

乍一看,这样的实例可以通过简单地减少层的维度来捕获和利用,从而降低操作空间的维度。这已经被MobileNetV1[27]成功利用,通过宽度乘数参数在计算量和精度之间进行有效折衷,并且已经被合并到其他网络的高效模型设计中[20]。遵循这种直觉,宽度乘数方法允许降低激活空间的维度,直到感兴趣的流形横跨整个空间为止。然而,当我们回想到深度卷积神经网络实际上具有非线性的每个坐标变换(例如ReLU)时,这种直觉就会失败。 例如,在1维空间中的一行应用ReLU会产生一个ray,在Rn空间中,它通常会产生一个具有n个连接的分段线性曲线。

很容易看出,如果层变换ReLU(Bx)的结果具有非零的体积S,映射到内部S的点通常通过输入的线性变换B获得,因此表明与全维度输出相对应的输入空间的一部分受限于线性变换。换句话说,深层网络只在输出域的非零体积部分具有线性分类器的能力。我们将在补充材料中进行更正式的说明。

另一方面,当ReLU破坏通道时,它不可避免地会丢失该通道的信息。但是,如果我们有很多通道,并且激活流形中有一个结构,信息可能仍然保留在其它通道中。在补充材料中,我们说明,如果输入流形可以嵌入到激活空间的显著较低维子空间中,则ReLU变换将保留该信息,同时将所需的复杂性引入到可表达的函数集中。

总而言之,我们已经强调了两个特性,这些特性表明需要的感兴趣流行应该位于较高维激活空间的低维子空间中:

1.如果感兴趣的流形在ReLU转换后保持非零体积,则其对应于线性转换。

2.只有当输入流形位于输入空间的低维子空间时,ReLU才能保留有关输入流形的完整信息。

这两个深刻见解为我们提供了优化现有神经架构的经验提示:假设感兴趣流形是低维的,我们可以通过将线性瓶颈层插入到卷积模块中来捕获这一点。实验证据表明,使用线性层是至关重要的,因为它可以防止非线性破坏太多的信息。在第6节中,我们通过经验证明,在瓶颈中使用非线性层确实会使性能降低几个百分点,进一步证实了我们的假设。我们注意到[29]报告了非线性得到帮助的类似报告,其中非线性已从传统残差块的输入中移除,并导致CIFAR数据集的性能得到了改善。

对于本文的其余部分,我们将利用瓶颈卷积。我们将把输入瓶颈的大小与内部大小之间的比例作为扩展比。


精读

v1的做法以及不足

**做法:**引入α参数来做模型通道的缩减,相当于给模型“瘦身”,这样特征信息就能更集中在缩减后的通道中。

**不足:**但研究人员发现深度可分离卷积中有大量卷积核为0,即有很多卷积核没有参与实际计算。

v2的作者发现是ReLU激活函数的问题,认为 ReLU这个激活函数,在低维空间运算中会损失很多信息,而在高维空间中会保留较多有用信息 。

img

ReLU与维度的关系

img

ReLU会对维度较低的张量造成较大的信息损耗。

  • 维度越低,损失信息越多。(如2和3已经没有螺旋的样子了)
  • 维度越高,损失信息越少。(当原始输入维度数增加到15以后再加ReLU,基本不会丢失太多的信息,接近输入)

两个性质

(1)如果"manifold of interest"都为非零值,则经过ReLU相当于只做了一个线性变换,没有信息丢失

(2)维度足够多时,ReLU能够保留"manifold of interest"的完整信息

本文方法

论文针对这个问题在Bottleneck末尾使用Linear Bottleneck(即不使用ReLU激活,做了线性变换)来代替原本的非线性激活变换。具体到v2网络中就是将最后的Point-Wise卷积的ReLU6都换成线性函数。

实验证据表明,使用线性层至关重要,因为它可以防止非线性破坏太多的信息。

可分离卷积块的演化

img

  • **2(a):**标准卷积(一个大方块);
  • **2(b):**深度可分离卷积(=Depthwise convolution+Pointwise Convolution=薄片片+方块块);
  • **2©:**linear bottleneck,(高维后)relu6-dw-relu6-pw,降维-升维-;
  • **2(d):**和图2©等效,(线性激活后)pw升维-relu6-dw-relu6-pw,降维-线性激活;

Inverted residuals—反向残差

翻译

瓶颈块与残差块类似,其中每个块包含一个输入,然后是几个瓶颈,然后是扩展[8]。然而,受直觉的启发,瓶颈实际上包含所有必要的信息,而扩展层只是伴随张量非线性变换的实现细节,我们直接在瓶颈之间使用快捷连接。图3提供了设计差异的示意图。插入快捷连接的动机与经典的残差连接类似:我们想要提高梯度在乘法层之间传播的能力。但是,倒置设计的内存效率要高得多(详见第5节),而且在我们的实验中效果稍好。

img

图3:残差块[8,30]和倒置残差之间的差异。对角阴影线层不使用非线性。我们用每个块的厚度来表明其相对数量的通道。注意经典残差是如何将通道数量较多的层连接起来的,而倒置残差则是连接瓶颈。最好通过颜色看。

瓶颈卷积的运行时间和参数计数基本实现结构如表1所示。对于大小为h×w的块,扩展因子为t,内核大小为k,具有d′维输入通道和d″维输出通道,所需的乘法加法总数为h⋅w⋅d′⋅t(d′+k2+d′′)。与(1)相比,这个表达式有一个额外项,因为实际上我们有一个额外的1×1卷积,但是我们的网络性质使我们能够利用更小的输入和输出维度。在表3中,我们比较了MobileNetV1,MobileNetV2和ShuffleNet之间每种分辨率所需的尺寸。

img

表1:瓶颈残差块从k转换为k′个通道,步长为s,扩展系数为t。

img

表3:不同架构中需要在每个空间分辨率上实现的最大通道数/内存(以Kb为单位)。我们假设激活使用16位浮点数。对于ShuffleNet,我们使用与MobileNetV1和MobileNetV2的性能相匹配的2x,g=3。对于MobileNetV2和ShuffleNet的第一层,我们可以采用第5节中描述的技巧来降低内存需求。尽管ShuffleNet在其它地方使用了瓶颈,但由于存在非瓶颈张量之间的快捷连接,因此非瓶颈张量仍然需要实现。


精读

引入问题

如果整个网络都是低维那么整体的运算速度就会很快,但会有信息丢失;如果提取足够多的特征的话,还是希望有高纬度通道来做这件事。

深度卷积本身没有改变通道的作用,比如本文前例中的深度可分离卷积的例子,在前一半的深度卷积操作中,输入通道数量就是输出通道数量。

本文的做法

MobileNetV2中首先在DW深度卷积之前使用PW卷积进行升维(升维倍数为t,t=6),再在一个更高维的空间中进行卷积操作来提取特征,最后再压缩数据,让网络变小。

img

举个例子: 假设输入到Inverted Residual的输入为56×56×24,则先经过1×1的Conv进行升维,扩展因子 t 为6,维度变为144。然后经过3×3的DW卷积,维度不变。最后再使用1×1的Conv进行降维,维度变为24.

ResNet和MobileNetV2对比

img

  • ResNet: 降维 (0.25倍)–>卷积–>再升维。
  • MobileNetV2 先升维 (6倍)–>卷积–>再降维。

论文中的图示

img

  • (a)为residual block模块,短路连接线之间通道数是少的,呈“两边多,中间小”。
  • (b)则是为了尽量使ReLU6能够更好与深度可分离卷积兼容,所以在短路连接线之间的通道数是最多的,而两边的通道则比中间小。呈“两边少,中间多”。所以作者称其为Inverted residual block。

Information flow interpretation—信息流解释

翻译

我们架构的一个有趣特性是它在构建块(瓶颈层)的输入/输出域与层转换之间提供了自然分离——这是一种将输入转换为输出的非线性函数。前者可以看作是网络在每一层的容量,而后者则是表现力。与常规和可分离的传统卷积块相比,其中表现力和容量都缠结在一起并且是输出层深度的函数。

特别是在我们的实例中,当内层深度为0时,由于快捷连接,基础卷积是恒等函数。当扩展比率小于1时,这是一个经典的残差卷积块[8,30]。但是,就我们的目的而言,我们表明扩大比率大于1是最有用的。

这种解释使我们能够独立于其容量研究网络的表现力,并且我们认为需要进一步探索这种分离,以便更好地理解网络性质。

精读

架构块的特点

它在构建块的输入/输出域(瓶颈层)和层转换之间提供了一种自然的分离,层转换是一种将输入转换为输出的非线性函数。

前者可以被视为网络在每一层的容量,而后者则被视为表现力。

传统卷积块的特点

在传统的卷积块中,表达能力和容量都纠结在一起,是输出层深度的函数。

Model Architecture—模型架构

翻译

现在我们详细描述我们的架构。正如前一节所讨论的那样,基本构件块是一个瓶颈深度可分离的残差卷积。该模块的详细结构如表1所示。MobileNetV2的架构包含具有32个滤波器的初始全卷积层,接着是表2中描述的19个残差瓶颈层。我们使用ReLU6作为非线性,因为用于低精度计算时它的鲁棒性[27]。我们总是使用现代网络中的标准核尺寸3×3,并在训练期间利用丢弃和批归一化。

除第一层外,我们在整个网络中使用恒定的扩展率。在我们的实验中,我们发现5到10之间的扩展速率导致几乎相同的性能曲线,较小的网络以较小的扩展速率更好,而较大的网络在较大扩展速率时具有稍微更好的性能。

对于我们所有的主要实验,我们使用扩展因子66来应用于输入张量的大小。例如,对于瓶颈层采用64通道的输入张量并产生具有128×128通道的张量,中间扩展层则具有64*6=384个通道。

和[27]一样,我们通过使用输入图像分辨率和宽度倍数作为可调超参数来调整我们的架构以适应不同的性能点,可以根据所需的精度/性能权衡来调整。我们的主要网络(宽度乘数1,224×224)的计算成本为3亿次乘法,并使用了340万个参数。我们研究了性能权衡,输入分辨率从96到224,宽度乘数从0.35到1.4。网络计算成本范围从7次乘法增加到585M MAdds,而模型大小在1.7M个参数和6.9M个参数之间变化。

一个较小的实现差异,[27]是对于小于1的乘数,我们将宽度乘数应用于除最后一个卷积层以外的所有层。这可以提高更小模型的性能。

精读

网络架构

表2:MobileNet V2实现架构。

img

  • t: 扩展因子(即升维倍数),一般与输入的通道数相乘;
  • c: 输出通道数;
  • n: 该层重复次数(比如重复4次,那么这4个相同操作的输出通道都是64);
  • s: 步幅,注意,shortcut只在s=1时才使用;
  • 卷积核大小均为3 * 3;
  • 本文使用ReLU6作为非线性激活函数,训练过程使用dropout和batch normalization。

除了第一层,在整个网络中使用恒定的扩展因子t;

较小的网络用较小的扩展因子t表现更好;

较大的网络使用较大的扩展因子时表现更好。

Tradeoff hyper parameters—超参数的权衡

MobileNet v2同样使用MobileNet V1中的两个超参数,宽度系数α和分辨率系数ρ;

与MobileNet v1的不同是,对于小于1的乘数,本文将宽度系数α应用于除最后一个卷积层之外的所有层。这提高了较小模型的性能。

Implementation Notes—实现细节说明

Memory efficient inference—高效推理内存

翻译

倒置的残差颈层允许特定地内存有效的实现,这对于移动应用非常重要。使用TensorFlow[31]或Caffe[32]等标准高效的推断实现,构建了一个有向无环计算超图G,由表示操作的边和代表中间计算张量的节点组成。预定计算是为了最小化需要存储在内存中的张量总数。在最一般的情况下,它会搜索所有合理的计算顺序Σ(G),并选择最小化

img

其中R(i, π, G)是连接到πi…πn任何节点的中间张量列表,|A|表示张量A的大小,size(i)是操作i期间内部存储所需的总内存量。

对于仅具有平凡并行结构(例如残差连接)的图,只有一个非平凡的可行计算顺序,因此可以简化计算图G推断所需的内存总量和界限:

img

或者重申,内存量只是在所有操作中组合输入和输出的最大总大小。在下文中我们将展示如果我们将瓶颈残差块视为单一操作(并将内部卷积视为一次性张量),则总内存量将由瓶颈张量的大小决定,而不是瓶颈的内部张量的大小(更大)。

精读

使用例如TensorFlow或Caffe 的推理的标准有效实现构建了有向非循环计算超图G,其包括表示操作的边和表示中间计算的张量的节点。

如果本文将瓶颈残差块视为单个操作(并将内卷积视为可任意处理的张量),则内存总量将由瓶颈张量的大小决定,而不是由瓶颈内部的张量(并且大得多)的大小决定。


Bottleneck Residual Block—残差瓶颈块

翻译

瓶颈残差块 图3b中所示的F(x)可以表示为三个运算符的组合F(x)=[A∘N∘B]x,其中A是线性变换A:Rs×s×k→Rs×s×n,N是一个非线性的每个通道的转换:N:Rs×s×n→Rs′×s′×n,B是输出域的线性转换:B:Rs′×s′×n→Rs′×s′×k′。

对于我们的网络N=ReLU6◦ dwise◦ ReLU6,但结果适用于任何的按通道转换。假设输入域的大小是|x|并且输出域的大小是|y|,那么计算F(X)所需的内存可以低至|s2k|+|s′2k′|+O(max(s2,s′2))。

该算法基于以下事实:内部张量I可以表示为t张量的连接,每个大小为n/t,则我们的函数可以表示为

F(x)=∑i=1t(Ai∘N∘Bi)(x)

通过累加和,我们只需要将一个大小为n/t的中间块始终保留在内存中。使用n=t,我们最终只需要保留中间表示的单个通道。使我们能够使用这一技巧的两个约束是(a)内部变换(包括非线性和深度)是每个通道的事实,以及(b)连续的非按通道运算符具有显著的输入输出大小比。对于大多数传统的神经网络,这种技巧不会产生显著的改善。

我们注意到,使用t路分割计算F(X)所需的乘加运算符的数目是独立于t的,但在现有实现中,我们发现由于增加的缓存未命中,用几个较小的矩阵乘法替换一个矩阵乘法会很损坏运行时的性能 。我们发现这种方法最有用,t是22和55之间的一个小常数。它显著降低了内存需求,但仍然可以利用深度学习框架提供的高度优化的矩阵乘法和卷积算子来获得的大部分效率。如果特殊的框架级优化可能导致进一步的运行时改进,这个方法还有待观察。

精读

残差块和逆残差的区别

对角线阴影层不使用非线性。本文用每个块的厚度来表示它的相对通道数。请注意经典残差如何连接具有大量通道的层,而反向残差如何连接瓶颈。

本文用到的原理

内部张量τ可以表示为t个张量的串联,每个张量的大小为n/t。函数可以表示为:

img

本文使用方法

本文通过累加总和,只需要在内存中一直保存一个大小为n/t的中间块。使用n = t,最终必须始终只保留中间表示的单个通道。

该方法的两个约束:

(a)内部变换(包括非线性和深度方向)是每通道的

(b)连续的非每通道操作符具有输入大小与输出的显著比率

Experiments—实验

文章从classification、detection、segmentation三个应用方面测试了该模型的效果。

ImageNet Classification—ImageNet数据集分类

翻译

训练设置我们使用TensorFlow[31]训练我们的模型。我们使用标准的RMSPropOptimizer,将衰减和动量都设置为0.9。我们在每层之后使用批标准化,并将标准权重衰减设置为0.00004。遵循MobileNetV1 [27]的设置,我们使用初始学习率为0.045,学习率的衰减比率为每个迭代周期衰减0.98。我们使用16个GPU异步,批大小为96。

结果我们将我们的网络与MobileNetV1,ShuffleNet和NASNet-A模型进行了比较。表4列出了一些选定模型的统计数据,完整的性能图如图5所示。

精读

训练参数设置

  • 框架: TensorFlow
  • 优化器: RMSPropOptimizer
  • 衰变和动量: 0.9
  • 标准重量衰减: 0.00004
  • 初始学习率: 0.045
  • 每个时期的学习率衰减率: 0.98
  • 线程数量: 16个
  • 批量大小: 96

将本文的网络与MobileNetV1、ShuffleNet和NASNet-A模型进行了比较

表4显示了一些选定模型的统计数据

img

图5显示了完整的性能图

img

**结论:**MobileNetV2比MobileNetV1性能提高很多。和ShuffleNet和NASNet-A相比虽然参数量和计算量有增加但精读有提升


Object Detection—目标检测

翻译

我们评估和比较了MobileNetV2和MobileNetV1的性能,MobileNetV1使用COCO数据集[2]上Single Shot Detector(SSD)[34]的修改版本作为目标检测的特征提取器[33]。我们还将YOLOv2[35]和原始SSD(以VGG-16[6]为基础网络)作为基准进行比较。由于我们专注于移动/实时模型,因此我们不会比较Faster-RCNN[36]和RFCN[37]等其它架构的性能。

SSDLite 在本文中,我们将介绍常规SSD的移动友好型变种。我们在SSD预测层中用可分离卷积(深度方向后接1×11×1投影)替换所有常规卷积。这种设计符合MobileNets的整体设计,并且在计算上效率更高。我们称之为修改版本的SSDLite。与常规SSD相比,SSDLite显著降低了参数计数和计算成本。

对于MobileNetV1,我们按照[33]中的设置进行。对于MobileNetV2,SSDLite的第一层被附加到层15的扩展(输出步长为16)。SSDLite层的第二层和其余层连接在最后一层的顶部(输出步长为32)。此设置与MobileNetV1一致,因为所有层都附加到相同输出步长的特征图上。

MobileNet模型都经过了开源TensorFlow目标检测API的训练和评估[38]。 两个模型的输入分辨率为320×320。我们进行了基准测试并比较了mAP(COCO挑战度量标准),参数数量和Multiply-Adds数量。结果如表6所示。MobileNetV2 SSDLite不仅是最高效的模型,而且也是三者中最准确的模型。值得注意的是,MobileNetV2 SSDLite效率高20倍,模型要小10倍,但仍优于COCO数据集上的YOLOv2。

精读

训练参数设置

**数据集:**COCO数据集

SSDLite设置

在SSD预测层中,将所有规则卷积替换为可分离卷积(深度为1×1投影)

表5显示了SSD和SSDLite的对比结果

img

**结论:**与常规SSD相比,SSDLite显著减少了参数计数和计算成本。


Semantic Segmenta tion—语义分割

翻译

在本节中,我们使用MobileNetV1和MobileNetV2模型作为特征提取器与DeepLabv3[39]在移动语义分割任务上进行比较。DeepLabv3采用了空洞卷积[40,41,42],这是一种显式控制计算特征映射分辨率的强大工具,并构建了五个平行头部,包括(a)包含三个具有不同空洞率的3×3卷积的Atrous Spatial Pyramid Pooling模块(ASPP)[43],(b)1×1卷积头部,以及(c)图像级特征[44]。我们用输出步长来表示输入图像空间分辨率与最终输出分辨率的比值,该分辨率通过适当地应用空洞卷积来控制。对于语义分割,我们通常使用输出stride=16或88来获取更密集的特征映射。我们在PASCAL VOC 2012数据集[3]上进行了实验,使用[45]中的额外标注图像和评估指标mIOU。

为了构建移动模型,我们尝试了三种设计变体:(1)不同的特征提取器,(2)简化DeepLabv3头部以加快计算速度,以及(3)提高性能的不同推断策略。我们的结果总结在表7中。我们已经观察到:(a)包括多尺度输入和添加左右翻转图像的推断策略显著增加了MAdds,因此不适合于在设备上应用,(b)使用输出步长16比使用输出步长8更有效率,(c)MobileNetV1已经是一个强大的特征提取器,并且只需要比ResNet-101少约4.9-5.7倍的MAdd[8](例如,mIOU:78.56与82.70和MAdds:941.9B vs 4870.6B),(d)在MobileNetV2的倒数第二个特征映射的顶部构建DeepLabv3头部比在原始的最后一个特征映射上更高效,因为倒数第二个特征映射包含320个通道而不是1280个通道,这样我们就可以达到类似的性能,但是要比MobileNetV1的通道少2.5倍,(e)DeepLabv3头部的计算成本很高,移除ASPP模块会显著减少MAdd并且只会稍微降低性能。在表7末尾,我们鉴定了一个设备上的潜在候选应用(粗体),该应用可以达到75.32%mIOU并且只需要2.75B MAdds。

精读

将MobileNetv1,v2作为DeepLabv3中的特征提取网络,随后经过ASPP融合多尺度语义信息以及解码网络用于语义分割

训练参数设置

**数据集:**PASCAL VOC 2012

三种变体

(1)不同的特征提取器

(2)简化DeepLabv3头部以加快计算速度

(3)不同的推理策略以提高性能

三种变体结果总结

img

结论

(1)多尺度输入和添加左右翻转图像,增加了计算力,并不适用

(2)使用输出步幅=16比输出步幅=8更有效

(3)MobileNetV2只需要大约4.9− MAdds,比ResNet-101少5.7倍

(4)MobileNetV2的第二个最后一层功能图上构建DeepLabv3比在原始的最后一层功能图上更有效

(5)DeepLabv3磁头的计算成本很高,移除ASPP模块可以显著降低MADD,而性能只会略有下降。


Ablation study—消融研究

翻译

倒置残差连接。残差连接的重要性已被广泛研究[8,30,46]。本文报告的新结果是连接瓶颈的快捷连接性能优于连接扩展层的的快捷连接(请参见图6b以供比较)。

线性瓶颈的重要性。线性瓶颈模型的严格来说比非线性模型要弱一些,因为激活总是可以在线性状态下进行,并对偏差和缩放进行适当的修改。然而,我们在图6a中展示的实验表明,线性瓶颈改善了性能,为非线性破坏低维空间中的信息提供了支持。

精读

Inverted residual connections—反向残差连接

图7(b)比较了快捷连接瓶颈层和扩展层以及不使用残差连接

img

**结论:**快捷方式连接瓶颈的性能优于连接扩展层的快捷方式

Importance of linear bottlenecks—线性瓶颈的重要性

线性瓶颈模型比非线性模型更弱,因为激活总是在线性范围内运行,并对偏差和比例做出适当的改变。然而,如图6a所示的实验表明,线性瓶颈提高了性能,提供了非线性破坏低维空间信息的支持。

Conclusions and future work—总结和未来工作

翻译

我们描述了一个非常简单的网络架构,使我们能够构建一系列高效的移动模型。我们的基本构建单元具有多种特性,使其特别适用于移动应用。它允许非常有效的内存推断,并依赖利用所有神经框架中的标准操作。

对于ImageNet数据集,我们的架构改善了许多性能点的最新技术水平。对于目标检测任务,我们的网络在精度和模型复杂度方面都优于COCO数据集上的最新实时检测器。值得注意的是,我们的架构与SSDLite检测模块相比,计算量少20倍,参数比YOLOv2少10倍。

理论上:所提出的卷积块具有独特的属性,允许将网络表现力(由扩展层编码)与其容量(由瓶颈输入编码)分开。探索这个是未来研究的重要方向。


精读

① 提出一个更轻量的网络,准确率高。

② 作者提出的这种改进模型效率的思路非常实用,如深度可分离卷积。这些思路可以用于改进当前表现好但是计算复杂的模型。

代码实现

import torch
from torch import nn
import torch.nn.functional as F
from torchsummary import summary# ------------------------------------------------------#
#   这个函数的目的是确保Channel个数能被8整除。
#	很多嵌入式设备做优化时都采用这个准则
# ------------------------------------------------------#
def _make_divisible(v, divisor, min_value=None):if min_value is None:min_value = divisor# int(v + divisor / 2) // divisor * divisor:四舍五入到8new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)# Make sure that round down does not go down by more than 10%.if new_v < 0.9 * v:new_v += divisorreturn new_v# -------------------------------------------------------------#
#   Conv+BN+ReLU经常会用到,组在一起
#   参数顺序:输入通道数,输出通道数...
#		最后的groups参数:groups=1时,普通卷积;
#						 groups=输入通道数in_planes时,DW卷积=深度可分离卷积
#	pytorch官方继承自nn.sequential,想用它的预训练权重,就得听它的
# -------------------------------------------------------------#
class ConvBNReLU(nn.Sequential):def __init__(self, in_planes, out_planes, kernel_size=3, stride=1, groups=1):padding = (kernel_size - 1) // 2super(ConvBNReLU, self).__init__(#	不使用偏置bias,因为使用了BN层,此时偏置不起作用了nn.Conv2d(in_planes, out_planes, kernel_size, stride, padding, groups=groups, bias=False),nn.BatchNorm2d(out_planes),nn.ReLU6(inplace=True))# ------------------------------------------------------#
#   InvertedResidual,先变胖后变瘦
#   参数顺序:输入通道数,输出通道数,步长,变胖倍数(扩展因子)
# ------------------------------------------------------#
class InvertedResidual(nn.Module):def __init__(self, inp, oup, stride, expand_ratio):super(InvertedResidual, self).__init__()self.stride = strideassert stride in [1, 2]# 所谓的隐藏维度,其实就是输入通道数*变胖倍数hidden_dim = int(round(inp * expand_ratio))# 只有同时满足两个条件时,才使用短连接self.use_res_connect = self.stride == 1 and inp == ouplayers = []# 如果扩展因子等于1,就没有第一个1x1的卷积层if expand_ratio != 1:layers.append(ConvBNReLU(inp, hidden_dim, kernel_size=1))   # pointwiselayers.extend([# 3x3 depthwise conv,因为使用了groups=hidden_dimConvBNReLU(hidden_dim, hidden_dim, stride=stride, groups=hidden_dim),# 1x1 pointwise conv(linear)nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False),nn.BatchNorm2d(oup),])self.conv = nn.Sequential(*layers)def forward(self, x):if self.use_res_connect:return x + self.conv(x)else:return self.conv(x)# MobileNetV2是一个类,继承自nn.module这个父类
class MobileNetV2(nn.Module):def __init__(self, num_classes=1000, width_mult=1.0, inverted_residual_setting=None, round_nearest=8):"""MobileNet V2 main classArgs:num_classes (int): Number of classeswidth_mult (float): Width multiplier - adjusts number of channels in each layer by this amountinverted_residual_setting: Network structureround_nearest (int): Round the number of channels in each layer to be a multiple of this numberSet to 1 to turn off rounding"""super(MobileNetV2, self).__init__()block = InvertedResidual# 保证通道数是 8 的倍数,原因是:适配于硬件优化加速input_channel = _make_divisible(32 * width_mult, round_nearest)last_channel = _make_divisible(1280 * width_mult, round_nearest)if inverted_residual_setting is None:# t表示扩展因子(变胖倍数);c是通道数;n是block重复几次;#	s:stride步长,只针对第一层,其它s都等于1inverted_residual_setting = [# t, c, n, s# 208,208,32 -> 208,208,16[1, 16, 1, 1],# 208,208,16 -> 104,104,24[6, 24, 2, 2],# 104,104,24 -> 52,52,32[6, 32, 3, 2],# 52,52,32 -> 26,26,64[6, 64, 4, 2],# 26,26,64 -> 26,26,96[6, 96, 3, 1],# 26,26,96 -> 13,13,160[6, 160, 3, 2],# 13,13,160 -> 13,13,320[6, 320, 1, 1],]# only check the first element, assuming user knows t,c,n,s are requiredif len(inverted_residual_setting) == 0 or len(inverted_residual_setting[0]) != 4:raise ValueError("inverted_residual_setting should be non-empty ""or a 4-element list, got {}".format(inverted_residual_setting))# conv1 layer# 416,416,3 -> 208,208,32features = [ConvBNReLU(3, input_channel, stride=2)]# building inverted residual blocksfor t, c, n, s in inverted_residual_setting:output_channel = _make_divisible(c * width_mult, round_nearest)for i in range(n):# -----------------------------------## 	s为1或者2 只针对重复了n次的bottleneck 的第一个bottleneck,#	重复n次的剩下几个bottleneck中s均为1。# -----------------------------------#stride = s if i == 0 else 1# 这个block就是上面那个InvertedResidual函数features.append(block(input_channel, output_channel, stride, expand_ratio=t))# 这一层的输出通道数作为下一层的输入通道数input_channel = output_channel# building last several layersfeatures.append(ConvBNReLU(input_channel, last_channel, kernel_size=1))# *features表示位置信息,将特征层利用nn.Sequential打包成一个整体self.features = nn.Sequential(*features)# building classifier# 自适应平均池化下采样层,输出矩阵高和宽均为1self.avgpool = nn.AdaptiveAvgPool2d((1, 1))self.classifier = nn.Sequential(nn.Dropout(0.2),nn.Linear(last_channel, num_classes),)# weight initializationfor 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):x = self.features(x)x = self.avgpool(x)x = torch.flatten(x, 1)		# 展平处理x = self.classifier(x)return xdef mobilenet_v2(num_classes: int = 1000):model = MobileNetV2(num_classes=num_classes)return modelif __name__ == '__main__':net = MobileNetV2().cuda()summary(net, (3, 224, 224))

网络结构打印如下:

----------------------------------------------------------------Layer (type)               Output Shape         Param #
================================================================Conv2d-1         [-1, 32, 112, 112]             864BatchNorm2d-2         [-1, 32, 112, 112]              64ReLU6-3         [-1, 32, 112, 112]               0Conv2d-4         [-1, 32, 112, 112]             288BatchNorm2d-5         [-1, 32, 112, 112]              64ReLU6-6         [-1, 32, 112, 112]               0Conv2d-7         [-1, 16, 112, 112]             512BatchNorm2d-8         [-1, 16, 112, 112]              32InvertedResidual-9         [-1, 16, 112, 112]               0Conv2d-10         [-1, 96, 112, 112]           1,536BatchNorm2d-11         [-1, 96, 112, 112]             192ReLU6-12         [-1, 96, 112, 112]               0Conv2d-13           [-1, 96, 56, 56]             864BatchNorm2d-14           [-1, 96, 56, 56]             192ReLU6-15           [-1, 96, 56, 56]               0Conv2d-16           [-1, 24, 56, 56]           2,304BatchNorm2d-17           [-1, 24, 56, 56]              48InvertedResidual-18           [-1, 24, 56, 56]               0Conv2d-19          [-1, 144, 56, 56]           3,456BatchNorm2d-20          [-1, 144, 56, 56]             288ReLU6-21          [-1, 144, 56, 56]               0Conv2d-22          [-1, 144, 56, 56]           1,296BatchNorm2d-23          [-1, 144, 56, 56]             288ReLU6-24          [-1, 144, 56, 56]               0Conv2d-25           [-1, 24, 56, 56]           3,456BatchNorm2d-26           [-1, 24, 56, 56]              48InvertedResidual-27           [-1, 24, 56, 56]               0Conv2d-28          [-1, 144, 56, 56]           3,456BatchNorm2d-29          [-1, 144, 56, 56]             288ReLU6-30          [-1, 144, 56, 56]               0Conv2d-31          [-1, 144, 28, 28]           1,296BatchNorm2d-32          [-1, 144, 28, 28]             288ReLU6-33          [-1, 144, 28, 28]               0Conv2d-34           [-1, 32, 28, 28]           4,608BatchNorm2d-35           [-1, 32, 28, 28]              64InvertedResidual-36           [-1, 32, 28, 28]               0Conv2d-37          [-1, 192, 28, 28]           6,144BatchNorm2d-38          [-1, 192, 28, 28]             384ReLU6-39          [-1, 192, 28, 28]               0Conv2d-40          [-1, 192, 28, 28]           1,728BatchNorm2d-41          [-1, 192, 28, 28]             384ReLU6-42          [-1, 192, 28, 28]               0Conv2d-43           [-1, 32, 28, 28]           6,144BatchNorm2d-44           [-1, 32, 28, 28]              64InvertedResidual-45           [-1, 32, 28, 28]               0Conv2d-46          [-1, 192, 28, 28]           6,144BatchNorm2d-47          [-1, 192, 28, 28]             384ReLU6-48          [-1, 192, 28, 28]               0Conv2d-49          [-1, 192, 28, 28]           1,728BatchNorm2d-50          [-1, 192, 28, 28]             384ReLU6-51          [-1, 192, 28, 28]               0Conv2d-52           [-1, 32, 28, 28]           6,144BatchNorm2d-53           [-1, 32, 28, 28]              64InvertedResidual-54           [-1, 32, 28, 28]               0Conv2d-55          [-1, 192, 28, 28]           6,144BatchNorm2d-56          [-1, 192, 28, 28]             384ReLU6-57          [-1, 192, 28, 28]               0Conv2d-58          [-1, 192, 14, 14]           1,728BatchNorm2d-59          [-1, 192, 14, 14]             384ReLU6-60          [-1, 192, 14, 14]               0Conv2d-61           [-1, 64, 14, 14]          12,288BatchNorm2d-62           [-1, 64, 14, 14]             128InvertedResidual-63           [-1, 64, 14, 14]               0Conv2d-64          [-1, 384, 14, 14]          24,576BatchNorm2d-65          [-1, 384, 14, 14]             768ReLU6-66          [-1, 384, 14, 14]               0Conv2d-67          [-1, 384, 14, 14]           3,456BatchNorm2d-68          [-1, 384, 14, 14]             768ReLU6-69          [-1, 384, 14, 14]               0Conv2d-70           [-1, 64, 14, 14]          24,576BatchNorm2d-71           [-1, 64, 14, 14]             128InvertedResidual-72           [-1, 64, 14, 14]               0Conv2d-73          [-1, 384, 14, 14]          24,576BatchNorm2d-74          [-1, 384, 14, 14]             768ReLU6-75          [-1, 384, 14, 14]               0Conv2d-76          [-1, 384, 14, 14]           3,456BatchNorm2d-77          [-1, 384, 14, 14]             768ReLU6-78          [-1, 384, 14, 14]               0Conv2d-79           [-1, 64, 14, 14]          24,576BatchNorm2d-80           [-1, 64, 14, 14]             128InvertedResidual-81           [-1, 64, 14, 14]               0Conv2d-82          [-1, 384, 14, 14]          24,576BatchNorm2d-83          [-1, 384, 14, 14]             768ReLU6-84          [-1, 384, 14, 14]               0Conv2d-85          [-1, 384, 14, 14]           3,456BatchNorm2d-86          [-1, 384, 14, 14]             768ReLU6-87          [-1, 384, 14, 14]               0Conv2d-88           [-1, 64, 14, 14]          24,576BatchNorm2d-89           [-1, 64, 14, 14]             128InvertedResidual-90           [-1, 64, 14, 14]               0Conv2d-91          [-1, 384, 14, 14]          24,576BatchNorm2d-92          [-1, 384, 14, 14]             768ReLU6-93          [-1, 384, 14, 14]               0Conv2d-94          [-1, 384, 14, 14]           3,456BatchNorm2d-95          [-1, 384, 14, 14]             768ReLU6-96          [-1, 384, 14, 14]               0Conv2d-97           [-1, 96, 14, 14]          36,864BatchNorm2d-98           [-1, 96, 14, 14]             192InvertedResidual-99           [-1, 96, 14, 14]               0Conv2d-100          [-1, 576, 14, 14]          55,296BatchNorm2d-101          [-1, 576, 14, 14]           1,152ReLU6-102          [-1, 576, 14, 14]               0Conv2d-103          [-1, 576, 14, 14]           5,184BatchNorm2d-104          [-1, 576, 14, 14]           1,152ReLU6-105          [-1, 576, 14, 14]               0Conv2d-106           [-1, 96, 14, 14]          55,296BatchNorm2d-107           [-1, 96, 14, 14]             192
InvertedResidual-108           [-1, 96, 14, 14]               0Conv2d-109          [-1, 576, 14, 14]          55,296BatchNorm2d-110          [-1, 576, 14, 14]           1,152ReLU6-111          [-1, 576, 14, 14]               0Conv2d-112          [-1, 576, 14, 14]           5,184BatchNorm2d-113          [-1, 576, 14, 14]           1,152ReLU6-114          [-1, 576, 14, 14]               0Conv2d-115           [-1, 96, 14, 14]          55,296BatchNorm2d-116           [-1, 96, 14, 14]             192
InvertedResidual-117           [-1, 96, 14, 14]               0Conv2d-118          [-1, 576, 14, 14]          55,296BatchNorm2d-119          [-1, 576, 14, 14]           1,152ReLU6-120          [-1, 576, 14, 14]               0Conv2d-121            [-1, 576, 7, 7]           5,184BatchNorm2d-122            [-1, 576, 7, 7]           1,152ReLU6-123            [-1, 576, 7, 7]               0Conv2d-124            [-1, 160, 7, 7]          92,160BatchNorm2d-125            [-1, 160, 7, 7]             320
InvertedResidual-126            [-1, 160, 7, 7]               0Conv2d-127            [-1, 960, 7, 7]         153,600BatchNorm2d-128            [-1, 960, 7, 7]           1,920ReLU6-129            [-1, 960, 7, 7]               0Conv2d-130            [-1, 960, 7, 7]           8,640BatchNorm2d-131            [-1, 960, 7, 7]           1,920ReLU6-132            [-1, 960, 7, 7]               0Conv2d-133            [-1, 160, 7, 7]         153,600BatchNorm2d-134            [-1, 160, 7, 7]             320
InvertedResidual-135            [-1, 160, 7, 7]               0Conv2d-136            [-1, 960, 7, 7]         153,600BatchNorm2d-137            [-1, 960, 7, 7]           1,920ReLU6-138            [-1, 960, 7, 7]               0Conv2d-139            [-1, 960, 7, 7]           8,640BatchNorm2d-140            [-1, 960, 7, 7]           1,920ReLU6-141            [-1, 960, 7, 7]               0Conv2d-142            [-1, 160, 7, 7]         153,600BatchNorm2d-143            [-1, 160, 7, 7]             320
InvertedResidual-144            [-1, 160, 7, 7]               0Conv2d-145            [-1, 960, 7, 7]         153,600BatchNorm2d-146            [-1, 960, 7, 7]           1,920ReLU6-147            [-1, 960, 7, 7]               0Conv2d-148            [-1, 960, 7, 7]           8,640BatchNorm2d-149            [-1, 960, 7, 7]           1,920ReLU6-150            [-1, 960, 7, 7]               0Conv2d-151            [-1, 320, 7, 7]         307,200BatchNorm2d-152            [-1, 320, 7, 7]             640
InvertedResidual-153            [-1, 320, 7, 7]               0Conv2d-154           [-1, 1280, 7, 7]         409,600BatchNorm2d-155           [-1, 1280, 7, 7]           2,560ReLU6-156           [-1, 1280, 7, 7]               0
AdaptiveAvgPool2d-157           [-1, 1280, 1, 1]               0Dropout-158                 [-1, 1280]               0Linear-159                 [-1, 1000]       1,281,000
================================================================
Total params: 3,504,872
Trainable params: 3,504,872
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.57
Forward/backward pass size (MB): 152.88
Params size (MB): 13.37
Estimated Total Size (MB): 166.82
----------------------------------------------------------------Process finished with exit code 0

MobileNetV3

前言

上周我们学习了MobileNetV1和MobileNetV2,本文的MobileNetV3,它首先引入MobileNetV1的深度可分离卷积,然后引入MobileNetV2的具有线性瓶颈的倒残差结构,后来使用了网络搜索算法,并引入了SE模块以及H-Swish激活函数等,可谓集大成者。

引用大佬的描述:MobileNet V3 = MobileNet v2 + SE结构 + hard-swish activation +网络结构头尾微调。

Abstract—摘要

翻译

我们展示了基于互补搜索技术和新颖架构设计相结合的下一代MobileNets。MobileNetV3通过结合硬件感知网络架构搜索(NAS)和NetAdapt算法对移动电话cpu进行调优,然后通过新的架构改进对其进行改进。本文开始探索自动化搜索算法和网络设计如何协同工作,利用互补的方法来提高整体水平。通过这个过程,我们创建了两个新的发布的MobileNet模型:MobileNetV3-Large和MobileNetV3-Small,它们针对高资源和低资源用例。然后将这些模型应用于目标检测和语义分割。针对语义分割(或任何密集像素预测)任务,我们提出了一种新的高效分割解码器Lite reduce Atrous Spatial Pyramid Pooling (LR-ASPP)。我们实现了移动分类、检测和分割的最新技术成果。与MobileNetV2相比,MobileNetV3-Large在ImageNet分类上的准确率提高了3.2%,同时延迟降低了15%。与MobileNetV2相比,MobileNetV2- small的准确率高4.6%,同时延迟降低了5%。MobileNetV3-Large检测速度比MobileNetV2快25%,在COCO检测上的精度大致相同。MobileNetV3-Large LR-ASPP的速度比MobileNetV2 R-ASPP快30%,在城市景观分割的精度类似。


精读

本文主要工作

(1)MobileNet V3通过结合NetAdapt算法辅助的硬件NAS和新颖的架构来优化到移动端的CPU上

(2)本文创建了两个新的MobileNet模型,应用于对象检测和语义分割的任务

  • MobileNetV3-Large
  • MobileNetV3-Small

(3)分割任务中提出了一种高效的轻量级空间金字塔池化策略Lite Reduced ASPP

(4)与MobileNetV2相比,MobileNetV3准确率更高,速度更快


Introduction—简介

翻译

高效的神经网络在移动应用程序中变得无处不在,从而实现全新的设备上体验。它们也是个人隐私的关键推动者,允许用户获得神经网络的好处,而不需要将数据发送到服务器进行评估。神经网络效率的提高不仅通过更高的精度和更低的延迟来改善用户体验,还通过降低功耗来帮助保持电池寿命。

本文描述了我们开发MobileNetV3大型和小型模型的方法,以提供下一代高精度高效的神经网络模型来驱动设备上的计算机视觉。新的网络推动了最新技术的发展,并展示了如何将自动化搜索与新的体系结构进步结合起来,以构建有效的模型。

本文的目标是开发最佳的移动计算机视觉架构,以优化移动设备上的精确延迟交换。为了实现这一点,我们引入了(1)互补搜索技术,(2)适用于移动设备的非线性的新高效版本,(3)新的高效网络设计,(4)一个新的高效分割解码器。我们提供了深入的实验,以证明每种技术在广泛的用例和移动电话上评估的有效性和价值。

论文组织如下。我们从第2节中有关工作的讨论开始。第3节回顾了用于移动模型的高效构建块。第4节回顾了体系结构搜索以及MnasNet和NetAdapt算法的互补性。第5节描述了通过联合搜索提高模型效率的新型架构设计。第6节介绍了大量的分类、检测和分割实验,以证明有效性和理解不同元素的贡献。第7节载有结论和今后的工作。

精读

本文目标

开发最佳的移动计算机视觉架构,以优化移动设备上的精确延迟交换

引入的技术

(1)网络模型搜索技术

(2)对于移动配置来说,新的高效版本的非线性实践

(3)新的高效网络设计

(4)新的高效分割解码器


Related Work—相关工作

翻译

设计深度神经网络结构来实现精度和效率之间的最优平衡是近年来一个活跃的研究领域。无论是新颖的手工结构还是算法神经结构搜索,都在这一领域发挥了重要作用。

SqueezeNet[20]广泛使用1x1卷积与挤压和扩展模块,主要集中于减少参数的数量。最近的工作将关注点从减少参数转移到减少操作的数量(MAdds)和实际测量的延迟。MobileNetV1[17]采用深度可分离卷积,大大提高了计算效率。MobileNetV2[37]在此基础上进行了扩展,引入了一个具有反向残差和线性瓶颈的资源高效块。ShuffleNet[47]利用组卷积和信道洗牌操作进一步减少MAdds。冷凝集[19]在训练阶段学习组卷积,以保持层与层之间有用的紧密连接,以便功能重用。ShiftNet[44]提出了与点向卷积交织的移位操作,以取代昂贵的空间卷积。

为了使体系结构设计过程自动化,首先引入了增强学习(RL)来搜索具有竞争力的精度的高效体系结构[51,52,3,25,33]。一个完全可配置的搜索空间可能会以指数级增长且难以处理。因此,早期的架构搜索工作主要关注单元级结构搜索,并且在所有层中重用相同的单元。最近,[41]探索了一个块级分层搜索空间,允许在网络的不同分辨率块上使用不同的层结构。为了降低搜索的计算成本,在[26,5,43]中使用了可微架构搜索框架,并进行了基于梯度的优化。针对现有网络适应受限移动平台的问题,[46,14,12]提出了更高效的自动化网络简化算法。

量化[21,23,45,39,49,50,35]是另一个重要的补充努力,以提高网络效率通过降低精度的算法。最后,知识蒸馏[4,15]提供了一种附加的补充方法,在大型“教师”网络的指导下生成精确的小型“学生”网络。

精读

  • 基于轻量化网络设计: 比如 MobileNet 系列,ShuffleNet系列,Xception等,使用Group卷积,1*1 卷积等技术减少网络计算量的同时,尽可能的保证网络的精度。
  • 模型剪枝: 大网络往往存在一定的冗余,通过减去冗余部分,减少网络计算量。
  • 量化: 利用 TensorRT 量化,一般在 GPU 上可以提速几倍
  • 知识蒸馏: 利用大模型(teacher model)来帮助小模型(student model)学习,提高 student model的精度。

Efficient Mobile Building Blocks—高效移动端构建块

翻译

移动模式已经建立在越来越高效的基础之上。MobileNetV1[17]引入深度可分离卷积作为传统卷积层的有效替代。深度可分卷积通过将空间滤波与特征生成机制分离,有效地分解了传统卷积。深度可分卷积由两个独立的层定义:用于空间滤波的轻量级深度卷积和用于特征生成的较重的1x1点卷积。

MobileNetV2[37]引入了线性瓶颈和反转残余结构,以便利用问题的低秩性质使层结构更加有效。这个结构如图3所示,由1x1展开卷积、深度卷积和1x1投影层定义。当且仅当输入和输出具有相同数量的通道时,才用剩余连接连接它们。这种结构在输入和输出处保持了紧凑的表示,同时在内部扩展到高维特征空间,以增加非线性每个通道转换的表达能力。

MnasNet[41]建立在MobileNetV2结构上,通过在瓶颈结构中引入基于挤压和激励的轻量级注意模块。注意,与[18]中提出的基于ResNet的模块相比,挤压和激励模块集成在不同的位置。模块位于展开中的深度过滤器之后,以便注意应用于最大的表示,如图4所示。

对于MobileNetV3,我们使用这些层的组合作为构建块,以便构建最有效的模型。层也升级与修改的swish非线性[34]。挤压和激励以及swish非线性都使用了sigmoid,它的计算效率很低,而且很难在定点算法中保持精度,因此我们将其替换为硬sigmoid[2,11],如5.2节所讨论的。

精读

之前的工作

  • MobileNetV1: 深度可分离卷积+1×1卷积
  • MobileNetV2: 线性瓶颈+反向残差
  • MnasNet: 建立在 MobileNetV2 结构上,将基于SE的注意力模块引入到bottleneck结构中

本文的方法

(1)上述三种结构相结合构建块来实现更高效的模型

(2)引入了改进的swish作为非线性函数

(3)将Sigmoid替换为hard Sigmoid

Network Search—网络搜索

**(1)资源受限的NAS(platform-aware NAS):**计算和参数量受限的前提下搜索网络的各个模块,所以称之为模块级的搜索(Block-wise Search)。
**(2)NetAdapt:**用于对各个模块确定之后网络层的微调。

Platform-Aware NAS for Block-wise Search—使用NAS感知平台进行逐块(Block-wise)搜索

翻译

与[41]类似,我们采用平台感知神经结构方法来寻找全局网络结构。由于我们使用相同的基于Rnn-based的控制器和相同的分解层次搜索空间,所以对于目标延迟在80ms左右的大型移动模型,我们发现了与[41]类似的结果。因此,我们只需重用与初始大型移动模型相同的MnasNet-A1[41],然后在其上应用NetAdapt[46]和其他优化。

然而,我们发现最初的奖励设计并没有针对小型手机模型进行优化。具体来说,它使用一个多目标奖励

img

来近似pareto最优解,根据目标延迟TAR为每个模型m平衡模型精度ACC(m)和延迟LAT(m)。我们观察到精度变化更显著延迟小模型;因此,我们需要一个较小的重量系数w =-0.15 (vs原始w=-0.07[41])来弥补大精度变化不同的延迟。在新的权重因子w的增强下,我们从头开始一个新的架构搜索,以找到初始的seed模型,然后应用NetAdapt和其他优化来获得最终的MobilenetV3-Small模型。

精读

尝试的方法

重用了相同的MnasNet-A1模型作为初始的移动端Large模型,之后采用了NetAdapt和基于此的其它优化。

MnasNet: 移动平台感知神经结构搜索是谷歌发表在CVPR2019的一篇论文。

本篇论文提出了一个自动的移动神经网络架构搜索方法(MNAS),它明确地把模型延迟纳入考虑,得到一个在精度和延迟之间达到平衡的模型。不像之前的网络选择延迟的一个不精确的度量——比如FLOPS,而是直接通过在移动手机上推理模型来衡量真实的延迟。为了进一步在灵活性和搜索空间尺寸上取得平衡,提出了一个新颖的分解式层次搜索空间,它鼓励整个网络层的多样性。

MnasNet同样在COCO目标检测上也取得了比MobileNets更好的MAP。

不足

上述方法对小型移动端模型不是最优的,小模型的精度会随着时延变化得更剧烈。

本文改进的方法

使用w = − 0.15代替原文的w = − 0.07

从头开始一个新的架构搜索,以找到初始的 seed 模型,然后应用 NetAdapt 和其他优化来获得最终的 MobileNetV3-Small模型。

NetAdapt for Layer-wise Search—使用NetAdapt 进行 Layerwise 搜索

翻译

我们在架构搜索中使用的第二种技术是NetAdapt[46]。这种方法是对平台感知NAS的补充:它允许以顺序的方式对单个层进行微调,而不是试图推断出粗糙但全局的体系结构。详情请参阅原文。简而言之,这项技术的进展如下:

从平台感知NAS发现的种子网络体系结构开始。

为每个步骤:

(a)提出一套新的建议。每个建议都表示对体系结构的修改,与前一步相比,该体系结构至少可以减少延迟。

(b)对于每一个提案,我们使用前一步骤的预先训练的模型,并填充新提出的架构,适当地截断和随机初始化缺失的权重。对T步的每个建议进行微调,以获得对精度的粗略估计。

©根据某种标准选择最佳建议。

  1. 重复前面的步骤,直到达到目标延迟。

在[46]中,度量是为了最小化精度的变化。我们修改了这个算法,使延迟变化和精度变化的比例最小化。也就是说,对于每个NetAdapt步骤中生成的所有建议,我们选择一个最大化的建议:ΔACC/|Δlatency|,延迟满足2(a)中的约束。直觉告诉我们,由于我们的建议是离散的,所以我们更喜欢最大化权衡曲线斜率的建议。

这个过程重复进行,直到延迟达到目标,然后从头开始重新培训新的体系结构。我们使用与在[46]中为MobilenetV2使用相同的提案生成器。具体来说,我们允许以下两种提议:

  1. 减小任何膨胀层的尺寸;
  2. 减少共享相同瓶颈大小的所有块中的瓶颈—以维护剩余连接。

在我们的实验中,我们使用T = 10000,并发现虽然它增加了建议的初始微调的准确性。然而,当从零开始训练时,它通常不会改变最终的精度。设δ = 0.01 ∣L∣ ,其中L为种子模型的延迟。

精读

NetAdapt: 一种新的网络压缩算法。

NetAdapt的网络优化以自动的方式进行,它使用一个预训练好的模型在固定计算资源的手机平台上进行压缩试验,逐渐降低预训练网络的资源消耗,直接采集压缩之后的性能表现(作为feedback,得到一系列满足资源限制、同时最大化精度的简化网络。)

本文对NetAdapt的处理如下

(1)从平台感知 NAS 发现的种子网络体系结构开始

(2)对于每一个步骤:

  1. 提出一套新的提议proposal, 每个提议都表示对体系结构的修改,与前一步相比,该体系结构至少可以减少延迟
  2. 对于每一个提议,使用前一个步骤的预先训练的模型,并填充新提出的架构,适当地截断和随机初始化缺失的权重。对于 T 步的每个建议进行微调,以获得对精度的粗略估计
  3. 根据某种标准选择最佳提议proposal

(3)重复前面的步骤,直到达到目标延迟

两个建议

(1)减小扩展层的尺寸;

(2)保持残差连接,减小瓶颈的尺寸。


Network Improvements—网络改进

Redesigning Expensive Layers—重新设计昂贵的层

翻译

一旦通过架构搜索找到模型,我们就会发现,一些最后的层以及一些较早的层比其他层更昂贵。我们建议对体系结构进行一些修改,以减少这些慢层的延迟,同时保持准确性。这些修改超出了当前搜索空间的范围。

第一个修改将重新处理网络的最后几层是如何交互的,以便生成最终层功能更有效率。目前的模型基于MobileNetV2的倒瓶颈结构和变体,使用1x1卷积作为最后一层,以扩展到高维特征空间。这一层非常重要,因为它具有丰富的预测功能。然而,这是以额外的延迟为代价的。

为了减少延迟并保留高维特性,我们将该层移到最终的平均池之后。最后一组特征现在计算为1x1空间分辨率,而不是7x7空间分辨率。这种设计选择的结果是,在计算和延迟方面,特性的计算变得几乎是免费的。

一旦降低了该特性生成层的成本,就不再需要以前的瓶颈投影层来减少计算量。该观察允许我们删除前一个瓶颈层中的投影和过滤层,从而进一步降低计算复杂度。原始阶段和优化后的阶段如图5所示。有效的最后一个阶段将延迟减少了10毫秒,即15%的运行时间,并将操作数量减少了3000万个madd,几乎没有损失精度。第6节包含了详细的结果。

img

另一个昂贵的层是初始过滤器集。目前的移动模型倾向于在一个完整的3x3卷积中使用32个滤波器来构建初始滤波器库进行边缘检测。通常这些过滤器是彼此的镜像。我们尝试减少滤波器的数量,并使用不同的非线性来尝试减少冗余。我们决定对这一层使用硬swish非线性,因为它的表现和其他非线性测试。我们能够将过滤器的数量减少到16个,同时保持与使用ReLU或swish的32个过滤器相同的精度。这节省了额外的3毫秒和1000万 MAdds。


精读

MobileNetV2的方法及不足

方法: 在最后一层使用了1×1卷积进行特征空间维度扩展。

不足: 会带来额外的延迟

本文改进的方法

(1)将该层移动到平均池化层之外。最终,维度扩展是在1×1而非7×7的分辨率上进行。

img

(2)使用hardswish非线性激活函数

(3)将过滤器的数量减少到 16 个


Nonlinearities—非线性函数

翻译

在[34]中引入了一种称为swish的非线性,当作为ReLU的替代时,它可以显著提高神经网络的精度。非线性定义为:

img

虽然这种非线性提高了精度,但在嵌入式环境中,它的成本是非零的,因为在移动设备上计算sigmoid函数要昂贵得多。我们用两种方法处理这个问题。

  1. 我们将sigmoid函数替换为它的分段线性硬模拟:ReLU6(x+3)/6​类似于[11,42]。小的区别是,我们使用的是ReLU6,而不是定制的裁剪常量。类似地,swish的硬版本也变成了:

img

最近在[2]中也提出了类似的hard-swish版本。图6显示了sigmoid和swish非线性的软、硬版本的比较。我们选择常量的动机是简单,并且与原始的平滑版本很好地匹配。在我们的实验中,我们发现所有这些函数的硬版本在精度上没有明显的差异,但是从部署的角度来看,它们具有多种优势。首先,几乎所有的软件和硬件框架上都可以使用ReLU6的优化实现。其次,在量子化模式下,它消除了由于近似sigmoid的不同实现而带来的潜在的数值精度损失。最后,即使优化了量化的sigmoid实现,其速度也比相应的ReLU慢得多。在我们的实验中,用量化模式下的swish替换h-swish使推理延迟增加了15%。

img

  1. 随着我们深入网络,应用非线性的成本会降低,因为每层激活内存通常在分辨率下降时减半。顺便说一句,我们发现swish的大多数好处都是通过只在更深的层中使用它们实现的。因此,在我们的架构中,我们只在模型的后半部分使用h-swish。我们参照表1和表2来获得精确的布局,即使有了这些优化,h-swish仍然会引入一些延迟成本。然而正如我们在第六节证明准确性和延迟的净效应是正的,它基于一个piece-wise函数提供了进一步优化。

精读

swish

swish是Google提出的一种非线性激活函数,在一些深层网络中优于ReLU,如在40层以上的全连接层的效果要明显优于其他激活函数。

img

h-swish

Swish 具备无上界有下界、平滑、非单调的特性,但由于sigmoid在硬件设备上无法实现,为此将sigmoid替换为相近的基于ReLU6的计算,即h-swish

h-swish计算速度比swish更快(但比ReLU慢),更易于量化,精度上没有差异。

img

而且实验发现h-swish激活在深层次网络中更有效,为此前层网络依旧使用的ReLU。

Large squeeze-and-excite—大型SE

翻译

在[41]中,SE的大小与卷积瓶颈的大小有关。取而代之的是,我们将它们全部替换为固定为膨胀层通道数的1/4。我们发现这样做可以在适当增加参数数量的情况下提高精度,并且没有明显的延迟成本。


精读

SE结构会消耗一定的时间,SE瓶颈的大小与卷积瓶颈的大小有关。将它们全部替换为固定为膨胀层通道数的1/4,可以在适当增加参数数量的情况下提高精度,并且没有明显的延迟成本。

SE模块被放在了Depthwise卷积后面。

MobileNetV3 Definitions—MobileNetV3 定义

翻译

MobileNetV3被定义为两个模型:MobileNetV3—大的和MobileNetV3—小的。这些模型分别针对高资源用例和低资源用例。通过应用平台感知的NAS和NetAdapt进行网络搜索,并结合本节定义的网络改进,可以创建模型。我们的网络的完整规范见表1和表2。

精读

MobileNetV3 被定义为两个模型

  1. MobileNetV3-Large(高资源用例)
  2. MobileNetV3-Small(低资源用例)

完整网络结构

MobileNetV3-Large网络结构图

img

  • input: 输入层特征矩阵的shape

  • operator:

    表示的是操作,对于第一个卷积层conv2d

    • NBN: 最后两个卷积的operator提示NBN,表示这两个卷积不使用BN结构,最后两个卷积相当于全连接的作用
    • 最后的conv2d 1x1: 相当于全连接层的作用
  • exp size 代表的是第一个升维的卷积,我们要将维度升到多少,exp size多少,我们就用第一层1x1卷积升到多少维

  • #out: 代表的是输出特征矩阵的channel,我们说过在v3版本中第一个卷积核使用的是16个卷积核

  • NL: 代表的是激活函数,其中HS代表的是hard swish激活函数,RE代表的是ReLU激活函数

  • s: 代表的DW卷积的步距(s=2,长宽变为原来一半)

  • beneck: 对应的是下图中的结构

  • SE: 表示是否使用注意力机制,只要表格中标√所对应的bneck结构才会使用我们的注意力机制,对没有打√就不会使用注意力机制

MobileNetV3-Small

MobileNetV3-Small网络结构图

img

参数同上。

Experiments—实验

Classification—分类

Training setup—训练设置

翻译

由于已经成为标准,我们在所有分类实验中都使用ImageNet[36],并将准确度与各种资源使用度量(如延迟和乘法加法(MAdds))进行比较。

我们在4x4 TPU Pod[22]上使用0.9动量的标准tensorflow RMSPropOptimizer进行同步训练。我们使用初始学习率为0.1,批次大小为4096(每个芯片128张图像),学习率衰减率为0.01每3个周期。我们使用dropout of 0.8, l2的权重衰减为1e-5。用于与Inception[40]相同的图像预处理。最后,我们使用衰减为0.9999的指数移动平均。我们所有的卷积层都使用批处理归一化层,平均衰减为0.99。

精读

  • 数据集: ImageNet
  • 配置: 4*4 TPU Pod
  • 动量标准: 0.9
  • 优化器: TensorFlow RMSProp Optimizer
  • 初始学习率: 0.1
  • batch-size: 4096
  • 学习衰减率: 0.01 每三个epoch
  • dropout: 0.8
  • l2权重衰减率: 1e-5
Measurement setup—测量设置

翻译

为了测量延迟,我们使用标准的谷歌像素手机,并通过标准的TFLite基准测试工具运行所有网络。我们在所有测量中都使用单线程大内核。我们没有报告多核推理时间,因为我们发现这种设置对移动应用程序不太实用。

精读

使用了标准的Google-Pixel手机,并使用标准的TFLite-Benchmark-Tool来运行所有的网络。

贡献: 本文为TensorflowLite贡献了H-Swish的原子运算符

图9中展示了优化后的h-swish的影响

img


Results—结果

翻译

如图1所示,我们的模型优于目前的技术状态,如MnasNet[41]、ProxylessNas[5]和MobileNetV2[37]。我们在表3中报告了不同像素手机上的浮点性能。我们在表4中包括量化结果。

在图7中,我们展示了MobileNetV3性能权衡作为乘数和分辨率的函数。请注意,MobileNetV3-Small的性能比MobileNetV3-Large的性能好得多,其乘法器缩放到与性能匹配的倍数接近3%。另一方面,决议提供了比乘数更好的权衡。但是,需要注意的是,分辨率通常是由问题决定的(例如分割和检测问题通常需要更高的分辨率),因此不能总是用作可调参数。

精读

表3展示了在不同Pixel手机上浮点运算的性能结果

img

表4展示了量化后的结果

img

结论:

  • MobileNetV3-Small在放大器的缩放作用下其性能比MobileNetV3-Large更好
  • 分辨率比放大器提供了更好的均衡性

图7展示了MobileNetV3作为平衡放大器和分辨率函数时的均衡性能

img

**结论:**本文的模型超越了现有的SOTA模型


Ablation study—消融实验

翻译

非线性的影响,在表5和图8中,我们展示了在何处插入h-swish的决定如何影响延迟。特别重要的是,我们注意到,在整个网络上使用h-swish会导致精度略有提高(0.2),同时增加了近20%的延迟,并再次回到有效边界。

另一方面,与ReLU相比,使用h-swish提高了效率边界,尽管仍然比ReLU耗时增加12%左右。最后,我们注意到,当h-swish通过融合到卷积运算符中得到优化时,我们预计h-swish和ReLU之间的延迟差距即使没有消失,也会显著减小。然而,h-swish和swish之间不可能有这样的改进,因为计算sigmoid本来就比较昂贵。

其他组件的影响,在图9中,我们展示了不同组件的引入是如何沿着延迟/准确度曲线移动的。

精读

(1)非线性函数的影响

图8展示了基于非线性函数选择和网络宽度的 efficient frontier

img

**结论:**MobileNetV3在网络的中间部分使用了H-Swish ,并且明显优于ReLU

(2)其它组件的影响

图9展示了引入不同组件后在latency/accuracy曲线上移动的情况

img


Detection—检测

翻译

在SSDLite[37]中,我们使用MobileNetV3作为骨干特征提取器的替代,并与COCO dataset[24]上的其他骨干网络进行了比较。

在MobileNetV2[37]之后,我们将第一层SSDLite附加到输出步长为16的最后一个特征提取器层,并将第二层SSDLite附加到输出步长为32的最后一个特征提取器层。根据检测文献,我们将这两个特征提取层分别称为C4和C5。对于MobileNetV3-Large, C4是第13个瓶颈块的膨胀层。对于MobileNetV3-Small, C4是第9个瓶颈块的膨胀层。对于这两个网络,C5都是池之前的一层。

我们还将C4和C5之间的所有特征层的信道数减少了2。这是因为MobileNetV3的最后几层被调优为输出1000个类,当将90个类转移到COCO时,这可能是多余的。

COCO测试集的结果如表6所示。在信道缩减的情况下,MobileNetV3-Large比具有几乎相同映射的MobileNetV2快25%。在相同的延迟下,MobileNetV2和MnasNet比MobileNetV2和MnasNet高2.4和0.5。对于这两种MobileNetV3模型,通道减少技巧在没有featuremap丢失的情况下可以减少大约15%的延迟,这表明Imagenet分类和COCO对象检测可能更喜欢不同的特征提取器形状。


精读

使用 MobileNet V3作为SSDLite的骨干特征提取器的替代,并与COCO dataset上与其他骨干网络进行了对比。

表6展示了COCO 测试集的结果

img

**结论:**ImageNet 分类和 COCO对象检测可能更喜欢不同的特征提取器形状。

Semantic Segmentation—语义分割

翻译

在本小节中,我们使用MobileNetV2[37]和提出的MobileNetV3作为移动语义分割的网络骨架。此外,我们比较了两个分割头。第一个是在[37]中提出的R-ASPP。R-ASPP是一种无源空间金字塔池化模块的简化设计[7,8,9],它只采用由11个卷积和一个全局平均池化操作组成的两个分支[27,48]。在本文中,我们提出了另一种轻量级分割头,称为Lite R-ASPP(或LR-ASPP),如图10所示。Lite R-ASPP是对R-ASPP的改进,它部署全局平均池的方式类似于挤压-激励模块[18],其中我们使用了一个大的池内核,具有较大的步长(以节省一些计算),并且模块中只有一个11个卷积。我们对MobileNetV3的最后一个块应用atrous convolution[16,38,31, 6]来提取更密集的特性,并进一步从底层特性添加一个跳过连接[28]来捕获更详细的信息。

我们使用度量mIOU[13]对Cityscapes数据集[10]进行了实验,只使用了“fine”注释。我们采用与[8,37]相同的培训方案。我们所有的模型都是从零开始训练,没有在ImageNet[36]上进行预训练,并使用单尺度输入进行评估。与目标检测类似,我们发现我们可以在不显著降低性能的情况下,将网络主干最后一块的信道减少2倍。我们认为这是因为主干网设计了1000类ImageNet图像分类[36],而Cityscapes只有19类,这意味着主干网中存在一定的信道冗余。

我们在表7中报告Cityscapes验证集的结果。如表所示,我们观察到(1)减少网络骨干的渠道在最后一块2倍显著提高速度的同时保持类似的表现(第一行和第二行和行5与行6),(2)提出分割头LR-ASPP略高于R-ASPP[37]虽然性能改善(第二行和第三行,行6 vs行7),(3)减少分割的过滤器头从256年到128年提高了速度稍差的成本性能(第3行与行4,行7与行8),(4)当使用相同的设置,MobileNetV3模型变体实现类似的性能时略高于MobileNetV2同行(第1行和5行,第二行与行6,第3行与行7日和行4与行8),(5)MobileNetV3-Small达到类似性能MobileNetV2 - 0.5时更快,(6) mobilenetv2 - small明显优于MobileNetV2-0.35,且速度相近。

精读

使用 MobileNetV2 和提出的 MobileNetV3作为移动语义分割的网络骨架。此外,比较了两个分割头。

图10展示的Lite R-ASPP是对 R-ASPP的改进

img

**结论:**主干网络存在一定的通道冗余。


Conclusions and future work—结论和未来工作

翻译

在本文中,我们介绍了MobileNetV3大大小小的模型,展示了在移动分类、检测和分割方面的最新技术。我们描述了我们的努力,利用多种类型的网络架构搜索以及先进的网络设计,以交付下一代移动模型。我们还展示了如何适应非线性,如swish和应用压缩和激励的量化友好和有效的方式,将它们作为有效的工具引入移动模型领域。我们还介绍了一种新的轻量级分割解码器,称为LR-ASPP。尽管如何将自动搜索技术与人类直觉最好地结合起来仍然是一个悬而未决的问题,但我们很高兴地展示了这些初步的积极结果,并将在未来的工作中继续改进这些方法。

精读

针对不同规模的嵌入式应用,本文提出了MobileNetV3-Large和MobileNetv3-Small两种轻量级模型用于图像分类、分割、物体检测的嵌入式或移动端应用。

主要创新点在于SE Module、h-swish和NAS的应用。在分割任务中还提出了新的解码结构LR-ASPP。未来还将进一步精简网络。

代码实现

import torch
import torch.nn as nn
import torchvision
import torch.nn.functional as F
from torchsummary import summaryclass HardSwish(nn.Module):def __init__(self, inplace=True):super(HardSwish, self).__init__()self.relu6 = nn.ReLU6(inplace)def forward(self, x):return x*self.relu6(x+3)/6def ConvBNActivation(in_channels,out_channels,kernel_size,stride,activate):return nn.Sequential(nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=kernel_size, stride=stride, padding=(kernel_size-1)//2, groups=in_channels),nn.BatchNorm2d(out_channels),nn.ReLU6(inplace=True) if activate == 'relu' else HardSwish())def Conv1x1BNActivation(in_channels,out_channels,activate):return nn.Sequential(nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=1, stride=1),nn.BatchNorm2d(out_channels),nn.ReLU6(inplace=True) if activate == 'relu' else HardSwish())def Conv1x1BN(in_channels,out_channels):return nn.Sequential(nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=1, stride=1),nn.BatchNorm2d(out_channels))class SqueezeAndExcite(nn.Module):def __init__(self, in_channels, out_channels,se_kernel_size, divide=4):super(SqueezeAndExcite, self).__init__()mid_channels = in_channels // divideself.pool = nn.AvgPool2d(kernel_size=se_kernel_size,stride=1)self.SEblock = nn.Sequential(nn.Linear(in_features=in_channels, out_features=mid_channels),nn.ReLU6(inplace=True),nn.Linear(in_features=mid_channels, out_features=out_channels),HardSwish(inplace=True),)def forward(self, x):b, c, h, w = x.size()out = self.pool(x)out = out.view(b, -1)out = self.SEblock(out)out = out.view(b, c, 1, 1)return out * xclass SEInvertedBottleneck(nn.Module):def __init__(self, in_channels, mid_channels, out_channels, kernel_size, stride,activate, use_se, se_kernel_size=1):super(SEInvertedBottleneck, self).__init__()self.stride = strideself.use_se = use_se# mid_channels = (in_channels * expansion_factor)self.conv = Conv1x1BNActivation(in_channels, mid_channels,activate)self.depth_conv = ConvBNActivation(mid_channels, mid_channels, kernel_size,stride,activate)if self.use_se:self.SEblock = SqueezeAndExcite(mid_channels, mid_channels, se_kernel_size)self.point_conv = Conv1x1BNActivation(mid_channels, out_channels,activate)if self.stride == 1:self.shortcut = Conv1x1BN(in_channels, out_channels)def forward(self, x):out = self.depth_conv(self.conv(x))if self.use_se:out = self.SEblock(out)out = self.point_conv(out)out = (out + self.shortcut(x)) if self.stride == 1 else outreturn outclass MobileNetV3(nn.Module):def __init__(self, num_classes=1000,type='large'):super(MobileNetV3, self).__init__()self.type = typeself.first_conv = nn.Sequential(nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, stride=2, padding=1),nn.BatchNorm2d(16),HardSwish(inplace=True),)if type=='large':self.large_bottleneck = nn.Sequential(SEInvertedBottleneck(in_channels=16, mid_channels=16, out_channels=16, kernel_size=3, stride=1,activate='relu', use_se=False),SEInvertedBottleneck(in_channels=16, mid_channels=64, out_channels=24, kernel_size=3, stride=2, activate='relu', use_se=False),SEInvertedBottleneck(in_channels=24, mid_channels=72, out_channels=24, kernel_size=3, stride=1, activate='relu', use_se=False),SEInvertedBottleneck(in_channels=24, mid_channels=72, out_channels=40, kernel_size=5, stride=2,activate='relu', use_se=True, se_kernel_size=28),SEInvertedBottleneck(in_channels=40, mid_channels=120, out_channels=40, kernel_size=5, stride=1,activate='relu', use_se=True, se_kernel_size=28),SEInvertedBottleneck(in_channels=40, mid_channels=120, out_channels=40, kernel_size=5, stride=1,activate='relu', use_se=True, se_kernel_size=28),SEInvertedBottleneck(in_channels=40, mid_channels=240, out_channels=80, kernel_size=3, stride=1,activate='hswish', use_se=False),SEInvertedBottleneck(in_channels=80, mid_channels=200, out_channels=80, kernel_size=3, stride=1,activate='hswish', use_se=False),SEInvertedBottleneck(in_channels=80, mid_channels=184, out_channels=80, kernel_size=3, stride=2,activate='hswish', use_se=False),SEInvertedBottleneck(in_channels=80, mid_channels=184, out_channels=80, kernel_size=3, stride=1,activate='hswish', use_se=False),SEInvertedBottleneck(in_channels=80, mid_channels=480, out_channels=112, kernel_size=3, stride=1,activate='hswish', use_se=True, se_kernel_size=14),SEInvertedBottleneck(in_channels=112, mid_channels=672, out_channels=112, kernel_size=3, stride=1,activate='hswish', use_se=True, se_kernel_size=14),SEInvertedBottleneck(in_channels=112, mid_channels=672, out_channels=160, kernel_size=5, stride=2,activate='hswish', use_se=True,se_kernel_size=7),SEInvertedBottleneck(in_channels=160, mid_channels=960, out_channels=160, kernel_size=5, stride=1,activate='hswish', use_se=True,se_kernel_size=7),SEInvertedBottleneck(in_channels=160, mid_channels=960, out_channels=160, kernel_size=5, stride=1,activate='hswish', use_se=True,se_kernel_size=7),)self.large_last_stage = nn.Sequential(nn.Conv2d(in_channels=160, out_channels=960, kernel_size=1, stride=1),nn.BatchNorm2d(960),HardSwish(inplace=True),nn.AvgPool2d(kernel_size=7, stride=1),nn.Conv2d(in_channels=960, out_channels=1280, kernel_size=1, stride=1),HardSwish(inplace=True),)else:self.small_bottleneck = nn.Sequential(SEInvertedBottleneck(in_channels=16, mid_channels=16, out_channels=16, kernel_size=3, stride=2,activate='relu', use_se=True, se_kernel_size=56),SEInvertedBottleneck(in_channels=16, mid_channels=72, out_channels=24, kernel_size=3, stride=2,activate='relu', use_se=False),SEInvertedBottleneck(in_channels=24, mid_channels=88, out_channels=24, kernel_size=3, stride=1,activate='relu', use_se=False),SEInvertedBottleneck(in_channels=24, mid_channels=96, out_channels=40, kernel_size=5, stride=2,activate='hswish', use_se=True, se_kernel_size=14),SEInvertedBottleneck(in_channels=40, mid_channels=240, out_channels=40, kernel_size=5, stride=1,activate='hswish', use_se=True, se_kernel_size=14),SEInvertedBottleneck(in_channels=40, mid_channels=240, out_channels=40, kernel_size=5, stride=1,activate='hswish', use_se=True, se_kernel_size=14),SEInvertedBottleneck(in_channels=40, mid_channels=120, out_channels=48, kernel_size=5, stride=1,activate='hswish', use_se=True, se_kernel_size=14),SEInvertedBottleneck(in_channels=48, mid_channels=144, out_channels=48, kernel_size=5, stride=1,activate='hswish', use_se=True, se_kernel_size=14),SEInvertedBottleneck(in_channels=48, mid_channels=288, out_channels=96, kernel_size=5, stride=2,activate='hswish', use_se=True, se_kernel_size=7),SEInvertedBottleneck(in_channels=96, mid_channels=576, out_channels=96, kernel_size=5, stride=1,activate='hswish', use_se=True, se_kernel_size=7),SEInvertedBottleneck(in_channels=96, mid_channels=576, out_channels=96, kernel_size=5, stride=1,activate='hswish', use_se=True, se_kernel_size=7),)self.small_last_stage = nn.Sequential(nn.Conv2d(in_channels=96, out_channels=576, kernel_size=1, stride=1),nn.BatchNorm2d(576),HardSwish(inplace=True),nn.AvgPool2d(kernel_size=7, stride=1),nn.Conv2d(in_channels=576, out_channels=1280, kernel_size=1, stride=1),HardSwish(inplace=True),)self.classifier = nn.Conv2d(in_channels=1280, out_channels=num_classes, kernel_size=1, stride=1)def init_params(self):for m in self.modules():if isinstance(m, nn.Conv2d):nn.init.kaiming_normal_(m.weight)nn.init.constant_(m.bias, 0)elif isinstance(m, nn.BatchNorm2d) or isinstance(m, nn.Linear):nn.init.constant_(m.weight, 1)nn.init.constant_(m.bias, 0)def forward(self, x):x = self.first_conv(x)if self.type == 'large':x = self.large_bottleneck(x)x = self.large_last_stage(x)else:x = self.small_bottleneck(x)x = self.small_last_stage(x)out = self.classifier(x)out = out.view(out.size(0), -1)return outif __name__ == '__main__':net = MobileNetV3().cuda()summary(net, (3, 224, 224))

网络结构打印如下:

----------------------------------------------------------------Layer (type)               Output Shape         Param #
================================================================Conv2d-1         [-1, 16, 112, 112]             448BatchNorm2d-2         [-1, 16, 112, 112]              32ReLU6-3         [-1, 16, 112, 112]               0HardSwish-4         [-1, 16, 112, 112]               0Conv2d-5         [-1, 16, 112, 112]             272BatchNorm2d-6         [-1, 16, 112, 112]              32ReLU6-7         [-1, 16, 112, 112]               0Conv2d-8         [-1, 16, 112, 112]             160BatchNorm2d-9         [-1, 16, 112, 112]              32ReLU6-10         [-1, 16, 112, 112]               0Conv2d-11         [-1, 16, 112, 112]             272BatchNorm2d-12         [-1, 16, 112, 112]              32ReLU6-13         [-1, 16, 112, 112]               0Conv2d-14         [-1, 16, 112, 112]             272BatchNorm2d-15         [-1, 16, 112, 112]              32
SEInvertedBottleneck-16         [-1, 16, 112, 112]               0Conv2d-17         [-1, 64, 112, 112]           1,088BatchNorm2d-18         [-1, 64, 112, 112]             128ReLU6-19         [-1, 64, 112, 112]               0Conv2d-20           [-1, 64, 56, 56]             640BatchNorm2d-21           [-1, 64, 56, 56]             128ReLU6-22           [-1, 64, 56, 56]               0Conv2d-23           [-1, 24, 56, 56]           1,560BatchNorm2d-24           [-1, 24, 56, 56]              48ReLU6-25           [-1, 24, 56, 56]               0
SEInvertedBottleneck-26           [-1, 24, 56, 56]               0Conv2d-27           [-1, 72, 56, 56]           1,800BatchNorm2d-28           [-1, 72, 56, 56]             144ReLU6-29           [-1, 72, 56, 56]               0Conv2d-30           [-1, 72, 56, 56]             720BatchNorm2d-31           [-1, 72, 56, 56]             144ReLU6-32           [-1, 72, 56, 56]               0Conv2d-33           [-1, 24, 56, 56]           1,752BatchNorm2d-34           [-1, 24, 56, 56]              48ReLU6-35           [-1, 24, 56, 56]               0Conv2d-36           [-1, 24, 56, 56]             600BatchNorm2d-37           [-1, 24, 56, 56]              48
SEInvertedBottleneck-38           [-1, 24, 56, 56]               0Conv2d-39           [-1, 72, 56, 56]           1,800BatchNorm2d-40           [-1, 72, 56, 56]             144ReLU6-41           [-1, 72, 56, 56]               0Conv2d-42           [-1, 72, 28, 28]           1,872BatchNorm2d-43           [-1, 72, 28, 28]             144ReLU6-44           [-1, 72, 28, 28]               0AvgPool2d-45             [-1, 72, 1, 1]               0Linear-46                   [-1, 18]           1,314ReLU6-47                   [-1, 18]               0Linear-48                   [-1, 72]           1,368ReLU6-49                   [-1, 72]               0HardSwish-50                   [-1, 72]               0SqueezeAndExcite-51           [-1, 72, 28, 28]               0Conv2d-52           [-1, 40, 28, 28]           2,920BatchNorm2d-53           [-1, 40, 28, 28]              80ReLU6-54           [-1, 40, 28, 28]               0
SEInvertedBottleneck-55           [-1, 40, 28, 28]               0Conv2d-56          [-1, 120, 28, 28]           4,920BatchNorm2d-57          [-1, 120, 28, 28]             240ReLU6-58          [-1, 120, 28, 28]               0Conv2d-59          [-1, 120, 28, 28]           3,120BatchNorm2d-60          [-1, 120, 28, 28]             240ReLU6-61          [-1, 120, 28, 28]               0AvgPool2d-62            [-1, 120, 1, 1]               0Linear-63                   [-1, 30]           3,630ReLU6-64                   [-1, 30]               0Linear-65                  [-1, 120]           3,720ReLU6-66                  [-1, 120]               0HardSwish-67                  [-1, 120]               0SqueezeAndExcite-68          [-1, 120, 28, 28]               0Conv2d-69           [-1, 40, 28, 28]           4,840BatchNorm2d-70           [-1, 40, 28, 28]              80ReLU6-71           [-1, 40, 28, 28]               0Conv2d-72           [-1, 40, 28, 28]           1,640BatchNorm2d-73           [-1, 40, 28, 28]              80
SEInvertedBottleneck-74           [-1, 40, 28, 28]               0Conv2d-75          [-1, 120, 28, 28]           4,920BatchNorm2d-76          [-1, 120, 28, 28]             240ReLU6-77          [-1, 120, 28, 28]               0Conv2d-78          [-1, 120, 28, 28]           3,120BatchNorm2d-79          [-1, 120, 28, 28]             240ReLU6-80          [-1, 120, 28, 28]               0AvgPool2d-81            [-1, 120, 1, 1]               0Linear-82                   [-1, 30]           3,630ReLU6-83                   [-1, 30]               0Linear-84                  [-1, 120]           3,720ReLU6-85                  [-1, 120]               0HardSwish-86                  [-1, 120]               0SqueezeAndExcite-87          [-1, 120, 28, 28]               0Conv2d-88           [-1, 40, 28, 28]           4,840BatchNorm2d-89           [-1, 40, 28, 28]              80ReLU6-90           [-1, 40, 28, 28]               0Conv2d-91           [-1, 40, 28, 28]           1,640BatchNorm2d-92           [-1, 40, 28, 28]              80
SEInvertedBottleneck-93           [-1, 40, 28, 28]               0Conv2d-94          [-1, 240, 28, 28]           9,840BatchNorm2d-95          [-1, 240, 28, 28]             480ReLU6-96          [-1, 240, 28, 28]               0HardSwish-97          [-1, 240, 28, 28]               0Conv2d-98          [-1, 240, 28, 28]           2,400BatchNorm2d-99          [-1, 240, 28, 28]             480ReLU6-100          [-1, 240, 28, 28]               0HardSwish-101          [-1, 240, 28, 28]               0Conv2d-102           [-1, 80, 28, 28]          19,280BatchNorm2d-103           [-1, 80, 28, 28]             160ReLU6-104           [-1, 80, 28, 28]               0HardSwish-105           [-1, 80, 28, 28]               0Conv2d-106           [-1, 80, 28, 28]           3,280BatchNorm2d-107           [-1, 80, 28, 28]             160
SEInvertedBottleneck-108           [-1, 80, 28, 28]               0Conv2d-109          [-1, 200, 28, 28]          16,200BatchNorm2d-110          [-1, 200, 28, 28]             400ReLU6-111          [-1, 200, 28, 28]               0HardSwish-112          [-1, 200, 28, 28]               0Conv2d-113          [-1, 200, 28, 28]           2,000BatchNorm2d-114          [-1, 200, 28, 28]             400ReLU6-115          [-1, 200, 28, 28]               0HardSwish-116          [-1, 200, 28, 28]               0Conv2d-117           [-1, 80, 28, 28]          16,080BatchNorm2d-118           [-1, 80, 28, 28]             160ReLU6-119           [-1, 80, 28, 28]               0HardSwish-120           [-1, 80, 28, 28]               0Conv2d-121           [-1, 80, 28, 28]           6,480BatchNorm2d-122           [-1, 80, 28, 28]             160
SEInvertedBottleneck-123           [-1, 80, 28, 28]               0Conv2d-124          [-1, 184, 28, 28]          14,904BatchNorm2d-125          [-1, 184, 28, 28]             368ReLU6-126          [-1, 184, 28, 28]               0HardSwish-127          [-1, 184, 28, 28]               0Conv2d-128          [-1, 184, 14, 14]           1,840BatchNorm2d-129          [-1, 184, 14, 14]             368ReLU6-130          [-1, 184, 14, 14]               0HardSwish-131          [-1, 184, 14, 14]               0Conv2d-132           [-1, 80, 14, 14]          14,800BatchNorm2d-133           [-1, 80, 14, 14]             160ReLU6-134           [-1, 80, 14, 14]               0HardSwish-135           [-1, 80, 14, 14]               0
SEInvertedBottleneck-136           [-1, 80, 14, 14]               0Conv2d-137          [-1, 184, 14, 14]          14,904BatchNorm2d-138          [-1, 184, 14, 14]             368ReLU6-139          [-1, 184, 14, 14]               0HardSwish-140          [-1, 184, 14, 14]               0Conv2d-141          [-1, 184, 14, 14]           1,840BatchNorm2d-142          [-1, 184, 14, 14]             368ReLU6-143          [-1, 184, 14, 14]               0HardSwish-144          [-1, 184, 14, 14]               0Conv2d-145           [-1, 80, 14, 14]          14,800BatchNorm2d-146           [-1, 80, 14, 14]             160ReLU6-147           [-1, 80, 14, 14]               0HardSwish-148           [-1, 80, 14, 14]               0Conv2d-149           [-1, 80, 14, 14]           6,480BatchNorm2d-150           [-1, 80, 14, 14]             160
SEInvertedBottleneck-151           [-1, 80, 14, 14]               0Conv2d-152          [-1, 480, 14, 14]          38,880BatchNorm2d-153          [-1, 480, 14, 14]             960ReLU6-154          [-1, 480, 14, 14]               0HardSwish-155          [-1, 480, 14, 14]               0Conv2d-156          [-1, 480, 14, 14]           4,800BatchNorm2d-157          [-1, 480, 14, 14]             960ReLU6-158          [-1, 480, 14, 14]               0HardSwish-159          [-1, 480, 14, 14]               0AvgPool2d-160            [-1, 480, 1, 1]               0Linear-161                  [-1, 120]          57,720ReLU6-162                  [-1, 120]               0Linear-163                  [-1, 480]          58,080ReLU6-164                  [-1, 480]               0HardSwish-165                  [-1, 480]               0
SqueezeAndExcite-166          [-1, 480, 14, 14]               0Conv2d-167          [-1, 112, 14, 14]          53,872BatchNorm2d-168          [-1, 112, 14, 14]             224ReLU6-169          [-1, 112, 14, 14]               0HardSwish-170          [-1, 112, 14, 14]               0Conv2d-171          [-1, 112, 14, 14]           9,072BatchNorm2d-172          [-1, 112, 14, 14]             224
SEInvertedBottleneck-173          [-1, 112, 14, 14]               0Conv2d-174          [-1, 672, 14, 14]          75,936BatchNorm2d-175          [-1, 672, 14, 14]           1,344ReLU6-176          [-1, 672, 14, 14]               0HardSwish-177          [-1, 672, 14, 14]               0Conv2d-178          [-1, 672, 14, 14]           6,720BatchNorm2d-179          [-1, 672, 14, 14]           1,344ReLU6-180          [-1, 672, 14, 14]               0HardSwish-181          [-1, 672, 14, 14]               0AvgPool2d-182            [-1, 672, 1, 1]               0Linear-183                  [-1, 168]         113,064ReLU6-184                  [-1, 168]               0Linear-185                  [-1, 672]         113,568ReLU6-186                  [-1, 672]               0HardSwish-187                  [-1, 672]               0
SqueezeAndExcite-188          [-1, 672, 14, 14]               0Conv2d-189          [-1, 112, 14, 14]          75,376BatchNorm2d-190          [-1, 112, 14, 14]             224ReLU6-191          [-1, 112, 14, 14]               0HardSwish-192          [-1, 112, 14, 14]               0Conv2d-193          [-1, 112, 14, 14]          12,656BatchNorm2d-194          [-1, 112, 14, 14]             224
SEInvertedBottleneck-195          [-1, 112, 14, 14]               0Conv2d-196          [-1, 672, 14, 14]          75,936BatchNorm2d-197          [-1, 672, 14, 14]           1,344ReLU6-198          [-1, 672, 14, 14]               0HardSwish-199          [-1, 672, 14, 14]               0Conv2d-200            [-1, 672, 7, 7]          17,472BatchNorm2d-201            [-1, 672, 7, 7]           1,344ReLU6-202            [-1, 672, 7, 7]               0HardSwish-203            [-1, 672, 7, 7]               0AvgPool2d-204            [-1, 672, 1, 1]               0Linear-205                  [-1, 168]         113,064ReLU6-206                  [-1, 168]               0Linear-207                  [-1, 672]         113,568ReLU6-208                  [-1, 672]               0HardSwish-209                  [-1, 672]               0
SqueezeAndExcite-210            [-1, 672, 7, 7]               0Conv2d-211            [-1, 160, 7, 7]         107,680BatchNorm2d-212            [-1, 160, 7, 7]             320ReLU6-213            [-1, 160, 7, 7]               0HardSwish-214            [-1, 160, 7, 7]               0
SEInvertedBottleneck-215            [-1, 160, 7, 7]               0Conv2d-216            [-1, 960, 7, 7]         154,560BatchNorm2d-217            [-1, 960, 7, 7]           1,920ReLU6-218            [-1, 960, 7, 7]               0HardSwish-219            [-1, 960, 7, 7]               0Conv2d-220            [-1, 960, 7, 7]          24,960BatchNorm2d-221            [-1, 960, 7, 7]           1,920ReLU6-222            [-1, 960, 7, 7]               0HardSwish-223            [-1, 960, 7, 7]               0AvgPool2d-224            [-1, 960, 1, 1]               0Linear-225                  [-1, 240]         230,640ReLU6-226                  [-1, 240]               0Linear-227                  [-1, 960]         231,360ReLU6-228                  [-1, 960]               0HardSwish-229                  [-1, 960]               0
SqueezeAndExcite-230            [-1, 960, 7, 7]               0Conv2d-231            [-1, 160, 7, 7]         153,760BatchNorm2d-232            [-1, 160, 7, 7]             320ReLU6-233            [-1, 160, 7, 7]               0HardSwish-234            [-1, 160, 7, 7]               0Conv2d-235            [-1, 160, 7, 7]          25,760BatchNorm2d-236            [-1, 160, 7, 7]             320
SEInvertedBottleneck-237            [-1, 160, 7, 7]               0Conv2d-238            [-1, 960, 7, 7]         154,560BatchNorm2d-239            [-1, 960, 7, 7]           1,920ReLU6-240            [-1, 960, 7, 7]               0HardSwish-241            [-1, 960, 7, 7]               0Conv2d-242            [-1, 960, 7, 7]          24,960BatchNorm2d-243            [-1, 960, 7, 7]           1,920ReLU6-244            [-1, 960, 7, 7]               0HardSwish-245            [-1, 960, 7, 7]               0AvgPool2d-246            [-1, 960, 1, 1]               0Linear-247                  [-1, 240]         230,640ReLU6-248                  [-1, 240]               0Linear-249                  [-1, 960]         231,360ReLU6-250                  [-1, 960]               0HardSwish-251                  [-1, 960]               0
SqueezeAndExcite-252            [-1, 960, 7, 7]               0Conv2d-253            [-1, 160, 7, 7]         153,760BatchNorm2d-254            [-1, 160, 7, 7]             320ReLU6-255            [-1, 160, 7, 7]               0HardSwish-256            [-1, 160, 7, 7]               0Conv2d-257            [-1, 160, 7, 7]          25,760BatchNorm2d-258            [-1, 160, 7, 7]             320
SEInvertedBottleneck-259            [-1, 160, 7, 7]               0Conv2d-260            [-1, 960, 7, 7]         154,560BatchNorm2d-261            [-1, 960, 7, 7]           1,920ReLU6-262            [-1, 960, 7, 7]               0HardSwish-263            [-1, 960, 7, 7]               0AvgPool2d-264            [-1, 960, 1, 1]               0Conv2d-265           [-1, 1280, 1, 1]       1,230,080ReLU6-266           [-1, 1280, 1, 1]               0HardSwish-267           [-1, 1280, 1, 1]               0Conv2d-268           [-1, 1000, 1, 1]       1,281,000
================================================================
Total params: 5,589,150
Trainable params: 5,589,150
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.57
Forward/backward pass size (MB): 153.55
Params size (MB): 21.32
Estimated Total Size (MB): 175.44
----------------------------------------------------------------

MobileNetV1&MobileNetV2&MobileNetV3总结

MobileNetV1MobileNetV2MobileNetV3
标准卷积改为深度可分离卷积,降低计算量;ReLU改为ReLU6;引入Width Multiplier(α)和Resolution Multiplier(ρ),调节模型的宽度(卷积核个数)和图像分辨率;**采用线性瓶颈层:**将深度可分离卷积中的1×1卷积后的ReLU替换成线性激活函数;**采用反向残差结构:**引入了Expansion layer,在进行深度分离卷积之前首先使用1×1卷积进行升维;引入Shortcut结构,在升维的1×1卷积之前与深度可分离卷积中的1×1卷积之后进行shortcut连接;采用增加了SE机制的Bottleneck模块结构;使用了一种新的激活函数h-swish(x)替代MobileNetV2中的ReLU6激活函数;网络结构搜索中,结合两种技术:资源受限的NAS(platform-aware NAS)与NetAdapt;修改了MobileNetV2网络端部最后阶段;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/148305.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Vue+SpringBoot的大病保险管理系统 开源项目

项目编号&#xff1a; S 031 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S031&#xff0c;文末获取源码。} 项目编号&#xff1a;S031&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统配置维护2.2 系统参保管理2.3 大…

SDUT OJ《算法分析与设计》搜索算法

A - 子集和问题 Description 子集和问题的一个实例为〈S,t〉。其中&#xff0c;S{ x1 &#xff0c; x2 &#xff0c;…&#xff0c;xn }是一个正整数的集合&#xff0c;c是一个正整数。子集和问题判定是否存在S的一个子集S1&#xff0c;使得&#xff1a; 。 试设计一个解子…

坐标系下的运动旋量转换

坐标系下的运动旋量转换 文章目录 坐标系下的运动旋量转换前言一、运动旋量物体运动旋量空间运动旋量 二、伴随变换矩阵三、坐标系下运动旋量的转换四、力旋量五、总结参考资料 前言 对于刚体而言&#xff0c;其角速度可以写为 ω ^ θ ˙ \hat {\omega} \dot \theta ω^θ˙&…

Pytorch torch.exp()的使用举例

代码实验展示: Microsoft Windows [版本 10.0.18363.1256] (c) 2019 Microsoft Corporation。保留所有权利。C:\Users\chenxuqi>conda activate ssd4pytorch1_2_0(ssd4pytorch1_2_0) C:\Users\chenxuqi>python Python 3.7.7 (default, May 6 2020, 11:45:54) [MSC v.191…

STL总结

STL vector 头文件<vector> 初始化,定义,定义长度&#xff0c;定义长度并且赋值&#xff0c;从数组中获取数据返回元素个数size()判断是否为空empty()返回第一个元素front()返回最后一个数back()删除最后一个数pop_back()插入push_back(x)清空clear()begin()end()使用s…

SQL SERVER 2008安装教程

SQL SERVER 2008安装教程 本篇文章介绍了安装SQL Server 2008企业版的软硬件配置要求&#xff0c;安装过程的详细步骤&#xff0c;以及需要注意的事项。 安装步骤 (1). 在安装文件setup.exe上&#xff0c;单击鼠标右键选择“以管理员的身份运行”&#xff0c;如下图所示&#…

皮肤性病科专家谭巍主任提出HPV转阴后饮食七点建议

HPV转阴是每一位感染者都期盼的&#xff0c;因为转阴所以健康&#xff0c;只有转为阴性才意味着不具备传染性&#xff0c;从此也不必再害怕将病毒传染给家人的风险&#xff0c;也不必再担忧持续感染而引发的健康风险。总之&#xff0c;HPV转阴是预示感染者恢复健康与否的主要标…

《洛谷深入浅出进阶篇》P1995 程序自动分析——并查集,离散化

上链接&#xff1a;P1955 [NOI2015] 程序自动分析 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P1955 上题干&#xff1a; 首先给你一个整数t&#xff0c;代表t次操作。 每一次操作包含以下内容&#xff1a; 1.给你一个整数n&#xff0c;让…

【机器学习13】生成对抗网络

1 GANs的基本思想和训练过程 生成器用于合成“假”样本&#xff0c; 判别器用于判断输入的样本是真实的还是合成的。 生成器从先验分布中采得随机信号&#xff0c;经过神经网络的变换&#xff0c; 得到模拟样本&#xff1b; 判别器既接收来自生成器的模拟样本&#xff0c; 也接…

数据结构:红黑树讲解(C++)

红黑树 1.前言2.红黑树简述2.1概念2.2性质 3.红黑树的插入3.1关于新插入节点的颜色3.2节点的定义3.3插入新节点3.4判断插入后是否需要调整3.5插入后维持红黑树结构&#xff08;重点&#xff09;3.5.1cur、p、u为红&#xff0c;g为黑3.5.2cur、p为红&#xff0c;g为黑&#xff0…

【【VDMA彩条显示实验之三 之 RGB LCD 彩条显示实验 】】

VDMA彩条显示实验之三 之 RGB LCD 彩条显示实验 VDMA彩条显示实验之三 之 RGB LCD 彩条显示实验 LCD 的构造是在两片平行的玻璃基板当中放置液晶盒&#xff0c;下基板玻璃上设置 TFT&#xff08;薄膜晶体管&#xff09;&#xff0c;上基板玻璃上设置彩色滤光片&#xff0c;通…

Flutter 应用启动从闪屏页短暂黑屏再到第一个页面

由于应用初始状态启动会有白屏现象&#xff0c;便使用 flutter_native_splash 2.3.5 插件生成了启动相关的配置&#xff0c;并且按照示例使用了 import package:flutter_native_splash/flutter_native_splash.dart;void main() {WidgetsBinding widgetsBinding WidgetsFlutte…

牛客 —— 链表中倒数第k个结点(C语言,快慢指针,配图)

目录 1. 思路1&#xff1a;倒数第K个节点&#xff0c;就是整数第N-K1的节点 2. 思路2&#xff1a;快慢指针 1. 思路1&#xff1a;倒数第K个节点&#xff0c;就是整数第N-K1的节点 链表中&#xff0c;一共有N个节点&#xff0c;如果我们想要得出倒数第K个节点&#xff0c;我们…

图像倾斜角度求取-Radon变换

Radon算法 Radon&#xff08;拉东&#xff09;算法是一种通过定方向投影叠加&#xff0c;找到最大投影值时角度&#xff0c;从而确定图像倾斜角度的算法。具体过程如图所示 图1 Radon变换算法 Radon计算示例 对于纹理方向明显的图像&#xff0c;如图2所示&#xff0c;可以通…

【设计模式】聊聊模板模式

原理和实现 设计模式的原理和实现是比较简单的&#xff0c;难的是掌握具体的应用场景和解决什么问题。而模板模式是为来解决复用和拓展两个问题。 模板模式在一个方法中定义好一个算法框架&#xff0c;然后将某些步骤推迟到子类中实现&#xff0c;子类可以在不修改父类流程的时…

qsort使用举例和qsort函数的模拟实现

qsort使用举例 qsort是C语言中的一个标准库函数&#xff0c;用于对数组或者其他数据结构中的元素进行排序。它的原型如下&#xff1a; void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)); 我们可以去官网搜来看一看&#xff1a;…

lxml基本使用

lxml是python的一个解析库&#xff0c;支持HTML和XML的解析&#xff0c;支持XPath解析方式&#xff0c;而且解析效率非常高 XPath&#xff0c;全称XML Path Language&#xff0c;即XML路径语言&#xff0c;它是一门在XML文档中查找信息的语言&#xff0c;它最初是用来搜寻XML文…

2024全网最新最全的Pytest接口自动化测试框架教程

pytest编写的规则&#xff1a; 1、测试文件以test_开头&#xff08;以_test结尾也可以&#xff09; 2、测试类以Test开头&#xff0c;并且不能带有__init__方法 3、测试函数以test_开头 4、断言必须使用assert pytest.main([-s,-v]) &#xff1a;用来执行测试用例 -s 打印prin…

卷积神经网络(CNN)天气识别

文章目录 前期工作1. 设置GPU&#xff08;如果使用的是CPU可以忽略这步&#xff09;我的环境&#xff1a; 2. 导入数据3. 查看数据 二、数据预处理1. 加载数据2. 可视化数据3. 再次检查数据4. 配置数据集 三、构建CNN网络四、编译五、训练模型六、模型评估 前期工作 1. 设置GP…

EEPROM与Flash的区别

EEPROM与Flash的区别 EEPROMEEPROM内部功能框图实现写入数据内部结构存储管在充电或放电状态下有着不同的阈值电压 问题点EEPROM是如何失效的呢&#xff1f;为何EEPROM不能做大呢&#xff1f; ------------------------------------------------------------------------------…