全卷积网络(FCN)入门指南:从图像分割原理到PyTorch实战

1次阅读
没有评论

共计 2236 个字符,预计需要花费 6 分钟才能阅读完成。

image.webp

图像分割与 FCN 的核心原理

1. 图像分割任务与 CNN 的局限性

图像分割要求对每个像素进行分类,输出与输入同尺寸的预测图。传统 CNN 存在两大缺陷:

全卷积网络 (FCN) 入门指南:从图像分割原理到 PyTorch 实战

  • 固定尺寸输出:全连接层迫使输入尺寸固定,破坏图像原始空间结构
  • 空间信息丢失:池化层降低分辨率,导致无法精确定位物体边界

例如,VGG16 最后特征图尺寸仅为原图的 1 /32,直接上采样会产生严重锯齿。

2. FCN 三大创新设计

2.1 全卷积结构(Fully Convolutional)

替换全连接层为 1 ×1 卷积层,实现任意尺寸输入输出。数学等价性证明见[1]:

# 传统全连接层 vs 1x1 卷积实现
fc = nn.Linear(4096, 1000)  # 固定输入维度
conv = nn.Conv2d(512, 1000, kernel_size=1)  # 动态处理任意尺寸

2.2 跳跃连接(Skip Architecture)

融合深层语义信息与浅层细节信息:

Input Image
  │
  ├──[Conv Layers]──低分辨率高级特征(语义强)│
  └──[Skip Layer]──高分辨率低级特征(定位准)

2.3 转置卷积(Transposed Convolution)

通过可学习参数实现智能上采样,比双线性插值提升 8% mIoU[2]:

# 转置卷积参数设置要点
upsample = nn.ConvTranspose2d(
    in_channels=512,
    out_channels=256,
    kernel_size=4,  # 控制上采样倍率
    stride=2,      # 必须与下采样步长对应
    padding=1       # 避免棋盘效应
)

PyTorch 实战实现

3. 模型构建关键代码

3.1 基于 VGG16 的编码器

class FCN32s(nn.Module):
    def __init__(self, num_classes):
        super().__init__()
        vgg = models.vgg16(pretrained=True)
        # 截取 VGG 前 30 层(到 conv5_3)self.features = nn.Sequential(*list(vgg.features.children())[:-1])
        # 替换全连接层
        self.fc6 = nn.Conv2d(512, 4096, 7)
        self.fc7 = nn.Conv2d(4096, 4096, 1)
        self.score = nn.Conv2d(4096, num_classes, 1)
        self.upsample = nn.ConvTranspose2d(num_classes, num_classes, 64, 32, 0)

3.2 混合损失函数实现

class HybridLoss(nn.Module):
    def __init__(self, class_weights):
        super().__init__()
        self.cross_entropy = nn.CrossEntropyLoss(weight=torch.tensor(class_weights)
        )
        self.dice_loss = DiceLoss()

    def forward(self, pred, target):
        ce = self.cross_entropy(pred, target)
        dice = self.dice_loss(pred.softmax(dim=1), target)
        return 0.7*ce + 0.3*dice  # 实验调优的权重比例

4. 实战注意事项

4.1 显存优化策略

  • 梯度累积:每 2 个小 batch 更新一次参数
  • 自动混合精度
    scaler = torch.cuda.amp.GradScaler()
    with torch.cuda.amp.autocast():
        output = model(input)
        loss = criterion(output, target)
    scaler.scale(loss).backward()

4.2 类别不平衡处理

对 Cityscapes 数据集采用中值频率加权[3]:

class_weights = [0.8, 1.2, 1.5, ..., 2.0]  # 根据类别像素频率计算

4.3 mIoU 实现要点

需注意忽略特定标签(如 255 表示背景):

def miou(pred, target, num_classes, ignore_index=255):
    mask = (target != ignore_index)
    pred = pred[mask].argmax(dim=1)
    target = target[mask]
    # 计算混淆矩阵...

进阶优化方向

5. 性能提升技巧

  • 预训练权重:在 Pascal VOC 上微调仅需 1 /10 迭代次数
  • 渐进式上采样
    低分辨率特征图 → 2 倍上采样 → 融合中层特征 → 再 2 倍上采样

6. 扩展思考与推荐阅读

思考题:要实现实时分割(>30FPS),可尝试:
1. 替换 backbone 为 MobileNetV3
2. 采用空洞空间金字塔池化(ASPP)
3. 知识蒸馏压缩模型

推荐论文:
DeepLabv3+
BiSeNet

[1] Long J, et al. Fully convolutional networks for semantic segmentation. CVPR 2015.
[2] 转置卷积可视化教程:https://github.com/vdumoulin/conv_arithmetic
[3] Eigen D, et al. Predicting Depth, Surface Normals and Semantic Labels with a Common Multi-Scale Convolutional Architecture. ICCV 2015.

正文完
 0
评论(没有评论)