2D卷积的基本原理
- 输入(Input): 输入通常是一个二维矩阵(例如灰度图像)或三维矩阵(例如RGB图像),其中第三个维度代表通道数。
- 卷积核(Kernel or Filter): 卷积核是一个较小的二维矩阵,通常由模型在训练过程中学习得到。卷积核的大小通常为 k×kk \times kk×k,例如 3×33 \times 33×3 或 5×55 \times 55×5。
- 卷积操作: 卷积核从输入图像的左上角开始逐步滑动,每次覆盖一个局部区域。对于每一个位置,卷积核中的数值与输入的对应区域元素进行逐点相乘,然后求和,结果作为输出特征图(Feature Map)中的一个像素值。
公式表示
重要概念
代码手撕
import numpy as np
# 2D 卷积实现,带偏置
def conv2d(image, kernel, bias=0, stride=1, padding=0):
# 获取输入图像和卷积核的大小
img_h, img_w = image.shape
kernel_h, kernel_w = kernel.shape
# 计算输出特征图的大小
output_h = (img_h - kernel_h + 2 * padding) // stride + 1
output_w = (img_w - kernel_w + 2 * padding) // stride + 1
# 对输入图像进行填充
if padding > 0:
image = np.pad(image, ((padding, padding), (padding, padding)), mode='constant', constant_values=0)
# 初始化输出矩阵
output = np.zeros((output_h, output_w))
# 执行卷积操作
for i in range(0, output_h):
for j in range(0, output_w):
# 选择输入图像中的对应区域
region = image[i*stride:i*stride+kernel_h, j*stride:j*stride+kernel_w]
# 进行逐点乘积并求和,再加上偏置
output[i, j] = np.sum(region * kernel) + bias
return output
# 示例输入图像和卷积核
image = np.array([
[1, 1, 1, 0, 0],
[0, 1, 1, 1, 0],
[0, 0, 1, 1, 1],
[1, 1, 0, 0, 0],
[0, 1, 1, 1, 0]
])
kernel = np.array([
[1, 0, 1],
[0, 1, 0],
[1, 0, 1]
])
# 定义偏置项
bias = 1
# 执行卷积
output = conv2d(image, kernel, bias=bias, stride=1, padding=0)
print("卷积结果带偏置:")
print(output)
偏置的作用
- 提高灵活性: 偏置值可以为模型提供更大的灵活性,使卷积层能够更好地适应各种输入数据。
- 避免零输出: 在所有输入特征为0时,卷积操作的结果也可能为0,偏置确保输出不总是零。
在实际的神经网络中,每个卷积核都会对应一个偏置值。这意味着如果网络有多个卷积核,每个卷积核的输出都可以加上对应的偏置。
填充的作用
在卷积操作中,添加填充(Padding)有几个主要的作用:
- 防止尺寸缩小:每次卷积操作都会导致输出图像的尺寸减小。通过添加填充,可以控制输出图像的尺寸,确保卷积操作不会让图像的大小减少得太多,甚至可以保持输入和输出的尺寸相同(称为 "same padding")。
- 保留边界信息:卷积操作的核心是在输入图像上移动卷积核,边缘像素可能被忽略。通过填充,可以确保边界信息被充分利用。