语义分割-CityScapes数据集实战:从数据准备到模型训练

发布时间:2026/7/10 12:24:45

语义分割-CityScapes数据集实战:从数据准备到模型训练 1. 初识CityScapes数据集街景语义分割的黄金标准第一次接触CityScapes数据集时我被它的规模和质量震撼到了。这个数据集就像是用高清摄像机记录下的欧洲城市日记5000张精细标注的街景图像每张分辨率高达1024x2048相当于普通高清电视的四倍清晰度。我在自动驾驶项目中最头疼的就是找不到高质量的道路场景数据直到发现了这个宝藏。CityScapes最特别的地方在于它的标注体系。举个例子同样是车辆这个类别它会细致区分轿车、卡车、公交车甚至自行车总共有30多个语义类别。我在处理数据时发现连红绿灯和交通标志这种小物体都有独立标签这对于训练精准的识别模型太重要了。数据集按用途分为训练集2975张、验证集500张和测试集1525张这种划分比例在实际项目中很实用——既保证足够的训练样本又能有效评估模型表现。提示下载数据集时需要注册账号建议使用学术邮箱申请通常审核通过率更高2. 数据获取与解压避开那些新手陷阱去年带实习生时发现十个有九个会在数据下载环节卡壳。官方下载页面像迷宫我整理了个傻瓜式流程先到cityscapes-dataset.com官网找到Downloads选项卡重点下载这两个压缩包leftImg8bit_trainvaltest.zip原始图像gtFine_trainvaltest.zip精细标注解压后目录结构特别重要我建议保持原始文件夹命名。leftImg8bit里按train/val/test分三级每个子目录又以城市命名。有次我手贱改了文件夹名结果跑官方评估脚本时路径全报错白白浪费半天时间。标注文件比想象中复杂每张图对应4个衍生文件_color.png可视化标注给人类看的_instanceIds.png实例分割专用_labelIds.png语义分割的核心标签_polygons.json原始标注坐标# 推荐的文件目录结构 cityscapes/ ├── leftImg8bit/ │ ├── train/ │ ├── val/ │ └── test/ └── gtFine/ ├── train/ ├── val/ └── test/3. 标签魔改实战让数据集听你的话真实项目中我们往往不需要识别全部30多个类别。去年做自动驾驶感知模块时老板突然要求只检测道路和车辆。这时候就需要修改标签映射关系官方提供的Python脚本库cityscapesScripts就是神器。在labels.py文件里每个类别有6个属性name类别名称如roadid原始ID固定不变trainId训练使用的ID重点修改这个category粗分类如vehiclecolor可视化颜色# 典型的两分类修改示例道路vs其他 labels [ Label(road, 7, 1, flat, 1, (128,64,128)), Label(car, 26, 2, vehicle, 7, (0,0,142)), # 其他类别全部映射为0 Label(unlabeled, 0, 0, void, 0, (0,0,0)), ... ]改完后运行createTrainIdLabelImgs.py脚本它会批量重生成标签图像。这里有个坑要注意Windows用户可能会遇到路径长度限制报错建议把数据集放在根目录如C:/cityscapes。我在公司服务器跑脚本时还遇到过内存不足的问题这时候可以分批次处理# 分批处理脚本示例 for city in os.listdir(gtFine/train): os.system(fpython createTrainIdLabelImgs.py --city {city})4. 图像预处理小显存也能玩转大图1024x2048的原图直接扔进模型我的RTX 3090显卡第一个抗议。经过多次试验我总结出三种实用预处理方案方案A等比缩放最省事import cv2 img cv2.resize(img, (512, 1024), interpolationcv2.INTER_LINEAR) label cv2.resize(label, (512, 1024), interpolationcv2.INTER_NEAREST)注意标签必须用INTER_NEAREST插值否则会产生无效的中间值方案B随机裁剪数据增强def random_crop(img, label, size(512,1024)): h, w img.shape[:2] x random.randint(0, w - size[1]) y random.randint(0, h - size[0]) return img[y:ysize[0], x:xsize[1]], label[y:ysize[0], x:xsize[1]]方案C滑动窗口适合推理我参考HRNet论文实现了重叠切片法把大图切成512x1024的瓦片预测后再拼接。虽然速度慢点但能保留更多细节。有个技巧重叠区域取预测结果的平均值可以避免接缝处的突变。5. 模型适配让主流框架吃得下数据最近在PyTorch和TensorFlow上都跑过CityScapes分享几个关键配置。以DeepLabv3为例数据加载器要特别注意标签的读取方式# PyTorch Dataset示例 class CityscapesDataset(Dataset): def __getitem__(self, idx): img Image.open(img_paths[idx]).convert(RGB) label Image.open(label_paths[idx]) # 关键步骤将PIL图像转为Tensor img transforms.ToTensor()(img) label torch.from_numpy(np.array(label)).long() return img, label在TensorFlow 2.x中推荐用tf.data做数据管道def parse_fn(img_path, label_path): img tf.io.read_file(img_path) img tf.image.decode_png(img, channels3) label tf.io.read_file(label_path) label tf.image.decode_png(label, channels1) return img, label train_ds tf.data.Dataset.from_tensor_slices((img_paths, label_paths)) train_ds train_ds.map(parse_fn).batch(8).prefetch(2)6. 训练技巧从baseline到SOTA的进阶之路刚开始用CityScapes时我的模型mIoU卡在60%上不去。后来通过这几个技巧逐步提升到75%技巧1类别权重平衡CityScapes的类别极度不均衡道路像素占比可能是信号灯的几千倍。我采用median frequency balancing算法自动计算权重# 计算每个类别的出现频率 pixel_counts np.bincount(labels.flatten()) # 计算权重 weights np.median(pixel_counts) / (pixel_counts 1e-5)技巧2学习率热身大尺寸图像训练需要更谨慎的学习率控制。我采用线性热身余弦退火策略# PyTorch示例 scheduler torch.optim.lr_scheduler.OneCycleLR( optimizer, max_lr0.01, steps_per_epochlen(train_loader), epochs50 )技巧3多尺度训练在数据增强时随机缩放图像0.5x-2.0x让模型适应不同距离的物体。实测这个技巧对提升小物体识别特别有效。7. 评估指标看懂官方评测的玄机CityScapes的评估服务器会返回4个关键指标IoU class标准交并比iIoU class实例级交并比IoU category粗类别交并比iIoU category实例级粗类别交并比最容易被忽视的是iIoUinstance-level IoU它要求模型不仅能识别类别还要区分不同实例。比如两辆并排的汽车如果预测成一个连通区域在IoU上可能得分高但在iIoU上就会扣分。我在模型中加入条件随机场CRF后iIoU提升了3个百分点。本地验证时可以用这个简化版评估代码def compute_iou(pred, target, n_classes19): ious [] for cls in range(n_classes): pred_inds pred cls target_inds target cls intersection (pred_inds target_inds).sum() union (pred_inds | target_inds).sum() ious.append(float(intersection) / max(union, 1)) return np.mean(ious)8. 实战经验那些官方文档没告诉你的坑内存泄漏陷阱使用OpenCV读取图像时默认是BGR格式如果混用PIL的RGB格式会导致内存缓慢增长。建议统一用OpenCV时加上cv2.cvtColor(img, cv2.COLOR_BGR2RGB)转换。验证集过拟合因为CityScapes的验证集来自3个固定城市反复调参可能导致模型只适应这几个城市的特征。我后来养成分出10%训练集做本地验证的习惯。标签偏移问题当修改trainId后某些类别可能被错误映射。有次我把摩托车和自行车合并成二轮车类别结果发现模型把行人误检为二轮车。后来在labels.py里仔细检查了所有类别的父子关系才解决。多GPU训练同步使用torch.nn.DataParallel时如果验证集的样本数不是batch_size的整数倍可能会导致某些GPU处理不到数据。解决方法是在验证时设置drop_lastFalse。

相关新闻