共计 2482 个字符,预计需要花费 7 分钟才能阅读完成。
1. CamVid 数据集概览
CamVid(Cambridge-Driving Labeled Video Database)是自动驾驶领域经典的语义分割数据集,包含 701 张街景图像(367 训练 +101 验证 +233 测试),标注分辨率 960×720。其 32 类标签(实际常用 11 类)能有效模拟车辆对道路、行人、建筑物的识别需求。下图示意数据集典型样本:

[左图:原始街景照片 | 右图:颜色编码的标注掩码]
道路 - 灰色 天空 - 蓝色 建筑物 - 红色 植被 - 绿色
2. 数据集目录解析
规范的数据存储结构能大幅减少预处理工作量,推荐按如下方式组织:
CamVid/
├── images/ # 原始图像
│ ├── 0001TP_006690.png
│ └── ...
├── labels/ # 标注图像
│ ├── 0001TP_006690.png
│ └── ...
└── class_dict.csv # 类别颜色对照表
关键文件说明:
- 标注 PNG 使用 RGB 三通道存储类别信息,如 (128,0,0) 代表建筑物
- class_dict.csv 需包含字段:class_name, r, g, b
3. PyTorch 数据处理实战
3.1 自定义 Dataset 类
核心任务是实现 __getitem__ 方法,将颜色编码转换为类别索引:
import torch
from PIL import Image
class CamVidDataset(torch.utils.data.Dataset):
def __init__(self, img_dir, label_dir, class_map):
self.img_paths = sorted(Path(img_dir).glob('*.png'))
self.label_paths = sorted(Path(label_dir).glob('*.png'))
self.class_map = class_map # {'sky': (128,128,128), ...}
def __getitem__(self, idx):
img = np.array(Image.open(self.img_paths[idx]))
label = np.array(Image.open(self.label_paths[idx]))
# 将 RGB 标注转换为类别索引矩阵
h, w = label.shape[:2]
class_mask = np.zeros((h, w), dtype=np.uint8)
for class_idx, (_, color) in enumerate(self.class_map.items()):
class_mask[(label == color).all(axis=-1)] = class_idx
return torch.FloatTensor(img).permute(2,0,1)/255., \
torch.LongTensor(class_mask)
3.2 数据增强策略
使用 Albumentations 库实现高效增强:
import albumentations as A
train_transform = A.Compose([A.RandomCrop(512, 512),
A.HorizontalFlip(p=0.5),
A.ColorJitter(brightness=0.2, contrast=0.2)
])
# 在 Dataset 类中调用
def __getitem__(self, idx):
transformed = train_transform(image=img, mask=label)
return transformed['image'], transformed['mask']
3.3 类别权重计算
应对样本不均衡的两种方法:
# 方法 1:统计像素类别频率
pixel_counts = np.bincount(class_mask.flatten())
class_weights = 1 / (pixel_counts + 1e-6) # 避免除零
# 方法 2:中值频率平衡(更鲁棒)median_freq = np.median(pixel_counts)
class_weights = median_freq / (pixel_counts + 1e-6)
4. UNet 模型训练关键代码
4.1 损失函数选择
带权重的 CrossEntropyLoss 应对类别不平衡:
criterion = torch.nn.CrossEntropyLoss(weight=torch.FloatTensor(class_weights).to(device)
)
4.2 训练循环片段
for epoch in range(epochs):
for images, labels in train_loader:
images, labels = images.to(device), labels.to(device)
optimizer.zero_grad()
outputs = model(images)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
# 计算 mIoU 等指标...
5. 生产环境注意事项
5.1 标注一致性检查
- 使用
np.unique()检查标注图中是否存在未定义颜色值 - 可视化随机样本的标注叠加效果
5.2 显存优化技巧
- 梯度累积:每 N 个小批量更新一次参数
- 混合精度训练:
torch.cuda.amp.autocast() - 减小验证批次:
val_loader = DataLoader(..., batch_size=1)
5.3 指标解读陷阱
- 测试集表现优于验证集?→ 检查数据泄露
- mIoU 提升但边界模糊?→ 尝试 Dice Loss
6. 延伸思考
迁移到 Cityscapes 数据集时需注意:
- 分辨率差异:Cityscapes 图像尺寸 2048×1024,需要调整裁剪策略
- 标注格式:需解析 JSON 文件获取多边形标注
- 类别映射:将 19 类合并为与原数据集相似的语义类别
通过本教程,你已掌握从数据准备到模型训练的全流程。建议尝试:
– 添加更多增强(旋转、透视变换)
– 替换 DeepLabv3+ 等更复杂模型
– 部署 TensorRT 加速推理
期待大家在评论区分享自己的改进方案!
正文完
