• 关于深度可分离卷积的理解


    常规卷积

    常规卷积中,连接的上一层一般具有多个通道(这里假设为n个通道),因此在做卷积时,一个滤波器(filter)必须具有n个卷积核(kernel)来与之对应。一个滤波器完成一次卷积,实际上是多个卷积核与上一层对应通道的特征图进行卷积后,再进行相加,从而输出下一层的一个通道特征图。在下一层中,若需要得到多个通道的特征图(这里假设为m个通道),那么对应的滤波器就需要m个。

    用通俗的话来概括卷积,他起到的作用就是两个:一个是对上一层的特征图进行尺寸调整,另一个是则是对上一层的特征图数量进行调整,也就是通道数的调整。

    常规卷积示意图

    这里不理解的可以看吴恩达有关三维卷积的讲解视频:

    深度可分离卷积

    深度可分离卷积,其实只对常规卷积做了一个很小的改动,但是带来的确实参数量的下降,这无疑为网络的轻量化带来了好处。

    对于来自上一层的多通道特征图,首先将其全部拆分为单个通道的特征图,分别对他们进行单通道卷积,然后重新堆叠到一起。这被称之为逐通道卷积(Depthwise Convolution)。这个拆分的动作十分关键,在这一步里,它只对来自上一层的特征图做了尺寸的调整,而通道数没有发生变化。于是将前面得到的特征图进行第二次卷积,这是采取的卷积核都是1×1大小的,滤波器包含了与上一层通道数一样数量的卷积核。一个滤波器输出一张特征图,因此多个通道,则需要多个滤波器。这又被称之为逐点卷积(Pointwise Convolution)。

    逐通道卷积示意图

    逐点卷积示意图

    参数量对比

    假设存在这样一个场景,上一层有一个64×64大小,3通道的特征图,需要经过卷积操作,输出4个通道的特征图,并且要求尺寸不改变。我们可以对比一下采用常规卷积和深度可分离卷积参数量各是多少。

    import torch.nn as nn
    from torchsummary import summary
    
    class normal_conv(nn.Module):
        def __init__(self, in_channels, out_channels):
            super(normal_conv, self).__init__()
            self.conv = nn.Conv2d(in_channels,
                                  out_channels,
                                  kernel_size=3,
                                  stride=1,
                                  padding=1,
                                  bias=True)
    
        def forward(self, x):
            return self.conv(x)
    
    
    class sep_conv(nn.Module):
        def __init__(self, in_channels, out_channels):
            super(sep_conv, self).__init__()
            self.deepthwise_conv = nn.Conv2d(in_channels,
                                             in_channels,
                                             kernel_size=3,
                                             stride=1,
                                             padding=1,
                                             bias=True,
                                             groups=in_channels)
            self.pointwise_conv = nn.Conv2d(in_channels,
                                            out_channels,
                                            kernel_size=1,
                                            stride=1,
                                            padding=0,
                                            bias=True,
                                            groups=1)
        def forward(self,x):
            d = self.deepthwise_conv(x)
            p = self.pointwise_conv(d)
            return p
    
    input_size = (3,64,64)
    
    conv1 = normal_conv(3,4)
    conv2 = sep_conv(3,4)
    
    print("使用常规卷积所需要的参数:")
    print(summary(conv1,input_size,batch_size=1))
    print("使用深度可分离卷积所需要的参数:")
    print(summary(conv2,input_size,batch_size=1))
    

    输出结果:

    使用常规卷积所需要的参数:
    ----------------------------------------------------------------
            Layer (type)               Output Shape         Param #
    ================================================================
                Conv2d-1             [1, 4, 64, 64]             112
    ================================================================
    Total params: 112
    Trainable params: 112
    Non-trainable params: 0
    ----------------------------------------------------------------
    Input size (MB): 0.05
    Forward/backward pass size (MB): 0.12
    Params size (MB): 0.00
    Estimated Total Size (MB): 0.17
    ----------------------------------------------------------------
    None
    使用深度可分离卷积所需要的参数:
    ----------------------------------------------------------------
            Layer (type)               Output Shape         Param #
    ================================================================
                Conv2d-1             [1, 3, 64, 64]              30
                Conv2d-2             [1, 4, 64, 64]              16
    ================================================================
    Total params: 46
    Trainable params: 46
    Non-trainable params: 0
    ----------------------------------------------------------------
    Input size (MB): 0.05
    Forward/backward pass size (MB): 0.22
    Params size (MB): 0.00
    Estimated Total Size (MB): 0.27
    ----------------------------------------------------------------
    None
    

    可以看到,参数由112下降到了46,通道越多这种效果越明显。

    参考文献

  • 相关阅读:
    解决-Dmaven.multiModuleProjectDirectory system property is not set. Check $M2_HOME environment variable and mvn script match.
    .net-C#代码判断
    ashx-auth-黑色简洁验证码
    ylbtech-权限管理-数据库设计-功能权限管理技术
    ylbtech-Model-Account(通用账户模块设计)
    ADO.NET访问Access(文本数据库)数据操作(CRUD)
    连接数据库的五种不同的方式
    ylbtech-数据库设计与优化-对作为复选框/单选列表的集合表的设计
    ylbtech-cnblogs(博客园)-数据库设计-7,News(新闻)
    ylbtech-cnblogs(博客园)-数据库设计-2,Admin(用户后台)-用户自定义参数设置
  • 原文地址:https://www.cnblogs.com/gshang/p/13548561.html
Copyright © 2020-2023  润新知