简单的例子学会在pytorch中实现更新Kernel——卷积核的操作

卷积神经网络

从传统的滤波器角度来看,其实卷积操作可以狭隘地理解为对图像进行锐化,模糊,寻找边缘等修图的操作,但是其核心是什么呢,是如何实现这些操作的呢?
图片模糊操作

1. 认识卷积操作

如果熟悉图像的构成(这里主要说明灰度图像),灰度图像的像素变化为0-255,其中0为黑色,255为白色。如下图所示,左边的input为一个55的二维矩阵(可以看成一个像素为55的正方形图片),中间的矩阵即为大小为33的卷积核,最右边的矩阵则为输出矩阵(图像)。如果想要自己动笔计算,可以回顾线性代数中学习的知识,矩阵的乘法,卷积核的移动(从左到右,从上到下)与原始矩阵相乘,便可以计算得出最终的33矩阵。接下来将在Pytorch中实现。
卷积操作

"""实现2维卷积函数"""
import torch
from torch import nn

# 输入
x = torch.tensor([[2, 1, 0, 2, 3],
                  [9, 5, 4, 2, 0],
                  [2, 3, 4, 5, 6],
                  [1, 2, 3, 1, 0],
                  [0, 4, 4, 2, 8]])
# 卷积核
k = torch.tensor([[0, 1],
                  [2, 3]])

# 创建卷积核移动过程的计算函数
def conv2d(x, k):
	h, w = k.shape
	y = torch.zeros((x.shape[0] - h + 1, x.shape[1] - w + 1))
    for i in range(y.shape[0]):
        for j in range(y.shape[1]):
            y[i, j] = (x[i:i + h, j:j + w] * k).sum()
	return y

# 输出
y = conv2d(x, k)
print(y)

2. 创建卷积核-并初始化

有的初学者在学习CNN的过程中,搞不明白卷积核是怎么选取数值的,接下来,将用一个小实例进行讲解,也是我在学习过程中的一个总结。最终结果对比给出的边界检测卷积核和梯度下降计算出来的卷积核。

"""
首先,创建要给Conv2D的类(class),继承nn.Moudule;
其次,人为设定一个图像,用于边界检测;
再次,选用一个边界检测卷积核,用于计算图像的边界;
最终,通过梯度下降,求解初始化的Conv2D类中卷积核的参数如何根据输入输出学习出正确的边界检测卷积核。
"""
import torch
from torch import nn


# 创建卷积核移动过程的计算函数
def conv2d(x, k):
	h, w = k.shape
	y = torch.zeros((x.shape[0] - h + 1, x.shape[1] - w + 1))
	for i in range(y.shape[0]):
		for j in range(y.shape[1]):
			y[i, j] = (x[i:i + h, j:j + w] * k).sum()
	return y


class Conv2D(nn.Module):
    def __init__(self, kernel_size):
        super(Conv2D, self).__init__()
        self.weight = nn.Parameter(torch.randn(kernel_size))
        self.bias = nn.Parameter(torch.randn(1))

    def forward(self, x):
        return conv2d(x, self.weight) + self.bias

# 创建图像x,其中人为设定边界区域
x = torch.ones(6, 8)
x[:, 3:7] = 0
# 创建卷积核
k = torch.tensor([[1, -1]])
# 通过卷积操作得到输出——边界检测结果
y = conv2d(x, k)
print(y)
# 构造一个卷积核为(2,1)的二维矩阵,自动初始化,输出权重
kernal = Conv2D(kernel_size=(1, 2))
print(kernal.weight, kernal.bias)
# 设置迭代次数
step = 40
# 学习率
lr = 0.01
for i in range(step):
    y_hat = kernal(x)
    l = ((y_hat - y) ** 2).sum()
    l.backward()
	# 梯度下降
    kernal.weight.data -= lr * kernal.weight.grad
    kernal.bias.data -= lr * kernal.bias.grad
	# 梯度清零
    kernal.weight.grad.fill_(0)
    kernal.bias.grad.fill_(0)
    if (i + 1) & 5 == 0:
        print('Step %d, loss %.3f' % (i + 1, l.item()))
   
# 输出训练(梯度下降)学习到的卷积核以及真实的卷积核对比
print("weight: ", kernal.weight.data)
print("bias: ", kernal.bias.data)
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要手动实现二维卷积核,我们首先需要了解卷积的工作原理。卷积操作的目的是将一个滤波器(也称为卷积核)在输入的图像上滑动,并对每个滑动位置的局部区域进行加权求和,从而得到一个输出特征图。 首先,我们需要准备输入图像和卷积核。假设输入图像是NxN大小的,卷积核大小为KxK,我们先创建一个大小为NxN的二维数组来表示输入图像,并用随机数初始化。接下来,我们创建一个大小为KxK的二维数组作为卷积核。 然后,我们需要遍历输入图像的每个位置,并在每个位置上进行卷积操作。对于每个位置,我们取与卷积核大小相同的局部区域,并将该区域与卷积核进行按元素相乘,并将结果求和。这个求和结果就是在当前位置上卷积的输出。 最后,我们将所有卷积的输出放入一个新的二维数组,这个数组的大小为(N-K+1)x(N-K+1)。这个输出数组就是经过卷积操作后得到的特征图。 在Python,我们可以使用循环来实现上述过程。具体代码如下: ```python import numpy as np def manual_convolution(input_image, kernel): N, _ = input_image.shape K, _ = kernel.shape output_size = N - K + 1 output = np.zeros((output_size, output_size)) for i in range(output_size): for j in range(output_size): output[i, j] = np.sum(input_image[i:i+K, j:j+K] * kernel) return output # 生成输入图像和卷积核 N = 5 K = 3 input_image = np.random.random((N, N)) kernel = np.random.random((K, K)) # 手动进行二维卷积操作 output = manual_convolution(input_image, kernel) print("输出特征图:") print(output) ``` 以上代码首先生成了一个5x5的随机输入图像和一个3x3的随机卷积核,然后调用`manual_convolution`函数进行手动实现的二维卷积操作。最后,输出得到的特征图。 请注意,手动实现的二维卷积操作只是一种简化的方式,如果需要高效地进行卷积操作,建议使用已经优化过的卷积函数,如PyTorch的`torch.nn.functional.conv2d`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值