前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【CNN结构设计】深入理解深度可分离卷积

【CNN结构设计】深入理解深度可分离卷积

作者头像
BBuf
发布2020-04-24 18:39:27
2.7K0
发布2020-04-24 18:39:27
举报
文章被收录于专栏:GiantPandaCVGiantPandaCV

1. 常规卷积

常规卷积

相信接触过卷积神经网络的都知道常规卷积的操作

我们通过个大小的卷积核

卷积出来的结果为

现在我们来计算一下常规卷积的计算开销(以最简单的stride(步长)为的情况进行讨论)

卷积层每一步操作的开销

一个卷积核做一次卷积操作需要的开销为,这里是卷积核大小,则为通道数。

一个卷积核完整地卷积完一次所需开销为,这里指的是卷积完成后的特征图长宽。

我们一共使用个这样的卷积核进行卷积计算,因此最后总的计算开销为:

2. Depthwise卷积

下面我们来看以下Depthwise卷积的步骤

在常规的卷积中,我们的卷积核都对每个通道进行了一次计算

而Depthwise卷积只对一个通道进行卷积计算,因此Depthwise卷积是不会改变原始特征图的通道数目

深度可分离卷积的Depthwise卷积步骤

原始特征图大小为

我们需要用相同通道数目个卷积核进行卷积

换句话说就是用个的卷积核分别对一个通道进行卷积计算

M个Dk*DK*1的卷积核分别对一个通道进行卷积计算

3. Pointwise卷积

上面的Depthwise卷积有一个问题是,它只让卷积核单独对一个通道进行计算,但是各个通道之间的信息并没有达到交换,从而在网络后续信息流动中会损失通道之间的信息 因此我们加入一个Pointwise操作,来进一步融合通道之间的信息这个操作也十分简单,就是常规的卷积核,形如下图:

1x1卷积核

通过这样一个卷积核,我们能在尽可能减少计算量的情况下,加强通道之间信息的交互

接下来我们继续推导下Pointwise卷积核这部分的计算量

假设一共有个的卷积核

Pointwise卷积示意图

原始特征图为

一个卷积核计算开销为:

一个卷积核卷积完原始特征图的计算开销为:

我们一共使用个卷积核,所以总开销为:

最后我们来看一下Depthwise和Pointwise这两部分的计算量:

Depthwise和Pointwise这两部分的计算量

4. 和传统卷积相比

和传统卷积相比,深度可分离卷积的计算量减少了N倍

可以看到Depthwise + Pointwise卷积的计算量相较于传统卷积减少了倍!

在达到相同目的(即对相邻元素以及通道之间信息进行计算)下,Dpethwise + Pointwise能极大减少卷积计算量,这也导致了大量移动端网络上都采用了这种卷积结构,再加上模型蒸馏,剪枝,能让移动端更高效的计算,推理。

5. 一个延伸

另外华为最近出了一篇GhostNet文章,对移动端网络感兴趣的可以去看看,该文章同时结合了常规卷积和Depthwise卷积,通过普通卷积得出一系列特征图,再通过Depthwise方式在这一系列特征图得出另外一部分特征图,最后「concate」到一起:

GhostNet的模块

6. 代码实现

部分框架有提供Depthwise卷积API,这里就不再赘述了。

其他框架可以参考下面我的PaddlePaddle框架代码来实现:

代码语言:javascript
复制
import paddle.fluid as fluid
from paddle.fluid.dygraph.nn import Conv2D, BatchNorm


class DepthwiseConv(fluid.dygraph.Layer):
    """
    通过分组卷积实现Depthwise卷积
    卷积前后通道数不变
    """

    def __init__(self, size, stride):
        """
        :param inputs: 输入张量
        :param size: 卷积核大小
        """
        super(DepthwiseConv, self).__init__()
        self.size = size
        self.stride = stride
        self.padding = (int(self.size - self.stride) + 1) // 2

    def forward(self, inputs):
        channels = inputs.shape[1]  # 获取输入通道数
        # print(channels)
        depthwise = Conv2D(num_channels=channels, filter_size=self.size, stride=self.stride,
                           padding=(self.padding, self.padding), num_filters=channels)
        out = depthwise(inputs)
        return out
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-04-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 GiantPandaCV 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 常规卷积
  • 2. Depthwise卷积
  • 3. Pointwise卷积
  • 4. 和传统卷积相比
  • 5. 一个延伸
  • 6. 代码实现
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档