分组 卷积 深度可分离卷积 详细代码解析

分组卷积

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

group参数的作用是控制分组卷积。

View的作用

# view的作用
# 当view()参数不止一个,且其中一个为-1时,则-1的作用相当于占位符,其大小由torch根据矩阵元素个数和其他维大小来自动计算
# x = torch.Tensor([1,10,100,1000,10000,100000]).view(1,-1,1,1) #torch.Size([1, 6, 1, 1])
# 注意:torch中的矩阵顺序为[batch_size, channels, x, y]
# a = torch.arange(0,20)		#此时a的shape是(1,20)
# a.view(4,5).shape		#输出为(4,5)
# a.view(4,5,1,1).shape	#输出为torch.Size([4, 5, 1, 1])
# # a.view(-1,5).shape		#输出为(4,5)
# # a.view(4,-1).shape		#输出为(4,5)

分组卷积实例

import torch
import torch.nn as nn

# https://blog.csdn.net/ECNU_LZJ/article/details/105265843  Pytorch-nn.Conv2d中groups参数的理解

# y = torch.Tensor([1,10,100,1000,10000,100000])  #torch.Size([6])
x = torch.Tensor([1,10,100,1000,10000,100000]).view(1,-1,1,1) #torch.Size([1, 6, 1, 1])

print("x:",x.int())

# x: tensor([[[[     1]],
#         [[    10]],
#         [[   100]],
#         [[  1000]],
#         [[ 10000]],
#         [[100000]]]], dtype=torch.int32)

# group参数的作用是控制分组卷积。
# 输入in_channels被划分为groups组, 每组通道数为in_channels/groups 6/3=2。每组需要重复计算out_channels/(in_channels/groups)次 3/1=3。

# 分组卷积
conv = nn.Conv2d(
    in_channels=6,out_channels=9,kernel_size=1,stride=1,padding=0,groups=3,bias=False
)

# 普通卷积
conv1 = nn.Conv2d(
    in_channels=6,out_channels=9,kernel_size=1,stride=1,padding=0,groups=1,bias=False
)

# 分别查看两种卷积的参数
print("Group Conv weight size: ", conv.weight.data.size()) #Group Conv weight size: torch.Size([9, 2, 1, 1])
print("Conv weight size: ", conv1.weight.data.size()) #Conv weight size: torch.Size([9, 6, 1, 1])

# 给分组卷积的参数赋值 1-18
conv.weight.data = torch.arange(1,19).float().view(9,2,1,1)

print("conv weight data: ",conv.weight.data.int())
# conv weight data:  tensor([[[[ 1]],
#          [[ 2]]],
#         [[[ 3]],
#          [[ 4]]],
#         [[[ 5]],
#          [[ 6]]],
#         [[[ 7]],
#          [[ 8]]],
#         [[[ 9]],
#          [[10]]],
#         [[[11]],
#          [[12]]],
#         [[[13]],
#          [[14]]],
#         [[[15]],
#          [[16]]],
#         [[[17]],
#          [[18]]]], dtype=torch.int32)

# 分组卷积运算
output = conv(x).int()
#print("output shape: ",output.shape) #output shape:  torch.Size([1, 9, 1, 1])

print("output: ",output)
# output:  tensor([[[[     21]],
#          [[     43]],
#          [[     65]],
#          [[   8700]],
#          [[  10900]],
#          [[  13100]],
#          [[1530000]],
#          [[1750000]],
#          [[1970000]]]], dtype=torch.int32)

如果是正常的卷积,参数大小应该为: [9(输出通道), 6(输入通道), 1(核h), 1(核w)]。
这是因为输出是9个通道,每个通道都需要一个[6, 1, 1]大小的卷积(输入的每个通道都参与到了运算)。
但是我们可以从代码的运行结果中看到Conv层的参数大小为: [9, 2, 1, 1]。这就说明对于每个输出的通道,只有两个输入的通道参与了运算。 这个2就是 input/group = 6/3 = 2
事实就是这样,分组卷积的过程中只有部分输入的通道才参与了运算。我们就以上面的代码为例进行讲解。

首先将输入的6个通道分为3组: [1, 10], [100, 1000], [10000, 100000],每一组都用来生成输出的一个通道。
3个组只能生成3个输出通道,但是要求输出是9个通道,所以每个组需要重复计算三次。
输出的第1个通道: 1 * 1 + 2 * 10 = 21,需要用到输入的第1组。
输出的第2个通道: 3 * 1 + 4 * 10 = 43,需要用到输入的第1组。
输出的第3个通道: 5 * 1 + 6 * 10 = 65,需要用到输入的第1组。
输出的第4个通道: 7 * 100 + 8 * 1000 = 8700,需要用到输入的第2组。
输出的第5个通道: 9 * 100 + 10 * 1000 = 10900,需要用到输入的第2组。
输出的第6个通道: 11 * 100 + 12 * 1000 = 13100,需要用到输入的第2组。
输出的第7个通道: 13 * 10000 + 14 * 100000 = 1530000,需要用到输入的第3组。
输出的第8个通道: 15 * 10000 + 16 * 100000 = 1750000,需要用到输入的第3组。
输出的第9个通道: 17 * 10000 + 18 * 100000 = 1970000,需要用到输入的第3组。

普通卷积 分组卷积 深度可分离卷积对比

#可分离卷积及深度可分离卷积详解 https://blog.csdn.net/qq_40406731/article/details/107398593

# 普通卷积:总参数量是 4x8x3x3=288。
# 分组卷积:假设输入层为一个大小为64×64像素的彩色图片、in_channels=4,out_channels=8,经过2组卷积层,最终输出8个Feature Map,我们可以计算出卷积层的参数数量是 2x8x3x3=144。
# 深度可分离卷积:逐深度卷积的卷积数量是 4x3x3=36, 逐点卷积卷积数量是 1x1x4x8=32,总参数量为68。

#  普通卷积     :  Conv2d( 4,8,3,stride=1,padding=1,groups=1,bias=False)            #torch.Size([8, 4, 3, 3])  Total params: 288
# 分组卷积      :  Conv2d(4,8,3,stride=1,padding=1,groups=2,bias=False)             #torch.Size([8, 2, 3, 3])  Total params: 144
# 深度可分离卷积:   Conv2d(4,4,3,stride=1,padding=1,groups=4,bias=False) (降通)+    #torch.Size([4, 1, 3, 3])  Total params: 36 +
#                 Conv2d(4,8,1,stride=1,padding=0,groups=1,bias=False) (升维)      #torch.Size([8, 4, 1, 1])  Total params: 32 = 68
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

#标准的卷积层,输入的是3*64*64,目标输出4个feature map
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
ordinary_conv = Conv_test(4, 8, 3, padding=1, groups=1).to(device)
ordinary_conv1 = nn.Conv2d( in_channels=4,out_channels=8,kernel_size=3,stride=1,padding=1,groups=1,bias=False)
print("ordinary_conv1 weight size:",ordinary_conv1.weight.data.size()) #torch.Size([8, 4, 3, 3])
# print(summary(ordinary_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
# ----------------------------------------------------------------

#分组卷积层,输入的是4*64*64,目标输出8个feature map
group_conv = Conv_test(4,8,3,padding=1,groups=2).to(device)
group_conv1 = nn.Conv2d(4,8,3,padding=1,groups=2)
print("group_conv1 weight size:",group_conv1.weight.data.size())#torch.Size([8, 2, 3, 3])
# print(summary(group_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
# ----------------------------------------------------------------



# 逐深度卷积层,输入同上
# group参数的作用是控制分组卷积。
# 输入in_channels被划分为groups组, 每组通道数为in_channels/groups 4/4=1。每组需要重复计算out_channels/(in_channels/groups)次 4/1=3。
# 总共是 3*3*1*3=27
depth_conv = Conv_test(4, 4, 3, padding=1, groups=4).to(device)
depth_conv1 = nn.Conv2d(4, 4, 3, padding=1, groups=4)
print("depth_conv1 weight size:",depth_conv1.weight.data.size()) #torch.Size([4, 1, 3, 3])
# print(summary(depth_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
# ----------------------------------------------------------------

# 逐点卷积层,输入即逐深度卷积的输出大小,目标输出也是8个feature map  channel=input/groups
point_conv = Conv_test(4, 8, kernel_size=1, padding=0, groups=1).to(device)
point_conv1 = nn.Conv2d(4, 8,1)
print("point_conv1  weight size:",point_conv1.weight.data.size()) #torch.Size([8, 4, 1, 1])
print(summary(point_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
# ----------------------------------------------------------------
  • 5
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值