深度学习中小知识点系列(二十四) 深入解读可分离卷积以及深度学习中的八种卷积

文章目录

  • 深入浅出可分离卷积
    • 空间可分离卷积
    • 深度可分离卷积
      • 普通卷积:
      • 第一部分 — 深度卷积
      • 第二部分 — 点卷积
      • 那么为什么要创建深度可分离卷积呢?
      • 1x1 卷积核
  • 可分离卷积及普通卷积与分组卷积对比
    • 可分离卷积
      • 1. 空间可分离卷积
      • 2. 深度可分离卷积
    • 代码测试
      • 1. 普通卷积、深度可分离卷积对比
      • 2. 分组卷积、深度可分离卷积对比
  • 一文看尽深度学习中的8种卷积(附源码整理和论文解读
    • 引言
    • 1. 原始卷积(Vanilla Convolution)
      • 1.1 背景
      • 1.2 原理
      • 1.3 特性
      • 1.3.1 稀疏连接(sparse connectivity)
      • 1.3.2 权值共享(shared weights)
      • 1.3.3 平移不变性(translation invariant)
      • 1.3.4 平移等变性(translation equivalence)
    • 2. 组卷积(Group convolution)
      • 2.1 背景
      • 2.2 原理
      • 2.3 特性
      • 2.3.1 降低参数量
      • 2.3.2 提高训练效率
      • 2.3.3 提高泛化性能
      • 2.4 改进
    • 3. 转置卷积(Transposed Convolution)
      • 3.1 背景
      • 3.2 原理
      • 3.3 特性
      • 3.3.1 特征上采样
      • 3.3.2 特征可视化
    • 4. 1×1 Convolution
      • 4.1 背景
      • 4.2 特性
      • 4.2.1 增强特征表达能力
      • 4.2.2 升维和降维
      • 4.2.3 跨通道的信息交互
    • 5. 空洞卷积(Atrous convolution)
      • 5.1 背景
      • 5.2 原理
      • 5.3 特性
      • 5.3.1 增大感受野
      • 5.3.2 表征多尺度信息
      • 5.4 局限性
      • 5.4.1 不好优化
      • 5.4.2 引入网格/棋盘效应
    • 6. 深度可分离卷积(Depthwise Separable Convolution)
      • 6.1 背景
      • 6.2 原理
      • 6.2.1 逐深度卷积
      • 6.2.2 逐点卷积
      • 6.3 特性
      • 6.3.1 降低参数量和计算量
      • 6.3.2 降低模型容量
    • 7. 可变形卷积(Deformable convolution)
      • 7.1 背景
      • 7.2 原理
      • 7.3 特性
      • 7.3.1 自适应感受野
      • 7.3.2 难以部署
      • 7.4 改进
    • 8. 空间可分离卷积(Spatially Separable Convolution)
      • 8.1 背景
      • 8.2 原理
      • 8.3 特性
      • 8.4 应用
      • 8.5 局限性
    • 5. 动态卷积(Dynamic Convolution)
      • 5.1 背景
      • 5.2 原理
      • 5.3 特性
      • 5.3.1 权重自适应
      • 5.3.2 训练方式
      • 5.3.3 内存计算开销

深入浅出可分离卷积

可分离卷积分为两种类型:「空间可分离卷积」 , 「深度可分离卷积」。


空间可分离卷积

从概念上讲, 相比于「深度可分离卷积」, 「空间可分离卷积」是比较容易的,并且很好地阐明了如何将一个卷积拆分成两个的想法。所以我将从它开始介绍。不幸的是,空间可分离卷积有一些重大的缺陷,这意味着它没有在深度学习中被广泛使用。

它之所以被称为「空间可分离卷积」,是因为它主要处理图片和卷积核的空间维度,也就是宽和高。(另一个维度是深,表示每张图片通道的数量)。

一个空间可分离卷积简单的把一个卷积核拆分成两个更小的卷积核。最常见的情况是把一个3x3的卷积核拆分成一个3x1 和 1x3的卷积核,如下图所示:

img

在空间上拆分一个3x3的卷积核

在拆分前, 完成一次卷积需要做9次乘法。拆分后,每个卷积需要做3次乘法,两个卷积组合起来共需要6次乘法就可以达到和之前一样的效果。乘法的次数减少了,所以计算的复杂度就下降了,因为网络可以跑的更快。

img

简单空间可分离卷积

对于空间可分离卷积,最著名的一个例子是用于边缘检测的「Sobel kernel」:

img

拆分Sobel kernel

并不是所有的卷积核都可以被拆分成两个小的卷积核,这是空间可分离卷积存在的主要问题。在训练模型的时候,这个问题变得特别麻烦。因为网络结构只能选用那些可以被拆分的卷积核,这大大限制了我们的选择空间。


深度可分离卷积

和空间可分离卷积不同的是,深度可分离卷积可以应用在那些不能被拆分的卷积核上。因为,它更常被使用。它也是我们在keras.layers.SeparableConv2D或tf.layers.separable_conv2d 中见到的卷积类型。

深度可分离卷积之所以被这样命名是因为它不仅处理空间维度,也处理深-通道数这一维度。一张输入的图片一般会有三个通道:RGB。在几个卷积之后,一张图片将会有多个通道。你可以把每个通道作为这张图片的一种特定解释;举例来说,“红色”通道解释每一个像素的“红色强度”,“蓝色“通道解释每一个像素的“蓝色强度”,“绿色“通道解释每一个像素的“绿色强度”。如果一张图片有64个通道,那么关于这张图片就有64种不同的解释。

类似于空间可分离卷积,深度可分离卷积也会把一个卷积核拆分为两个,然后对这两种卷积核分别实行两种不同的卷积方案:「深度卷积」 , 「点卷积」。但是我们还是需要先看一下一个普通的卷积是如何工作的。


普通卷积:

假设我们有一张尺寸为12x12的RGB图片,那么他的像素就是12x12x3。

接下来我们对这张图片做一个5x5的卷积操作。不进行边界填充并且步长为1. 如果我们只考虑这张图片的宽和高,卷积处理是这样的:12x12 — (5x5) — >8x8。5x5的卷积核对每25个像素点做一次标量乘法(对应元素相乘,然后相加),每次输出一个数字。最终图片的尺寸变为8x8,因为没有进行边界填充(12-5+1=8)。

然而,因为这张图片有3个通道,我们的卷积核也需要有3个通道。这意味着在每一次卷积核移动的时候,我们实际做了5x5x3=75次乘法而不是5x5=25次。

正如2-D解释的那样,我们每25个像素点做标量矩阵相乘,输出一个数字。经过一个5x5x3的卷积核之后,这个12x12x3的图片将会变成一张8x8x1的图片。

img

一个普通的卷积 输出 8x8x1 的矩阵

如果我们想要增加输出图片的通道数,比如输入尺寸为8x8x256怎么办?

我们可以创建256个卷积核去产生256个8x8x1的图片,然后把他们叠加在一起就得到了一张8x8x256的图片。

img

一个普通的卷积 输出 8x8x256 的矩阵

以上就是一个普通的卷积如何工作的。我更倾向于把它看做一个函数:12x12x3 — (5x5x3x256) — >12x12x256 (5x5x3x256代表长,宽,卷积核的输入和输出通道数)。注意这不是一个矩阵相乘。我们没有用整个图片和这个卷积核相乘,而是在图片上去移动卷积核,每次分别对卷积核和图片的一小部分进行乘法操作。

一个深度可分离卷积把这个过程拆分为2个部分:一个「深度卷积」 和一个「点卷积」。


第一部分 — 深度卷积

在这部分,深度卷积,在不改变深度的情况下,我们对输入图片做卷积。使用3个尺寸为5x5x1的卷积核达到这个目的。

img

深度卷积,使用3个卷积核把一个 12x12x3 的图片转为 8x8x3

每一个5x5x1的卷积核在图片的一个通道重复操作 (注意:一个通道,不是所有通道), 没25个像素点就会输出一个标量, 最终生成一个8x8x1的图片. 叠加这些图片得到一张8x8x3的图片。


第二部分 — 点卷积

记住,最开始的卷积把一张12x12x3的图片转为8x8x256。目前,深度卷积已经把图片从12x12x3转为8x8x3。现在我们需要增加图片的通道数。

点卷积之所以被这样命名是因为它使用了1x1的卷积核,也可以说这个卷积核以每个点为最小单位进行重复。这个卷积核的通道数和输入图片一样的通道数;在我们的例子里是3.因此,我们在8x8x3的图片上重复一个1x1x3卷积核,去获得一个8x8x1的图片。

img

点卷积,将3通道的图片转为1通道

我们可以创建256个1x1x3的卷积核,每个卷积核生成一个8x8x1的图片,将他们叠加起来就得到一张尺寸为8x8x256的图片。

img

点卷积 256个卷积核,输出一张256通道图片

到现在为止,我们已经把一个卷积操作拆分为2个:一个「深度卷积」 和一个「点卷积」。如果原始的卷积函数是12x12x3 — (5x5x3x256) →12x12x256,那么新的卷积就是12x12x3 — (5x5x1x1) — > (1x1x3x256) — >12x12x256。


那么为什么要创建深度可分离卷积呢?

首先我们来计算一下,如果使用原来的卷积操作计算机需要做多少次乘法。有256个5x5x3的卷积核移动了8x8次,所以总共是256x3x5x5x8x8=1,228,800次乘法操作。

那么可分离卷积呢?在「深度卷积」里,我们有3个5x5x1的卷积核,移动了8x8次。在这里做的乘法次数是3x5x5x8x8 = 4,800。在「点卷积」里,有256 个1x1x3的卷积核,移动了8x8次。在这里做的乘法次数是256x1x1x3x8x8=49,152。加起来总共是53,952。

52952远远少于1,228,800。计算量变小了,所以网络能够在更短的时间内处理更多的数据。

但是它是怎样工作的呢?当我第一次听到这个解释的时候,我并不是很懂。这两个卷积不是在做一样的事情吗?在两个例子里, 我们应用一个5x5的卷积核,将图片压缩到一个通道,然后再把它扩展为256个通道。为什么一个会比另外一个快两倍呢?

在思考了一段时间之后,我意识到主要的不同在于:在普通卷积中,我们将图片转换了256次,每一次转换使用的乘法次数是5x5x3x8x8=4800。在可分离卷积中,我们仅仅真正转换了1次-「深度卷积」。然后我们拿着这个转换后的图片,仅仅把它拉长到256个通道。不必一次次的转换图片,就可以节省计算量。

值得一提的是在Keras和Tensorflow里,有一个叫做“depth multiplier”的参数。默认设置为1.在「深度卷积」中,改变这个参数,我们可以改变输出的通道数。举例来说,如果设置“depth multiplier”为2,每一个5x5x1的卷积核将会输入一个8x8x2的图片,所以刚刚的深度卷积最后会产生8x8x6的图片而不是8x8x3.一些人也许会选择手动设置这个参数去增加网络结构中参数的数量为了更好地学习更多的特征。

这是「深度可分离卷积」的缺点吗?当然!因为它减少了卷积中参数的数量。如果网络已经很小,那么应用了「深度可分离卷积」之后,参数会变得更少,可能会导致网络在训练的时候不能正确的学习。如果使用恰当的话,它就能有效的提升效率同时保证不大幅度降低有效性。这也让它成为很受欢迎。


1x1 卷积核

最后,因为点卷积使用了这个概念, 我想要谈论一些关于1x1卷积核的用处。

一个1x1卷积核—更精确的说,n个1x1xm卷积核(n:输入通道数,m:输出通道数),不仅仅可以在可分离卷积中使用。它最直接的目的是增加或减少图片的深度。如果你觉得你的卷积有太多或太少的通道,一个1x1卷积核可以帮助平衡通道的数量。

然而,我认为1x1卷积核主要目的是应用非线性。在神经网络的每一层,我们可以增加一个激活层。无论是ReLU,PReLU,Softmax,或者其他的,激活层都是非线性的。“线的线性组合仍然是线”。非线性层赋予了模型更多的可能。这就是为什么“深”的网络比“宽”的网络好。为了在不显著增加模型的参数和计算量的情况下去增加非线性层的数量,我们可以使用一个1x1的卷积核,然后在它的后面接激活层。这增加了网络的深度。

可分离卷积及普通卷积与分组卷积对比

再来看一下nn.Conv2d()

torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros')

输入为(N,C_in,H,W),输出为(N,C_out,H_out,W_out).
dilation空洞卷积来控制卷积膨胀间隔;
groups分组卷积来控制输入和输出的连接方式,in_channels和out_channels都要被groups整除。当groups设置不同时,可以区分出分组卷积或深度可分离卷积:

  1. groups=1时,表示普通卷积层
  2. groups<in_channels时,表示普通的分组卷积
  3. groups=in_channels时,表示深度可分离卷积,每个通道都有一组自己的滤波器,大小为:img

可分离卷积

可分离卷积包括空间可分离卷积(Spatially Separable Convolutions)和深度可分离卷积(depthwise separable convolution)。

假设feature的size为[channel, height , width]

  • 空间也就是指:[height, width]这两维度组成的。
  • 深度也就是指:channel这一维度。

1. 空间可分离卷积

通俗的说,空间可分离卷积就是将nxn的卷积分成1xn和nx1两步计算。

  • 普通的3x3卷积在一个5x5的feature map上的计算方式如下图,每个位置需要9此惩罚,一共9个位置,整个操作要81次做乘法:

img

* 同样的状况在空间可分离卷积中的计算方式如下图,第一步先使用3x1的filter,所需计算量为:15x3=45;第二步使用1x3的filter,所需计算量为:9x3=27;总共需要72次乘法就可以得到最终结果,要小于普通卷积的81次乘法。

img

虽然空间可分离卷积可以节省计算成本,但一般情况下很少用到。所以我们后面主要以深度可分离卷积展开讲解。

2. 深度可分离卷积

在Google的Xception以及MobileNet论文中都有描述。它的核心思想是将一个完整的卷积运算分解为两步进行,分别为Depthwise Convolution(逐深度卷积)与Pointwise Convolution(逐点1*1卷积)。

高效的神经网络主要通过:1. 减少参数数量;2. 量化参数,减少每个参数占用内存
目前的研究总结来看分为两个方向:

一是对训练好的复杂模型进行压缩得到小模型;

二是直接设计小模型并进行训练。(Mobile Net属于这类)

首先,我们比较下全卷积和深度可分离卷积:

  • 常规卷积:假设输入层为一个大小为64×64像素、三通道彩色图片。经过一个包含4个Filter的卷积层,最终输出4个Feature Map,且尺寸与输入层相同。我们可以计算出卷积层的参数数量是 4x3x3x3=108,参考下图:

img

  • 逐深度卷积(滤波):将单个滤波器应用到每一个输入通道。还用上面那个例子,这里的Filter的数量与上一层的Depth相同。所以一个三通道的图像经过运算后生成了3个Feature map,参数数量是 3x3x3=27,参考下图:

img

* 逐点卷积(组合):用1*1的卷积组合不同深度卷积的输出,得到一组新的输出。卷积核的尺寸为 1×1×M,M为上一层的depth。这里的卷积运算会将上一步的map在深度方向上进行加权组合,生成新的Feature map。有几个Filter就有几个Feature map,计算参数量为 1x1x3x4=12,参考下图:

img

综上,我们比对一下:常规卷积的参数个数为108;深度可分离卷积的参数个数为39,参数个数是常规卷积的约1/3。 下面我们用代码来验证一下!

代码测试

1. 普通卷积、深度可分离卷积对比

import torch.nn as nn
import torch
from torchsummary import summary 
class Conv_test(nn.Module):
    def __init__(self, in_ch, out_ch, kernel_size, padding, groups):
        super(Conv_test, self).__init__()
        self.conv = nn.Conv2d(
            in_channels=in_ch,
            out_channels=out_ch,
            kernel_size=kernel_size,
            stride=1,
            padding=padding,
            groups=groups,
            bias=False
        )

    def forward(self, input):
        out = self.conv(input)
        return out
#标准的卷积层,输入的是3x64x64,目标输出4个feature map
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
conv = Conv_test(3, 4, 3, 1, 1).to(device)
print(summary(conv,  input_size=(3, 64, 64)))
----------------------------------------------------------------
        Layer (type)               Output Shape         Param #
================================================================
            Conv2d-1            [-1, 4, 64, 64]             108
================================================================
Total params: 108
Trainable params: 108
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
---------------------------
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小酒馆燃着灯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值