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

26-27 逐行实现二维空洞卷积dilation与群卷积groups文章目录1.Dilation2.Groups3.撸代码4.小结1.DilationDilation的作用是对卷积核进行扩充;默认dilation=1不扩充,dilation>1表示卷积核内两两行两两列之间填充dilation-1个0;如下图所示:2.Groupsgroups的作用是将输入和输出通道进行分组,避免所有的通道都进行融合,而是以组为单位进行融合,可以大大的减少训练参数;groups=1时的操作:groups=2时的操作:3.撸代码import

大家好,欢迎来到IT知识分享网。

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进行分组后,每组之间进行通道融合

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/21495.html

(0)

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

关注微信