您现在的位置是:首页 >学无止境 >什么是分组卷积、深度可分离卷积?附上深度可分离卷积代码网站首页学无止境

什么是分组卷积、深度可分离卷积?附上深度可分离卷积代码

WTIAW.TIAW 2023-06-03 08:00:03
简介什么是分组卷积、深度可分离卷积?附上深度可分离卷积代码

分组卷积 Group Converlution

1、由来和用途

分组卷积最开始被使用在经典入门卷积神经网络AlexNet上,用于解决显存不足的问题。在现在被广泛用于各种轻量化模型中,用于减少运算量和参数量,其中应用最广的就是深度可分离卷积。

2、常规卷积和分组卷积的区别

现在我们编写代码时,在PyTorch中常常要处理的数据维度就是 (Batch,Channel, Height, Width),简写(B,C,H,W)。

以下图可以说很直观了,相同颜色的卷积核只负责和它相同颜色的featuremap.
在这里插入图片描述
在这里插入图片描述

2.1、常规卷积:

在这里插入图片描述

常规卷积的运算量:

  1. 卷积核的运算量应该由乘法和加法两部分组成, 也就是乘加次数MAC(Multiply
    Accumulate))需要计算乘法和加法两种操作的计算次数。
  2. 一个卷积核在某一像素点上的运算量是:
    在这里插入图片描述
    常规卷积的参数量:

在这里插入图片描述

# 在Jupyter运行下面代码
from torch import nn
cnn = nn.Conv2d(2, 3, 3, 1, 1, bias=True)

print(f"{cnn.weight.shape=}")
#  cnn.weight.shape=torch.Size([3, 2, 3, 3]), 表示三个卷积核,每个卷积核2个通道,每个通道掩膜大小为3x3

print(f"{cnn.bias.shape=}")
#  cnn.bias.shape=torch.Size([3]), 表示三个卷积核有三个偏置bias,并不是每个卷积核每个通道一个bias

2.2、分组卷积:

在这里插入图片描述

3、分组卷积的作用

在这里插入图片描述

在这里插入图片描述

4、深度可分离卷积

总结:先做分组卷积,再做1 x 1卷积

  • 分组卷积,g = in = out,此时每个卷积核只负责一个通道,生成的特征图之间不存在信息交换(即在通道维度不存在信息交换)

  • 1 x 1卷积,用来实现通道件的信息交换,但在空间层面上缺少信息交流。 可以使用 torch.nn.Conv2d() 中的卷积组参数groups,来实现深度可分离卷积。groups 参数是用于控制输入和输出的连接的,表示要分的组数(in_channels 和out_channels 都必须能被 groups 参数整除)。例如:

1.当 groups =1 (默认值)时,就是同普通的卷积;
2.当 groups=n 时,相当于把原来的卷积分成 n 组,每组 in_channels/n 的输入与 out_channels/n 个 kernel_size x kernel_size x in_channels/n的卷积核卷积,生成 out_channels/n 的输出
,然后将各组输出连接起来,形成完整的 out_channels 的输出;
3.当 groups = in_channels 时,每个输入通道都只跟 out_channels/in_channels 个卷积核卷积; out_channels = in_channels 时就是 Depthwise 卷积。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

深度可分离卷积代码

import torch
from torchsummary import summary

class myGroupConv(torch.nn.Module):
    def __init__(self):
        super(myGroupConv, self).__init__()
        self.conv2d = torch.nn.Conv2d(in_channels=4,
                                      out_channels=8,
                                      kernel_size=3,
                                      stride=1,
                                      padding=1,
                                      groups=1,
                                      bias=False)
        self.relu = torch.nn.ReLU()

    def forward(self, x):
        x = self.conv2d(x)
        x = self.relu(x)

        return x


# 先做分组卷积再做1x1卷积提取通道之间的信息通信
class depthwise_separable_conv(torch.nn.Module):
    def __init__(self, ch_in, ch_out):
        super(depthwise_separable_conv, self).__init__()
        self.ch_in = ch_in
        self.ch_out = ch_out
        self.depth_conv = torch.nn.Conv2d(ch_in, ch_in, kernel_size=3, padding=1, groups=ch_in, bias=False)
        self.point_conv = torch.nn.Conv2d(ch_in, ch_out, kernel_size=1, bias=False)

    def forward(self, x):
        x = self.depth_conv(x)
        x = self.point_conv(x)
        return x

class mydspConv(torch.nn.Module):
    def __init__(self):
        super(mydspConv, self).__init__()
        self.conv2d = depthwise_separable_conv(4, 8)
        self.relu = torch.nn.ReLU()

    def forward(self, x):
        x = self.conv2d(x)
        x = self.relu(x)

        return x

device = torch.device("cuda" )
model_1 = myGroupConv().to(device)
summary(model_1, (4, 3, 3))

model_2 = mydspConv().to(device)
summary(model_2, (4, 3, 3))

输出:
在这里插入图片描述

说明:
输入尺寸:3x3x4
输出尺寸:3x3x8

常规卷积,group=1,参数量:3x3x4x8=288;测试代码中偏置设为False,所以不加上偏置的参数量,若设为true,则参数量还需要加上等于输出通道个数的偏执量的个数,等于296;

深度可分离卷积:
逐通道卷积:groups=输入通道数,输出通道数=输入通道数,kernel_size=3,每一个卷积核只在一个通道上进行卷积,其参数量=3×3×4=36
逐点卷积:kernel_size=1, 其参数量=1×1×4×8=32;
总参数量=36 + 32 = 68

参考博客:

https://blog.csdn.net/zfjBIT/article/details/127521956
https://zhuanlan.zhihu.com/p/490685194

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。