Cityscapes数据集下载与预处理全指南:从数据获取到模型训练

1次阅读
没有评论

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

image.webp

背景与痛点

Cityscapes 数据集是自动驾驶和计算机视觉领域的重要基准数据集,包含来自 50 个不同城市的街景图像,涵盖各种天气条件和交通场景。该数据集提供了高质量的像素级标注,包括语义分割、实例分割和全景分割等多种任务。

Cityscapes 数据集下载与预处理全指南:从数据获取到模型训练

然而,Cityscapes 数据集的官方下载流程相对复杂,需要注册、同意许可协议,并通过命令行工具下载。此外,数据集预处理也面临一些挑战:

  • 数据量大(约 5GB 的压缩包,解压后约 70GB)
  • 标注文件格式特殊(使用 JSON 和 PNG 混合格式)
  • 类别标签需要转换才能用于训练
  • 数据增强和批处理需要特别考虑内存效率

下载指南

1. 注册账户

首先访问 Cityscapes 官方网站(https://www.cityscapes-dataset.com/)并注册账户。注册后需要等待 1 - 2 个工作日获得下载权限。

2. 命令行下载(推荐)

获得权限后,可以使用官方提供的命令行工具下载:

  1. 安装下载工具

    pip install cityscapesscripts

  2. 下载数据集

    python -m cityscapesscripts.download.downloader \
        --username YOUR_USERNAME \
        --password YOUR_PASSWORD \
        --dataset all \
        --quality fine \
        --out_dir ./cityscapes_data

3. Python API 下载

对于更喜欢编程方式的用户,可以使用 Python API:

from cityscapesscripts.download import downloader

downloader.download_cityscapes(
    username='YOUR_USERNAME',
    password='YOUR_PASSWORD',
    quality='fine',  # or 'coarse'
    dataset='all',  # or specific subsets
    out_dir='./cityscapes_data'
)

数据结构解析

下载完成后,目录结构如下:

cityscapes_data/
├── gtFine/
│   ├── train/
│   │   ├── city1/
│   │   │   ├── image1_gtFine_color.png
│   │   │   ├── image1_gtFine_instanceIds.png
│   │   │   ├── image1_gtFine_labelIds.png
│   │   │   └── image1_gtFine_polygons.json
│   │   └── ...
│   └── val/
│       └── ...
├── leftImg8bit/
│   ├── train/
│   │   ├── city1/
│   │   │   └── image1_leftImg8bit.png
│   │   └── ...
│   └── val/
│       └── ...
└── license.txt
  • leftImg8bit/: 包含原始 RGB 图像
  • gtFine/: 包含精细标注
  • _color.png: 彩色标注图(可视化用)
  • _labelIds.png: 每个像素的类别 ID
  • _instanceIds.png: 实例 ID(同一类别的不同实例)
  • _polygons.json: 多边形标注信息

预处理实战

1. 加载和转换标注

Cityscapes 使用 19 个语义类别(忽略 id 为 0 的 ’void’ 类)。我们需要将 labelIds.png 转换为训练可用的格式:

import numpy as np
from PIL import Image

# 官方提供的类别映射
ID_TO_TRAINID = {
    0: 255, 1: 255, 2: 255, 3: 255, 4: 255, 5: 255, 6: 255,
    7: 0, 8: 1, 9: 255, 10: 255, 11: 2, 12: 3, 13: 4,
    14: 255, 15: 255, 16: 255, 17: 5, 18: 255, 19: 6, 20: 7,
    21: 8, 22: 9, 23: 10, 24: 11, 25: 12, 26: 13, 27: 14,
    28: 15, 29: 255, 30: 255, 31: 16, 32: 17, 33: 18, -1: 255
}

def convert_label(label_path):
    # 加载原始标注
    label = np.array(Image.open(label_path))

    # 创建空白数组
    semantic_map = np.zeros_like(label, dtype=np.uint8)

    # 转换每个像素
    for id_in, id_out in ID_TO_TRAINID.items():
        semantic_map[label == id_in] = id_out

    return semantic_map

2. 创建 PyTorch Dataset

from torch.utils.data import Dataset
import os

class CityscapesDataset(Dataset):
    def __init__(self, root_dir, split='train', transform=None):
        self.root_dir = root_dir
        self.split = split
        self.transform = transform

        # 收集所有图像和标注路径
        self.images = []
        self.labels = []

        img_dir = os.path.join(root_dir, 'leftImg8bit', split)
        label_dir = os.path.join(root_dir, 'gtFine', split)

        for city in os.listdir(img_dir):
            city_img_dir = os.path.join(img_dir, city)
            city_label_dir = os.path.join(label_dir, city)

            for img_name in os.listdir(city_img_dir):
                if img_name.endswith('_leftImg8bit.png'):
                    base_name = img_name.replace('_leftImg8bit.png', '')

                    img_path = os.path.join(city_img_dir, img_name)
                    label_path = os.path.join(
                        city_label_dir, 
                        f"{base_name}_gtFine_labelIds.png"
                    )

                    self.images.append(img_path)
                    self.labels.append(label_path)

    def __len__(self):
        return len(self.images)

    def __getitem__(self, idx):
        img = Image.open(self.images[idx]).convert('RGB')
        label = convert_label(self.labels[idx])

        if self.transform:
            img = self.transform(img)

        return img, label

3. 数据增强

from torchvision import transforms

# 训练时的增强
train_transform = transforms.Compose([transforms.Resize((512, 1024)),  # Cityscapes 常用分辨率
    transforms.RandomHorizontalFlip(),
    transforms.ColorJitter(brightness=0.5, contrast=0.5, saturation=0.5),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], 
                         std=[0.229, 0.224, 0.225])
])

# 验证时仅需基础转换
val_transform = transforms.Compose([transforms.Resize((512, 1024)),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], 
                         std=[0.229, 0.224, 0.225])
])

性能优化

处理大规模数据集时,性能至关重要:

  1. 预加载标注 :在__init__ 中预加载所有标注的路径,而不是每次迭代时搜索

  2. 多进程加载 :使用torch.utils.data.DataLoadernum_workers参数

from torch.utils.data import DataLoader

train_dataset = CityscapesDataset('cityscapes_data', 'train', train_transform)
train_loader = DataLoader(
    train_dataset, 
    batch_size=8, 
    shuffle=True, 
    num_workers=4,  # 根据 CPU 核心数调整
    pin_memory=True  # 如果使用 GPU
)
  1. 使用内存映射文件:对于非常大的数据集,考虑使用numpy.memmap

  2. 混合精度训练:减少显存占用,加快训练速度

避坑指南

  1. 下载失败:确保账户已激活,网络连接稳定。如果中断,可以尝试分段下载。

  2. 标注转换错误 :检查ID_TO_TRAINID 映射是否正确,特别是新版本的数据集可能有变化。

  3. 内存不足:减小批次大小,或使用梯度累积。

  4. 类别不平衡:Cityscapes 中 ’road’ 和 ’sky’ 等类别占比很大,考虑使用加权损失函数。

  5. 验证集性能差:确保训练和验证使用相同的预处理流程。

应用示例

将处理好的数据输入到 UNet 模型中进行训练:

import torch
import torch.nn as nn
import torch.optim as optim

# 简化版 UNet
model = UNet(num_classes=19).cuda()
criterion = nn.CrossEntropyLoss(ignore_index=255)
optimizer = optim.Adam(model.parameters(), lr=1e-4)

# 训练循环
for epoch in range(100):
    model.train()
    for images, labels in train_loader:
        images = images.cuda()
        labels = labels.cuda()

        optimizer.zero_grad()
        outputs = model(images)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

    # 验证...

总结与思考

Cityscapes 数据集虽然下载和预处理流程复杂,但通过合理的工具和方法可以高效完成。本文介绍了完整的下载、解析和预处理流程,并提供了可直接使用的代码示例。

思考题:
1. 如何针对 Cityscapes 的长尾分布设计更有效的损失函数?
2. 对于实时应用,如何在保持精度的同时减少输入分辨率?
3. 如何利用实例标注信息提升语义分割性能?

希望本指南能帮助你快速开始 Cityscapes 数据集的实验和研究。

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