【卷积基础】CNN中一些常见卷积(1*1卷积、膨胀卷积、组卷积、深度可分离卷积)
文章目录
- 逐通道卷积(Pointwise Convolution,1x1 卷积)
- 主要作用
- 逐通道卷积的操作过程
- 优势
- 代码示例
- 典型应用
- 膨胀卷积(Dilated Convolution)
- 主要作用
- 工作原理
- 膨胀率 (dilation rate) 的定义
- 代码实例
- 膨胀卷积的优点
- 组卷积(Group Convolution)
- 主要作用
- 工作原理
- 普通卷积
- 分组卷积
- 代码实例
- 深度可分离卷积(Depthwise Separable Convolution)
- 主要作用
- 深度卷积(Depthwise Convolution)
- 原理
- 实现方法
- 1*1卷积
- 原理
- 实现方法
- 代码
参考: CNN 理解神经网络中卷积(大小,通道数,深度)
逐通道卷积(Pointwise Convolution,1x1 卷积)
逐通道卷积(Pointwise Convolution),也称为 1x1 卷积,是一种特殊的卷积操作,其中卷积核的大小为 1x1。
这种卷积操作不会覆盖空间维度(height 和 width),而是只作用于每个位置上的所有通道,这使得逐通道卷积主要用于调整通道数量或整合通道信息。
主要作用
-
降维( dimension reductionality ): 比如,一张500 * 500且厚度depth为100 的图片在20个filter上做1*1的卷积,那么结果的大小为500×500×20。就是改变了输入和输出的通道数,可以减少参数。
-
增加非线性:卷积层之后经过激励层,1*1的卷积在前一层的学习表示上添加了非线性激励( non-linear activation ),提升网络的表达能力;很明显,增加了非线性,因为相当于又进行了一次运算。
逐通道卷积的操作过程
逐通道卷积对输入特征图的每个空间位置都使用一个 1x1 的卷积核来进行计算,因此该操作不改变特征图的空间分辨率(height 和 width),而是针对通道进行操作。
例如,假设输入特征图的大小为 [height, width, channels_in]
,逐通道卷积会:
-
仅在每个空间位置的通道维度上进行加权求和,输出为
[height, width, channels_out]
。 -
通过多个 1x1 卷积核堆叠,实现对所有通道的线性组合,从而调整通道数量。
优势
-
降维或升维:可以调整通道数,例如从较高的通道数降维为较低的通道数,或从较低的通道数升维为较高的通道数。
-
减少计算量:在深层网络中,先通过 1x1 卷积减少通道数,再应用较大卷积核,可以降低计算复杂度。
-
融合通道信息:通过对不同通道进行线性组合,逐通道卷积可以聚合通道之间的信息,从而提取到更丰富的特征。
代码示例
在这个例子中,1x1
卷积调整了通道数,从 64 转换为 128,但空间分辨率(height 和 width)保持不变(即32x32)。
import torch
import torch.nn as nn
# 定义1x1逐通道卷积
conv1x1 = nn.Conv2d(in_channels=64, out_channels=128, kernel_size=1)
# 输入一个大小为 (batch_size, 64, height, width) 的特征图
input_tensor = torch.randn(1, 64, 32, 32)
output_tensor = conv1x1(input_tensor)
print("输出特征图形状:", output_tensor.shape) # (1, 128, 32, 32)
典型应用
-
通道整合:用于将特征进行通道混合,常用于 MobileNet 和 ResNet 等网络结构。
-
深度可分离卷积:在深度可分离卷积中,逐通道卷积和深度卷积结合,形成一种高效的特征提取方式,显著减少参数和计算量。
-
调整特征图维度:在网络的不同层之间,通过 1x1 卷积来匹配不同层的通道数。
膨胀卷积(Dilated Convolution)
参考:空洞卷积(膨胀卷积)的相关知识以及使用建议(HDC原则)
膨胀卷积(Dilated Convolution),又称为扩张卷积或空洞卷积,是一种特殊的卷积操作,它通过在卷积核的元素之间插入间隔(称为膨胀率或扩张率)来扩大感受野。这样一来,膨胀卷积在不增加参数数量和计算量的前提下可以获取更大的上下文信息。
在nn.conv2d中由dilation参数决定。
主要作用
-
增大感受野
-
保持原输入特征图的高度和宽度
工作原理
在标准卷积中,每个卷积核会直接作用于相邻的输入像素。而在膨胀卷积中,通过在卷积核元素之间引入空隙,使得卷积核可以“跳跃”着查看更远的像素,感受野因此被扩大。
例如,假设一个 3x3
的标准卷积核作用在输入特征图上。对于膨胀率为 2
的膨胀卷积,卷积核会在每个元素之间留出 1 个空位,相当于“跳”过一个像素。这种操作使得卷积核感知更大区域的特征,而无需增加参数。
膨胀率 (dilation rate) 的定义
膨胀卷积的核心参数是膨胀率 d,它决定了卷积核的“跳跃”距离:
- 当 d=1 时,膨胀卷积退化为标准卷积。
- 当 d=2 时,卷积核的每个元素之间有 1 个空隙,即相隔 2 个像素。
- 当 d=3 时,卷积核的每个元素之间有 2 个空隙,即相隔 3 个像素。
计算公式:
输出尺寸 = 输入尺寸 − 膨胀卷积核尺寸 步幅 + 1 输出尺寸 = \frac{输入尺寸-膨胀卷积核尺寸}{步幅}+1 输出尺寸=步幅输入尺寸−膨胀卷积核尺寸+1
代码实例
import torch
import torch.nn as nn
# 使用膨胀率为2的3x3卷积核
dilated_conv = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=3, dilation=2)
# 创建一个输入特征图
input_tensor = torch.randn(1, 1, 7, 7)
output_tensor = dilated_conv(input_tensor)
# (1, 1, 3, 3)
print("输出特征图形状:", output_tensor.shape)
- 膨胀卷积核大小:3+(3-1)*(2-1)=5
- 输出尺寸:(7-5)/1+1=3
因此输出是 (1, 1, 3, 3)
膨胀卷积的优点
- 扩大感受野:无需增加计算量就可以获取更大的感受野。
- 减少信息丢失:相比使用较大的步幅或池化层,膨胀卷积不会丢失输入特征图的空间分辨率。
- 提高网络性能:在图像分割和目标检测中常用,可以更好地捕捉多尺度的上下文信息。
组卷积(Group Convolution)
参考:卷积 - 3. 分组卷积 详解
组卷积(Group Convolution)是一种将通道分组的卷积方法,主要用于减少计算量,提升模型效率。
在nn.conv2d中由groups参数决定。
主要作用
通过将输入特征图的通道分成多个独立的组,每个组内进行单独的卷积运算,从而降低计算复杂度。
工作原理
普通卷积
输入特征为 (H × W × C)
,然后应用 C’ 个filters(每个filter的大小为 (h × w × c),输入层被转换为大小为 (H' × W' × C')
的输出特征
分组卷积
-
分组操作:假设输入有
C
个通道,组卷积会将这些通道分成G
组。每个组包含 C G \frac{C}{G} GC个通道。 -
独立卷积:每一组通道都会用各自的卷积核进行卷积。每组的计算是独立的,不会和其他组互相影响。
-
输出拼接:对每组通道的卷积操作完成后,组卷积将各组输出拼接在一起,形成最终的输出。
代码实例
import torch
import torch.nn as nn
# 创建一个组卷积层,输入和输出通道数都为64,卷积核大小为3x3,分组数为4
group_conv = nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, padding=1, groups=4)
# 输入特征图,形状为[批次大小, 通道数, 高度, 宽度]
input_tensor = torch.randn(1, 64, 32, 32)
# 进行组卷积操作
output_tensor = group_conv(input_tensor)
# 输出特征图形状: torch.Size([1, 64, 32, 32])
print("输出特征图形状:", output_tensor.shape)
深度可分离卷积(Depthwise Separable Convolution)
深度可分离卷积(Depthwise Separable Convolution) 是一种将标准卷积操作拆分为两个独立操作的卷积方式,目的是降低计算复杂度和提高效率。
深度可分离卷积将标准卷积操作分解成两个更简单的卷积步骤:
- 深度卷积(Depthwise Convolution)
- 逐点卷积(Pointwise Convolution)
主要作用
通过将传统卷积操作拆分成两步,显著减少了计算量和参数量,是一种高效的卷积方式,特别适合在移动设备等资源有限的环境中应用。
深度卷积(Depthwise Convolution)
在传统卷积中,一个卷积核会与输入图像的所有通道进行卷积。
一个大小为64×64像素、3通道彩色图片,经过4个Filters,输出为4张
32x32
的特征图
原理
而在深度卷积中,每个输入通道都使用一个单独的卷积核进行卷积。如果输入特征图有 C 个通道,就会用 C 个卷积核来进行卷积,每个卷积核只对单个通道进行卷积操作。
一个大小为64×64像素、3通道彩色图片,3个单通道卷积核分别进行卷积计算,输出3个单通道的特征图。所以,一个3通道的图像经过运算后生成了3个Feature map,如下图所示。
深度卷积: 输入特征图通道数=卷积核个数=输出特征图个数
实现方法
# 深度卷积:每个通道使用独立的卷积核
self.depthwise = nn.Conv2d(in_channels, in_channels, kernel_size=kernel_size, padding=padding, groups=in_channels)
可以看到:
-
in_channels和out_channels都是相同的,输入特征图通道数=卷积核个数=输出特征图个数;
-
卷积的设置参数中groups=in_channels,有几个通道数就分成几个组,即就安排几个卷积进行分通道操作。
1*1卷积
在深度卷积之后,通常会使用一个 1x1 卷积(即逐点卷积),它的作用是将深度卷积的输出进行通道间的混合。
根据深度卷积可知,输入特征图通道数=卷积核个数=输出特征图个数,这样会导致输出的特征图个数过少(或者说输出特征图的通道数过少,可看成是输出特征图个数为1,通道数为3),从而可能影响信息的有效性。此时,就需要进行逐点卷积。
原理
逐点卷积(Pointwise Convolution,PWConv) 实质上是用1x1的卷积核进行升维。在GoogleNet中大量使用1x1的卷积核,那里主要是用来降维。1x1的卷积核主要作用是对特征图进行升维和降维。
从深度卷积得到的3个单通道特征图,经过4个大小为1x1x3卷积核的卷积计算,输出4个特征图,而输出特征图的个数取决于Filter的个数。
实现方法
# 逐点卷积:1x1卷积对通道进行组合
self.pointwise = nn.Conv2d(in_channels, out_channels, kernel_size=1)
代码
import torch
import torch.nn as nn
class DepthwiseSeparableConv(nn.Module):
def __init__(self, in_channels, out_channels, kernel_size=3, padding=1):
super(DepthwiseSeparableConv, self).__init__()
# 深度卷积:每个通道使用独立的卷积核
self.depthwise = nn.Conv2d(in_channels, in_channels, kernel_size=kernel_size, padding=padding, groups=in_channels)
# 逐点卷积:1x1卷积对通道进行组合
self.pointwise = nn.Conv2d(in_channels, out_channels, kernel_size=1)
def forward(self, x):
x = self.depthwise(x) # 深度卷积
x = self.pointwise(x) # 逐点卷积
return x
# 创建一个输入张量
input_tensor = torch.randn(1, 64, 32, 32) # [batch_size, channels, height, width]
# 创建一个深度可分离卷积层,输入通道为64,输出通道为128
model = DepthwiseSeparableConv(64, 128)
# 进行前向传播
output_tensor = model(input_tensor)
print("输出特征图形状:", output_tensor.shape)