前言
上周我们学习了MobileNetV1和MobileNetV2,本文的MobileNetV3,它首先引入MobileNetV1的深度可分离卷积,然后引入MobileNetV2的具有线性瓶颈的倒残差结构,后来使用了网络搜索算法,并引入了SE模块以及H-Swish激活函数等,可谓集大成者。
引用大佬的描述:MobileNet V3 = MobileNet v2 + SE结构 + hard-swish activation +网络结构头尾微调。
学习资料:
- 论文题目:《MobileNetV3: Searching for MobileNetV3》(《MobileNetV3: 搜索MobileNetV3)
- 原文地址:https://arxiv.org/abs/1905.02244.pdf
- 项目地址:GitHub - d-li14/mobilenetv3.pytorch: 74.3% MobileNetV3-Large and 67.2% MobileNetV3-Small model on ImageNet
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:用于对各个模块确定之后网络层的微调。
4.1 Platform-Aware NAS for Block-wise Search—使用NAS感知平台进行逐块(Block-wise)搜索
翻译
与[41]类似,我们采用平台感知神经结构方法来寻找全局网络结构。由于我们使用相同的基于Rnn-based的控制器和相同的分解层次搜索空间,所以对于目标延迟在80ms左右的大型移动模型,我们发现了与[41]类似的结果。因此,我们只需重用与初始大型移动模型相同的MnasNet-A1[41],然后在其上应用NetAdapt[46]和其他优化。
然而,我们发现最初的奖励设计并没有针对小型手机模型进行优化。具体来说,它使用一个多目标奖励
来近似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模型。
4.2 NetAdapt for Layer-wise Search—使用NetAdapt 进行 Layerwise 搜索
翻译
我们在架构搜索中使用的第二种技术是NetAdapt[46]。这种方法是对平台感知NAS的补充:它允许以顺序的方式对单个层进行微调,而不是试图推断出粗糙但全局的体系结构。详情请参阅原文。简而言之,这项技术的进展如下:
从平台感知NAS发现的种子网络体系结构开始。
为每个步骤:
(a)提出一套新的建议。每个建议都表示对体系结构的修改,与前一步相比,该体系结构至少可以减少延迟。
(b)对于每一个提案,我们使用前一步骤的预先训练的模型,并填充新提出的架构,适当地截断和随机初始化缺失的权重。对T步的每个建议进行微调,以获得对精度的粗略估计。
(c)根据某种标准选择最佳建议。
- 重复前面的步骤,直到达到目标延迟。
在[46]中,度量是为了最小化精度的变化。我们修改了这个算法,使延迟变化和精度变化的比例最小化。也就是说,对于每个NetAdapt步骤中生成的所有建议,我们选择一个最大化的建议:ΔACC/|Δlatency|,延迟满足2(a)中的约束。直觉告诉我们,由于我们的建议是离散的,所以我们更喜欢最大化权衡曲线斜率的建议。
这个过程重复进行,直到延迟达到目标,然后从头开始重新培训新的体系结构。我们使用与在[46]中为MobilenetV2使用相同的提案生成器。具体来说,我们允许以下两种提议:
- 减小任何膨胀层的尺寸;
- 减少共享相同瓶颈大小的所有块中的瓶颈—以维护剩余连接。
在我们的实验中,我们使用T = 10000,并发现虽然它增加了建议的初始微调的准确性。然而,当从零开始训练时,它通常不会改变最终的精度。设δ = 0.01 ∣L∣ ,其中L为种子模型的延迟。
精读
NetAdapt: 一种新的网络压缩算法。
NetAdapt的网络优化以自动的方式进行,它使用一个预训练好的模型在固定计算资源的手机平台上进行压缩试验,逐渐降低预训练网络的资源消耗,直接采集压缩之后的性能表现(作为feedback,得到一系列满足资源限制、同时最大化精度的简化网络。)
本文对NetAdapt的处理如下
(1)从平台感知 NAS 发现的种子网络体系结构开始
(2)对于每一个步骤:
- 提出一套新的提议proposal, 每个提议都表示对体系结构的修改,与前一步相比,该体系结构至少可以减少延迟
- 对于每一个提议,使用前一个步骤的预先训练的模型,并填充新提出的架构,适当地截断和随机初始化缺失的权重。对于 T 步的每个建议进行微调,以获得对精度的粗略估计
- 根据某种标准选择最佳提议proposal
(3)重复前面的步骤,直到达到目标延迟
两个建议
(1)减小扩展层的尺寸;
(2)保持残差连接,减小瓶颈的尺寸。
五、Network Improvements—网络改进
5.1 Redesigning Expensive Layers—重新设计昂贵的层
翻译
一旦通过架构搜索找到模型,我们就会发现,一些最后的层以及一些较早的层比其他层更昂贵。我们建议对体系结构进行一些修改,以减少这些慢层的延迟,同时保持准确性。这些修改超出了当前搜索空间的范围。
第一个修改将重新处理网络的最后几层是如何交互的,以便生成最终层功能更有效率。目前的模型基于MobileNetV2的倒瓶颈结构和变体,使用1x1卷积作为最后一层,以扩展到高维特征空间。这一层非常重要,因为它具有丰富的预测功能。然而,这是以额外的延迟为代价的。
为了减少延迟并保留高维特性,我们将该层移到最终的平均池之后。最后一组特征现在计算为1x1空间分辨率,而不是7x7空间分辨率。这种设计选择的结果是,在计算和延迟方面,特性的计算变得几乎是免费的。
一旦降低了该特性生成层的成本,就不再需要以前的瓶颈投影层来减少计算量。该观察允许我们删除前一个瓶颈层中的投影和过滤层,从而进一步降低计算复杂度。原始阶段和优化后的阶段如图5所示。有效的最后一个阶段将延迟减少了10毫秒,即15%的运行时间,并将操作数量减少了3000万个madd,几乎没有损失精度。第6节包含了详细的结果。
另一个昂贵的层是初始过滤器集。目前的移动模型倾向于在一个完整的3x3卷积中使用32个滤波器来构建初始滤波器库进行边缘检测。通常这些过滤器是彼此的镜像。我们尝试减少滤波器的数量,并使用不同的非线性来尝试减少冗余。我们决定对这一层使用硬swish非线性,因为它的表现和其他非线性测试。我们能够将过滤器的数量减少到16个,同时保持与使用ReLU或swish的32个过滤器相同的精度。这节省了额外的3毫秒和1000万 MAdds。
精读
MobileNetV2的方法及不足
方法: 在最后一层使用了1×1卷积进行特征空间维度扩展。
不足: 会带来额外的延迟
本文改进的方法
(1)将该层移动到平均池化层之外。最终,维度扩展是在1×1而非7×7的分辨率上进行。
(2)使用hardswish非线性激活函数
(3)将过滤器的数量减少到 16 个
5.2 Nonlinearities—非线性函数
翻译
在[34]中引入了一种称为swish的非线性,当作为ReLU的替代时,它可以显著提高神经网络的精度。非线性定义为:
虽然这种非线性提高了精度,但在嵌入式环境中,它的成本是非零的,因为在移动设备上计算sigmoid函数要昂贵得多。我们用两种方法处理这个问题。
1. 我们将sigmoid函数替换为它的分段线性硬模拟:ReLU6(x+3)/6类似于[11,42]。小的区别是,我们使用的是ReLU6,而不是定制的裁剪常量。类似地,swish的硬版本也变成了:
最近在[2]中也提出了类似的hard-swish版本。图6显示了sigmoid和swish非线性的软、硬版本的比较。我们选择常量的动机是简单,并且与原始的平滑版本很好地匹配。在我们的实验中,我们发现所有这些函数的硬版本在精度上没有明显的差异,但是从部署的角度来看,它们具有多种优势。首先,几乎所有的软件和硬件框架上都可以使用ReLU6的优化实现。其次,在量子化模式下,它消除了由于近似sigmoid的不同实现而带来的潜在的数值精度损失。最后,即使优化了量化的sigmoid实现,其速度也比相应的ReLU慢得多。在我们的实验中,用量化模式下的swish替换h-swish使推理延迟增加了15%。
2. 随着我们深入网络,应用非线性的成本会降低,因为每层激活内存通常在分辨率下降时减半。顺便说一句,我们发现swish的大多数好处都是通过只在更深的层中使用它们实现的。因此,在我们的架构中,我们只在模型的后半部分使用h-swish。我们参照表1和表2来获得精确的布局,即使有了这些优化,h-swish仍然会引入一些延迟成本。然而正如我们在第六节证明准确性和延迟的净效应是正的,它基于一个piece-wise函数提供了进一步优化。
精读
swish
swish是Google提出的一种非线性激活函数,在一些深层网络中优于ReLU,如在40层以上的全连接层的效果要明显优于其他激活函数。
h-swish
Swish 具备无上界有下界、平滑、非单调的特性,但由于sigmoid在硬件设备上无法实现,为此将sigmoid替换为相近的基于ReLU6的计算,即h-swish。
h-swish计算速度比swish更快(但比ReLU慢),更易于量化,精度上没有差异。
而且实验发现h-swish激活在深层次网络中更有效,为此前层网络依旧使用的ReLU。
5.3 Large squeeze-and-excite—大型SE
翻译
在[41]中,SE的大小与卷积瓶颈的大小有关。取而代之的是,我们将它们全部替换为固定为膨胀层通道数的1/4。我们发现这样做可以在适当增加参数数量的情况下提高精度,并且没有明显的延迟成本。
精读
SE结构会消耗一定的时间,SE瓶颈的大小与卷积瓶颈的大小有关。将它们全部替换为固定为膨胀层通道数的1/4,可以在适当增加参数数量的情况下提高精度,并且没有明显的延迟成本。
SE模块被放在了Depthwise卷积后面。
5.4 MobileNetV3 Definitions—MobileNetV3 定义
翻译
MobileNetV3被定义为两个模型:MobileNetV3—大的和MobileNetV3—小的。这些模型分别针对高资源用例和低资源用例。通过应用平台感知的NAS和NetAdapt进行网络搜索,并结合本节定义的网络改进,可以创建模型。我们的网络的完整规范见表1和表2。
精读
MobileNetV3 被定义为两个模型
- MobileNetV3-Large(高资源用例)
- MobileNetV3-Small(低资源用例)
完整网络结构
MobileNetV3-Large网络结构图
- 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网络结构图
参数同上。
六、Experiments—实验
6.1 Classification—分类
6.1.1 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
6.1.2 Measurement setup—测量设置
翻译
为了测量延迟,我们使用标准的谷歌像素手机,并通过标准的TFLite基准测试工具运行所有网络。我们在所有测量中都使用单线程大内核。我们没有报告多核推理时间,因为我们发现这种设置对移动应用程序不太实用。
精读
使用了标准的Google-Pixel手机,并使用标准的TFLite-Benchmark-Tool来运行所有的网络。
贡献: 本文为TensorflowLite贡献了H-Swish的原子运算符
图9中展示了优化后的h-swish的影响
6.2 Results—结果
翻译
如图1所示,我们的模型优于目前的技术状态,如MnasNet[41]、ProxylessNas[5]和MobileNetV2[37]。我们在表3中报告了不同像素手机上的浮点性能。我们在表4中包括量化结果。
在图7中,我们展示了MobileNetV3性能权衡作为乘数和分辨率的函数。请注意,MobileNetV3-Small的性能比MobileNetV3-Large的性能好得多,其乘法器缩放到与性能匹配的倍数接近3%。另一方面,决议提供了比乘数更好的权衡。但是,需要注意的是,分辨率通常是由问题决定的(例如分割和检测问题通常需要更高的分辨率),因此不能总是用作可调参数。
精读
表3展示了在不同Pixel手机上浮点运算的性能结果
表4展示了量化后的结果
结论:
- MobileNetV3-Small在放大器的缩放作用下其性能比MobileNetV3-Large更好
- 分辨率比放大器提供了更好的均衡性
图7展示了MobileNetV3作为平衡放大器和分辨率函数时的均衡性能
结论:本文的模型超越了现有的SOTA模型
6.2.1 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
结论:MobileNetV3在网络的中间部分使用了H-Swish ,并且明显优于ReLU
(2)其它组件的影响
图9展示了引入不同组件后在latency/accuracy曲线上移动的情况
6.3 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 测试集的结果
结论:ImageNet 分类和 COCO对象检测可能更喜欢不同的特征提取器形状。
6.4 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的改进
结论:主干网络存在一定的通道冗余。
七、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 summary class 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)/6 def 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 // divide self.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 * x class 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 = stride self.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 out return out class MobileNetV3(nn.Module): def __init__(self, num_classes=1000,type='large'): super(MobileNetV3, self).__init__() self.type = type self.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 out if __name__ == '__main__': net = MobileNetV3().cuda() summary(net, (3, 224, 224))
网络结构打印如下:
---------------------------------------------------------------- Layer (type) Output Shape Param # ================================================================ Conv2d-1 [-1, 16, 112, 112] 448 BatchNorm2d-2 [-1, 16, 112, 112] 32 ReLU6-3 [-1, 16, 112, 112] 0 HardSwish-4 [-1, 16, 112, 112] 0 Conv2d-5 [-1, 16, 112, 112] 272 BatchNorm2d-6 [-1, 16, 112, 112] 32 ReLU6-7 [-1, 16, 112, 112] 0 Conv2d-8 [-1, 16, 112, 112] 160 BatchNorm2d-9 [-1, 16, 112, 112] 32 ReLU6-10 [-1, 16, 112, 112] 0 Conv2d-11 [-1, 16, 112, 112] 272 BatchNorm2d-12 [-1, 16, 112, 112] 32 ReLU6-13 [-1, 16, 112, 112] 0 Conv2d-14 [-1, 16, 112, 112] 272 BatchNorm2d-15 [-1, 16, 112, 112] 32 SEInvertedBottleneck-16 [-1, 16, 112, 112] 0 Conv2d-17 [-1, 64, 112, 112] 1,088 BatchNorm2d-18 [-1, 64, 112, 112] 128 ReLU6-19 [-1, 64, 112, 112] 0 Conv2d-20 [-1, 64, 56, 56] 640 BatchNorm2d-21 [-1, 64, 56, 56] 128 ReLU6-22 [-1, 64, 56, 56] 0 Conv2d-23 [-1, 24, 56, 56] 1,560 BatchNorm2d-24 [-1, 24, 56, 56] 48 ReLU6-25 [-1, 24, 56, 56] 0 SEInvertedBottleneck-26 [-1, 24, 56, 56] 0 Conv2d-27 [-1, 72, 56, 56] 1,800 BatchNorm2d-28 [-1, 72, 56, 56] 144 ReLU6-29 [-1, 72, 56, 56] 0 Conv2d-30 [-1, 72, 56, 56] 720 BatchNorm2d-31 [-1, 72, 56, 56] 144 ReLU6-32 [-1, 72, 56, 56] 0 Conv2d-33 [-1, 24, 56, 56] 1,752 BatchNorm2d-34 [-1, 24, 56, 56] 48 ReLU6-35 [-1, 24, 56, 56] 0 Conv2d-36 [-1, 24, 56, 56] 600 BatchNorm2d-37 [-1, 24, 56, 56] 48 SEInvertedBottleneck-38 [-1, 24, 56, 56] 0 Conv2d-39 [-1, 72, 56, 56] 1,800 BatchNorm2d-40 [-1, 72, 56, 56] 144 ReLU6-41 [-1, 72, 56, 56] 0 Conv2d-42 [-1, 72, 28, 28] 1,872 BatchNorm2d-43 [-1, 72, 28, 28] 144 ReLU6-44 [-1, 72, 28, 28] 0 AvgPool2d-45 [-1, 72, 1, 1] 0 Linear-46 [-1, 18] 1,314 ReLU6-47 [-1, 18] 0 Linear-48 [-1, 72] 1,368 ReLU6-49 [-1, 72] 0 HardSwish-50 [-1, 72] 0 SqueezeAndExcite-51 [-1, 72, 28, 28] 0 Conv2d-52 [-1, 40, 28, 28] 2,920 BatchNorm2d-53 [-1, 40, 28, 28] 80 ReLU6-54 [-1, 40, 28, 28] 0 SEInvertedBottleneck-55 [-1, 40, 28, 28] 0 Conv2d-56 [-1, 120, 28, 28] 4,920 BatchNorm2d-57 [-1, 120, 28, 28] 240 ReLU6-58 [-1, 120, 28, 28] 0 Conv2d-59 [-1, 120, 28, 28] 3,120 BatchNorm2d-60 [-1, 120, 28, 28] 240 ReLU6-61 [-1, 120, 28, 28] 0 AvgPool2d-62 [-1, 120, 1, 1] 0 Linear-63 [-1, 30] 3,630 ReLU6-64 [-1, 30] 0 Linear-65 [-1, 120] 3,720 ReLU6-66 [-1, 120] 0 HardSwish-67 [-1, 120] 0 SqueezeAndExcite-68 [-1, 120, 28, 28] 0 Conv2d-69 [-1, 40, 28, 28] 4,840 BatchNorm2d-70 [-1, 40, 28, 28] 80 ReLU6-71 [-1, 40, 28, 28] 0 Conv2d-72 [-1, 40, 28, 28] 1,640 BatchNorm2d-73 [-1, 40, 28, 28] 80 SEInvertedBottleneck-74 [-1, 40, 28, 28] 0 Conv2d-75 [-1, 120, 28, 28] 4,920 BatchNorm2d-76 [-1, 120, 28, 28] 240 ReLU6-77 [-1, 120, 28, 28] 0 Conv2d-78 [-1, 120, 28, 28] 3,120 BatchNorm2d-79 [-1, 120, 28, 28] 240 ReLU6-80 [-1, 120, 28, 28] 0 AvgPool2d-81 [-1, 120, 1, 1] 0 Linear-82 [-1, 30] 3,630 ReLU6-83 [-1, 30] 0 Linear-84 [-1, 120] 3,720 ReLU6-85 [-1, 120] 0 HardSwish-86 [-1, 120] 0 SqueezeAndExcite-87 [-1, 120, 28, 28] 0 Conv2d-88 [-1, 40, 28, 28] 4,840 BatchNorm2d-89 [-1, 40, 28, 28] 80 ReLU6-90 [-1, 40, 28, 28] 0 Conv2d-91 [-1, 40, 28, 28] 1,640 BatchNorm2d-92 [-1, 40, 28, 28] 80 SEInvertedBottleneck-93 [-1, 40, 28, 28] 0 Conv2d-94 [-1, 240, 28, 28] 9,840 BatchNorm2d-95 [-1, 240, 28, 28] 480 ReLU6-96 [-1, 240, 28, 28] 0 HardSwish-97 [-1, 240, 28, 28] 0 Conv2d-98 [-1, 240, 28, 28] 2,400 BatchNorm2d-99 [-1, 240, 28, 28] 480 ReLU6-100 [-1, 240, 28, 28] 0 HardSwish-101 [-1, 240, 28, 28] 0 Conv2d-102 [-1, 80, 28, 28] 19,280 BatchNorm2d-103 [-1, 80, 28, 28] 160 ReLU6-104 [-1, 80, 28, 28] 0 HardSwish-105 [-1, 80, 28, 28] 0 Conv2d-106 [-1, 80, 28, 28] 3,280 BatchNorm2d-107 [-1, 80, 28, 28] 160 SEInvertedBottleneck-108 [-1, 80, 28, 28] 0 Conv2d-109 [-1, 200, 28, 28] 16,200 BatchNorm2d-110 [-1, 200, 28, 28] 400 ReLU6-111 [-1, 200, 28, 28] 0 HardSwish-112 [-1, 200, 28, 28] 0 Conv2d-113 [-1, 200, 28, 28] 2,000 BatchNorm2d-114 [-1, 200, 28, 28] 400 ReLU6-115 [-1, 200, 28, 28] 0 HardSwish-116 [-1, 200, 28, 28] 0 Conv2d-117 [-1, 80, 28, 28] 16,080 BatchNorm2d-118 [-1, 80, 28, 28] 160 ReLU6-119 [-1, 80, 28, 28] 0 HardSwish-120 [-1, 80, 28, 28] 0 Conv2d-121 [-1, 80, 28, 28] 6,480 BatchNorm2d-122 [-1, 80, 28, 28] 160 SEInvertedBottleneck-123 [-1, 80, 28, 28] 0 Conv2d-124 [-1, 184, 28, 28] 14,904 BatchNorm2d-125 [-1, 184, 28, 28] 368 ReLU6-126 [-1, 184, 28, 28] 0 HardSwish-127 [-1, 184, 28, 28] 0 Conv2d-128 [-1, 184, 14, 14] 1,840 BatchNorm2d-129 [-1, 184, 14, 14] 368 ReLU6-130 [-1, 184, 14, 14] 0 HardSwish-131 [-1, 184, 14, 14] 0 Conv2d-132 [-1, 80, 14, 14] 14,800 BatchNorm2d-133 [-1, 80, 14, 14] 160 ReLU6-134 [-1, 80, 14, 14] 0 HardSwish-135 [-1, 80, 14, 14] 0 SEInvertedBottleneck-136 [-1, 80, 14, 14] 0 Conv2d-137 [-1, 184, 14, 14] 14,904 BatchNorm2d-138 [-1, 184, 14, 14] 368 ReLU6-139 [-1, 184, 14, 14] 0 HardSwish-140 [-1, 184, 14, 14] 0 Conv2d-141 [-1, 184, 14, 14] 1,840 BatchNorm2d-142 [-1, 184, 14, 14] 368 ReLU6-143 [-1, 184, 14, 14] 0 HardSwish-144 [-1, 184, 14, 14] 0 Conv2d-145 [-1, 80, 14, 14] 14,800 BatchNorm2d-146 [-1, 80, 14, 14] 160 ReLU6-147 [-1, 80, 14, 14] 0 HardSwish-148 [-1, 80, 14, 14] 0 Conv2d-149 [-1, 80, 14, 14] 6,480 BatchNorm2d-150 [-1, 80, 14, 14] 160 SEInvertedBottleneck-151 [-1, 80, 14, 14] 0 Conv2d-152 [-1, 480, 14, 14] 38,880 BatchNorm2d-153 [-1, 480, 14, 14] 960 ReLU6-154 [-1, 480, 14, 14] 0 HardSwish-155 [-1, 480, 14, 14] 0 Conv2d-156 [-1, 480, 14, 14] 4,800 BatchNorm2d-157 [-1, 480, 14, 14] 960 ReLU6-158 [-1, 480, 14, 14] 0 HardSwish-159 [-1, 480, 14, 14] 0 AvgPool2d-160 [-1, 480, 1, 1] 0 Linear-161 [-1, 120] 57,720 ReLU6-162 [-1, 120] 0 Linear-163 [-1, 480] 58,080 ReLU6-164 [-1, 480] 0 HardSwish-165 [-1, 480] 0 SqueezeAndExcite-166 [-1, 480, 14, 14] 0 Conv2d-167 [-1, 112, 14, 14] 53,872 BatchNorm2d-168 [-1, 112, 14, 14] 224 ReLU6-169 [-1, 112, 14, 14] 0 HardSwish-170 [-1, 112, 14, 14] 0 Conv2d-171 [-1, 112, 14, 14] 9,072 BatchNorm2d-172 [-1, 112, 14, 14] 224 SEInvertedBottleneck-173 [-1, 112, 14, 14] 0 Conv2d-174 [-1, 672, 14, 14] 75,936 BatchNorm2d-175 [-1, 672, 14, 14] 1,344 ReLU6-176 [-1, 672, 14, 14] 0 HardSwish-177 [-1, 672, 14, 14] 0 Conv2d-178 [-1, 672, 14, 14] 6,720 BatchNorm2d-179 [-1, 672, 14, 14] 1,344 ReLU6-180 [-1, 672, 14, 14] 0 HardSwish-181 [-1, 672, 14, 14] 0 AvgPool2d-182 [-1, 672, 1, 1] 0 Linear-183 [-1, 168] 113,064 ReLU6-184 [-1, 168] 0 Linear-185 [-1, 672] 113,568 ReLU6-186 [-1, 672] 0 HardSwish-187 [-1, 672] 0 SqueezeAndExcite-188 [-1, 672, 14, 14] 0 Conv2d-189 [-1, 112, 14, 14] 75,376 BatchNorm2d-190 [-1, 112, 14, 14] 224 ReLU6-191 [-1, 112, 14, 14] 0 HardSwish-192 [-1, 112, 14, 14] 0 Conv2d-193 [-1, 112, 14, 14] 12,656 BatchNorm2d-194 [-1, 112, 14, 14] 224 SEInvertedBottleneck-195 [-1, 112, 14, 14] 0 Conv2d-196 [-1, 672, 14, 14] 75,936 BatchNorm2d-197 [-1, 672, 14, 14] 1,344 ReLU6-198 [-1, 672, 14, 14] 0 HardSwish-199 [-1, 672, 14, 14] 0 Conv2d-200 [-1, 672, 7, 7] 17,472 BatchNorm2d-201 [-1, 672, 7, 7] 1,344 ReLU6-202 [-1, 672, 7, 7] 0 HardSwish-203 [-1, 672, 7, 7] 0 AvgPool2d-204 [-1, 672, 1, 1] 0 Linear-205 [-1, 168] 113,064 ReLU6-206 [-1, 168] 0 Linear-207 [-1, 672] 113,568 ReLU6-208 [-1, 672] 0 HardSwish-209 [-1, 672] 0 SqueezeAndExcite-210 [-1, 672, 7, 7] 0 Conv2d-211 [-1, 160, 7, 7] 107,680 BatchNorm2d-212 [-1, 160, 7, 7] 320 ReLU6-213 [-1, 160, 7, 7] 0 HardSwish-214 [-1, 160, 7, 7] 0 SEInvertedBottleneck-215 [-1, 160, 7, 7] 0 Conv2d-216 [-1, 960, 7, 7] 154,560 BatchNorm2d-217 [-1, 960, 7, 7] 1,920 ReLU6-218 [-1, 960, 7, 7] 0 HardSwish-219 [-1, 960, 7, 7] 0 Conv2d-220 [-1, 960, 7, 7] 24,960 BatchNorm2d-221 [-1, 960, 7, 7] 1,920 ReLU6-222 [-1, 960, 7, 7] 0 HardSwish-223 [-1, 960, 7, 7] 0 AvgPool2d-224 [-1, 960, 1, 1] 0 Linear-225 [-1, 240] 230,640 ReLU6-226 [-1, 240] 0 Linear-227 [-1, 960] 231,360 ReLU6-228 [-1, 960] 0 HardSwish-229 [-1, 960] 0 SqueezeAndExcite-230 [-1, 960, 7, 7] 0 Conv2d-231 [-1, 160, 7, 7] 153,760 BatchNorm2d-232 [-1, 160, 7, 7] 320 ReLU6-233 [-1, 160, 7, 7] 0 HardSwish-234 [-1, 160, 7, 7] 0 Conv2d-235 [-1, 160, 7, 7] 25,760 BatchNorm2d-236 [-1, 160, 7, 7] 320 SEInvertedBottleneck-237 [-1, 160, 7, 7] 0 Conv2d-238 [-1, 960, 7, 7] 154,560 BatchNorm2d-239 [-1, 960, 7, 7] 1,920 ReLU6-240 [-1, 960, 7, 7] 0 HardSwish-241 [-1, 960, 7, 7] 0 Conv2d-242 [-1, 960, 7, 7] 24,960 BatchNorm2d-243 [-1, 960, 7, 7] 1,920 ReLU6-244 [-1, 960, 7, 7] 0 HardSwish-245 [-1, 960, 7, 7] 0 AvgPool2d-246 [-1, 960, 1, 1] 0 Linear-247 [-1, 240] 230,640 ReLU6-248 [-1, 240] 0 Linear-249 [-1, 960] 231,360 ReLU6-250 [-1, 960] 0 HardSwish-251 [-1, 960] 0 SqueezeAndExcite-252 [-1, 960, 7, 7] 0 Conv2d-253 [-1, 160, 7, 7] 153,760 BatchNorm2d-254 [-1, 160, 7, 7] 320 ReLU6-255 [-1, 160, 7, 7] 0 HardSwish-256 [-1, 160, 7, 7] 0 Conv2d-257 [-1, 160, 7, 7] 25,760 BatchNorm2d-258 [-1, 160, 7, 7] 320 SEInvertedBottleneck-259 [-1, 160, 7, 7] 0 Conv2d-260 [-1, 960, 7, 7] 154,560 BatchNorm2d-261 [-1, 960, 7, 7] 1,920 ReLU6-262 [-1, 960, 7, 7] 0 HardSwish-263 [-1, 960, 7, 7] 0 AvgPool2d-264 [-1, 960, 1, 1] 0 Conv2d-265 [-1, 1280, 1, 1] 1,230,080 ReLU6-266 [-1, 1280, 1, 1] 0 HardSwish-267 [-1, 1280, 1, 1] 0 Conv2d-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总结
MobileNetV1 | MobileNetV2 | MobileNetV3 |
|
|
|