3. 深度学习基础回顾:卷积神经网络(CNN)核心概念、感受野、池化层、上采样与下采样

各位同学,咱们今天聊点硬核的。图像分割绕不开CNN,就像炒菜绕不开油盐。我当年刚接触深度学习时,总觉得CNN就是个黑盒子,往里扔图片,往外吐结果。后来踩了不少坑才明白——理解CNN的底层逻辑,才是真正掌握图像分割的关键

3.1 卷积核:CNN的“眼睛”

说白了,卷积核就是一组可学习的权重矩阵。它在输入图像上滑动,每次做点积运算。你想想看,一个3×3的卷积核,其实就是在看局部9个像素的关系。

核心公式:输出特征图尺寸 = (输入尺寸 - 卷积核尺寸 + 2×填充) / 步长 + 1

我在项目中遇到过一个问题:用7×7的大卷积核还是堆3个3×3的小卷积核?我个人习惯用3×3堆叠。为什么?因为3个3×3的堆叠,感受野同样是7×7,但参数量只有3×3×3=27,而7×7是49。参数量少了,非线性还多了,何乐而不为?

3.2 感受野:网络到底“看”了多大范围

感受野这个概念,我刚开始学的时候觉得挺玄乎。其实很简单——输出特征图上某个点,对应输入图像上的区域大小

举个例子:

  • 第一层卷积(3×3,步长1):感受野 = 3×3
  • 第二层卷积(3×3,步长1):感受野 = 5×5
  • 第三层卷积(3×3,步长1):感受野 = 7×7

嗯,这里要注意:空洞卷积(Dilated Convolution)可以指数级扩大感受野。我在做语义分割时,经常用空洞卷积来平衡分辨率和感受野。比如DeepLab系列,就是靠不同膨胀率的空洞卷积来捕获多尺度上下文。

我的经验:感受野不是越大越好。太大容易丢失细节,太小又看不到全局。图像分割任务中,我通常会让感受野覆盖输入图像的30%-50%。

3.3 池化层:降维的艺术

池化层,说白了就是下采样的一种方式。常见的两种:

池化类型 操作 特点
最大池化 取窗口内最大值 保留最显著特征,对纹理敏感
平均池化 取窗口内平均值 保留整体信息,对背景平滑

我曾经在分割任务中犯过一个低级错误:用最大池化做下采样,结果小目标直接消失了。后来我改用步长为2的卷积来做下采样,效果好了很多。池化层虽然简单,但信息丢失是不可逆的

避坑指南:我曾经在U-Net中用最大池化做下采样,结果小目标分割效果极差。后来换成步长为2的卷积,小目标召回率提升了12%。

3.4 上采样与下采样:尺寸的博弈

图像分割里,下采样提取语义,上采样恢复分辨率。这两者缺一不可。

3.4.1 下采样方法

  • 池化:简单粗暴,但信息丢失严重
  • 步长卷积:可学习,信息保留更好
  • 空洞卷积:不下采样也能扩大感受野

3.4.2 上采样方法

  • 双线性插值:简单,但不够精细
  • 转置卷积:可学习,但容易产生棋盘效应
  • 反池化:记录池化位置,恢复时填充

你想想看,为什么U-Net那么火?因为它用跳跃连接把下采样丢失的细节又补回来了。我建议你在做分割网络时,上采样尽量用双线性插值+卷积的组合,而不是直接用转置卷积。为什么?因为转置卷积的棋盘效应太难调了,我调了整整一周才搞定。

我的建议:上采样用双线性插值(不学习参数),然后接一个3×3卷积(学习细节)。这样既稳定又灵活。

3.5 实战:一个简单的CNN分割头

光说不练假把式。我写个简单的分割头代码,你感受一下:

import torch.nn as nn

class SimpleSegHead(nn.Module):
    def __init__(self, in_channels, num_classes):
        super().__init__()
        # 下采样:提取高层语义
        self.down = nn.Sequential(
            nn.Conv2d(in_channels, 256, 3, stride=2, padding=1),
            nn.BatchNorm2d(256),
            nn.ReLU()
        )
        # 上采样:恢复分辨率
        self.up = nn.Sequential(
            nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True),
            nn.Conv2d(256, num_classes, 3, padding=1)
        )
    
    def forward(self, x):
        x = self.down(x)   # 下采样,感受野变大
        x = self.up(x)     # 上采样,恢复尺寸
        return x

这段代码虽然简单,但包含了CNN分割的核心思想:先下采样提取语义,再上采样恢复分辨率。我在实际项目中,通常会在中间加几个残差块,效果会更好。

3.6 总结:CNN在分割中的角色

好了,咱们回顾一下今天的内容:

  • 卷积核:局部特征提取器,3×3堆叠优于大核
  • 感受野:网络看到的范围,空洞卷积是神器
  • 池化层:降维但丢失信息,步长卷积是更好的选择
  • 上/下采样:语义与分辨率的平衡,U-Net的跳跃连接值得学习

我记得刚入行时,总觉得CNN就是堆层数。后来做了几个分割项目才明白——理解每个组件的物理意义,比盲目堆叠重要得多。下一章咱们聊FCN和U-Net,到时候你会更深刻地体会到今天这些概念的价值。

嗯,今天就到这儿。有问题随时问我。