共计 2436 个字符,预计需要花费 7 分钟才能阅读完成。
背景介绍
Cityscapes 是自动驾驶领域广泛使用的语义分割数据集,包含 5000 张精细标注的城市街景图像(2975 训练,500 验证,1525 测试),覆盖 19 类常见物体如道路、车辆、行人等。其特点包括:

- 高分辨率(2048×1024)带来细节保留优势,但显存消耗大
- 标注包含
group(如交通标志)和instance(如车辆)两个层级 - 使用 mIoU(平均交并比)作为核心指标,计算各类预测区域与真实标注的重合度均值
数据预处理
标注文件解析
Cityscapes 使用 JSON 格式存储多边形标注,推荐使用官方 cityscapesscripts 工具包处理:
from cityscapesscripts.helpers.labels import trainId2label
# 转换原始标签 ID 为训练用的 19 类 ID(0-18)def convert_label(label_map):
for label in trainId2label.values():
label_map[label_map == label.id] = label.trainId
return label_map
数据增强策略
高分辨率图像需谨慎选择增强方式,典型组合:
- 随机水平翻转(p=0.5)
- 随机缩放(0.5-2.0 范围)
- 颜色抖动(亮度 0.1, 对比度 0.1, 饱和度 0.1)
- 标准化参数:mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]
模型架构选型
DeepLabv3+ 优势
- 空洞卷积保持感受野同时减少下采样
- ASPP 模块多尺度特征融合
- 适合显存有限的设备(约 8GB 可训练 1024×512 尺寸)
HRNet 特点
- 并行多分辨率子网络
- 始终保持高分辨率特征
- 需要更大显存(16GB+ 推荐)
新手建议:显存 <12GB 选 DeepLabv3+,否则优先 HRNet-W48
代码实战
数据加载器实现
关键点:处理类别不平衡(道路像素占比约 30%)
class CityscapesDataset(Dataset):
def __init__(self, root, split='train'):
self.class_weights = torch.tensor([
0.8373, 0.918, 0.866, 1.0345, 1.0166, 0.9969, 0.9754,
1.0489, 0.8786, 1.0023, 0.9539, 0.9843, 1.1116, 0.9037,
1.0865, 1.0955, 1.0865, 1.1529, 1.0507 # 逆频率加权
])
def __getitem__(self, idx):
image = Image.open(img_path).convert('RGB')
label = convert_label(np.array(Image.open(label_path)))
if self.transform:
image, label = self.transform(image, label)
return image, label, self.class_weights[label]
损失函数设计
推荐组合:
criterion = nn.CrossEntropyLoss(weight=class_weights, ignore_index=255)
aux_criterion = nn.CrossEntropyLoss(weight=class_weights) # 用于 DeepLab 辅助头
训练技巧
学习率调度
三阶段策略:
- Warmup(前 500 迭代):lr = base_lr * (iter/500)
- 余弦衰减:lr = base_lr * 0.5(1 + cos(iter/max_iterπ))
- 最终微调:最后 1 /10 训练时冻结 BN 层
OHEM 实现
在线难例挖掘示例:
class OhemCELoss(nn.Module):
def __init__(self, thresh=0.7):
super().__init__()
self.thresh = -torch.log(torch.tensor(thresh))
def forward(self, pred, target):
n_min = target.numel() // 16 # 取损失值前 6.25% 的样本
loss = F.cross_entropy(pred, target, reduction='none')
loss = loss[loss > self.thresh]
return loss[:n_min].mean()
避坑指南
标签映射
常见错误:
- 未处理
ignore_index=255导致梯度异常 - 混淆
id与trainId(如交通灯 id=19 应映射到 trainId=6)
解决方案:
# 官方提供的标签对照表
{0: ('road', 7, 0, 255),
1: ('sidewalk', 8, 1, 255),
# ... 其他类别
18: ('motorcycle', 17, 18, 255)
}
验证集数据泄露
严禁在验证集上:
- 执行任何数据增强(除标准化)
- 使用验证集统计结果调整超参数
- 多次重复验证影响早停判断
性能优化
显存管理技巧
- 梯度累积:batch_size= 4 时,每 2 次迭代更新一次(等效 bs=8)
- 混合精度训练:
scaler = torch.cuda.amp.GradScaler()
with torch.cuda.amp.autocast():
output = model(inputs)
loss = criterion(output, labels)
scaler.scale(loss).backward()
scaler.step(optimizer)
scaler.update()
- 使用
torch.backends.cudnn.benchmark = True加速卷积
总结
通过合理的数据预处理、模型选择以及训练技巧,在 Cityscapes 上达到 75+ mIoU 是完全可行的。建议初学者先用 DeepLabv3+ 在缩小尺寸(1024×512)上实验,待流程跑通后再尝试更大模型。关键是要理解每个技术选择背后的动机,而不是盲目套用参数。
正文完
