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

文章目录

  • 深入浅出可分离卷积
    • 空间可分离卷积
    • 深度可分离卷积
      • 普通卷积:
      • 第一部分 — 深度卷积
      • 第二部分 — 点卷积
      • 那么为什么要创建深度可分离卷积呢?
      • 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
----------------------------------------------------------------
None
# 逐深度卷积层,输入同上
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
conv = Conv_test(3, 3, 3, padding=1, groups=3).to(device)
print(summary(conv,  input_size=(3, 64, 64)))
----------------------------------------------------------------
        Layer (type)               Output Shape         Param #
================================================================
            Conv2d-1            [-1, 3, 64, 64]              27
================================================================
Total params: 27
Trainable params: 27
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.05
Forward/backward pass size (MB): 0.09
Params size (MB): 0.00
Estimated Total Size (MB): 0.14
----------------------------------------------------------------
None
# 逐点卷积层,输入即逐深度卷积的输出大小,目标输出也是4个feature map
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
conv = Conv_test(3, 4, kernel_size=1, padding=0, groups=1).to(device)
print(summary(conv,  input_size=(3, 64, 64)))
----------------------------------------------------------------
        Layer (type)               Output Shape         Param #
================================================================
            Conv2d-1            [-1, 4, 64, 64]              12
================================================================
Total params: 12
Trainable params: 12
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

2. 分组卷积、深度可分离卷积对比

  • 普通卷积:总参数量是 4x8x3x3=288。
  • 分组卷积:假设输入层为一个大小为64×64像素的彩色图片、in_channels=4,out_channels=8,经过2组卷积层,最终输出8个Feature Map,我们可以计算出卷积层的参数数量是 2x8x3x3=144。
  • 深度可分离卷积:逐深度卷积的卷积数量是 4x3x3=36, 逐点卷积卷积数量是 1x1x4x8=32,总参数量为68。
#普通卷积层
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
conv = Conv_test(4, 8, 3, padding=1, groups=1).to(device)
print(summary(conv,  input_size=(4, 64, 64)))
----------------------------------------------------------------
        Layer (type)               Output Shape         Param #
================================================================
            Conv2d-1            [-1, 8, 64, 64]             288
================================================================
Total params: 288
Trainable params: 288
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.06
Forward/backward pass size (MB): 0.25
Params size (MB): 0.00
Estimated Total Size (MB): 0.31
----------------------------------------------------------------
None
# 分组卷积层,输入的是4x64x64,目标输出8个feature map
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
conv = Conv_test(4, 8, 3, padding=1, groups=2).to(device)
print(summary(conv,  input_size=(4, 64, 64)))
----------------------------------------------------------------
        Layer (type)               Output Shape         Param #
================================================================
            Conv2d-1            [-1, 8, 64, 64]             144
================================================================
Total params: 144
Trainable params: 144
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.06
Forward/backward pass size (MB): 0.25
Params size (MB): 0.00
Estimated Total Size (MB): 0.31
----------------------------------------------------------------
None
# 逐深度卷积层,输入同上
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
conv = Conv_test(4, 4, 3, padding=1, groups=4).to(device)
print(summary(conv,  input_size=(4, 64, 64)))
----------------------------------------------------------------
        Layer (type)               Output Shape         Param #
================================================================
            Conv2d-1            [-1, 4, 64, 64]              36
================================================================
Total params: 36
Trainable params: 36
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.06
Forward/backward pass size (MB): 0.12
Params size (MB): 0.00
Estimated Total Size (MB): 0.19
----------------------------------------------------------------
None
# 逐点卷积层,输入即逐深度卷积的输出大小,目标输出也是8个feature map
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
conv = Conv_test(4, 8, kernel_size=1, padding=0, groups=1).to(device)
print(summary(conv,  input_size=(4, 64, 64)))
----------------------------------------------------------------
        Layer (type)               Output Shape         Param #
================================================================
            Conv2d-1            [-1, 8, 64, 64]              32
================================================================
Total params: 32
Trainable params: 32
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.06
Forward/backward pass size (MB): 0.25
Params size (MB): 0.00
Estimated Total Size (MB): 0.31
----------------------------------------------------------------
None

一文看尽深度学习中的8种卷积(附源码整理和论文解读

引言

卷积,是卷积神经网络中最重要的组件之一。不同的卷积结构有着不一样的功能,但本质上都是用于提取特征。比如,在传统图像处理中,人们通过设定不同的算子来提取诸如边缘、水平、垂直等固定的特征。而在卷积神经网络中,仅需要随机初始化一个固定卷积核大小的滤波器,并通过诸如反向传播的技术来实现卷积核参数的自动更新即可。其中,浅层的滤波器对诸如点、线、面等底层特征比较敏感,深层的滤波器则可以用于提取更加抽象的高级语义特征,以完成从低级特征到高级特征的映射。

【经典卷积系列】

  1. 原始卷积 (Vanilla Convolution)
  2. 组卷积 (Group convolution)
  3. 转置卷积 (Transposed Convolution)
  4. 1×1卷积 (1×1 Convolution)
  5. 空洞卷积 (Atrous convolution)
  6. 深度可分离卷积 (Depthwise Separable Convolution)
  7. 可变形卷积 (Deformable convolution)
  8. 空间可分离卷积 (Spatially Separable Convolution)
  9. 动态卷积(Dynamic Convolution)

1. 原始卷积(Vanilla Convolution)

讲解:https://mp.weixin.qq.com/s/LOQLOF67Z9r0UOXCPes9_Q

1.1 背景

CNNs中的卷积,也称为滤波器,是由一组具有固定窗口大小且带可学习参数(learnable paramerters)的卷积核所组成,可用于提取特征。

1.2 原理

如下图所示,卷积的过程是通过滑动窗口从上到下,从左到右对输入特征图进行遍历,每次遍历的结果为相应位置元素的加权求和:

动图封面

1.3 特性

1.3.1 稀疏连接(sparse connectivity)

传统的神经网络层使用矩阵乘法,由一个参数矩阵和一个单独的参数描述每个输入和每个输出之间的交互,即每个输出单元与每个输入单元进行密集交互。

img

然而,卷积网络具有稀疏交互作用,有时也称为稀疏连接或稀疏权值。

img

总的来说,使用稀疏连接方式可以使网络储存更少的参数,降低模型的内存要求,同时提高计算效率。

1.3.2 权值共享(shared weights)

在传统的神经网络中,每个元素都使用一个对应的参数(权重)进行学习。但是,在CNNs中卷积核参数是共享的。权值共享,也称为参数共享,是指在计算图层的输出时多次使用相同的参数进行卷积运算。

img

1.3.3 平移不变性(translation invariant)

CNNs中的平移不变性指的是当图像中的目标发生偏移时网络仍然能够输出同源图像一致的结果。对于图像分类任务来说,我们希望CNNs具备平移不变性,因为当图像中目标发生位置偏移时其输出结果应该保持一致。然而,CNNs结构本身所带来的平移不变性是非常脆弱的,大多数时候还是需要从大量数据中学习出来。

1.3.4 平移等变性(translation equivalence)

CNNs中的平移等变性指的是当输入发生偏移时网络的输出结果也应该发生相应的偏移。这种特性比较适用于目标检测和语义分割等任务。CNNs中卷积操作的参数共享使得它对平移操作具有等变性,而一些池化操作对平移有近似不变性。

2. 组卷积(Group convolution)

论文:AlexNet[1] (Accepted by NIPS 2012)

2.1 背景

受单个GPU算力的瓶颈限制,组卷积在早期阶段是被应用于切分网络使其能够在多个GPU上进行并行计算,之后被广泛应用到ResNeXt[2]网络中。

2.2 原理

原始卷积操作中每一个输出通道都与输入的每一个通道相连接,通道之间是以稠密方式进行连接。而组卷积中输入和输出的通道会被划分为多个组,每个组的输出通道只和对应组内的输入通道相连接,而与其它组的通道无关。这种分组(split)的思想随后被绝大多数的新晋卷积所应用。

img

2.3 特性

2.3.1 降低参数量

参数量为原始卷积的1/g,其中g为分组数。

2.3.2 提高训练效率

通过将卷积运算按通道划分为多个路径,可以尽可能地利用分布式的计算资源进行并行运算,有利于大规模深度神经网络的训练。

2.3.3 提高泛化性能

组卷积可以看成是对原始卷积操作的一种解耦,改善原始卷积操作中滤波器之间的稀疏性,在一定程度上起到正则化的作用。

2.4 改进

原始的组卷积实现中,不同通道的特征会被划分到不同的组里面,直到网络的末端才将其融合起来,中间过程显然缺乏信息的交互(考虑到不同滤波器可提取到不同的特征)。

img

为了解决此问题,ShuffleNet[3]结合了逐点组卷积(Pointwise Group Convolution, PGC)和通道混洗(channel shuffle),来实现一个高效轻量化的移动端网络设计。

img

单纯地应用PGC虽然可以有效的降低计算复杂度,但同时也会引入副作用(组与组之间的信息无交互)。因此,作者进一步地应用通道混洗操作来促使信息更好的流通。最后,论文中也提出了一种Shuffle单元。

img

3. 转置卷积(Transposed Convolution)

论文:《A guide to convolution arithmetic for deeplearning》[4]

3.1 背景

转置卷积,也称为反卷积(Deconvolution)或微步卷积(Fractionally-strided Convolution),一般应用在编解码结构中的解码器部分或者DCGAN中的生成器中等。但由于数字信号处理中也有反卷积的概念,所以一般为了不造成歧义,大多数框架的API都会定义为转置卷积。

img

3.2 原理

与常规的卷积操作不同,转置卷积是一种一对多的映射关系,即输入矩阵中的一个值映射到输出矩阵的K×K(i.e., kernel size)个值。在具体的实现当中,需要维护一个转置矩阵,这个矩阵参数是可学习的。

3.3 特性

3.3.1 特征上采样

利用转置卷积,可以引入参数让网络自动学习卷积核的权重以更好地恢复空间分辨率。一般来说,利用转置卷积来替代常规的上采样操作(最近邻插值、双线性插值即双立方插值)会取得更好的效果(在没有过拟合的情况下),弊端是增大了参数量,且容易出现网格效应[5]。

3.3.2 特征可视化

利用转置卷积还可以对特征图进行可视化。有时间的强烈推荐大家去阅读原论文《Visualizing and Understanding Convolutional Networks》[6],有助于帮助大家理解不同深度的各个特征图究竟学到了什么特征。比如,增加网络的深度有利于提取更加抽象的高级语义特征,而增加网络的宽度有利于增强特征多样性的表达。或者是小的卷积核有利于特征的学习,而小的步长则有利于保留更多的空间细节信息。

4. 1×1 Convolution

论文:《Network In Network》[7] (Accepted by ICLR 2014)

4.1 背景

1×1卷积最初提出的目的是用于增强模型对特定感受野下的局部区域的判定能力。后续也被GoogleNet[8]和ResNet[9]进一步的应用。

img

4.2 特性

4.2.1 增强特征表达能力

1×1卷积本质上也是一个带参数的滤波器,在不改变特征图本身尺寸的情况下,能够增加网络深度。通过在卷积后通过非线性激活函数可以有效的增强网络的表达能力。

4.2.2 升维和降维

1×1卷积可以通过增加或减少滤波器的数量来实现升维或降维的目的。与全连接层不同,由于卷积是基于权值共享,因此能够有效的降低网络的参数量和计算量。另一方面,降低维度可以认为是通过减少冗余的特征图来降低模型中间层权重的稀疏性,从而得到一个更加紧凑的网络结构。

4.2.3 跨通道的信息交互

类似于多层感知机,1×1卷积本质上就是多个特征图之间的线性组合。因此,通过1×1卷积操作可以轻松实现跨通道的信息交互和整合。

5. 空洞卷积(Atrous convolution)

论文:《Multi-Scale Context Aggregation by Dilated Convolutions》[10] (Accepted by ICLR 2016)
讲解:https://mp.weixin.qq.com/s/DWGqjMruicwIDKhsmossmg

5.1 背景

空洞卷积,也称为扩张卷积(Dilated Convolution),最早是针对语义分割任务所提出来的。由于语义分割是一种像素级的分类,经过编码器所提取出的高级特征图最终需要上采样到原始输入特征图的空间分辨率。因此,为了限制网络整体的计算效率,通常会采用池化和插值等上/下采样操作,但这对语义分割这种稠密预测任务来说是非常致命的,主要体现在以下三方面:

  • 不可学习:由于上采样操作(如双线性插值法)是固定的即不可学习的,所以并不能重建回原始的空间信息。
  • 损失空间信息:引入池化操作不可避免的会导致内部数据结构丢失,导致空间细节信息严重丢失。
  • 丢失小目标:经过N次池化(每次下采样2倍),原则上小于2^{N}个像素点的目标信息将不可重建,这对于语义分割这种密集型预测任务来说是致命的。

动图封面

5.2 原理

空洞卷积可看成是原始卷积更进一步的扩展,通过在原始卷积的基础上引入空洞率这个超参数,用于调节卷积核的间隔数量。比如,原始卷积核其空洞率为1,而对于空洞率为k的卷积则用0去填充空白的区域。

5.3 特性

5.3.1 增大感受野

空洞卷积可以在同等卷积核参数下获得更大的感受野。所以,对于需要较为全局的语义信息或类似于语音文本需要较长的序列信息依赖的任务中,都可以尝试应用空洞卷积。

5.3.2 表征多尺度信息

利用带有不同空洞率的卷积,还可以捕捉到多尺度的上下文语义信息。不同的空洞率代表着不同的感受野,意味着网络能够感知到不同尺寸的目标。

5.4 局限性

5.4.1 不好优化

虽然引入空洞卷积可以在参数不变的情况增大感受野,但是由于空间分辨率的增大,所以在实际中常常会不好优化,速度方面是一个诟病,因此在工业上对实时性有要求的应用更多的还是类FCN结构。

5.4.2 引入网格/棋盘效应

应用空洞卷积也引入网格效应。由图森和谷歌大脑合作研究的《Understanding Convolution for Semantic Segmentation》[11]文章指出了如果多次使用空洞率相同的卷积去提取特征时会损失掉信息的连续性。这是因为卷积核并不连续,导致许多的像素从头到尾都没有参与到运算当中,相当于失效了,这对于语义分割这类的密集型预测任务来说是十分不友好的,特别是针对小目标来说。一个解决方案便是令所叠加的卷积其空洞率不能出现大于1的公约数,如令其等于[1, 2, 5],使其呈现锯齿结构。

img

6. 深度可分离卷积(Depthwise Separable Convolution)

论文:《Xception: Deep Learning with Depthwise Separable Convolutions》[12] (Accepted by CVPR 2017)
代码:https://github.com/CVHuber/Convolution/blob/main/Depthwise%20Separable%20Convolution.py
讲解:https://mp.weixin.qq.com/s/qkldaRnuN-R0B64ssUs47w

6.1 背景

深度可分离卷积,由深度卷积(Depthwise Convolution)和逐点卷积(Pointwise Convolution)两部分组成,后也被MobileNet[13]等著名网络大规模应用。标准的卷积过程中对应图像区域中的所有通道均被同时考虑,而深度可分离卷积打破了这层瓶颈,将通道和空间区域分开考虑,对不同的输入通道采取不同的卷积核进行卷积,它将普通的卷积操作分解为两个过程,目的是希望能用较少的参数学习更丰富的特征表示。

img

6.2 原理

img

6.2.1 逐深度卷积

不同于原始卷积,深度卷积是一个卷积核负责一个通道,独立地在每个通道上进行空间卷积。因此,深度卷积的输出特征图数量等于输入特征图数量,无法进行有效的维度扩展。

6.2.2 逐点卷积

由于一个特征图仅被一个滤波器卷积,无法有效的利用不同通道在相同空间位置上的特征信息,由此加入了逐点卷积。点卷积主要是要1×1卷积构成,负责将深度卷积的输出按通道投影到一个新的特征图上。

6.3 特性

6.3.1 降低参数量和计算量

深度可分离卷积将原始的卷积运算分为两层,一层用于滤波(深度卷积),一层用于组合(逐点卷积)。这种分解过程能极大减少模型的参数量和计算量。

6.3.2 降低模型容量

深度可分离卷积在应用时并没有使用激活函数。此外,虽然深度可分离卷积可以显著的降低模型的计算量,但同时也会导致模型的容量显著降低,从而导致模型精度的下降。

7. 可变形卷积(Deformable convolution)

论文:《Deformable Convolutional Networks》[14] (Accepted by ICCV 2017)
代码:https://github.com/CVHuber/Convolution/blob/main/Deformable%20Convolution.py
讲解:https://mp.weixin.qq.com/s/O9ToEnVC-H7qPwxPQN-a7A

7.1 背景

在计算机视觉领域,同一物体在不同场景,角度中未知的几何变换是任务的一大挑战,通常来说要么通过充足的数据增强,扩充足够多的样本去增强模型适应尺度变换的能力,要么设置一些针对几何变换不变的特征或者算法,比如SIFT或者滑动窗口等。然而传统CNNs固定的几何结构无法对未知的物体形变进行有效建模,因此可变形卷积的提出便是用于解决此问题。

img

7.2 原理

需要注意的是,可变形卷积并不是真正意义上的学习可变形的卷积核,而是利用额外的卷积层去学习相应的偏移量,将得到的偏移量叠加到输入特征图中相应位置的像素点中。但由于偏移量的生成会产生浮点数类型,而偏移量又必须转换为整形,如果直接取整的话是无法进行反向传播的,因此原文是利用双线性插值的方式来间接的计算对应的像素值。

7.3 特性

7.3.1 自适应感受野

传统的卷积核由于尺寸形状固定,其激活单元的感受野也相对固定。但实际上同一个物体由于在不同位置上可能对应着不同的尺度或者变形,因此自适应感受野是进行精确定位所需要的,特别是对于密集型预测任务来说。可变形卷积基于一个平行的网络来学习偏移,让卷积核在输入特征图能够发散采样,使网络能够聚焦目标中心,从而提高对物体形变的建模能力。

7.3.2 难以部署

DCN虽然可以带来高精度,但是仍然存在一个缺陷,即当卷积核过大时,会占用非常大的内存空间,因此在落地部署方面的应用很受限制。不过对于参加竞赛而言倒不失为一种提分的trick。

7.4 改进

可变形卷积可以在一定程度上提升模型特征提取的泛化能力,但同时也会引入一些不相关的背景噪声干扰。为此,作者提出了改进的版本《Deformable ConvNets v2: More Deformable, Better Results》[15],并给出了三种相应的解决方案:使用更多数量的可变形卷积、为每个偏置都添加相应的权重、模仿R-CNN中的特征。然而,可变形卷积的计算效率也是一个值得商榷的问题。从另一个侧面来看,可变形卷积可以看做是对局部区域进行自注意力操作。

8. 空间可分离卷积(Spatially Separable Convolution)

8.1 背景

与深度可分离卷积一样,空间可分离卷积也属于因式分离卷积的一种,其核心思想是从图像空间维度(宽度和高度)进行卷积运算。

8.2 原理

空间可分离卷积的工作原理是将卷积核拆分为两部分,即将一个k×k的卷积核拆成k×1和1×k两个方向的卷积核分别对输入特征图进行卷积,以降低计算的复杂度。

img

8.3 特性

如上图所示,以5×5的输入特征图为例,如果我们直接用一个3×3的卷积核去卷积,共需要9×9=81次乘法运算。而如果换成空间可分离卷积,那么计算量为15×3+9×3=72次乘法运算。共节省了约11%的计算量。

8.4 应用

可以在空间上分离的最著名的卷积之一是Sobel算子,用于检测边缘。

img

8.5 局限性

空间可分离卷积在实际当中很少被广泛应用,最主要的一个原因是并不是所有的卷积核都能够有效的拆分成小的卷积核。

5. 动态卷积(Dynamic Convolution)

论文:《Dynamic Convolution: Attention over Convolution Kernels》[29] (Accepted by CVPR 2020)
代码:https://github.com/CVHuber/Convolution/blob/main/Dynamic%20Convolution.py
讲解:https://mp.weixin.qq.com/s/zyhZvQXBoadA1m762s2B9g

5.1 背景

轻量级卷积神经网络能够在较低的计算预算下运行,却也牺牲了模型性能和表达能力。为此提出了动态卷积,与传统的静态卷积(每层单个卷积核)相比,根据注意力动态叠加多个卷积核不仅显著提升了表达能力,额外的计算成本也很小,因而对高效的 CNN 更加友好,同时可以容易地整合入现有 CNN 架构中。

img

5.2 原理

动态卷积的原理根据输入图像,自适应的调整卷积的参数。如上图所示,静态的卷积核对于不同的输入均作同样的处理,而动态的卷积核则会根据输入的不同针对性地利用不同的卷积核选择合适的卷积的参数去进行特征的提取。

5.3 特性

5.3.1 权重自适应

动态卷积通过融合注意力机制动态地聚合多个并行的卷积核。首先对输入进行一次注意力操作然后得到每个卷积核的权重,将学习到的权重叠加到不同的卷积核上以实现卷积核的动态选取。

img

5.3.2 训练方式

动态卷积的一个训练难点在于随着网络深度的加深,如何协调多个卷积核和注意力模型之间的共同学习。作者指出需要限制注意力的取值(令权重和为1)以此来简化注意力模型的学习。其次,在训练初期限制注意力接近均匀分布有利于多个卷积核的共同学习,提出了利用Temperature annealing来提升模型的准确性。

img

5.3.3 内存计算开销

动态卷积主要包含两部分开销:注意力计算以及卷积核的叠加。其中注意力机制是由GAP和两个FC层组成的,计算复杂度低。而叠加的多个卷积核由于内核尺寸较小,计算复杂度也不高。因此,整体来说动态卷积仅引入了少量额外的计算开销却显著增加了特征表达能力。然而,由于采用多个卷积核并行的方式,必然会极大的增大内存开销。

  • 25
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小酒馆燃着灯

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

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

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

打赏作者

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

抵扣说明:

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

余额充值