大家好,欢迎来到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