owned this note
owned this note
Published
Linked with GitHub
# MobileNet V1~V3
###### tags: `paper notes` `deep learning`
[V1 paper link](https://arxiv.org/pdf/1704.04861.pdf)
[V1 Code](https://github.com/shanglianlm0525/PyTorch-Networks/blob/master/Lightweight/MobileNetV1.py)
[V2 paper link](https://arxiv.org/pdf/1801.04381.pdf)
[V2 Code](https://github.com/shanglianlm0525/PyTorch-Networks/blob/master/Lightweight/MobileNetV2.py)
[V3 paper link](https://arxiv.org/pdf/1905.02244.pdf)
[V3 Code](https://github.com/rwightman/pytorch-image-models/blob/master/timm/models/mobilenetv3.py)
## What is MobileNet?
- Google於2017年提出的輕量級 CNN 圖片分類模型,主要使用在手機和嵌入式裝置上
![](https://i.imgur.com/FPIVZQb.jpg)
- 並不是唯一一種輕量級模型,其他還有像是 Squeezenet 或是Shufflenet 等等模型
- 我手上這台 [Pixel 4](https://ai.googleblog.com/2019/11/introducing-next-generation-on-device.html) 裡面的 Pixel Neural Core 就是用了 MobileNetV3 加上利用 autoML 在 TPU 上優化而生的 MobileNetEdgeTPU
- 順帶一提最新的 [Pixel 6](https://ai.googleblog.com/2021/11/improved-on-device-ml-on-pixel-6-with.html) 搭載的是 MobileNetEdgeTPUV2 (圖片分類)、SpaghettiNet-EdgeTPU (物件偵測)、FaceSSD (人臉辨識)、MobileBERT (NLP)
![](https://i.imgur.com/E4sMnjn.jpg)
## MobileNet V1: Depthwise Separable Convolution
- Depthwise Separable Conv == Depthwise Conv + Pointwise Conv
- Depthwise Conv 將每個 channel 分開做 Conv 來降低計算量,而 Pointwise Conv 則用來來學習同一張圖不同 channel 之間的關係
- Standard Conv 和 Depthwise Conv 差別在於 channel
![](https://i.imgur.com/ook6xdF.jpg)
- Pointwise Conv 就是 1x1 Conv,針對一張圖片 1x1 區域的所有 channel 做 Conv
![](https://i.imgur.com/2RkXLbO.jpg)
- 順帶一提 MobileNet 並不是第一個提出 Separable Convolution,這個作法早在 [Simplifying ConvNets for Fast Learning, 2012](https://liris.cnrs.fr/Documents/Liris-5659.pdf) 就已經出現,並且在 [Rigid-Motion Scattering For Image Classification, 2013](https://www.di.ens.fr/data/publications/papers/phd_sifre.pdf)中被推廣到 Depthwise Separable
### 將 channel 分開做 Conv 為什麼可以降低參數量?
符號定義
$D_k:$ Kernel 的 width and height
$D_F:$ feature map 的 width and height
$M:$ Input Channel 數量
$N:$ Output Channel 數量 (Kernel 數量)
- Standard Conv 的計算成本:
![](https://i.imgur.com/4yYEuSs.jpg)
- Depthwise Conv 的計算成本:
![](https://i.imgur.com/6XrG95F.jpg)
- Depthwise Separable Conv 的計算成本
![](https://i.imgur.com/bXIOG7Y.jpg)
- 拆分
![](https://i.imgur.com/6rm1wdl.jpg)
### 少了多少計算量?
![](https://i.imgur.com/pBCBRsK.jpg)
### 架構對比
- Standard Conv vs Depthwise Separable Conv
![](https://i.imgur.com/S2iNLTK.jpg)
![](https://i.imgur.com/tZQp62o.jpg)
- V1 完整架構
![](https://i.imgur.com/qkx2Zoo.png)
### V1 result
- 展示了 mobileNet 在使用較少計算複雜度和模型大小的情況下,表現能與其他較大的模型差不多
![](https://i.imgur.com/N3IbMXh.png)
- 作者也有統計每個 component 所佔的計算量比例,可見 1x1 Conv 所佔比例最高
![](https://i.imgur.com/Ht6uEr0.png)
## MobileNet V2: Inverted Residuals and Linear Bottlenecks
- 作者發現 V1 的 Depth-wise separable convolution 中有許多空的 Conv kernel,並發現原因是在低維度空間做 ReLU 會失去很多資訊,但在高維度空間裡面做卻不會
- 因為 ReLU 的 dead relu problem
![](https://i.imgur.com/HChl8FX.png)
- 因此 V2 在 V1 的 Depth-wise separable convolution 的基礎上增加了 Linear Bottlenecks,就是在把做 ReLU 之前的輸入維度提高並換掉 ReLU
![](https://i.imgur.com/UeNtzOJ.jpg)
### Linear Bottlenacks
- 把 Point-wise Conv 中的 ReLU 換成 Linear function
![](https://i.imgur.com/cYyPTMI.png)
- V2 也在 Depth-wise Conv 之前先做 Point-wise Conv(1x1 conv) 來做升維度,好讓其提取到更多特徵,原文稱這個為 expansion layer
![](https://i.imgur.com/IFEcriu.jpg)
### Inverted Residuals
- 最近很紅的 [ConvNeXt, 2020s](https://github.com/facebookresearch/ConvNeXt) 採用此設計來降低運算量
- 這裡加入了 residual connection 的概念,來達到更高的 memory efficient
- 注意到 classicial residual block 在連接的時候 channel 很多,但 inverted residual 只連接了 bottlenneck
- 有標註對角線的 layer 不使用非線性層
![](https://i.imgur.com/7g0B0SS.png)
```python=
class InvertedResidual(nn.Module):
def __init__(self, in_channels, out_channels, stride, expansion_factor=6):
super(InvertedResidual, self).__init__()
self.stride = stride
mid_channels = (in_channels * expansion_factor)
self.bottleneck = nn.Sequential(
Conv1x1BNReLU(in_channels, mid_channels),
Conv3x3BNReLU(mid_channels, mid_channels, stride,groups=mid_channels),
Conv1x1BN(mid_channels, out_channels)
)
if self.stride == 1:
self.shortcut = Conv1x1BN(in_channels, out_channels)
def forward(self, x):
out = self.bottleneck(x)
out = (out+self.shortcut(x)) if self.stride==1 else out
return out
```
- 運算量的對比
![](https://i.imgur.com/NKYsy4x.png)
- MobileNet V1 vs MobileNet V2
![](https://i.imgur.com/fSv01JY.jpg)
- ResNet vs MobileNet V2
- ResNet 先降維 (0.25倍)-> Conv -> 再升維
- MobileNetV2 先升維(6倍) -> Conv -> 再降維
- 這樣設計的原因就是他們希望讓特徵能夠在高維的空間作擷取
![](https://i.imgur.com/FRmvt12.jpg)
### 整體架構
![](https://i.imgur.com/xtiwAmV.png)
- 這邊可以得知 expansion factor $t$ =6,也就是說每次的 Point-wise Conv 會輸出 6*k 個 channel
- $c$ = channel, $n$ = 重複幾次, $s$ = stride
與其他類似網路的對比
- V2在遇到 stride=2 的 3x3 Conv 的時候會取消使用 residual connection,因為輸入和輸出的尺寸會不一樣 (尺寸會減半)
![](https://i.imgur.com/MbLoXWL.png)
- V2 和其他網路對比其實在中間層的時候就參數量較少了
![](https://i.imgur.com/HYaSaxj.png)
### V2 Result
- On ImageNet (Google Pixel 1)
![](https://i.imgur.com/EhS20ep.png)
- On COCO
- 這邊所謂的 SSDLite 指的是將 SSD 裡面的 Conv 換成 separable convolutions (depthwise followed by 1x1 projection) 的輕量變形模型![](https://i.imgur.com/1e97pa9.png)
![](https://i.imgur.com/3ACcjjQ.png)
- 可見其參數量遠遠小於 YoloV2 和 SSD
## MobileNet V3: Squeeze and Excitation with NAS
- 在 V3 中,除了保留前代特性以外還加入了 NAS 以及 SENet 的 Squeeze and Excitation 架構,透過 Global Average Pooling (GAP)計算每個 feature map 的權重,用來強化重要的 feature map 的影響力,並減弱不重要的 feature map 的影響力
- NAS: Neural Architecture Search,一種 Auto-ML 的方法,G社一直都很愛 ~~(因為很少人玩得起)~~
- 除此之外也把原本使用的 activation function swish 改為 h-swish 以避免計算 sigmoid,並微調了一點 V2 架構來更進一步降低計算成本
### SENet
[paper link](https://arxiv.org/pdf/1709.01507.pdf)
- 主要目標是學習 feature channel 間的關係,凸顯不同 feature channel 的重要度,進而提高模型表現
- 所謂的學習是透過 attention 或是 gating 方式進行,因此實作方法並不唯一
- 可用來強化重要的 feature map 的影響力,並減弱不重要的 feature map 的影響力
![](https://i.imgur.com/faehOlm.png)
- x 為輸入,x = w * h * c1 (width * height * channel)
- 透過卷積變換 $F_{tr}$, 輸出 w * h * c2 (width * height * channel),c2 個大小為w*h的feature map $u_c$
![](https://i.imgur.com/ayiponP.png =400x150)
- $v_c$ 為 c-th filter 的參數
SENet 流程:
1. 透過 $F_{sq}$ 壓縮操作,輸出 1 * 1 * c2 (Squeeze部分)
- 這邊作者用global average pooling 作為 Squeeze 操作(就是把w和h維度取平均變成一個scalar),作為等等學習的準備
![](https://i.imgur.com/JFul9qD.png)
2. 透過 $F_{ex}(W)$ 操作學到權重 (Excitation部分)
- $F_{ex}(W)$操作包括兩個全連接層和兩個非線性激活函數(ReLu, Sigmoid)來製作出一個 gating 機制來學習
![](https://i.imgur.com/vkZex16.png)
3. 最後透過 $F_{sacle}$ 輸出 re-wight 後的 w * h * c2
- $s_c$ 就是 feature map 的 weights,論文提到這樣的操作其實就等於在對每一個 feature map 學習其 self-attention weight,但沒有詳細說明怎麼替換成 SA 版本
![](https://i.imgur.com/nYHYNtm.png)
Implementation of SENet in [timm](https://github.com/rwightman/pytorch-image-models/blob/07379c6d5dbb809b3f255966295a4b03f23af843/timm/models/efficientnet_blocks.py#L17), using gating
```python=
class SqueezeExcite(nn.Module):
""" Squeeze-and-Excitation w/ specific features for EfficientNet/MobileNet family
Args:
in_chs (int): input channels to layer
rd_ratio (float): ratio of squeeze reduction
act_layer (nn.Module): activation layer of containing block
gate_layer (Callable): attention gate function
force_act_layer (nn.Module): override block's activation fn if this is set/bound
rd_round_fn (Callable): specify a fn to calculate rounding of reduced chs
"""
def __init__(
self, in_chs, rd_ratio=0.25, rd_channels=None, act_layer=nn.ReLU,
gate_layer=nn.Sigmoid, force_act_layer=None, rd_round_fn=None):
super(SqueezeExcite, self).__init__()
if rd_channels is None:
rd_round_fn = rd_round_fn or round
rd_channels = rd_round_fn(in_chs * rd_ratio)
act_layer = force_act_layer or act_layer
self.conv_reduce = nn.Conv2d(in_chs, rd_channels, 1, bias=True)
self.act1 = create_act_layer(act_layer, inplace=True)
self.conv_expand = nn.Conv2d(rd_channels, in_chs, 1, bias=True)
self.gate = create_act_layer(gate_layer)
def forward(self, x):
x_se = x.mean((2, 3), keepdim=True)
x_se = self.conv_reduce(x_se)
x_se = self.act1(x_se)
x_se = self.conv_expand(x_se)
return x * self.gate(x_se)
```
SENet 可替換掉 inception block 或是 residual block
![](https://i.imgur.com/0bwmZC7.png)
MobileNet V2
![](https://i.imgur.com/vEMBGON.png)
MobileNetV2 + Squeeze-and-Excite = MobileNetV3
- 整個架構是將 SENet 放在 depthwise conv 之後,變成新的 bottleneck
- 這樣放的原因是因為 SENet 的計算會花費一定時間,所以作者在含有 SENet 的架構中將 expansion layer 的 channel 變為原本的 1/4,這樣一來他們發現不僅可以提高準確度也沒有增加所需時間
![](https://i.imgur.com/RCFdf3Y.png)
### NAS
- 沒怎麼接觸所以簡單講
- 主要利用 platform-aware NAS + NetAdapt
- 前者用於在計算量受限的前提下來搜尋網路的每一個 block,稱為 block-wise search
![](https://i.imgur.com/RaParbs.png)
- 後者則用於針對每一個確定的 block 之中的網路層 kernel 數量做學習,稱為 layer-wise search
![](https://i.imgur.com/G2X4rxF.png)
- 搜尋的目標主要是有兩個: 1) 減少任何一個 expansion layer 的 size, 2) 減少所有 block 中的 bottleneck
- 在使用 NAS 的過程中他們也因此發現 V2 的某幾個層計算成本相對高,因此才會又對其架構做了進一步修改
### 架構微調
- 他們實驗發現 V2 之中用來提高維度的 1x1 Conv (Expansion layer) 其實反而增加了模型的計算量,因此改為將其放在 avg pooling 之後
- 整個流程會先利用 avg pooling 將 feature map 從 7x7 降為 1x1,再利用 1x1 Conv 提高維度,減少了 7x7=49 倍的計算量
- 除此之外作者也去掉了前面的 3x3 Conv 和 1x1 Conv,因此降低 15ms 的速度但沒有喪失準確率
- V2
![](https://i.imgur.com/tG8oUOc.png)
- V3
- 眼睛比較利的話也可以發現 V3 還有調整一開始的 filter 數量,V2 是使用 32 個 3x3 conv kernel,而經過實驗後他們發現可以降為 16 個並且不影響準確率又可以降低 2ms
![](https://i.imgur.com/swNdrwP.jpg)
- 微調後的整體架構
![](https://i.imgur.com/qDIV2CU.png)
### Nonlinearities
- 原本的 swish 中有使用到 sigmoid,但其計算放在行動裝置上面的計算非常貴
![](https://i.imgur.com/ByUgXtT.png)
- 所以他們對其做了修改,將一部分較深層的激活函數改用 h-swish,剩下的則使用 ReLU 來替代掉 swish
![](https://i.imgur.com/3413W1t.png)
使用 ReLU 的好處有兩個:
1. 可在任何平台上進行運算
2. 消除了潛在的由於浮點數運算缺陷而導致的準確度損失
![](https://i.imgur.com/f98J0rb.png)
- 比較使用 h-swish 之後所能降低的 latency (ms)
- @n, n=number of channel
![](https://i.imgur.com/5CSmTUV.png)
- 作者的實驗發現 h-swish 應該使用在 channel >= 80 的 layer 才能得到最好效果
![](https://i.imgur.com/dl5uXPt.png)
### V3 Result
- 整個 MobileNet V3 發展的流程與模型增進程度
![](https://i.imgur.com/HlcyspF.png)
- V1 vs V2 vs V3 in COCO
![](https://i.imgur.com/fuOQ2zJ.png)
- V1 vs V2 on Pixel 1
![](https://i.imgur.com/MuegIrN.png)
- Experiments on Pixel, 2, 3
![](https://i.imgur.com/GkkITtm.png)
![](https://i.imgur.com/tspno96.png)
## References
- [轻量级神经网络“巡礼”(二)—— MobileNet,从V1到V3](https://zhuanlan.zhihu.com/p/70703846)
- [卷積神經網路(Convolutional neural network, CNN): 1×1卷積計算在做什麼](https://chih-sheng-huang821.medium.com/%E5%8D%B7%E7%A9%8D%E7%A5%9E%E7%B6%93%E7%B6%B2%E8%B7%AF-convolutional-neural-network-cnn-1-1%E5%8D%B7%E7%A9%8D%E8%A8%88%E7%AE%97%E5%9C%A8%E5%81%9A%E4%BB%80%E9%BA%BC-7d7ebfe34b8)
- [深度學習-MobileNet (Depthwise separable convolution)](https://chih-sheng-huang821.medium.com/%E6%B7%B1%E5%BA%A6%E5%AD%B8%E7%BF%92-mobilenet-depthwise-separable-convolution-f1ed016b3467)
- [[論文筆記] MobileNet演變史-從MobileNetV1到MobileNetV3](https://chihangchen.medium.com/%E8%AB%96%E6%96%87%E7%AD%86%E8%A8%98-mobilenetv3%E6%BC%94%E8%AE%8A%E5%8F%B2-f5de728725bc)