MobileNet_v2

一.概述

MobileNetV1网络是一条路的单通道结构,没有feature map的复用。ResNetDenseNet等网络的提出,也验证了feature map复用对提升网络性能的有效性,MobileNetV2便应运而生。MobileNetV2提出使用 inverted residual with linear bottleneck,有很大residual block的影子在里面。接下来便介绍一下MobileNetV2Linear BottlenecksInverted residuals这两个核心创新点。

当我们单独去看Feature Map的每个通道的像素的值的时候,其实这些值代表的特征可以映射到一个低维子空间的一个流形区域上。在进行完卷积操作之后往往会接一层激活函数来增加特征的非线性性,一个最常见的激活函数便是ReLU。根据我们在残差网络中介绍的数据处理不等式(DPI),ReLU一定会带来信息损耗,而且这种损耗是没有办法恢复的,ReLU的信息损耗是当通道数非常少的时候更为明显。为什么这么说呢?我们看图6中这个例子,其输入是一个表示流形数据的矩阵,和卷机操作类似,他会经过 n 个ReLU的操作得到 n 个通道的Feature Map,然后我们试图通过这 n 个Feature Map还原输入数据,还原的越像说明信息损耗的越少。从下图中我们可以看出,当 n 的值比较小时,ReLU的信息损耗非常严重,但是当 n 的值比较大的时候,输入流形就能还原的很好了。

                            

                                                     使用ReLU激活函数的通道数和信息损耗之间的关系

根据对上面提到的信息损耗问题分析,我们可以有两种解决方案:

  1. 既然是ReLU导致的信息损耗,那么我们就将ReLU替换成线性激活函数;
  2. 如果比较多的通道数能减少信息损耗,那么我们就使用更多的通道。

二.网络结构详解

1.Linear Bottlenecks

假设某层的输出的feature map大小为HxWxD,经过激活层后称之为manifold of interest,可以理解为感兴趣流形或有用的信息,大小仍为HxWxD,经验证明manifold of interest完全可以压缩到低维子空间,在V1版本中便可以通过width multiplier parameter来降低激活空间的维数使得manifold of interest充满整个空间。问题就来了,在使用ReLU函数进行激活时,负数直接变为0,这样就会导致失去较多有用的信息(这在manifold of interest占激活空间较小时不是一个问题)。
总结一下,有以下两点:

  • 如果manifold of interest经过ReLU后均为非零,意味着只经过了一个线性变换
  • 除非input manifold位于输入空间的低维子空间,经过ReLU后才能保持完整的信息

因此,论文中使用了linear bottleneck来解决由于非线性激活函数造成的信息损失问题。linear bottleneck本质上是不带ReLU的1x1的卷积层。

我们当然不能把ReLU全部换成线性激活函数,不然网络将会退化为单层神经网络,一个折中方案是在输出Feature Map的通道数较少的时候也就是bottleneck部分使用线性激活函数,其它时候使用ReLU。代码片段如下:

def _bottleneck(inputs, nb_filters, t):
    x = Conv2D(filters=nb_filters * t, kernel_size=(1,1), padding='same')(inputs)
    x = Activation(relu6)(x)
    x = DepthwiseConv2D(kernel_size=(3,3), padding='same')(x)
    x = Activation(relu6)(x)
    x = Conv2D(filters=nb_filters, kernel_size=(1,1), padding='same')(x)
    # do not use activation function
    if not K.get_variable_shape(inputs)[3] == nb_filters:
        inputs = Conv2D(filters=nb_filters, kernel_size=(1,1), padding='same')(inputs)
    outputs = add([x, inputs])
    return outputs

这里使用了MobileNet中介绍的ReLU6激活函数,它是对ReLU在6上的截断,数学形式为:

                                                              \operatorname{Re} L U(6)=\min (\max (0, x), 6)

下图便是结合了残差网络和线性激活函数的MobileNet v2的一个block。

特别的,针对stride=1 和stride=2,在block上有稍微不同,主要是为了与shortcut的维度匹配,因此,stride=2时,不采用shortcut。 

                         

2.Inverted Residual

当激活函数使用ReLU时,我们可以通过增加通道数来减少信息的损耗,使用参数 t 来控制,该层的通道数是输入Feature Map的 t 倍。传统的残差块的 t 一般取小于1的小数,常见的取值为0.1,而在v2中这个值一般是介于 5-10 之间的数,在作者的实验中, t=6 。考虑到残差网络和v2的 t 的不同取值范围,他们分别形成了锥子形(两头小中间大)和沙漏形(两头大中间小)的结构,如下图所示,其中斜线Feature Map表示使用的是线性激活函数。这也就是为什么这种形式的卷积block被叫做Interved Residual block,因为他把short-cut转移到了bottleneck层。

                                         残差网络的的Residual block和v2的Inverted Residual block卷积对比

创新点:
1. Inverted residuals,通常的residuals block是先经过一个1*1的Conv layer,把feature map的通道数“压”下来,再经过3*3 Conv layer,最后经过一个1*1 的Conv layer,将feature map 通道数再“扩张”回去。即先“压缩”,最后“扩张”回去。
而 inverted residuals就是 先“扩张”,最后“压缩”。

2.Linear bottlenecks,为了避免Relu对特征的破坏,在residual block的Eltwise sum之前的那个 1*1 Conv 不再采用Relu。

主要是两点:

  1. Depth-wise convolution之前多了一个1*1的“扩张”层,目的是为了提升通道数,获得更多特征;
  2. 最后不采用Relu,而是Linear,目的是防止Relu破坏特征。这个线性是通过1*1的卷积实现的。

 再看看MobileNetV2的block 与ResNet 的block:

这里写图片描述

主要不同之处就在于,ResNet是:压缩”→“卷积提特征”→“扩张”,MobileNetV2则是Inverted residuals,即:“扩张”→“卷积提特征”→ “压缩”。 

MobileNet-V1 最大的特点就是采用depth-wise separable convolution来减少运算量以及参数量,而在网络结构上,没有采用shortcut的方式。
Resnet及Densenet等一系列采用shortcut的网络的成功,表明了shortcut是个非常好的东西,于是MobileNet-V2就将这个好东西拿来用。

拿来主义,最重要的就是要结合自身的特点,MobileNet的特点就是depth-wise separable convolution,但是直接把depth-wise separable convolution应用到 residual block中,会碰到如下问题:

1.DWConv layer层提取得到的特征受限于输入的通道数,若是采用以往的residual block,先“压缩”,再卷积提特征,那么DWConv layer可提取得特征就太少了,因此一开始不“压缩”,MobileNetV2反其道而行,一开始先“扩张”,本文实验“扩张”倍数为6。 通常residual block里面是 “压缩”→“卷积提特征”→“扩张”,MobileNetV2就变成了 “扩张”→“卷积提特征”→ “压缩”,因此称为Inverted residuals

2.当采用“扩张”→“卷积提特征”→ “压缩”时,在“压缩”之后会碰到一个问题,那就是Relu会破坏特征。为什么这里的Relu会破坏特征呢?这得从Relu的性质说起,Relu对于负的输入,输出全为零;而本来特征就已经被“压缩”,再经过Relu的话,又要“损失”一部分特征,因此这里不采用Relu,实验结果表明这样做是正确的,这就称为Linear bottlenecks

 综上我们可以得到MobileNet v2的一个block的详细参数,Conv2d 和avgpool和传统CNN里的操作一样;最大的特点是bottleneck,一个bottleneck由如下三个部分构成,如下图所示,其中 s 代表步长:

                       

 MobileNet v2的实现可以通过堆叠bottleneck的形式实现,如下面代码片段

def MobileNetV2_relu(input_shape, k):
    inputs = Input(shape = input_shape)
    x = Conv2D(filters=32, kernel_size=(3,3), padding='same')(inputs)
    x = _bottleneck_relu(x, 8, 6)
    x = MaxPooling2D((2,2))(x)
    x = _bottleneck_relu(x, 16, 6)
    x = _bottleneck_relu(x, 16, 6)
    x = MaxPooling2D((2,2))(x)
    x = _bottleneck_relu(x, 32, 6)
    x = GlobalAveragePooling2D()(x)
    x = Dense(128, activation='relu')(x)
    outputs = Dense(k, activation='softmax')(x)
    model = Model(inputs, outputs)
    return model

网络结构如下: 

                                    

其中:t表示“扩张”倍数,c表示输出通道数,n表示重复次数,s表示步长stride。

可以发现,除了最后的avgpool,整个网络并没有采用pooling进行下采样,而是利用stride=2来下采样,此法已经成为主流。

三.实验

看看MobileNet-V2 分类时,inference速度: 

                                  

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值