概念介绍

感受野是指在CNN(卷积神经网络)中,输出特征的一个像素点对应输入图像上的区域大小。换句话说它表示输出特征能“看到”输入图像的范围。还有另外一种说法就是感受野指的是网络中某特特定层的输出特征图上的一个点对应的输入图像的区域。感受野是在输入图像上影响输出特征图中的某个点的所有像素集合。简单来说,感受野是决定该输出点的“视野”。

感受野的计算公式

def calculate_receptive_field():
    """
    展示多层网络中感受野的计算过程
    """
    class ConvLayer:
        def __init__(self, kernel_size, stride):
            self.kernel_size = kernel_size
            self.stride = stride
            
    def compute_rf_size(layers):
        rf_size = 1  # 初始感受野为1
        total_stride = 1
        
        print("感受野计算过程:")
        print("层数\t核大小\t步长\t感受野大小\t累计步长")
        print("-" * 50)
        
        for i, layer in enumerate(layers, 1):
            # 感受野计算公式:RF = RF_prev + (kernel_size - 1) * total_stride
            rf_size = rf_size + (layer.kernel_size - 1) * total_stride
            total_stride *= layer.stride
            
            print(f"{i}\t{layer.kernel_size}\t{layer.stride}\t{rf_size}\t\t{total_stride}")
        
        return rf_size, total_stride
    
    # 示例网络结构
    layers = [
        ConvLayer(kernel_size=3, stride=1),  # 第一层
        ConvLayer(kernel_size=3, stride=2),  # 第二层
        ConvLayer(kernel_size=3, stride=1),  # 第三层
        ConvLayer(kernel_size=3, stride=2),  # 第四层
    ]
    
    final_rf, final_stride = compute_rf_size(layers)
    print(f"\n最终感受野大小:{final_rf}")
    print(f"最终累计步长:{final_stride}")

calculate_receptive_field()

卷积输出特征的大小计算公式

 

感受野对不同任务的影响

目标检测

  • 小目标检测需要较小的感受野
  • 大目标检测需要较大的感受野,获取更多的上下文信息

语义分割

  • 需要平衡局部细节和全局上下文
  • 常用多尺度特征融合

图像分类

  • 通常需要较大的感受野
  • 获取全局特征信息

感受野优化技巧

多尺度融合

class MultiScaleFeature(nn.Module):
    def __init__(self, in_channels):
        super().__init__()
        
        # 不同感受野的分支
        self.branch1 = nn.Conv2d(in_channels, 64, 1)  # 1x1卷积
        self.branch2 = nn.Sequential(
            nn.Conv2d(in_channels, 64, 3, padding=1),  # 3x3卷积
            nn.ReLU(),
            nn.Conv2d(64, 64, 3, padding=1)
        )
        self.branch3 = nn.Sequential(
            nn.Conv2d(in_channels, 64, 3, padding=2, dilation=2),  # 空洞卷积
            nn.ReLU(),
            nn.Conv2d(64, 64, 3, padding=2, dilation=2)
        )
        
    def forward(self, x):
        # 多尺度特征融合
        return self.branch1(x) + self.branch2(x) + self.branch3(x)

扩大感受野的方法

class ReceptiveFieldMethods(nn.Module):
    def __init__(self):
        super().__init__()
        
        # 1. 堆叠小卷积核
        self.stack_conv = nn.Sequential(
            nn.Conv2d(64, 64, 3, padding=1),
            nn.Conv2d(64, 64, 3, padding=1)
        )
        
        # 2. 空洞卷积
        self.dilated_conv = nn.Conv2d(64, 64, 3, 
                                     padding=2, dilation=2)
        
        # 3. 池化层
        self.pool_conv = nn.Sequential(
            nn.MaxPool2d(2),
            nn.Conv2d(64, 64, 3, padding=1)
        )
        
        # 4. 大卷积核
        self.large_kernel = nn.Conv2d(64, 64, 7, padding=3)
 

池化层为什么可以扩大感受野? 

答:简单的说池化层会将输入特征缩小,即下采样,经过池化后的输出的特征图的感受野肯定是变大。因为感受野的概念是输出特征图的一个点对应原始输入图像的范围,在输出特征图再次变小的情况下,相对于原始输入图像一定会变大。

感受野使用建议

def design_receptive_field(task, input_size):
    if task == 'fine_detail':
        # 精细特征识别(如纹理分析)
        return [
            {'kernel': 3, 'stride': 1, 'padding': 1},  # 保持小感受野
            {'kernel': 3, 'stride': 1, 'padding': 1}
        ]
    
    elif task == 'object_detection':
        # 目标检测(需要多尺度)
        return [
            {'kernel': 3, 'stride': 1, 'padding': 1},
            {'kernel': 3, 'stride': 2, 'padding': 1},  # 逐步增大
            {'kernel': 3, 'stride': 1, 'padding': 2, 'dilation': 2}
        ]
    
    elif task == 'scene_understanding':
        # 场景理解(需要大感受野)
        return [
            {'kernel': 7, 'stride': 2, 'padding': 3},  # 快速增大
            {'kernel': 3, 'stride': 2, 'padding': 1},
            {'kernel': 3, 'stride': 1, 'padding': 4, 'dilation': 4}
        ]
 

选择感受野大小的方法

  • 目标尺寸<感受野,确保模型能够看到完整目标
  • 感受野太大:可能引入无用信息,增加计算量
  • 感受野太小:可能丢失重要上下文信息

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐