22&23 - 卷积基础原理与PyTorch卷积API基础功能介绍

该文详细介绍了卷积的基础原理,并通过手动计算与PyTorch的`nn.Conv2d`及`F.conv2d`函数进行了对比,展示了如何使用矩阵滑动相乘实现二维卷积,同时验证了自定义函数计算结果与PyTorch计算结果的一致性。
摘要由CSDN通过智能技术生成

22集 - 卷积基础原理与PyTorch卷积API基础功能介绍

22.1 卷积的操作

在这里插入图片描述

22.2 手动计算

  • 定义输入矩阵:
    在这里插入图片描述
  • 定义卷积核权重矩阵
    在这里插入图片描述
  • 通过卷积计算可以得到一个输出矩阵
    在这里插入图片描述
  • 具体计算过程如下
    在这里插入图片描述

22.3 代码测试

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

# 定义输入的矩阵
input_feature_map = torch.arange(16,dtype=torch.float).reshape((1,1,4,4))
# 定义输入通道为1
in_channel = 1
# 定义输出通道为1
out_channel =1
# 定义卷积核大小
kernel_size = 3
# 定义卷积核的权重值;kernel_weight.shape = torch.Size([out_channel,in_channel,kernel_height,kernel_width])
kernel_weight = torch.arange(9,dtype=torch.float).reshape(1,1,3,3)
# 通过Conv2d类实例化一个卷积核
my_conv2d = nn.Conv2d(in_channels=in_channel,out_channels=out_channel,kernel_size=kernel_size,bias=False)
# 将卷积核的权重赋值
my_conv2d.weight = nn.Parameter(kernel_weight,requires_grad=True)
# 得到输出特征矩阵,此时用的是nn.Conv2d类处理
output_feature_map = my_conv2d(input_feature_map)
# 得到输出特征矩阵,此时用的是F.conv2d方法处理
functional_output_feature_map = F.conv2d(input_feature_map,kernel_weight)
print(f"input_feature_map={input_feature_map}")
print(f"input_feature_map.shape={input_feature_map.shape}")
print(f"my_conv2d.weight={my_conv2d.weight}")
print(f"my_conv2d.weight.shape={my_conv2d.weight.shape}")
print(f"output_feature_map={output_feature_map}")
print(f"output_feature_map.shape={output_feature_map.shape}")
print(f"functional_output_feature_map={functional_output_feature_map}")
print(f"functional_output_feature_map.shape={functional_output_feature_map.shape}")
input_feature_map=tensor([[[[ 0.,  1.,  2.,  3.],
          [ 4.,  5.,  6.,  7.],
          [ 8.,  9., 10., 11.],
          [12., 13., 14., 15.]]]])
input_feature_map.shape=torch.Size([1, 1, 4, 4])
my_conv2d.weight=Parameter containing:
tensor([[[[0., 1., 2.],
          [3., 4., 5.],
          [6., 7., 8.]]]], requires_grad=True)
my_conv2d.weight.shape=torch.Size([1, 1, 3, 3])
output_feature_map=tensor([[[[258., 294.],
          [402., 438.]]]], grad_fn=<ThnnConv2DBackward>)
output_feature_map.shape=torch.Size([1, 1, 2, 2])
functional_output_feature_map=tensor([[[[258., 294.],
          [402., 438.]]]])
functional_output_feature_map.shape=torch.Size([1, 1, 2, 2])
  • 我们通过手动计算的输出矩阵和代码计算得到的矩阵结果一致;

23集 - 基于矩阵滑动相乘逐行实现PyTorch二维卷积

  • 基于矩阵滑动相乘逐行计算的二维矩阵对二维矩阵计算
import torch
from torch import nn
from torch.nn import functional as F
import math

# 定义输入的矩阵
input_feature_map = torch.arange(16, dtype=torch.float).reshape((1, 1, 4, 4))
# 定义输入通道为1
in_channel = 1
# 定义输出通道为1
out_channel = 1
# 定义卷积核大小
kernel_size = 3
# 定义卷积核的权重值;kernel_weight.shape = torch.Size([out_channel,in_channel,kernel_height,kernel_width])
kernel_weight = torch.arange(9, dtype=torch.float).reshape(1, 1, 3, 3)
# 通过Conv2d类实例化一个卷积核
my_conv2d = nn.Conv2d(in_channels=in_channel, out_channels=out_channel, kernel_size=kernel_size, bias=False)
# 将卷积核的权重赋值
my_conv2d.weight = nn.Parameter(kernel_weight, requires_grad=True)
# 得到输出特征矩阵,此时用的是nn.Conv2d类处理
output_feature_map = my_conv2d(input_feature_map)
# 得到输出特征矩阵,此时用的是F.conv2d方法处理
functional_output_feature_map = F.conv2d(input_feature_map, kernel_weight)
print(f"input_feature_map={input_feature_map}")
print(f"input_feature_map.shape={input_feature_map.shape}")
print(f"my_conv2d.weight={my_conv2d.weight}")
print(f"my_conv2d.weight.shape={my_conv2d.weight.shape}")
print(f"output_feature_map={output_feature_map}")
print(f"output_feature_map.shape={output_feature_map.shape}")
print(f"functional_output_feature_map={functional_output_feature_map}")
print(f"functional_output_feature_map.shape={functional_output_feature_map.shape}")


# 定义输入矩阵
my_input_matrix = torch.arange(16, dtype=torch.float).reshape(4, 4)
# 定义卷积核矩阵
my_kernel = torch.arange(9, dtype=torch.float).reshape(3, 3)


# 自定义一个矩阵滑动的卷积函数,这里只做二维矩阵和二维矩阵的卷积计算
def matrix_multiplication_for_conv2d(input, kernel, stride=1, padding=0,bias=0):
	# 判断是否需要填充,如果需要,就将上下左右都进行填充指定padding行
	if padding > 0:
		input = F.pad(input, (padding, padding, padding, padding))
	# 得到填充后矩阵的高宽
	input_h, input_w = input.shape
	# 得到卷积核的高宽
	kernel_h, kernel_w = kernel.shape
	# 得到输出矩阵高宽
	output_h = math.floor((input_h - kernel_h) / stride + 1)
	output_w = math.floor((input_w - kernel_w) / stride + 1)
	# 生成一个全0大小的输出矩阵
	output_matrix = torch.zeros(output_h, output_w)
	# 开始遍历,先得到遍历坐标
	for i in range(0, input_h - kernel_h + 1, stride):
		for j in range(0, input_w - kernel_w + 1, stride):
			# 获取遍历的区间region
			region = input[i:i + kernel_h, j: j + kernel_w]
			# 点积后求和得到相应的值
			output_matrix[int(i / stride), int(j / stride)] = torch.sum(region * kernel)+bias

	return output_matrix

# 根据自定义的卷积函数求出输出矩阵
my_output = matrix_multiplication_for_conv2d(my_input_matrix, my_kernel)
# 打印输出结果
print(f"my_output={my_output}")
print(f"判断自定义函数得到的结果是否跟pytorch计算结果一致\n{torch.isclose(my_output,torch.squeeze(functional_output_feature_map))}")
my_input_new = torch.randn(5,5)
my_kernel_weight = torch.randn(3,3)
my_kernel_bias = torch.randn(1)
my_ouput_new = torch.squeeze(F.conv2d(my_input_new.reshape(1,1,5,5),weight=my_kernel_weight.reshape(1,1,3,3),
						bias=my_kernel_bias,stride=2,padding=2))
my_ouput_fun = matrix_multiplication_for_conv2d(my_input_new,my_kernel_weight,stride=2,padding=2,bias=my_kernel_bias)
print(f"my_ouput_new={my_ouput_new}")
print(f"my_ouput_fun={my_ouput_fun}")
print(torch.isclose(my_ouput_new,my_ouput_fun))
  • 结果:
input_feature_map=tensor([[[[ 0.,  1.,  2.,  3.],
          [ 4.,  5.,  6.,  7.],
          [ 8.,  9., 10., 11.],
          [12., 13., 14., 15.]]]])
input_feature_map.shape=torch.Size([1, 1, 4, 4])
my_conv2d.weight=Parameter containing:
tensor([[[[0., 1., 2.],
          [3., 4., 5.],
          [6., 7., 8.]]]], requires_grad=True)
my_conv2d.weight.shape=torch.Size([1, 1, 3, 3])
output_feature_map=tensor([[[[258., 294.],
          [402., 438.]]]], grad_fn=<ThnnConv2DBackward>)
output_feature_map.shape=torch.Size([1, 1, 2, 2])
functional_output_feature_map=tensor([[[[258., 294.],
          [402., 438.]]]])
functional_output_feature_map.shape=torch.Size([1, 1, 2, 2])
my_output=tensor([[258., 294.],
        [402., 438.]])
判断自定义函数得到的结果是否跟pytorch计算结果一致
tensor([[True, True],
        [True, True]])
my_ouput_new=tensor([[-1.2405, -0.9159, -1.1279, -1.0144],
        [-3.2825,  0.0432, -0.3291,  0.2662],
        [ 0.0200,  2.7674,  1.8148, -1.2932],
        [-1.3802, -2.4980, -1.6681, -1.0186]])
my_ouput_fun=tensor([[-1.2405, -0.9159, -1.1279, -1.0144],
        [-3.2825,  0.0432, -0.3291,  0.2662],
        [ 0.0200,  2.7674,  1.8148, -1.2932],
        [-1.3802, -2.4980, -1.6681, -1.0186]])
tensor([[True, True, True, True],
        [True, True, True, True],
        [True, True, True, True],
        [True, True, True, True]])
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的一维卷积CNN-LSTM PyTorch模型代码,用于预测刀具磨损量。这个模型由一维卷积层和LSTM层组成,用于处理时间序列数据。 ```python import torch import torch.nn as nn import torch.optim as optim import numpy as np class ConvLSTM(nn.Module): def __init__(self, input_size, hidden_size, kernel_size, num_layers, dropout): super(ConvLSTM, self).__init__() self.hidden_size = hidden_size self.num_layers = num_layers self.conv = nn.Conv1d(input_size, input_size, kernel_size, padding=(kernel_size - 1) // 2) self.lstm = nn.LSTM(input_size, hidden_size, num_layers, dropout=dropout, batch_first=True) self.linear = nn.Linear(hidden_size, 1) def forward(self, x): x = self.conv(x) h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device) c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device) out, _ = self.lstm(x, (h0, c0)) out = self.linear(out[:, -1, :]) return out # Hyperparameters input_size = 1 hidden_size = 64 kernel_size = 3 num_layers = 2 dropout = 0.2 lr = 0.001 num_epochs = 100 # Model, Loss and Optimizer model = ConvLSTM(input_size, hidden_size, kernel_size, num_layers, dropout).to(device) criterion = nn.MSELoss() optimizer = optim.Adam(model.parameters(), lr=lr) # Train the model for epoch in range(num_epochs): for i, (inputs, labels) in enumerate(train_loader): inputs = inputs.to(device) labels = labels.to(device) # Forward pass outputs = model(inputs) loss = criterion(outputs, labels) # Backward and optimize optimizer.zero_grad() loss.backward() optimizer.step() # Print the loss if (epoch+1) % 10 == 0: print('Epoch [{}/{}], Loss: {:.4f}'.format(epoch+1, num_epochs, loss.item())) # Test the model with torch.no_grad(): correct = 0 total = 0 for inputs, labels in test_loader: inputs = inputs.to(device) labels = labels.to(device) # Forward pass outputs = model(inputs) # Calculate the loss loss = criterion(outputs, labels) total += labels.size(0) correct += (abs(outputs - labels) <= 0.1).sum().item() print('Test Accuracy of the model on the test data: {} %'.format(100 * correct / total)) ``` 在训练之前,你需要准备你的数据,并将其转换为PyTorch张量格式。你可以使用PyTorch的DataLoader类来批量加载数据。在上面的代码中,我们使用均方误差损失函数和Adam优化器来训练模型。最后,我们在测试集上评估了模型的准确性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值