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,到时候你会更深刻地体会到今天这些概念的价值。
嗯,今天就到这儿。有问题随时问我。