天天看点

深入浅出谈谈深度可分离卷积及 tensorflow 实现1 简介3 点评4 tensorflow 实现

1 简介

    深度可分离卷积的核心思想就是将普通N个通道为M的卷积拆分成1个通道为M的卷积(这个卷积进行单通道滤波操作,区别于普通卷积滤波后通道相加)和N个1×1×M的卷积,其作用在于减少运行的参数量。如果采用 3 × 3 的卷积,那么采用深度可分离卷积后,参数将变成原来的1/8~1/9。

2 原理

2.1 普通卷积

深入浅出谈谈深度可分离卷积及 tensorflow 实现1 简介3 点评4 tensorflow 实现

    对于普通卷积而言,一个边长为Dk,通道为M的卷积核(N个卷积),处理一个输入矩阵(通道为M),得到一个宽为Dw,高为Dh,通道为N的输出特征图(上图)。

    仅仅考虑乘加计算,其参数量为:

深入浅出谈谈深度可分离卷积及 tensorflow 实现1 简介3 点评4 tensorflow 实现

    计算量为:

深入浅出谈谈深度可分离卷积及 tensorflow 实现1 简介3 点评4 tensorflow 实现

2.2 深度可分离卷积

深入浅出谈谈深度可分离卷积及 tensorflow 实现1 简介3 点评4 tensorflow 实现

    对于普通卷积而言,一个边长为Dk,通道为M的卷积核,处理一个输入矩阵(通道为M),得到一个宽为Dw,高为Dh,通道为M的中间特征图。为了获得和普通卷积一样的深度,通过N个通道为M的单位卷积核,得到宽为Dw,高为Dh,通道为N的输出特征图(上图)。

    与普通卷积相比,最大特点在于通道M的深度可分离卷积核进行的是单个通道的点乘计算,所以一个卷积核处理后得到的中间特征图的通道依旧是M,而一个普通卷积核处理后得到的特征图的通道是1。

   仅仅考虑乘加计算,其参数量为:

深入浅出谈谈深度可分离卷积及 tensorflow 实现1 简介3 点评4 tensorflow 实现

    计算量为:

深入浅出谈谈深度可分离卷积及 tensorflow 实现1 简介3 点评4 tensorflow 实现

2.3 效率比较

深入浅出谈谈深度可分离卷积及 tensorflow 实现1 简介3 点评4 tensorflow 实现
深入浅出谈谈深度可分离卷积及 tensorflow 实现1 简介3 点评4 tensorflow 实现

    提高计算效率显著。

3 点评

    没看MobileNet论文原文,推测深度可分离卷积的思想源于卷积中很多参数为0或者接近0,不然这样压缩参数岂不是有很大损失?倘若很多参数不中用,目测直接压缩网络也可以了吧。

    嵌入式设备对模型的大小要求很高,需要根据实际需求做出调整。

4 tensorflow 实现

def NonLocalBlock(input, subsample=False, scope='nlb'):
    """
    @Non-local Neural Networks
    Non-local Block
    """
    with tf.variable_scope(scope):
        _, height, width, channel = input.get_shape().as_list()     # (B, H, W, C)

        theta = slim.conv2d(input, channel // 2, [1, 1], scope='conv_theta')  # (B, H, W, C // 2)
        theta = tf.reshape(theta, [-1, height*width, channel // 2])  # (B, H*W, C // 2)

        phi = slim.conv2d(input, channel // 2, [1, 1], scope='conv_phi')  # (B, H, W, C // 2)
        if subsample:
            phi = tf.layers.max_pooling2d(phi, 2, 2)  # (B, H / 2, W / 2, C // 2)
            phi = tf.reshape(phi, [-1, height * width // 4, channel // 2])  # (B, H * W / 4, C // 2)
        else:
            phi = tf.reshape(phi, [-1, height * width, channel // 2])   # (B, H*W, C // 2)
        phi = tf.transpose(phi, [0, 2, 1])  # (B, C // 2, H*W)

        f = tf.matmul(theta, phi)   # (B, H*W, H*W)
        f = tf.nn.softmax(f)    # (B, H*W, H*W)

        g = slim.conv2d(input, channel // 2, [1, 1], scope='conv_g')  # (B, H, W, C // 2)
        if subsample:
            g = tf.layers.max_pooling2d(g, 2, 2)  # (B, H / 2, W / 2, C // 2)
            g = tf.reshape(g, [-1, height * width // 4, channel // 2])  # (B, H*W, C // 2)
        else:
            g = tf.reshape(g, [-1, height * width, channel // 2])  # (B, H*W, C // 2)

        y = tf.matmul(f, g)     # (B, H*W, C // 2)
        y = tf.reshape(y, [-1, height, width, channel // 2])    # (B, H, W, C // 2)
        y = slim.conv2d(y, channel, [1, 1], scope='conv_y')     # (B, H, W, C)

        y = tf.add(input, y)    # (B, W, H, C)

        return y
           

继续阅读