保姆级教程:用YOLOv8在Cityscapes数据集上搞定语义分割(附源码与可视化脚本)
从零实现YOLOv8语义分割:Cityscapes数据集实战指南
在计算机视觉领域,语义分割技术正逐渐成为自动驾驶、智能监控等场景的核心支撑。不同于目标检测只需框出物体位置,语义分割需要精确到像素级别的分类,这对算法提出了更高要求。本文将手把手带您使用最新的YOLOv8框架,在Cityscapes数据集上构建完整的语义分割流水线。
1. 环境配置与数据准备
1.1 开发环境搭建
推荐使用Python 3.8+和PyTorch 1.12+环境,以下是关键依赖的安装命令:
pip install ultralytics torch==1.13.1 torchvision==0.14.1 --extra-index-url https://download.pytorch.org/whl/cu117
pip install cityscapesscripts opencv-python matplotlib
硬件配置建议:
- GPU :至少8GB显存(如RTX 3070)
- 内存 :16GB以上
- 存储 :50GB可用空间(Cityscapes数据集约30GB)
1.2 Cityscapes数据集处理
Cityscapes原始数据包含34个类别,但通常只需关注19个主要类别。使用官方脚本转换标签:
from cityscapesscripts.preparation.createTrainIdLabelImgs import main
main({
'cityscapes_path': '/path/to/cityscapes',
'output_path': '/path/to/converted'
})
目录结构处理后应如下:
cityscapes/
├── leftImg8bit/
│ ├── train/
│ ├── val/
│ └── test/
└── gtFine/
├── train/
├── val/
└── test/
注意:转换后会生成
*_labelTrainIds.png文件,其中不关注的类别像素值为255
2. YOLOv8模型定制
2.1 配置文件调整
创建自定义的YOLOv8分割模型配置文件
yolov8-seg-cityscapes.yaml
:
# YOLOv8 Segmentation config
num_classes: 19
backbone:
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
# ...完整backbone结构...
head:
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
- [[-1, 6], 1, Concat, [1]] # 特征融合
- [-1, 3, C2f, [512]] # 分割头
- [-1, 1, Conv, [19, 1, 1]] # 19类输出
2.2 数据加载适配
创建数据集描述文件
cityscapes-seg.yaml
:
path: /path/to/cityscapes
train: leftImg8bit/train
val: leftImg8bit/val
test: leftImg8bit/test
names:
0: road
1: sidewalk
2: building
# ...完整19个类别...
3. 训练与优化策略
3.1 基础训练命令
启动训练的基本命令示例:
yolo segment train data=cityscapes-seg.yaml model=yolov8n-seg.yaml epochs=100 imgsz=1024 batch=8
关键参数说明:
| 参数 | 推荐值 | 作用 |
|---|---|---|
| imgsz | 1024 | 输入图像尺寸 |
| batch | 8-16 | 根据显存调整 |
| lr0 | 0.01 | 初始学习率 |
| weight_decay | 0.0005 | 权重衰减 |
3.2 高级训练技巧
-
学习率调度 :
from ultralytics import YOLO model = YOLO('yolov8n-seg.yaml') model.train( data='cityscapes-seg.yaml', lr0=0.01, lrf=0.1, # 最终学习率=lr0*lrf warmup_epochs=3 ) -
数据增强配置 :
# 在cityscapes-seg.yaml中添加 augment: hsv_h: 0.015 # 色调增强 hsv_s: 0.7 # 饱和度增强 flipud: 0.5 # 垂直翻转概率 mixup: 0.2 # MixUp概率
4. 结果可视化与分析
4.1 Python可视化脚本
使用OpenCV实现结果可视化:
import cv2
import numpy as np
def visualize_segmentation(image_path, mask_path):
image = cv2.imread(image_path)
mask = cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE)
# Cityscapes官方配色方案
palette = [
(128, 64, 128), # road
(244, 35, 232), # sidewalk
(70, 70, 70), # building
# ...其他类别颜色...
]
colored_mask = np.zeros((*mask.shape, 3), dtype=np.uint8)
for class_id, color in enumerate(palette):
colored_mask[mask == class_id] = color
overlay = cv2.addWeighted(image, 0.7, colored_mask, 0.3, 0)
return overlay
4.2 性能评估指标
使用官方评估脚本计算指标:
python cityscapesscripts/evaluation/evalPixelLevelSemanticLabeling.py \
--gtPath gtFine/val \
--predPath runs/segment/predict \
--outputFile evaluation.json
典型优化方向:
- mIoU提升 :关注低分类别,增加对应样本
- 边界精度 :使用Dice Loss替代交叉熵
- 推理速度 :尝试模型量化(FP16/INT8)
5. 常见问题解决方案
5.1 显存不足处理
当遇到CUDA out of memory错误时:
-
减小
batch_size(最低可设为1) -
启用梯度累积:
yolo train ... batch=4 accumulate=2 # 等效batch=8 - 使用更小的模型(如yolov8s-seg)
5.2 类别不平衡对策
Cityscapes中"road"类别占比约40%,可采用:
-
样本加权
:
class_weights = torch.tensor([1.0, 2.0, ..., 0.5]) # 根据频率设置 criterion = nn.CrossEntropyLoss(weight=class_weights) -
过采样少数类
:
# 在数据配置中添加 sample_weights: - {class: 15, weight: 3.0} # 对稀有类别加权
5.3 预测结果碎片化
改善分割连贯性的技巧:
-
后处理使用CRF(条件随机场):
from pydensecrf import densecrf crf = densecrf.DenseCRF2D(width, height, 19) # 添加颜色和位置特征 crf.addPairwiseBilateral(sxy=80, srgb=13, rgbim=image) -
训练时加入边界感知损失:
class EdgeAwareLoss(nn.Module): def forward(self, pred, target): edge = cv2.Canny(target, 0.1, 0.2) weight = 1 + edge * 5 # 边界区域权重更高 return (F.cross_entropy(pred, target) * weight).mean()
在实际项目中,发现将图像尺寸调整为1024x1024时,相比默认的640x640能提升约3%的mIoU,但推理速度下降40%。对于实时性要求高的场景,建议使用768x768作为平衡点。
更多推荐
所有评论(0)