卷积 - 感受野(Receptive Field)
flyfish
感受野(Receptive Field)是指卷积神经网络中某一层的一个特定神经元能够“看到”并响应的输入图像区域。简单来说,它是指卷积核在输入图像上滑动过程中每次覆盖的区域。感受野的大小随着卷积层的增加而增大,即网络越深,感受野越大。
感受野的直观理解
假设我们有一个简单的卷积神经网络,只有一层卷积层,卷积核大小为 3 × 3 3 \times 3 3×3,步长为 1,没有填充。
例子
输入图像(大小为 5 × 5 5 \times 5 5×5):
[ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 ] \begin{bmatrix} 1 & 2 & 3 & 4 & 5 \\ 6 & 7 & 8 & 9 & 10 \\ 11 & 12 & 13 & 14 & 15 \\ 16 & 17 & 18 & 19 & 20 \\ 21 & 22 & 23 & 24 & 25 \\ \end{bmatrix} 16111621271217223813182349141924510152025
卷积核(大小为 3 × 3 3 \times 3 3×3):
[ 1 0 − 1 1 0 − 1 1 0 − 1 ] \begin{bmatrix} 1 & 0 & -1 \\ 1 & 0 & -1 \\ 1 & 0 & -1 \\ \end{bmatrix} 111000−1−1−1
卷积操作的步骤:
- 卷积核首先覆盖输入图像的左上角 3 × 3 3 \times 3 3×3 区域: [ 1 2 3 6 7 8 11 12 13 ] \begin{bmatrix} 1 & 2 & 3 \\ 6 & 7 & 8 \\ 11 & 12 & 13 \\ \end{bmatrix} 161127123813 这个区域就是第一个神经元的感受野。
- 卷积核向右滑动一个步长,覆盖下一个 3 × 3 3 \times 3 3×3 区域: [ 2 3 4 7 8 9 12 13 14 ] \begin{bmatrix} 2 & 3 & 4 \\ 7 & 8 & 9 \\ 12 & 13 & 14 \\ \end{bmatrix} 271238134914 这个区域就是第二个神经元的感受野。
以此类推,卷积核会覆盖输入图像上的每一个可能的 3 × 3 3 \times 3 3×3 区域,每个区域都对应一个神经元的感受野。
更深层的感受野
假设我们有一个两层卷积神经网络:
- 第一层卷积层的卷积核大小为 3 × 3 3 \times 3 3×3,步长为 1,没有填充。
- 第二层卷积层的卷积核大小为 3 × 3 3 \times 3 3×3,步长为 1,没有填充。
在第一层,感受野的大小为 3 × 3 3 \times 3 3×3。在第二层,每个神经元的感受野由它在第一层的感受野决定,并且考虑到卷积核的大小,它实际上看到了第一层的 3 × 3 3 \times 3 3×3 区域的 3 × 3 3 \times 3 3×3 感受野。
第二层神经元的实际感受野大小可以通过计算来确定:
- 第一层的感受野大小: 3 × 3 3 \times 3 3×3
- 第二层的卷积核大小: 3 × 3 3 \times 3 3×3
- 第二层的每个神经元的感受野包括第一层中 3 × 3 3 \times 3 3×3 区域的感受野。
所以,第二层的感受野大小是 5 × 5 5 \times 5 5×5,因为第二层的卷积核会覆盖第一层卷积的多个感受野,具体如下:
- 如果考虑第一层的每个感受野( 3 × 3 3 \times 3 3×3)作为一个单位块,那么第二层的感受野大小就是这些单位块的覆盖范围。
- 例如,第二层的一个神经元可能会结合第一层的9个不同感受野的输出
import torch
import torch.nn as nnclass SimpleCNN(nn.Module):def __init__(self):super(SimpleCNN, self).__init__()self.conv1 = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=3, stride=1, padding=0)self.conv2 = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=3, stride=1, padding=0)def forward(self, x):x = self.conv1(x)print(f"After conv1: {x.shape}")x = self.conv2(x)print(f"After conv2: {x.shape}")return xdef calculate_receptive_field(layers):receptive_field = 1for layer in layers:kernel_size = layer.kernel_size[0]stride = layer.stride[0]padding = layer.padding[0]receptive_field = ((receptive_field - 1) * stride) + kernel_size - 2 * paddingprint(f"Layer {layer}: receptive field size = {receptive_field}")# 输入图像
input_image = torch.tensor([[1, 2, 3, 4, 5],[6, 7, 8, 9, 10],[11, 12, 13, 14, 15],[16, 17, 18, 19, 20],[21, 22, 23, 24, 25]
], dtype=torch.float32).unsqueeze(0).unsqueeze(0) # 添加批次和通道维度# 创建模型
model = SimpleCNN()# 进行前向传播
output = model(input_image)# 打印输出结果
print("输出结果:")
print(output.squeeze().detach().numpy())# 计算并输出感受野大小
calculate_receptive_field([model.conv1, model.conv2])
After conv1: torch.Size([1, 1, 3, 3])
After conv2: torch.Size([1, 1, 1, 1])
输出结果:
4.2884874
Layer Conv2d(1, 1, kernel_size=(3, 3), stride=(1, 1)): receptive field size = 3
Layer Conv2d(1, 1, kernel_size=(3, 3), stride=(1, 1)): receptive field size = 5
运行这段代码将会输出每一层卷积之后的特征图形状,以及每一层的感受野大小。输出结果将会显示每一层卷积操作后的感受野如何变化。
感受野大小的计算步骤
第一层卷积 c o n v 1 conv1 conv1
- 输入图像大小: 5 × 5 5 \times 5 5×5
- 卷积核大小: 3 × 3 3 \times 3 3×3
- 步长: 1 1 1
- 填充: 0 0 0
计算第一层感受野大小:
R 1 = 3 R_1 = 3 R1=3
第二层卷积 c o n v 2 conv2 conv2
- 第一层输出特征图大小: 3 × 3 3 \times 3 3×3
- 卷积核大小: 3 × 3 3 \times 3 3×3
- 步长: 1 1 1
- 填充: 0 0 0
计算第二层感受野大小:
R 2 = ( ( R 1 − 1 ) × stride ) + kernel size − 2 × padding R_2 = ((R_1 - 1) \times \text{stride}) + \text{kernel size} - 2 \times \text{padding} R2=((R1−1)×stride)+kernel size−2×padding
R 2 = ( ( 3 − 1 ) × 1 ) + 3 − 2 × 0 R_2 = ((3 - 1) \times 1) + 3 - 2 \times 0 R2=((3−1)×1)+3−2×0
R 2 = 5 R_2 = 5 R2=5
通过这种方式,我们可以跟踪每一层卷积操作后感受野大小的变化。代码中的 calculate_receptive_field 函数通过遍历每一层卷积层来计算和输出感受野大小。
核心概念
卷积神经网络(CNN)之所以在处理图像等数据时非常有效,是因为它们利用了三大核心概念:局部连接(Local Connectivity)、权值共享(Weight Sharing)、平移不变性(Translation Invariance)。让我们详细探讨这些概念。
1. 局部连接(Local Connectivity)
在传统的全连接神经网络中,每个神经元与上一层的每个神经元相连接,形成一个全连接的网络结构。而在卷积神经网络中,卷积层的每个神经元只与上一层的局部区域(称为感受野)相连接。
解释:
- 局部连接是指每个卷积核仅覆盖输入图像的一个小区域(如 3 × 3 3 \times 3 3×3 或 5 × 5 5 \times 5 5×5)。
- 这种局部连接的方式使得卷积层能够捕捉局部特征,如边缘、角点等。
例子:
假设我们有一个 5 × 5 5 \times 5 5×5 的输入图像和一个 3 × 3 3 \times 3 3×3 的卷积核。卷积核每次只关注输入图像的一个 3 × 3 3 \times 3 3×3 的区域,逐步滑动覆盖整个图像。这种方式使得网络能够有效地学习局部特征。
2. 权值共享(Weight Sharing)
在卷积神经网络中,卷积核的参数(权重)在整个输入图像上是共享的。这意味着卷积核在不同位置上应用相同的一组参数进行卷积操作。
解释:
- 权值共享是指在整个输入图像上使用相同的卷积核,减少了需要训练的参数数量。
- 这种方式确保了在不同位置检测到的相同特征具有相同的权重。
例子:
如果我们使用一个 3 × 3 3 \times 3 3×3 的卷积核在 5 × 5 5 \times 5 5×5 的输入图像上滑动,该卷积核会在每个位置上应用相同的权重。这样,不管特征出现在图像的哪个部分,该卷积核都能有效地检测到它。
3. 平移不变性(Translation Invariance)
平移不变性是指卷积神经网络能够识别出图像中的特征,无论这些特征出现在图像的哪个位置。卷积操作通过滑动窗口机制,确保网络对图像中不同位置的特征具有相同的响应。
解释:
- 平移不变性使得网络能够在图像的任何位置检测到相同的特征。
- 这种特性使得卷积神经网络在处理图像分类等任务时非常有效,因为特征的位置不再重要,网络关注的是特征本身。
例子:
假设我们有一张包含数字“7”的图片。不管“7”出现在图像的左上角还是右下角,卷积神经网络都能够识别出这个特征。这是因为卷积核在整个图像上滑动,确保能够检测到特征的位置。