目录
1.1 kernel and filter Definition
1. What is convolution?
卷积的本质是卷!什么是卷?
- 在给出“卷”的定义前,先介绍一个先验知识—— kernel and filter
1.1 kernel and filter Definition
kernel 是filter 的基本元素, 多张kernel 组成一个filter (形象解释如下图)
注:
- 一个filter中的kernel个数=input channel number (由输入通道数决定)
当输入通道是3个特征时,后续的每个filter中包含3个kernel;如果输入通道数是64,则后续每个filter中包含64个kernel.
- filter个数=feature number (输出多少特征,即这一层设置多少个filter)
一个filter负责提取某一种特征,N个filter即提取N个特征.
1.2 什么是卷?
举一个Kernel size=3,Stride=1和Padding=1的2D-卷积栗子:
- Kernel size(核的大小):1.1讨论了Kernel。核的大小定义了卷积的视图。
- Stride(步长):它定义了在图像中滑动时,Kernels的步长。Stride=1表示Kernels逐像素滑动通过图像。
Stride=2表示Kernels通过每步移动2个像素(即跳过1个像素)在图像中滑动。我们可以使用Stride >= 2对图像进行下采样。
- Padding(填充):Padding定义了图像边框的处理方式。Padding方式有两种 "valid" & "same"。
- same: 填充卷积(Tensorflow中的same填充)通过在输入边界周围填充0来保持输出的大小等于输入图像的大小。(上图2D-卷积的例子为 same方式!)
- valid: 未填充的卷积(Tensorflow中的valid填充)仅对输入图像的像素执行卷积,而在输入边界周围不填充0,输出的大小小于输入的大小。
2. 代码实现
2.1 一维卷积 (对应torch.nn.Conv1d)
- 一维卷积常用于数字信号处理以及时间序列数据分析(一般输入向量长度>卷积核长度,卷积核长度一般为奇数)
- 一维的意思是说卷积的方向是一维的。
- 首先,您需要定义一个卷积核 ,然后将它应用于输入信号。
- 关于输出向量的长度:(输入向量长度: m; 卷积核长度: n)
- 窄卷积:输出向量长度=m-n+1 (下面例子:5-3+1=3)
- 等宽卷积:输入向量两边都填充(n-1)/2长度的0 padding,然后最终的输出向量长度:(m+((n-1)/2)*2)-n+1 = m
Code Implementation
# numpy.convolve 函数用于执行一维卷积操作
import numpy as np
# 定义输入信号
signal = np.array([1, 2, 3, 4, 5])
# 定义卷积核(滤波器)
kernel = np.array([-1, 2, 1])
# 法一:numpy.convolve 函数用于执行一维卷积操作
# 使用 numpy.convolve 执行卷积操作
convolution_result = np.convolve(signal, kernel, mode='valid')
print("使用numpy.convolve卷积结果:", convolution_result)
# 徒手写
# output len
# 初始化卷积结果数组
conv_result = np.zeros(len(signal) - len(kernel) + 1)
# 执行卷积操作
for i in range(len(convolution_result)):
convolution_result[i] = np.sum(signal[i:i + len(kernel)] * kernel)
print("徒手写卷积结果:", convolution_result)
2.2 二维卷积 (对应torch.nn.Conv2d)
- 输入图像上滑动并执行点积运算的过程(又称之为二维互相关运算)。
- 常见于图像处理。
Padding公式:
Code Implementation
1. 简单版
import torch
def corr2d(x,k):
k_h,k_w = k.shape
result=torch.zeros(x.shape[0]+1-k_h, x.shape[1]+1-k_w) # 初始化最后的输出
for i in range(result.shape[0]):
for j in range(result.shape[1]):
result[i,j]=(x[i:i+k_h, j:j+k_w]*k).sum() #点积运算:对应数值相乘,最后相加
return result
X = torch.tensor([[0, 1, 2], [3, 4, 5], [6, 7, 8]]) # input tensor
K = torch.tensor([[0, 1], [2, 3]]) # kernel
print(corr2d(X, K))
2. 图像验证版(以及考虑padding和stride)
使用loopy来验证一下hhh!
核心Conv2D实现Code
# 定义Conv2D (以及考虑padding和stride=1)
def conv2d_numpy(input_data, kernel, stride=1, padding=0):
input_height, input_width = input_data.shape
# 获取卷积核的尺寸
kernel_height, kernel_width = kernel.shape
# 计算输出图像的尺寸
output_height = (input_height - kernel_height + 2 * padding) // stride + 1
output_width = (input_width - kernel_width + 2 * padding) // stride + 1
# 初始化输出图像
output_data = np.zeros((output_height, output_width))
# 填充输入数据(根据填充数量添加额外的行和列)
if padding > 0:
input_data = np.pad(input_data, ((padding, padding), (padding, padding)), mode='constant')
# 执行卷积操作
for i in range(0, input_height - kernel_height + 1, stride):
for j in range(0, input_width - kernel_width + 1, stride):
output_data[i // stride, j // stride] = np.sum(input_data[i:i+kernel_height, j:j+kernel_width] * kernel)
return output_data
# 执行自定义的卷积操作
result = conv2d_numpy(input_image, k1, stride=1, padding=0)
# 打印卷积结果
print(result)
#卷积结果可视化
plt.imshow(result, cmap='gray')
plt.axis('off')
Code:上述过程可以用torch.nn.Conv2d实现
import torch
import torch.nn as nn
import numpy as np
input_image_tensor = torch.tensor(input_image[np.newaxis, np.newaxis, :, :], dtype=torch.float32)
# 指定卷积核k1
k1 = np.array([
[1, 0, -1],
[1, 0, -1],
[1, 0, -1]
])
# 将k1转换为PyTorch张量,并添加必要的维度
kernel_tensor = torch.tensor(k1[np.newaxis, np.newaxis, :, :], dtype=torch.float32)
conv_layer = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=k1.shape, stride=1, padding=0)
# 使用自定义卷积核
with torch.no_grad(): # 不计算梯度,因为我们只是在设置权重
conv_layer.weight = nn.Parameter(kernel_tensor)
conv_layer.bias.data.fill_(0) # 假设没有偏置,或者设置为0
# 应用卷积层
result_tensor = conv_layer(input_image_tensor)
# 如果需要,将结果转换回numpy数组
result_numpy = result_tensor.detach().numpy()
print(result_numpy)
plt.imshow(result, cmap='gray')
plt.axis('off')
输出与之前的效果一致!Bingo!!!
参考文章
计算机视觉:卷积步长(Stride)_csdn卷积 步长-优快云博客 (图片展现了什么是stride=1以及stride=2)
深度学习笔记(3)——kernel(内核)与filter(滤波器)_深度学习filter-优快云博客
[CNN] 卷积、反卷积、池化、反池化「建议收藏」-腾讯云开发者社区-腾讯云 (本文还讲解了池化的三种方式:最大池化,平均池化,和随机池化)
手写代码实现卷积操作(Python)_手写卷积-优快云博客 (使用了金鱼姬的图片例子,生动展现了两种kernel对图片的处理的影响(两种kernel分别为:垂直边缘检测和水平边缘检测))