26-27 逐行实现二维空洞卷积dilation与群卷积groups

75 篇文章 2 订阅

1. Dilation

Dilation 的作用是对卷积核进行扩充;默认dilation=1不扩充,dilation>1 表示卷积核内两两行两两列之间填充dilation-1个0;如下图所示:
在这里插入图片描述
在这里插入图片描述

2. Groups

groups的作用是将输入和输出通道进行分组,避免所有的通道都进行融合,而是以组为单位进行融合,可以大大的减少训练参数;
在这里插入图片描述

  • groups=1时的操作:
    在这里插入图片描述
  • groups=2时的操作:
    在这里插入图片描述

3. 撸代码

import torch
from torch.nn import functional as F
import math


# input  = (bs,groups,                      in_channel//groups,  input_h,   input_w)
# kernel =    (groups,out_channel//groups,  in_channel//groups,  kernel_h,  kernel_w)
# Output1 = input * kernel
# Output1 = (bs,groups,out_channel//groups,output_h,output_w)
# Output2 = (bs,out_channel,output_h,output_w)


# 自定义卷积操作,
def matrix_multiplication_for_conv2d_final(input, kernel, bias=None, stride=1, padding=0, dilation=1, groups=1):
	# 如果有填充,就需要在卷积核的上下作用进行填充padding,pytorch中的pad函数是从里到外的,注意顺序
	if padding > 0:
		# input.shape = torch.Size((batch_size,in_channel,input_h,input_w))
		input = F.pad(input, (padding, padding, padding, padding, 0, 0, 0, 0))
	# 获取输入input相关参数
	bs, in_channel, input_h, input_w = input.shape
	# 获取相关卷积核参数
	out_channel, m, kernel_h, kernel_w = kernel.shape
	# reshape input and kernel
	assert out_channel % groups == 0 and in_channel % groups == 0, "groups必须同时被输入通道数和输出通道数整除"
	# 将input进行分组
	# before: (bs,in_channel,input_h,input_w)
	#  after: (bs,groups,in_channel//groups,input_h,input_w)

	input = input.reshape((bs, groups, in_channel // groups, input_h, input_w))
	# before: kernel.shape = (out_channel,in_channel//groups,kernel_h,kernel_w)
	# after : kernel.shape = (groups,out_channel//groups,in_channel//groups,kernel_h,kernel_w)
	kernel = kernel.reshape((groups, out_channel // groups, in_channel // groups, kernel_h, kernel_w))

	# 得到扩张后的卷积核大小 kernel_h,kernel_w
	kernel_h = (kernel_h - 1) * (dilation - 1) + kernel_h
	kernel_w = (kernel_w - 1) * (dilation - 1) + kernel_w

	# 得到输出卷积的大小 output_h and output_w
	output_h = math.floor((input_h - kernel_h) / stride) + 1
	output_w = math.floor((input_w - kernel_w) / stride) + 1

	# 为了计算,需要将output添加一个groups维度
	output_shape = (bs, groups, out_channel // groups, output_h, output_w)
	output = torch.zeros(output_shape)
	if bias is None:
		bias = torch.zeros(out_channel)
	for ind in range(bs):  # 对batch_size进行遍历
		for g in range(groups):  # 对群组进行遍历
			for oc in range(out_channel // groups):  # 对分组后的输出通道进行遍历
				for ic in range(in_channel // groups):  # 对分组后的输入通道进行遍历
					for i in range(0, input_h - kernel_h + 1, stride):  # 对高度进行遍历
						for j in range(0, input_w - kernel_w + 1, stride):  # 对宽度进行遍历
							# input_shape = [bs,groups,in_channel//groups,input_h,input_w]
							region = input[ind, g, ic, i:i + kernel_h:dilation, j:j + kernel_w:dilation]  # 特征区域
							# kernel_shape = [groups,out_channel//groups,in_channel//groups,kernel_h,kernel_w]
							# output_shape = [bs,groups,out_channel//groups,output_h,output_w]
							output[ind, g, oc, int(i / stride), int(j / stride)] += torch.sum(
								region * kernel[g, oc, ic])
				output[ind, g, oc] += bias[g * (out_channel // groups) + oc]  # 考虑偏置
	# (bs,groups,out_channel//groups,output_h,output_w) -> (bs,out_channel,output_h,output_w)
	output = output.reshape((bs, out_channel, output_h, output_w))  # 还原成四维

	return output


kernel_size = 3
bs, in_channel, input_h, input_w = 2, 2, 5, 5
out_channel = 4
groups, dilation, stride, padding = 2, 2, 2, 1

input = torch.randn((bs, in_channel, input_h, input_w))
kernel = torch.randn(out_channel, in_channel // groups, kernel_size, kernel_size)
bias = torch.randn(out_channel)

pytorch_conv2d_api_ouput = F.conv2d(input, kernel, bias=bias, padding=padding, stride=stride, dilation=dilation,
									groups=groups)
mm_conv2d_final_output = matrix_multiplication_for_conv2d_final(input, kernel, bias=bias, padding=padding,
																stride=stride, dilation=dilation, groups=groups)

# 验证手写的卷积操作跟pytorch自带的卷积操作结果是否一致
flag = torch.allclose(pytorch_conv2d_api_ouput, mm_conv2d_final_output)
# 如果flag=True表示计算结果与pytorch官网结果一致
print(f"flag={flag}")
  • 结果:
flag=True

4. 小结

groups可以减少操作,将in_channel和out_channel进行分组后,每组之间进行通道融合

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值