卷积层常用的方法与适用范围与深度可分离卷积详解
卷积层常用的方法与适用范围与深度可分离卷积详解
卷积神经网络(CNN)是深度学习中非常重要的一种神经网络结构,广泛应用于图像识别、语义分割、视频分析等领域。卷积层作为CNN的核心组成部分,其变体和方法多种多样,每种方法都有其独特的适用范围。本文将详细介绍几种常用的卷积方法及其适用场景,帮助读者更好地理解和应用卷积神经网络。
1. 标准卷积(Standard Convolution)
方法:
- 使用固定的卷积核(滤波器)在输入特征图上滑动,提取局部特征。
适用范围:
- 图像分类:如在 AlexNet、VGGNet 中,标准卷积用于逐步提取图像的局部特征。
- 通用特征提取:适用于大多数需要提取局部特征的任务。
2. 深度可分离卷积(Depthwise Separable Convolution)
方法:
- 将标准卷积分解为两个独立的操作:
- 深度卷积(Depthwise Convolution):对每个输入通道单独进行卷积。
- 逐点卷积(Pointwise Convolution):使用1×1 卷积核对深度卷积的输出进行组合。
- 减少了计算量和参数数量。
适用范围:
- 轻量级模型:如 MobileNet 和 EfficientNet,适用于移动设备和资源受限的环境。
- 实时应用:如实时视频处理、移动设备上的图像识别。
3. 扩张卷积(Dilated Convolution)
方法:
- 在卷积核中引入扩张率(Dilation Rate),扩大了卷积核的感受野,而不需要增加额外的参数。
适用范围:
- 语义分割:如在 DeepLab 中,扩张卷积用于扩大感受野,捕捉更多上下文信息。
- 图像生成:如在生成对抗网络(GAN)中,用于生成更高质量的图像。
4. 转置卷积(Transposed Convolution)
方法:
- 用于上采样(Upsampling),通过卷积操作增加特征图的分辨率。
- 常用于生成模型和语义分割任务中的上采样模块。
适用范围:
- 语义分割:如在 U-Net 和 DeepLab 中,用于将特征图上采样到原始图像大小。
- 生成模型:如在 GAN 的生成器中,用于生成高分辨率图像。
5. 分组卷积(Grouped Convolution)
方法:
- 将输入通道分成多个组,每个组独立进行卷积操作。
- 减少了计算量和参数数量,同时保持了特征的多样性。
适用范围:
- 轻量级模型:如 ResNeXt,通过分组卷积提高模型的效率。
- 多尺度特征提取:适用于需要处理多尺度特征的任务。
6. 混合精度卷积(Mixed Precision Convolution)
方法:
- 使用不同的数据精度(如 FP16 和 FP32)进行卷积操作,减少计算量和内存占用,同时保持模型性能。
适用范围:
- 大规模训练:在 GPU 和 TPU 上加速训练过程,同时减少内存占用。
- 推理优化:在部署时使用混合精度,提高推理速度。
7. 3D 卷积(3D Convolution)
方法:
- 在三维数据(如视频或体积数据)上进行卷积操作,捕捉时空特征。
适用范围:
- 视频分析:如在视频分类和目标检测中,捕捉时间维度的特征。
- 医学图像分析:如在 CT 和 MRI 数据中,处理三维体积数据。
8. 可变形卷积(Deformable Convolution)
方法:
- 在标准卷积的基础上引入可变形的采样点,能够捕捉不规则形状的特征。
- 通过学习偏移量来调整卷积核的采样位置。
适用范围:
- 目标检测:如在 Faster R-CNN 中,用于处理目标的不规则形状。
- 语义分割:在复杂场景中,能够更好地捕捉物体的边界。
总结
卷积层的变体和方法多种多样,每种方法都有其独特的适用范围。选择合适的卷积方法取决于具体任务的需求,例如:
- 效率优先:使用深度可分离卷积或分组卷积。
- 扩大感受野:使用扩张卷积。
- 上采样:使用转置卷积。
- 处理视频或体积数据:使用 3D 卷积。
深度可分离卷积详解
一些轻量级的网络,如mobilenet中,会有深度可分离卷积depthwise separable convolution,由depthwise(DW)和pointwise(PW)两个部分结合起来,用来提取特征feature map。相比常规的卷积操作,其参数数量和运算成本比较低。
深度可分离卷积主要分为两个过程,分别为逐通道卷积(Depthwise Convolution)和逐点卷积(Pointwise Convolution)。
逐通道卷积(Depthwise Convolution)
Depthwise Convolution的一个卷积核负责一个通道,一个通道只被一个卷积核卷积,这个过程产生的feature map通道数和输入的通道数完全一样。
一张5×5像素、三通道彩色输入图片(shape为5×5×3),Depthwise Convolution首先经过第一次卷积运算,DW完全是在二维平面内进行。卷积核的数量与上一层的通道数相同(通道和卷积核一一对应)。所以一个三通道的图像经过运算后生成了3个Feature map(如果有same padding则尺寸与输入层相同为5×5),如下图所示。(卷积核的shape即为:卷积核W x 卷积核H x 输入通道数)
其中一个Filter只包含一个大小为3×3的Kernel,卷积部分的参数个数计算如下(即为:卷积核Wx卷积核Hx输入通道数):
N_depthwise = 3 × 3 × 3 = 27
计算量为(即:卷积核W x 卷积核H x (图片W-卷积核W+1) x (图片H-卷积核H+1) x 输入通道数)
C_depthwise=3x3x(5-2)x(5-2)x3=243
Depthwise Convolution完成后的Feature map数量与输入层的通道数相同,无法扩展Feature map。而且这种运算对输入层的每个通道独立进行卷积运算,没有有效的利用不同通道在相同空间位置上的feature信息。因此需要Pointwise Convolution来将这些Feature map进行组合生成新的Feature map。
逐点卷积(Pointwise Convolution)
Pointwise Convolution的运算与常规卷积运算非常相似,它的卷积核的尺寸为 1×1×M,M为上一层的通道数。所以这里的卷积运算会将上一步的map在深度方向上进行加权组合,生成新的Feature map。有几个卷积核就有几个输出Feature map。(卷积核的shape即为:1 x 1 x 输入通道数 x 输出通道数)
由于采用的是1×1卷积的方式,此步中卷积涉及到的参数个数可以计算为(即为:1 x 1 x 输入通道数 x 输出通道数):
N_pointwise = 1 × 1 × 3 × 4 = 12
计算量(即为:1 x 1 x 特征层W x 特征层H x 输入通道数 x 输出通道数):
C_pointwise = 1 × 1 × 3 × 3 × 3 × 4 = 108
经过Pointwise Convolution之后,同样输出了4张Feature map,与常规卷积的输出维度相同。
参数对比
回顾一下,常规卷积的参数个数为:
N_std = 4 × 3 × 3 × 3 = 108
Separable Convolution的参数由两部分相加得到:
N_depthwise = 3 × 3 × 3 = 27
N_pointwise = 1 × 1 × 3 × 4 = 12
N_separable = N_depthwise + N_pointwise = 39
相同的输入,同样是得到4张Feature map,Separable Convolution的参数个数是常规卷积的约1/3。因此,在参数量相同的前提下,采用Separable Convolution的神经网络层数可以做的更深。
计算量对比
回顾一下,常规卷积的计算量为:
C_std =33(5-2)*(5-2)34=972
Separable Convolution的计算量由两部分相加得到:
C_depthwise=3x3x(5-2)x(5-2)x3=243
C_pointwise = 1 × 1 × 3 × 3 × 3 × 4 = 108
C_separable = C_depthwise + C_pointwise = 351
相同的输入,同样是得到4张Feature map,Separable Convolution的计算量是常规卷积的约1/3。因此,在计算量相同的情况下,Depthwise Separable Convolution可以将神经网络层数可以做的更深。
PyTorch实现
import torch
from torch import nn
from torchsummary import summary
class depth_separable(nn.Module):
def __init__(self, in_channels:int, out_channels:int) -> None:
super(depth_separable,self).__init__()
self.depth_conv = nn.Conv2d( #和常规卷积不同就是设置了groups参数
in_channels,
in_channels,
kernel_size=3,
stride=1,
groups=in_channels, #groups设置为输入通道数,可以使逐通道卷积
)
self.point_conv = nn.Conv2d( #实现点卷积
in_channels,
out_channels,
kernel_size=1,
)
def forward(self, x):
return self.point_conv(self.depth_conv(x))
class mydepth_separable(nn.Module):
def __init__(self) -> None:
super(mydepth_separable,self).__init__()
self.conv2d = depth_separable(3,8)
self.relu = nn.ReLU()
def forward(self, x):
return self.relu(self.conv2d(x))
device = torch.device("cuda" )
model=mydepth_separable().to(device)
summary(model, (3, 5, 5)) #查看参数量(3,5,5)表示输入的尺寸是5×5×3
本文原文来自CSDN博客