卷积核(Convolution Kernel)是卷积神经网络(CNN)里最核心的组件之一,大量用在图像处理和深度学习模型中。它本质上是一个小矩阵,拿它对输入图像做卷积运算,就能从图里提出特征。具体做法是让这个小矩阵在图像上慢慢滑动,每到一个位置就做一次逐点相乘再求和,最终把原图转成一张特征图。
1. 卷积计算

- input 表示输入的图像。
- filter 表示卷积核,也叫滤波器。
- input 经过 filter 处理后得到最右侧那张图,这张输出就叫特征图。
那么它到底是怎么算的呢?卷积运算的本质,就是在滤波器和输入数据的局部区域之间做点积。

先看左上角那个点是怎么算出来的:

按上面的方法把每个位置都算一遍,就得到最终的特征图:

2. Padding
看完上面的计算我们会发现,卷积出来的特征图比原图小了一圈。如果想让卷积之后的图像尺寸保持不变,办法是在原图四周补一圈 padding。

3. Stride
卷积核每走一步的距离叫步长(Stride)。先看步长为 1 时的特征图:

如果把 Stride 增大到 2,卷积核每次跳两格,同样能提取出特征图,只是尺寸更小,如下图:

4. 多通道卷积
真实的图像都是多个通道叠起来的,比如 RGB 三个通道。这种多通道的卷积该怎么算呢?

计算规则是这样的:
- 当输入有多个通道(Channel)时,比如 RGB 三个通道,卷积核的通道数也必须跟它保持一致。
- 卷积核的每一个通道,分别和输入图像对应的那个通道做卷积。
- 最后把各个通道的卷积结果按位相加,就得到最终的一张特征图。
如下图所示:

5. 多核卷积
上面的例子里我们只用了一个卷积核。真正做图像特征提取时,往往要用一堆卷积核。这一堆卷积核可以理解成从不同视角、不同角度去打量同一张图,各自捕捉不同的特征。
那么用上多个卷积核之后,特征该怎么提取呢?

6. 特征图大小
输出特征图的大小,由下面这几个参数决定:
- size:卷积核(过滤器)的大小,一般选奇数,比如 1*1、3*3、5*5。
- Padding:四周零填充的圈数。
- Stride:卷积核移动的步长。
具体怎么算呢,先把变量约定一下:
- 输入图像大小:W x W。
- 卷积核大小:F x F。
- Stride:S。
- Padding:P。
- 输出图像大小:N x N。

我们拿一组数字代入算一遍:
- 图像大小:5 x 5。
- 卷积核大小:3 x 3。
- Stride:1。
- Padding:1。
- 代入公式 (5 – 3 + 2) / 1 + 1 = 5,得到的特征图大小就是 5 x 5。

7. PyTorch 卷积层 API
做图像主要用 Conv2D 卷积层,我们来看它怎么用。示例代码如下:
import torch.nn as nn
import torch
import torch.nn.functional as F
# 1. nn.Conv2d 参数解释
def test01():
# Conv2d 表示卷积层, 由 out_channels 个卷积核组成,每个卷积核有 in_channels 个通道
conv2d = nn.Conv2d(in_channels=3, out_channels=5, kernel_size=2)
# 卷积核权重参数:
# 5: 表示需要 5 个卷积核, 输出几个通道 out_channels 对应就有几个卷积核
# 3: 输入的图像有 in_channels=3 个,那么对应每个卷积核就有 3 个通道
# [2, 2]: 表示卷积核的 kernel size
# torch.Size([5, 3, 2, 2])
print(conv2d.weight.shape)
# 卷积核偏置参数:
# 5: 表示共有 5 个卷积核对应 5 个偏置
# torch.Size([5])
print(conv2d.bias.shape)
# 卷积时候向右、向下的步长分别为 1
# (1, 1)
print(conv2d.stride)
# 卷积时候向右、向下的填充分别为 0
# (0, 0)
print(conv2d.padding)
# 卷积时候向右、向下的扩张为 1,可以增加范围
# (1, 1)
print(conv2d.dilation)
# 2. nn.Conv2d 计算过程
def test02():
torch.manual_seed(0)
inputs = torch.randint(0, 10, size=[2, 3, 3, 3]).float()
print(inputs)
print('-' * 60)
# 设置卷积核权重参数
weight = torch.ones(size=[5, 3, 2, 2]).float()
# 设置卷积核偏置参数
bias = torch.zeros(size=[5,]).float()
output = F.conv2d(inputs, weight=weight, bias=bias)
print(output)
if __name__ == '__main__':
test02()




冀公网安备13050302001966号