CamVid数据集实战指南:从数据预处理到语义分割模型训练

1次阅读
没有评论

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

image.webp

1. CamVid 数据集概览

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

CamVid 数据集实战指南:从数据预处理到语义分割模型训练

[左图:原始街景照片 | 右图:颜色编码的标注掩码]
道路 - 灰色 天空 - 蓝色 建筑物 - 红色 植被 - 绿色

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 数据集时需注意:

  1. 分辨率差异:Cityscapes 图像尺寸 2048×1024,需要调整裁剪策略
  2. 标注格式:需解析 JSON 文件获取多边形标注
  3. 类别映射:将 19 类合并为与原数据集相似的语义类别

通过本教程,你已掌握从数据准备到模型训练的全流程。建议尝试:
– 添加更多增强(旋转、透视变换)
– 替换 DeepLabv3+ 等更复杂模型
– 部署 TensorRT 加速推理

期待大家在评论区分享自己的改进方案!

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