FEATURED · 精选文章

Cityscapes数据集详解:从目录结构到mmsegmentation训练实战

发布时间 / 2026/9/2 4:25:23
来源 / 创域科博编辑部
栏目 / 资讯中心
Cityscapes数据集详解:从目录结构到mmsegmentation训练实战 简介Cityscapes数据集一是面向城市街景理解与自动驾驶应用的计算机视觉资源包含来自30个欧洲城市的高分辨率RGB图像及对应的精细像素级标注适合机器学习、深度学习研究者用于语义分割模型训练与评估。这一部分为数据集gtFine子集的json标注文件集合共2000个json文件压缩包大小约730MB。这些json文件采用polygons多边形格式精确勾勒道路、建筑、行人、车辆、交通标志等30个类别的轮廓覆盖晴天、阴天、雨天等多种时段与天气条件是监督学习所必需的真实标签。目前已有2130人学习下载可用于训练U-Net、DeepLab等主流分割网络也可用于验证集性能测试、数据增强或多模态融合研究。对从事智能交通、无人驾驶感知算法开发的工程师与高校师生而言这份精细标注数据能有效省去自行采集与标注的繁杂流程直接服务于模型调优、论文实验与竞赛项目有助于提升模型对复杂城市环境的泛化能力。 做语义分割的这几年几乎每个接触过自动驾驶感知或图像分割方向的人都会在某个时刻打开 cityscapes 数据集——它不是最早的城市街景数据集却硬生生靠着统一的标注规范和足够大的规模成了语义分割领域绕不开的 benchmark。我最初跑分割模型时第一个正式训练的数据集也是它当时在官网注册、下载、解压、配置环境一来一回折腾了一整天踩了不少坑。这篇先把最基础也最关键的部分讲透cityscapes 到底装了什么、目录结构怎么理解、怎么用 mmsegmentation 跑通训练再附上我实际调参过程中遇到的一堆问题方便你少走弯路。1. 先搞清楚Cityscapes 到底装了什么1.1 数据规模与任务定位Cityscapes 是奔驰、达姆施塔特工业大学等机构联合发布的城市场景理解数据集采集自德国的多个城市一共包含约 25000 帧视频图像。它最有价值的地方在于其中 5000 张图像拥有高质量的精细像素级标注fine annotation另外 20000 张拥有粗糙标注coarse annotation。官方把精细标注部分又划分为 train2975 张、val500 张、test1525 张三份粗糙标注则只有 train_extra 和 val 两个子集。这套数据覆盖了语义分割、实例分割、全景分割、深度估计等多项任务。日常我们讨论“cityscapes 数据集”时绝大多数情况指的是语义分割并且只用其中 19 个类别进行评估而非原始的 30 类。因为官方在评估时对部分细分类别做了合并或忽略比如 terrain 和 vegetation 会合并评估摩托车和自行车等也基于实际用途调整。最终模型输出的 logits 一般就是 19 通道对应骑手、行人、汽车、卡车、公交车、火车、摩托车、自行车、天空、建筑、墙体、围栏、杆子、交通灯、交通标志、植被、地面、人、机动车道等常用类别。为什么要专门强调这一点因为很多新手下载完数据后直接去看 gtFine 目录里的 PNG 标注图发现颜色花花绿绿数一下有 30 多种颜色就对不上模型需要的 19 类第一反应以为是数据损坏或版本不对。实际上只是没有搞清楚原始类别和训练类别之间的映射关系这部分我后面会详细说。1.2 和 Cityscapes 常对比的几份数据我经常被问到一个问题既然有 CamVid、BDD100K 这些同样面向自动驾驶的数据集为什么还要优先学 Cityscapes简单做一张对比表你就能看明白各自的定位数据集图像数量标注质量类别数特点Cityscapes25000 帧5000 精细标注精细像素级多边形标注30 类评估常用 19 类城市街景标注规范学术界最常用 benchmarkCamVid701 帧像素级32 类常用 11 类数据量小适合快速验证BDD100K10 万帧像素级部分弱标注19 类数据量大场景来自多个国家但标注质量参差Mapillary Vistas25000 张像素级66 类覆盖范围广类别细但获取有商业限制Cityscapes 最大的优势是标注质量和组织规范度非常高图像分辨率为 1024×2048在自动驾驶场景中属于比较标准的街景视角。它适合用来做模型选型、算法对比也是大多数论文汇报 mIoU 的默认数据集。如果你想验证某个新想法直接用 Cityscapes 跑一个相对小的模型比如 segformer、deeplabv3在单卡上也能出结果如果只是想验证代码跑通CamVid 更轻量但论文说服力就差多了。2. 下载与目录结构别在第一步卡住2.1 获取数据的正确姿势Cityscapes 的下载不像 MNIST 或 CIFAR 那样一行代码自动拉取官方要求研究者先在其官网注册账号同意数据集许可协议后才能进入下载页面。这里提醒一句官方下载渠道只对学术研究和教育用途免费如果用于商业项目需要单独联系版权方获取商业授权这一点在课题立项前就要确认清楚避免后续产生合规风险。我自己当时第一次下载时因为嫌官网注册麻烦去网上找过别人分享的压缩包结果解压到一半发现文件缺失标注文件和图片对不上非常耽误时间。后来老老实实回到官网注册下载虽然要填机构信息、用途说明但下载下来的包是完整且校验一致的。如果你所在的高校或公司已经购买了相关数据服务也可以直接从学校数据集服务器、实验室内部共享存储里拷贝这是比个人下载更高效的途径只要确认数据来源合规即可。下载页面会提供多个 zip 包建议按需选择leftImg8bit_trainvaltest.zip左侧摄像头 8bit 彩色图像训练、验证、测试全集。gtFine_trainvaltest.zip精细标注全集。gtCoarse.zip粗糙标注全集量比较大如果用 Cityscapes 做预训练或半监督任务再下载普通跑分割模型可以跳过。另外官方还提供 leftImg8bit_trainextra.zip、camera_trainvaltest.zip 等扩展包前者对应粗标注的额外训练图后者是相机参数做单目深度估计时会用到。常规语义分割只需要前两个包约 11GB 左右。2.2 目录结构与文件命名规则下载解压后目录结构大致如下cityscapes/ ├── leftImg8bit/ │ ├── train/ │ │ ├── aachen/ │ │ │ ├── aachen_000000_000019_leftImg8bit.png │ │ │ └── ... │ │ ├── bochum/ │ │ └── ... │ ├── val/ │ └── test/ └── gtFine/ ├── train/ │ ├── aachen/ │ │ ├── aachen_000000_000019_gtFine_color.png │ │ ├── aachen_000000_000019_gtFine_instanceIds.png │ │ ├── aachen_000000_000019_gtFine_labelIds.png │ │ ├── aachen_000000_000019_gtFine_labelTrainIds.png │ │ ├── aachen_000000_000019_gtFine_polygons.json │ │ └── ... ├── val/ └── test/文件命名的格式比较统一都是“城市_序列号_帧号_类型后缀.png”。重点拆解一下 gtFine 目录下的几个标注文件这直接关系到训练数据怎么喂给模型gtFine_labelIds.png单通道 PNG每个像素存储的是原始类别 ID0~33对应 30 多个具体类别。gtFine_labelTrainIds.png单通道 PNG已经将原始类别 ID 映射到训练使用的 19 类 ID值是 0~18背景或忽略区域为 255。gtFine_instanceIds.png单通道 PNG存储实例级标注车辆、行人等每个独立物体会分配不同 ID用于实例分割。gtFine_color.png三通道彩色可视化图专为人眼查看准备的。gtFine_polygons.json包含每个对象的多边形坐标、标签等原始标注信息做精细化分析或转换标注格式时用。很多同学一开始在 mmsegmentation 里加载数据发现模型 Loss 不下降或者训练出的分割图完全混乱有很大概率是用错了标注文件。训练时要用 labelTrainIds.png而不是 labelIds.png更不是 color.png。因为 labelIds 里的 0~33 并不连续且类别映射与模型输出维度不一致color.png 是三通道彩色图直接当单通道 label 读进去会直接报 shape 错误或类别爆炸。3. 用 mmsegmentation 训练 Cityscapes 的完整实操3.1 环境准备mmsegmentation 是基于 PyTorch 的语义分割工具箱底层依赖 mmcv版本匹配是新手最容易翻车的地方。建议直接用 mim 安装conda create -n openmmlab python3.8 -y conda activate openmmlab pip install torch1.13.1 torchvision0.14.1 --index-url https://download.pytorch.org/whl/cu116 pip install -U openmim mim install mmcv-full1.7.1 git clone -b v0.30.0 https://github.com/open-mmlab/mmsegmentation.git cd mmsegmentation pip install -e .为什么特意指定版本因为 mmsegmentation 0.x 系列与 mmcv-full 1.x 系列兼容性最成熟文档和教程也多。如果你用最新版 mmsegmentation 1.x请按官方文档安装对应 mmcv 2.x接口差异比较大网上很多教程会失效。安装完毕后验证一下python -c import mmcv, mmseg; print(mmcv.__version__, mmseg.__version__)如果打印出版本号说明环境基本就绪。3.2 数据准备与目录软链接mmsegmentation 默认从data/cityscapes目录读取数据。最简单的方式是在项目根目录创建 data 目录然后把解压后的两个文件夹软链接进去mkdir -p data ln -s /path/to/your/leftImg8bit data/cityscapes/leftImg8bit ln -s /path/to/your/gtFine data/cityscapes/gtFine注意 Cityscapes 有自己的目录组织方式但 mmsegmentation 的 CityscapesDataset 会自动查找data/cityscapes/leftImg8bit/train和data/cityscapes/gtFine/train。这里有个小坑如果你下载的是leftImg8bit_trainvaltest.zip解压出来就是leftImg8bit这个文件夹名字别改错否则死活读取不到数据。另外建议检查一下 gtFine 中是否有_labelTrainIds.png文件。官方下载包里已经有这个文件但如果你是从旧版本或其他转换工具得到的标注可能只有 labelIds需要手动转换。mmsegmentation 并没有内置“从 labelIds 自动转 labelTrainIds”的逻辑所以一旦缺少该文件训练时会报错或者类别数量对不上。手动转换的参考脚本也不复杂官方 GitHub 仓库里有tools/convert_datasets/cityscapes.py可以直接执行python tools/convert_datasets/cityscapes.py data/cityscapes --nproc 8这个脚本会遍历 gtFine 目录将 labelIds 映射为 labelTrainIds同时生成train.txt、val.txt等文件列表。如果你想从零开始自己写转换逻辑核心就是一张 34 长度的映射表ignore: -1 road: 0 sidewalk: 1 building: 2 wall: 3 fence: 4 pole: 5 traffic light: 6 traffic sign: 7 vegetation: 8 terrain: 9 sky: 10 person: 11 rider: 12 car: 13 truck: 14 bus: 15 train: 16 motorcycle: 17 bicycle: 18原始类别中不属于以上 19 类的统一映射为 255忽略类别在损失函数中不参与梯度计算。3.3 修改配置文件mmsegmentation 提供了很多现成配置比如经典的deeplabv3plus_r101-d8_4xb4-80k_cityscapes-512x1024.py这类。日常可以基于它改。需要重点理解几个字段dataset_type CityscapesDataset data_root data/cityscapes/ img_norm_cfg dict( mean[123.675, 116.28, 103.53], std[58.395, 57.12, 57.375], to_rgbTrue)训练 pipeline 中最关键的几个操作为train_pipeline [ dict(typeLoadImageFromFile), dict(typeLoadAnnotations), dict(typeResize, img_scale(2048, 1024), ratio_range(0.5, 2.0)), dict(typeRandomCrop, crop_size(512, 1024), cat_max_ratio0.75), dict(typeRandomFlip, prob0.5), dict(typePhotoMetricDistortion), dict(typeNormalize, **img_norm_cfg), dict(typePad, size(512, 1024), pad_val0, seg_pad_val255), dict(typeDefaultFormatBundle), dict(typeCollect, keys[img, gt_semantic_seg]), ]这里解释一下cat_max_ratio0.75的作用。Cityscapes 街景图像中天空、建筑这类大类别经常占据大量面积如果随机裁剪时不做限制会导致某些 batch 里全是背景类模型学不到小类别行人、摩托的特征。这个参数限制单个类别在裁剪区域内的最大占比超过 0.75 会重新裁剪相当于一种类别平衡策略我实际训练时把它保留mIoU 比去掉它高 1~2 个点。数据加载器部分data dict( samples_per_gpu2, workers_per_gpu4, traindict( typedataset_type, data_rootdata_root, img_dirleftImg8bit/train, ann_dirgtFine/train, pipelinetrain_pipeline), valdict( typedataset_type, data_rootdata_root, img_dirleftImg8bit/val, ann_dirgtFine/val, pipelinetest_pipeline), testdict( typedataset_type, data_rootdata_root, img_dirleftImg8bit/val, ann_dirgtFine/val, pipelinetest_pipeline))特别注意ann_dirgtFine/train指向的是 gtFine 根目录mmsegmentation 会在该目录下自动寻找*_labelTrainIds.png文件。如果你想用gtCoarse做预训练可以把ann_dir换成gtCoarse/train但仍要注意粗标注文件命名中的_labelTrainIds.png是否存在。3.4 训练与评估配置改好后启动训练python tools/train.py configs/deeplabv3plus/deeplabv3plus_r101-d8_4xb4-80k_cityscapes-512x1024.py --work-dir work_dirs/deeplabv3plus_cityscapes训练命令的核心参数80k表示迭代 8 万次。为什么是 8 万而不是直接按 epoch 数设置因为 Cityscapes 的 train 集只有 2975 张如果 batch size 为 8一个 epoch 大约 372 次迭代80k 次迭代相当于 215 个 epoch足够模型充分收敛。实际上我用单张 V100 训练 deeplabv3ResNet-101 骨架大约需要 12~16 小时具体时间取决于输入分辨率、batch size 和 GPU 型号。如果显卡一般可以把max_iters80000调低到 40000mIoU 可能低 1~2 个点但已经能看出模型效果。训练结束后验证python tools/test.py configs/deeplabv3plus/deeplabv3plus_r101-d8_4xb4-80k_cityscapes-512x1024.py work_dirs/deeplabv3plus_cityscapes/best_mIoU_iter_80000.pth --eval mIoUmmsegmentation 会自动在验证集上计算 mIoU。需要注意的是官方排行榜要求以 1024×2048 原始分辨率输入测试而很多教程配置里默认训练分辨率为 512×1024这会导致本地验证分数和论文报告分数有差距。为了接近官方分数可以在 test pipeline 里把img_scale(2048, 1024)设置成原始分辨率同时开启 TTATest Time Augmentation也就是水平翻转测试。我实测同样的模型从 512×1024 提升到 1024×2048 输入mIoU 能涨 3 到 5 个点说明分辨率对分割精度影响非常大。4. 训练时常见的坑与排查实录4.1 类别对应不上的经典事故我在前面反复强调 labelTrainIds就是因为这部分实际踩过坑。有一次我训练用的标注还是 labelIds 转换前的版本模型输出的 19 类概率图看起来很正常但可视化出来颜色完全错位行人的地方预测成建筑车辆的地方预测成植被。排查了半天打印数据集返回的gt_semantic_seg才发现像素值范围是 0~33而不是 0~18问题一目了然。如果你也遇到类似情况建议先做一步快速自查随便加载一张训练数据打印标注图的 unique 值from mmseg.datasets import build_dataset from mmseg.apis import inference_segmentor, init_segmentor # 这里更简单的做法是直接读 labelTrainIds.png import numpy as np from PIL import Image mask np.array(Image.open(data/cityscapes/gtFine/val/aachen/aachen_000000_000019_gtFine_labelTrainIds.png)) print(np.unique(mask))如果输出包含 255说明忽略区域没问题如果输出最大值超过 18说明你加载的是 labelIds需要重新转换。另一个相关坑是有些工具包转换出的 mask 是int32或float32而模型输入要求int64mmseg 内部会自动处理但如果你自己写 DataLoader 就很容易出错报错信息通常是RuntimeError: Expected a Long tensor。遇到这个问题直接用mask.long()转换即可。4.2 显存不足与 BatchSize 调整Cityscapes 原始分辨率是 1024×2048在 512×1024 输入下单张 ResNet-101 的显存占用已经不小了。直接用官方默认的samples_per_gpu2在 11GB 显存的 2080Ti 上训练基本秒 OOM。我自己的处理方案是先调小samples_per_gpu到 1如果还 OOM再把crop_size从(512, 1024)降到(512, 512)。保持总 batch size 不变的话可以开启梯度累积用optimizer_configdict(typeGradientCumulativeOptimizerHook, cumulative_iters4)相当于每 4 个 step 更新一次参数。开启混合精度训练mmseg 支持--amp参数例如python tools/train.py configs/xxx.py --amp不过混合精度在部分显卡上会略微损失精度先确认 GPU 支持 tensor core 再开启。我自己的经验是如果只是做算法验证没必要为了省一两小时显存去折腾 AMP降低分辨率更省心。4.3 验证结果和排行榜对不上的原因本地验证集 mIoU 和官方排行榜分数对不上属于 Cityscapes 新手一定会遇到的困惑主要原因有输入分辨率不同。排行榜要求 1024×2048 原始分辨率而你本地可能用了 512×1024这会导致几十分之一的差距被放大。测试增强。官方评估允许 TTAmmseg 的--tta参数可以启用水平翻转增强本地不开 TTA 自然分数偏低。模型权重筛选策略。我见过有人用最后一个 iter 的权重进行验证而不是用 best mIoU 权重导致分数波动较大。训练时建议每隔 2000 次迭代验证一次保存best_mIoU模型后续统一用这个权重测试。类别忽略区域处理。如果验证代码没有正确忽略 255 区域会把 ignored pixels 也算进准确率结果虚高但这种虚高在论文投稿时没有说服力。mmseg 的--eval mIoU自带 ignore基本不会出问题。我在一次实验中本地 val mIoU 是 76.3提交到官网评测却只有 74.8后来发现是因为官网评测用更严格的边界处理mask 边缘 1 像素收缩后再评估属于正常现象不必过度惊慌。4.4 体验总结与一个建议最后分享一点个人体会。Cityscapes 是一个“看起来简单、跑起来处处是细节”的数据集。虽然下载、配置、训练这条流程我已经走过很多次但每次换新模型、新框架还是会遇到新的坑尤其是数据路径、类别映射、评估协议这三个环节最容易出幺蛾子。建议第一次跑通的人不要急着追求高分先把默认配置原封不动跑完 40k 迭代确认流程没问题后再逐步解锁大分辨率、强增强、多尺度测试这些提点手段后面任何一步调整都更容易定位问题。如果你正在折腾 Cityscapes后面可以继续关注这个系列下一篇我准备拆一拆 Cityscapes 训练进阶的提点技巧比如伪标签半监督、类别不平衡处理、多尺度融合这些实用手段以及对应的消融实验怎么做才有效。本文还有配套的精品资源点击获取
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻