SqueezeNet & SqueezeNext 简介

一、SqueezeNet 模型原理

  • 采用 Global Average Pooling 代替 FC 层
  • 采用不同于传统的卷积方式,提出 fire module;fire module 包含两部分:squeeze 层 和 expand
    • squeeze 层是一个 1*1 卷积核的卷积层,expand 层是一个 1*13*3 卷积核的卷积层,在 expand 层后,要把 1*13*3 卷积后得到的 feature map 进行 concat
    • fire module 有三个可调参数:s1,e1,e3,分别代表卷积核的个数,同时也表示对应输出 feature map 的维数,在论文中提出的 SqueezeNet 结构中,e1=e3=4s1
      SqueezeNet & SqueezeNext 简介_第1张图片
  • fire module block 的参数量(Params)以及理论计算量(FLOPs)分析?
    • Params: 5 / 4 × C 2 5/4 \times C^2 5/4×C2
    • FLOPs: 5 / 4 × C 2 × H × W 5/4 \times C^2 \times H \times W 5/4×C2×H×W
    • 相比较直接使用 3 × 3 3 \times 3 3×3 的卷积核,参数量和理论计算量都降为原来的 5 / 36 5/36 5/36
      SqueezeNet & SqueezeNext 简介_第2张图片

二、SqueezeNet 模型结构及设计思路

  • 相同 分辨率fire module block 数量前面要少一点,后面要多一点(这里为[2, 2, 4]),通道数通常以 3264 的倍数增加([128, 256, 384-512]
  • 在通道数相同的层之间,添加旁路相加结构(short-cut)可以明显提升准确性(top-1 和 top-5 分别提升 2.9%2.2%
  • 带有卷积的旁路结构可以在任意层之间添加(1*1 卷积调控 depth),准确性提升较小,模型增大
    SqueezeNet & SqueezeNext 简介_第3张图片

三、改进版本之 SqueezeNext

  • Low Rank Filters:decompose the K × K K \times K K×K convolutions into two separable convolutions of size 1 × K 1 \times K 1×K and K × 1 K \times 1 K×1
  • SqueezeNext Block:减少 C_in ,即在 3 × 1 3\times 1 3×1 的卷积前,用两个 1 × 1 1 \times 1 1×1 的卷积进一步把 input channels 减少
  • Fully Connected Layers:在全连接层之前再用一个 bottleneck layer,把 C_in 变小
  • Short-Cut
    SqueezeNet & SqueezeNext 简介_第4张图片
  • SqueezeNext Block 的参数量(Params)以及理论计算量(FLOPs)分析?
    • Params: 9 / 4 × C 2 9/4 \times C^2 9/4×C2
    • FLOPs: 9 / 4 × C 2 × H × W 9/4 \times C^2 \times H \times W 9/4×C2×H×W
    • 相比较直接使用 3 × 3 3 \times 3 3×3 的卷积核,参数量和理论计算量都降为原来的 1 / 4 1/4 1/4,通道数量相比 SqueezeNet 更小
      SqueezeNet & SqueezeNext 简介_第5张图片

四、SqueezeNet 模型代码

class SqueezeNet(object):
    def __init__(self, inputs, nb_classes=1000, is_training=True):
        # conv1
        net = tf.layers.conv2d(inputs, 96, [7, 7], strides=[2, 2],
                                 padding="SAME", activation=tf.nn.relu,
                                 name="conv1")
        # maxpool1
        net = tf.layers.max_pooling2d(net, [3, 3], strides=[2, 2],
                                      name="maxpool1")
        # fire2
        net = self._fire(net, 16, 64, "fire2")
        # fire3
        net = self._fire(net, 16, 64, "fire3")
        # fire4
        net = self._fire(net, 32, 128, "fire4")
        # maxpool4
        net = tf.layers.max_pooling2d(net, [3, 3], strides=[2, 2],
                                      name="maxpool4")
        # fire5
        net = self._fire(net, 32, 128, "fire5")
        # fire6
        net = self._fire(net, 48, 192, "fire6")
        # fire7
        net = self._fire(net, 48, 192, "fire7")
        # fire8
        net = self._fire(net, 64, 256, "fire8")
        # maxpool8
        net = tf.layers.max_pooling2d(net, [3, 3], strides=[2, 2],
                                      name="maxpool8")
        # fire9
        net = self._fire(net, 64, 256, "fire9")
        # dropout
        net = tf.layers.dropout(net, 0.5, training=is_training)
        # conv10
        net = tf.layers.conv2d(net, 1000, [1, 1], strides=[1, 1],
                               padding="SAME", activation=tf.nn.relu,
                               name="conv10")
        # avgpool10
        net = tf.layers.average_pooling2d(net, [13, 13], strides=[1, 1],
                                          name="avgpool10")
        # squeeze the axis
        net = tf.squeeze(net, axis=[1, 2])

        self.logits = net
        self.prediction = tf.nn.softmax(net)


    def _fire(self, inputs, squeeze_depth, expand_depth, scope):
        with tf.variable_scope(scope):
            squeeze = tf.layers.conv2d(inputs, squeeze_depth, [1, 1],
                                       strides=[1, 1], padding="SAME",
                                       activation=tf.nn.relu, name="squeeze")
            # squeeze
            expand_1x1 = tf.layers.conv2d(squeeze, expand_depth, [1, 1],
                                          strides=[1, 1], padding="SAME",
                                          activation=tf.nn.relu, name="expand_1x1")
            expand_3x3 = tf.layers.conv2d(squeeze, expand_depth, [3, 3],
                                          strides=[1, 1], padding="SAME",
                                          activation=tf.nn.relu, name="expand_3x3")
            return tf.concat([expand_1x1, expand_3x3], axis=3)

五、参考资料

1、纵览轻量化卷积神经网络:SqueezeNet、MobileNet、ShuffleNet、Xception
2、CVPR 2018 高效小网络探密(上)
3、如何评价轻量级深度神经网络 SqueezeNext?

你可能感兴趣的:(深度学习,TensorFLow)