MobileNet
参考
题外话
- 本文是在复现MobileNet的时候顺便看了一下原文,因此会用简短的语言简单解释下网络思想,对于某些概念不懂的可以看参考中的文章(主要是深度可分离这个结构)
主体思想
- 文章中作者的贡献是减少了计算复杂度——用了以下两种方式
- Depthwise Separable Convolution
- 使用超参 α \alpha α统一减少channel,从而进一步实现减少计算量的效果
Depthwise Separable Convolution
- 作者认为:卷积是基于卷积核的特征过滤和特征组合以产生新的表示,因此可以将这两个过程分开(有点类似于因式分解的思想),从而达到减少计算量的效果。
- 因此作者提出两种卷积:Depthwise Convolutional & Pointwise Convolution
- depthwise convolutions
- 可以理解为每一个kernel只有一层,只计算一个channel的特征,然后有channel个kernel
- pointwise convolutions
- 可以理解为每个kernel都是一条1x1的卷积,总共hxw个kernel
- 下面这个图比较形象
torch实现(模块)
-
depthwise conv的实现就是groups这个参数,将groups设置为channel的个数就能实现
-
pointwise conv就更简单了,kernel_size=1即可
-
注意代码中的ConvBNReLU只是简单的Conv+BN+ReLU的Sequential而已
-
还有一点就是这份代码中加了残差边
-
class InvertedResidual(nn.Module): def __init__(self, in_channel, out_channel, stride, expand_ratio): super(InvertedResidual, self).__init__() hidden_channel = in_channel * expand_ratio self.use_shortcut = stride == 1 and in_channel == out_channel layers = [] if expand_ratio != 1: # 1x1 pointwise conv layers.append(ConvBNReLU(in_channel, hidden_channel, kernel_size=1)) layers.extend([ # 这里深度可分离的实现就是1、groups=hidden_channel实现depthwise 2、kernel_size=1实现pointwise # 3x3 depthwise conv ConvBNReLU(hidden_channel, hidden_channel, stride=stride, groups=hidden_channel), # 1x1 pointwise conv(linear) nn.Conv2d(hidden_channel, out_channel, kernel_size=1, bias=False), nn.BatchNorm2d(out_channel), ]) self.conv = nn.Sequential(*layers) def forward(self, x): if self.use_shortcut: return x + self.conv(x) else: return self.conv(x)
Width Multiplier
- 超参 α \alpha α
- 成比例的减少channel维度的大小,其实这个在设计的时候就可以做到,作者在3.3说了这个,我理解可能是为了统一方便吧