最近看了一些classification网络的源代码,一些比较有亮点的思想的源代码阅读了一下,把他们总结在这个分类里面。
这篇blog写一下关于mobilenet。
对于一些移动设备,参数较少的net需要被构建起来。这时候我们的mobilenet 一个精简性能又还过得去的net应运而生。
作者在文章中对于mobilenet和一些常用的cnn进行了一系列对比,感兴趣的可以自己去查看,这里就不做赘叙。
我们来看一下mobilenet v2和 v3。
Mobilenet V2
在我看来mobilenet相比于之前的alexnet等等一众cnn主要有以下的一些优点:
- 采用Depthwise Convolution
- 增加了超参数α及β
1.Depthwise Convolution
相比传统的多个卷积核卷积 作者首先进行深度方向各channel分别进行卷积随后对于得到的与原卷积核形状一致的features进行1X1的卷积来改变channel数。
对于depthwise convolution 作者在代码中对group进行修改来实现。
layers.extend([
# 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),
])
当然 作者对于是否运用shortcut的方法也进行了定义,总结来说就是 能用就用 不能用不强求。
self.use_shortcut = stride == 1 and in_channel == out_channel
另外还有对于超参数的设定 即对于通道数及你所输入的图片进行处理,来得到一个更小更瘦的网络。
这里就不再多说了 ,代码上比较简单。
Mobilenet V3
对于该版本的mobilenet作者主要更新了激活函数且加入了SE模块,使得网络性能进一步提升。
SE模块
这里主要是对于特征图进行一系列操作生成一个系数矩阵,最后与特征图进行相乘得到最后的特征图。
#SE模块定义
class SqueezeExcitation(nn.Module):
def __init__(self, input_c: int, squeeze_factor: int = 4):
super(SqueezeExcitation, self).__init__()
squeeze_c = _make_divisible(input_c // squeeze_factor, 8)
self.fc1 = nn.Conv2d(input_c, squeeze_c, 1)
self.fc2 = nn.Conv2d(squeeze_c, input_c, 1)
def forward(self, x: Tensor) -> Tensor:
scale = F.adaptive_avg_pool2d(x, output_size=(1, 1))
scale = self.fc1(scale)
scale = F.relu(scale, inplace=True)
scale = self.fc2(scale)
scale = F.hardsigmoid(scale, inplace=True)
return scale * x
这里进行的操作主要是首先pooling到1x1的Tensor,两个全连接层,最后HS激活函数进行激活。得到的scale与features进行相乘即可得到最终的结果。