MobileNetV2 精读笔记:Inverted Residuals 与 Linear Bottlenecks

今天精读了 MobileNetV2 这篇论文,核心改动是 inverted residual structure 和 linear bottleneck,在 accuracy、FLOPs、latency 三者之间做平衡。论文在 classification、detection、segmentation 三类任务上都做了实验。下面把读论文的思路整理一下。

为什么要在低维瓶颈处去掉 ReLU

这是整篇论文最需要先想清楚的问题。论文的出发点是:要让 manifold of interest(感兴趣的特征分布)能够在高维激活空间的某个子空间内得到完整保留,需要满足两个条件:

  • 如果特征分布在 ReLU 之后仍然非零,那么它对应的是一个线性变换;
  • 只有当输入分布处于输入空间的某个子空间内时,ReLU 才能完整保留输入分布的信息。

这两点的含义是:在低维的 bottleneck 处加 ReLU,负半轴的截断会不可逆地折叠特征信息,后续层无法恢复。Xception 此前已经用实验表明,depthwise conv 之后紧跟 ReLU 效果会变差,这与上面的分析方向一致。

Inverted Residual Structure

基于上面的分析,MobileNetV2 的 bottleneck 设计是「窄-宽-窄」,与 ResNet 的「宽-窄-宽」正好相反,因此叫 inverted residual。具体流程是:

  1. 输入是低维的 bottleneck;
  2. 用 1×1 conv 按 expansion rate 展开到高维;
  3. 在高维空间做 depthwise conv(3×3);
  4. 用 1×1 linear conv(不加激活)映射回低维;
  5. 残差连接连在两端的低维 bottleneck 之间。

这种结构内存占用小,适合移动端部署。残差连接两端都是低维 tensor,峰值内存远小于普通 ResNet bottleneck。

最后那个 1×1 conv 不加 ReLU,论文中称为 linear conv,原因正是前面分析的:输出是低维的,此处加 ReLU 会不可逆地破坏信息。论文有正式证明,过程比较复杂。

论文还指出,这种结构允许输入域与输出域在一定程度上解耦。

扩展率的选取

expansion rate 在全网使用同一个常数,通常在 5 到 10 之间,差异不大;小网络可以取稍小的值,大网络取稍大的值。

整体网络结构

整个网络先用一个 initial conv 把 channel 提升到 32(或 64),然后接 19 个 residual bottleneck 层,每一层都加了 BN。

下图是论文给出的完整网络配置,t 是每个 stage 的 expansion rate:

InputOperatorttccnnss
2242×3224^2 \times 3conv2d-3212
1122×32112^2 \times 32bottleneck11611
1122×16112^2 \times 16bottleneck62422
562×2456^2 \times 24bottleneck63232
282×3228^2 \times 32bottleneck66442
142×6414^2 \times 64bottleneck69631
142×9614^2 \times 96bottleneck616032
72×1607^2 \times 160bottleneck632011
72×3207^2 \times 320conv2d 1x1-128011
72×12807^2 \times 1280avgpool 7x7--1-
1×1×12801 \times 1 \times 1280conv2d 1x1-k--

其中 tt 是 expansion rate,cc 是输出通道数,nn 是该 stage 重复次数,ss 是首个 block 的 stride。

bottleneck 模块分两种情况,stride=1 的版本带残差连接,stride=2 的版本(用于下采样)不带残差连接:

MobileNetV2 两种 bottleneck 模块结构图
图 1:两种 bottleneck 模块。左为 stride=1 版本(input 经 1x1 升维 + Relu6 → 3x3 depthwise + Relu6 → 1x1 线性降维,并与 input 相加做残差),右为 stride=2 版本(同样三层但 depthwise stride=2,无残差连接)。

ReLU6

模块内部(高维空间的 depthwise conv 之后)使用的是 ReLU6,而不是普通 ReLU。ReLU6 把激活值 clip 到最大为 6。

原因是移动端量化友好性:移动端常用 float16 甚至 int8 推理,如果激活值的动态范围很大(可以到几百甚至几千),float16 的有限精度会造成表示误差。把激活值限制在 [0, 6] 这个固定区间内,可以让 float16 的数值分辨率得到充分利用,精度损失更小。

实验结果

在 ImageNet 上,输入 224×224、宽度乘子为 1 的配置下,整网约 300M multi-adds,参数量约 3.4M。论文中 multi-scale 测试结果如下:

MobileNetV2 与 MobileNetV1、ShuffleNet、NAS 的性能曲线
图 2:MobileNetV2 与 MobileNetV1、ShuffleNet、NASNet 在 ImageNet 上的精度-计算量曲线(横轴 Multiply-Adds,纵轴 Top-1 精度)。各分辨率(96–224)下分别用 0.35、0.5、0.75、1.0 的宽度乘子,224 额外加了 1.4。