DeepLab 系列:空洞卷积与 ASPP 的像素级分类
语义分割与 DeepLab 系列
什么是语义分割
语义分割(Semantic Segmentation)是计算机视觉中的核心任务之一,目标是为图像中的每一个像素分配一个语义类别标签。与图像分类的输出是单个标签、目标检测的输出是边界框不同,语义分割需要实现像素级别的密集预测。例如,在自动驾驶场景中,需要将图像中的每个像素区分为道路、行人、车辆、天空等。
这一任务面临的挑战在于:既要理解全局上下文(如“这是一辆车”),又要保留精确的空间位置信息(如“车的边界在哪里”)。许多早期方法使用卷积神经网络接全连接层进行分类,但会丢失空间细节。全卷积网络(FCN)开启了深度学习分割的先河,而 DeepLab 系列则是将语义分割推向高精度的里程碑式工作。
DeepLab 系列的演进
DeepLab 由 Google 团队提出,历经多个版本迭代,其核心思想围绕着空洞卷积和空间金字塔池化来高效扩大感受野并融合多尺度信息。主要版本如下:
- DeepLabv1:首次将空洞卷积引入语义分割,在不增加参数量、不降低特征图分辨率的前提下大幅提升感受野。
- DeepLabv2:提出 ASPP(Atrous Spatial Pyramid Pooling) 模块,用不同空洞率的卷积并行处理,聚合多尺度上下文信息。
- DeepLabv3:改进 ASPP,加入全局平均池化分支,并讨论了级联空洞卷积时的“多网格”策略。
- DeepLabv3+:引入编码器-解码器结构,结合深度可分离卷积和 Xception 主干网络,进一步细化边界,达到当时最优性能。
下面我们从核心组件开始,逐步深入每个版本的精髓。
空洞卷积:不增加参数扩大感受野
传统卷积的局限
在分类网络中,通常使用池化(Pooling)或步长卷积来逐步降低特征图的分辨率,以增大高层特征的感受野并减少计算量。然而,对于密集预测任务,空间信息的丢失是致命的:经过多次下采样后,小物体的位置信息可能被稀释,再通过上采样恢复分辨率时会产生粗糙的分割边界。如图像被 8 倍下采样后直接上采样到原尺寸,输出往往非常模糊。
有没有一种方法,能够在不降低特征图分辨率、不增加额外参数的前提下,获得更大的感受野?这就是空洞卷积的出发点。
空洞卷积的原理
空洞卷积(Dilated / Atrous Convolution)通过在卷积核的元素之间插入“空洞”(即 0)来扩张卷积核的跨度。与标准卷积的不同仅在于一个超参数:空洞率(dilation rate)。
对于大小为 k 的卷积核,空洞率为 r 时,其有效感受野大小为:
k' = k + (k - 1)(r - 1)
但实际的参数量仍为 k²,因为新增的空间部分由 0 填充,不参与学习。这使得我们可以像使用放大镜一样,灵活控制卷积核的观察范围。
一个常见的组合是:在移除最后几个池化层的网络(如 VGG16 的 pool4 和 pool5)中,将原本的卷积替换为空洞率逐渐增大的空洞卷积。这样特征图分辨率保持为输入的 1/8 或 1/16,但高层特征能感知到非常大的上下文区域。
空洞率的设置与感受野计算
感受野的增大遵循级联空洞卷积的累积规律。若连续使用空洞率分别为 r₁, r₂, ..., rₙ 的卷积,则最终感受野近似为所有层级感受野之和。DeepLab 中常见的设计是采用**多网格(Multi-grid)**策略:即在 Block4 到 Block7 中将空洞率设置为 (1, 2, 4) 的倍数,例如 r = (2, 4, 8) 乘以一个基速率,从而获得覆盖整个图像的大感受野。
要注意的是,空洞率过大容易引发“网格效应”(gridding),即并非所有像素均等参与计算,导致远处信息丢失。DeepLabv3 通过引入全局平均池化分支来缓解此问题。
ASPP:多尺度信息的汇聚
空间金字塔池化思想
图像中物体存在巨大的尺度差异,同一个网络很难同时兼顾大小物体。空间金字塔池化(Spatial Pyramid Pooling)是解决多尺度问题的经典思路,例如 PSPNet 采用不同核大小的池化操作。DeepLab 则创造性地提出了基于空洞卷积的版本:ASPP。
ASPP 模块结构
ASPP 的核心是在同一特征图上并行应用多个不同空洞率的卷积核,以及一个全局平均池化分支,最后将所有分支的输出拼接(或相加)并融合,生成包含多尺度信息的特征。具体来说:
- 一个 1×1 卷积分支:等同于空洞率极大(覆盖全图)时的效果,捕捉图级上下文。
- 多个 3×3 空洞卷积分支,空洞率分别设为
(6, 12, 18)或(12, 24, 36)等,用以捕捉中等范围和大范围的上下文。 - (DeepLabv3 新增)一个图像级别的全局平均池化分支:对整张特征图做全局平均池化,再通过 1×1 卷积和上采样恢复到原尺寸,提供最全局的先验。
之后将所有分支的结果在通道维度上拼接,再用一个 1×1 卷积融合通道,输出最终的多尺度特征图。这种设计让每个像素位置都能整合其自身的局部细节以及多种尺度的语境信息,极大提升了分割的一致性。
DeepLabv2 中的 ASPP
DeepLabv2 首次在分割中引入 ASPP,使用了四个平行分支:一个 1×1 卷积和三个 3×3 空洞卷积(空洞率分别为 6, 12, 18)。当时主干网络为 VGG16,通过多尺度特征融合显著提升了分割精度。
DeepLabv3 的改进 ASPP
DeepLabv3 对 ASPP 做了两方面改进:
- 增加了全局平均池化分支,以消除大空洞率带来的网格效应并捕获全图信息。
- 引入了更深的网络(ResNet)和级联空洞卷积的“多网格”设计,让整个编码器部分在保持高分辨率特征图的同时拥有极大的有效感受野。
此时的 ASPP 成为语义分割中的标杆模块,后续很多工作都以此为基线。
DeepLab 版本详解
DeepLabv1:基于 VGG 的空洞卷积
- 主干网络:VGG16,移除最后两个最大池化层(pool4 和 pool5),使最终特征图下采样倍数为 8x。
- 空洞卷积:将原 conv5 中的标准卷积替换为空洞率 2 的空洞卷积,保证感受野与原网络一致,但分辨率提升 4 倍。
- 后处理:使用全连接条件随机场(Fully Connected CRF)细化边缘,但这一步骤在后续版本中被丢弃。
DeepLabv1 证明了空洞卷积在分割任务中的有效性,在 PASCAL VOC 2012 上取得了顶尖性能。
DeepLabv2:ASPP 与多尺度
- 在 v1 的基础上,将网络最后的单个空洞卷积分支替换为 ASPP 模块。
- 多尺度输入(MSI):训练和测试时使用多尺度图像增强,进一步提升鲁棒性。
- CRF 仍作为后处理,但逐渐发现端到端的神经网络已足够强大。
DeepLabv3:改进的 ASPP 和多网格空洞率
- 主干网络升级为 ResNet-101,利用其残差结构获得更深的模型。
- 级联空洞卷积:在 block4 到 block7 中采用多网格策略,基速率设置为
(1, 2, 4),输出步幅(output stride)为 16 或 8。 - ASPP 模块加入全局平均池化分支,并且增加 batchnorm 层。
- 完全丢弃了 CRF 后处理,实现纯神经网络分割。
DeepLabv3+:编码器-解码器结构
DeepLabv3 虽然上下文丰富,但输出特征图分辨率通常只有原图的 1/16(output stride = 16),再直接上采样 16 倍会导致边缘丢失细节。v3+ 吸收了编码器-解码器架构的优势:
- 编码器:就是 DeepLabv3,输出多尺度融合后的特征图,作为高级语义信息。
- 解码器:将编码器的输出上采样 4 倍,然后与主干网络中低层的高分辨率特征(如 ResNet 的 conv2 输出)拼接,再通过几个卷积细化后上采样 4 倍,最终达到输出步幅为 4 的预测。边缘因此更锐利。
使用深度可分离卷积和 Xception 主干
为了在不降低性能的前提下大幅减少计算量,DeepLabv3+ 探索了将深度可分离卷积(Depthwise Separable Convolution)应用于 ASPP 和解码器模块。同时引入改进的 Aligned Xception 作为主干网络,进一步提升了精度和速度。这一版本成为当时多个分割基准上的 SOTA,也是工程实践中广泛使用的结构。
动手实践:理解空洞卷积与 ASPP
在 PyTorch 中,一个空洞卷积可以简单表示为:
import torch.nn as nn
# 标准卷积:kernel_size=3, pad=1, dilation=1
# 空洞卷积:kernel_size=3, pad=2, dilation=2
conv_dilated = nn.Conv2d(in_channels=256, out_channels=256,
kernel_size=3, padding=2, dilation=2)
感受野计算示例:假设输入步长为 1,连续使用三个空洞卷积,空洞率分别为 r=2,4,8,每个卷积核大小均为 3。计算每层感受野的递推公式为:
RF(i+1) = RF(i) + (kernel_size - 1) * dilation * stride_prod_before
若步长均为 1,则感受野依次为 3, 7, 15, 31... 可以看到,三层空洞卷积就能让最深层神经元看到直径 31 的区域,但特征图分辨率保持不变。
若要构建一个简易的 ASPP 模块:
class SimpleASPP(nn.Module):
def __init__(self, in_channels, out_channels):
super().__init__()
self.conv1x1 = nn.Conv2d(in_channels, out_channels, 1)
self.conv3_6 = nn.Conv2d(in_channels, out_channels, 3, padding=6, dilation=6)
self.conv3_12 = nn.Conv2d(in_channels, out_channels, 3, padding=12, dilation=12)
self.conv3_18 = nn.Conv2d(in_channels, out_channels, 3, padding=18, dilation=18)
self.global_avg_pool = nn.Sequential(
nn.AdaptiveAvgPool2d(1),
nn.Conv2d(in_channels, out_channels, 1)
)
self.fuse = nn.Conv2d(out_channels * 5, out_channels, 1)
def forward(self, x):
size = x.shape[2:]
feat1 = self.conv1x1(x)
feat2 = self.conv3_6(x)
feat3 = self.conv3_12(x)
feat4 = self.conv3_18(x)
global_feat = self.global_avg_pool(x)
global_feat = nn.functional.interpolate(global_feat, size=size, mode='bilinear')
concat = torch.cat([feat1, feat2, feat3, feat4, global_feat], dim=1)
return self.fuse(concat)
通过这种多分支设计,网络会学会根据目标尺度自动选择最合适的空洞率分支。
总结与学习路径
DeepLab 系列的核心贡献在于:
- 空洞卷积:无需下采样即可指数级扩大感受野。
- ASPP:多尺度空洞卷积与全局池化并行,高效抓取多尺度上下文。
- 从 v1 到 v3+ 的持续改进:引入更强的残差网络、编码器-解码器结构、深度可分离卷积,最终实现了速度和精度的极佳平衡。
对于想要深入学习语义分割的读者,建议路径如下:
- 理解全卷积网络(FCN)的原理与局限。
- 动手实现一个基础的 DeepLab 模型(可参考 torchvision 中的 deeplabv3 实现)。
- 对比不同 output stride 设置(8 和 16)对速度与精度的影响。
- 将 ASPP 迁移到自己的分割项目中,观察多尺度融合的效果。
掌握 DeepLab 的设计哲学后,你将对现代视觉骨干网络和密集预测任务有更深刻的认识,也为理解更新的 Transformer 分割模型(如 SegFormer、Mask2Former)打下坚实基础。