共计 2611 个字符,预计需要花费 7 分钟才能阅读完成。
技术背景
传统 CNN 在图像分类任务中表现出色,但在图像分割任务中存在明显局限性。主要问题包括:

- 固定尺寸输出:传统 CNN 通过全连接层输出固定长度的向量,无法适应不同尺寸的输入图像
- 空间信息丢失:池化操作虽然能扩大感受野,但会丢失精确的空间位置信息
- 局部预测能力弱:传统 CNN 难以实现像素级的精确分类
这些限制促使了全卷积网络(FCN)的发展,其核心思想是将 CNN 中的全连接层替换为卷积层,实现端到端的像素级预测。
架构解析
转置卷积上采样原理
FCN 通过转置卷积(Transposed Convolution)实现特征图的上采样,逐步恢复空间分辨率。转置卷积本质上是学习一种上采样方式,而非简单的插值运算。
- 输入特征图尺寸:H×W×C
- 转置卷积核大小:k×k
- 步长:s
- 输出特征图尺寸:(s×(H-1)+k)×(s×(W-1)+k)×C’
FCN 变体对比
FCN 主要有三种变体,区别在于上采样的程度:
- FCN-32s:直接 32 倍上采样,计算量最小但精度最低
- FCN-16s:先 16 倍上采样,再与 pool4 融合
- FCN-8s:先 8 倍上采样,依次与 pool4 和 pool3 融合
FLOPs 计算公式:
FLOPs = (2×Cin×K²-1)×Hout×Wout×Cout
其中 Cin/Cout 为输入 / 输出通道数,K 为卷积核尺寸。
PyTorch 实战
带 Skip Connection 的 FCN-8s 实现
import torch
import torch.nn as nn
from torchvision.models import vgg16
class FCN8s(nn.Module):
def __init__(self, num_classes):
super().__init__()
# 特征提取(使用预训练 VGG16 的前 5 个 block)vgg = vgg16(pretrained=True)
features = list(vgg.features.children())
# 编码器部分
self.block1 = nn.Sequential(*features[:5]) # pool1
self.block2 = nn.Sequential(*features[5:10]) # pool2
self.block3 = nn.Sequential(*features[10:17]) # pool3
self.block4 = nn.Sequential(*features[17:24]) # pool4
self.block5 = nn.Sequential(*features[24:]) # pool5
# 解码器部分
self.conv6 = nn.Conv2d(512, 4096, 7, padding=3) # 减少显存使用:kernel_size= 7 改为 3
self.conv7 = nn.Conv2d(4096, 4096, 1)
self.score_pool3 = nn.Conv2d(256, num_classes, 1)
self.score_pool4 = nn.Conv2d(512, num_classes, 1)
# 转置卷积
self.upscore2 = nn.ConvTranspose2d(num_classes, num_classes, 4, stride=2, bias=False)
self.upscore8 = nn.ConvTranspose2d(num_classes, num_classes, 16, stride=8, bias=False)
self.upscore_pool4 = nn.ConvTranspose2d(num_classes, num_classes, 4, stride=2, bias=False)
def forward(self, x):
# 编码过程
h = self.block1(x)
h = self.block2(h)
pool3 = self.block3(h) # 1/8
pool4 = self.block4(pool3) # 1/16
pool5 = self.block5(pool4) # 1/32
# 解码过程
h = self.conv6(pool5)
h = self.conv7(h)
h = self.upscore2(h) # 1/16
pool4_out = self.score_pool4(pool4)
h = h + pool4_out[:, :, 5:5+h.size(2), 5:5+h.size(3)]
h = self.upscore_pool4(h) # 1/8
pool3_out = self.score_pool3(pool3)
h = h + pool3_out[:, :, 9:9+h.size(2), 9:9+h.size(3)]
return self.upscore8(h) # 原始尺寸
数据增强策略
针对医学影像特点推荐的 Albumentations 增强方案:
import albumentations as A
transform = A.Compose([A.RandomRotate90(p=0.5),
A.Flip(p=0.5),
A.ElasticTransform(alpha=120, sigma=6,
alpha_affine=3.6, p=0.3),
A.GridDistortion(p=0.3),
A.RandomBrightnessContrast(p=0.4),
A.Resize(512, 512, always_apply=True) # 统一尺寸
])
生产部署
模型量化影响
实验表明,在不同量化精度下模型性能变化:
| 精度 | mIoU(%) | 模型大小(MB) |
|---|---|---|
| FP32 | 72.3 | 523 |
| FP16 | 72.1 | 262 |
| INT8 | 70.8 | 131 |
| INT8(QAT) | 71.5 | 131 |
TensorRT 优化
关键层融合策略:
- Conv+BN+ReLU 合并为单个 CBR 层
- 相邻的 1 ×1 卷积合并
- 使用
trtexec时添加--fp16和--best参数
避坑指南
类别不平衡处理
- CrossEntropy Loss:适合类别分布相对均衡场景
- Dice Loss:对前景像素更加敏感,公式:
Dice = 1 - (2*|X∩Y|)/(|X|+|Y|)实验表明,在医学影像中 Dice Loss 比 CrossEntropy 提升 3 -5% mIoU
小样本迁移学习
- 冻结编码器部分(VGG16 前 4 个 block)
- 使用
lr=1e-4微调解码器 - 添加 auxiliary loss 监督中间层
开放问题
当处理 4K 医疗图像时,如何解决 FCN 的显存瓶颈?可能的探索方向包括:
- 分块推理与结果拼接
- 更轻量化的编码器设计
- 混合精度训练策略
- 使用梯度检查点技术
正文完
发表至: 未分类
近一天内
