文章目录
1 MobileNetV2简介
MobileNetV2是一个轻量型卷积神经网络,使用深度可分离卷积。
如下图表示其中一个block的结构(学名:Inverted residual block),主要包括Expansion layer,Depthwise Convolution,Projection layer。
Expansion layer表示扩展层,使用1x1卷积,目的是将低维空间映射到高维空间(升维)。
Projection layer表示投影层,使用1x1卷积,目的是把高维特征映射到低维空间去(降维)。
Depthwise Convolution表示深度可分离卷积,完成卷积功能,降低计算量、参数量。

宏观上看,结构是短连接,内部结构是CBR+CBR+CB,最后一个没有Relu了。[注释: CBR表示Conv+BN+Relu]
这种Inverted residual block是一种中间胖,两头窄的结构,像一个纺锤形,常规Residual Block结构,是两头胖,中间窄的结构。
那Inverted residual block从瘦到胖,胖多少呢?再从胖到瘦,又瘦多少呢?这就涉及到新名词Expansion factor(扩展系数),它控制着网络维度,为了保证短连接的形成,一个block中的“胖瘦”系数相同,这个系数通常是6,可改动。如下图所示。

2 线性激活函数的使用原因
论文中所谓使用了线性激活函数,也就是恒等函数( f ( x ) = x f(x)=x f(x)=x)的意思。为什么要这样做呢?
回答:ReLu激活函数对低维特征信息造成较大损失,对高维特征信息影响较小,在Inverted residual block这种中间胖,两头窄的结构输出时,输出的是一种相对低维的特征,故使用线性激活函数。
3 Inverted residual block 和 residual block的区别
下图参考 霹雳吧啦Wz 大佬的b站视频,图中明确指明了三点区别。

此外,residual block采用ReLu激活函数,Inverted residual block采用ReLu6激活函数,ReLu6激活函数如下图所示,相当于加了个最大值6进行限制。

4 一种常规MobileNetv2结构
如下表所示,t 表示bottleneck中“胖瘦”系数,通道数变为几倍;c 表示输出通道数,n 表示bottleneck模块重复了几次,s 表示stride,步长,控制特征图尺寸大小,1的话尺寸不变,2的话,尺寸变为原来的一半,下图中s为1或者2 只针对重复了n次的bottleneck 的第一个bottleneck,重复n次的剩下几个bottleneck中s均为1。
在此处着重强调一下,并不是所有的Inverted residual block都有shortcut短连接的!只有当stride=1(特征图尺寸一致)且输入特征矩阵与输出特征矩阵shape相同(也就是输入输出 通道数c 也要相同)时才有短连接。

5 MobilenetV2代码
直接看代码,可运行,获取网络计算量与参数量。
import torch
from torch import nn
# ------------------------------------------------------#
# 这个函数的目的是确保Channel个数能被8整除。
# 很多嵌入式设备做优化时都采用这个准则
# ------------------------------------------------------#
def _make_divisible(v, divisor, min_value=None):
if min_value is None:
min_value = divisor
# int(v + divisor / 2) // divisor * divisor:四舍五入到8
new_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 += divisor
return 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) // 2
super(ConvBNReLU, self).__init__(</
MobileNetV2详解:结构、激活函数与实现

本文详细介绍了MobileNetV2的结构,包括InvertedResidualBlock的工作原理、线性激活函数的使用原因以及与ResidualBlock的区别。此外,还提供了MobileNetV2的PyTorch实现代码,展示了网络的计算量和参数量。重点讨论了网络的宽度乘数、步长和扩展系数如何影响网络性能。
最低0.47元/天 解锁文章
3323





