ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

俯拍交通目标检测数据集实战:YOLO训练与切片推理优化

俯拍交通目标检测数据集实战:YOLO训练与切片推理优化 简介这是一份面向目标检测学习与开发者的俯拍道路场景数据集聚焦城市交通监控与自动驾驶辅助等应用适合使用YOLO系列网络进行训练与验证的研究人员和开发者。压缩包共2000个文件以1999个txt标签文件和1个py脚本为主txt文件对应每张图片的目标位置与类别标注py脚本可用于数据查看与格式检查整体约463.11MB。数据集包含训练集、验证集及对应标签图片经过旋转、缩放、裁剪、颜色变化等数据增强处理有助于降低过拟合、提升模型泛化能力。类别共10类涵盖汽车、摩托车、行人、卡车等常见道路目标具体类别可参考class类别文本文件。资源采用YOLO格式兼容YOLOv3、YOLOv4等系列网络可直接投入训练。目前已有1615人学习能帮助读者省去图像收集与标注成本快速搭建目标检测实验流程。1. 俯拍交通目标检测数据集3000 张图能直接喂给 YOLO 吗先说结论能但别急着把压缩包解开就往data.yaml里一填了事。我拿到这份俯拍道路交通工具与行人检测数据集的第一反应是翻它的标签目录和 class 文件而不是看图片有多清晰。原因很简单——俯拍视角的目标检测和常规街景视角完全是两套分布行人头顶朝上、车辆只露车顶、摩托车和汽车在 640 分辨率下可能只差几十个像素标注框稍微偏一点mAP 就掉得很难看。这份资源的核心价值在于它把 3000 多张俯拍图像连同 YOLO 格式的 txt 标签、训练集/验证集划分、class 类别文件一起打包好了类别覆盖汽车、摩托车、行人、卡车等 10 类城市道路常见目标。对做智慧交通监控、无人机巡检、自动驾驶辅助感知的团队来说省掉的是最耗时的采集和标注环节。适合谁适合已经跑通过 YOLOv5/v8/v11 任意一版训练流程、手里有 GPU、想快速验证俯拍场景检测方案的人。新手也能跟但得先把 YOLO 的数据组织规则搞清楚否则后面全是玄学报错。2. 拆开数据集看结构YOLO 格式的目录该怎么摆2.1 从文件名反推数据组织方式项目正文里给了一串文件名比如13-ocak-12389_jpg.rf.007d396d6d8c08481f5d3860a89715c7.txt。这个命名很有信息量13-ocak是原始图像编号前缀_jpg说明原图是 jpg.rf.后面那串哈希是数据增强或导出时生成的唯一标识。也就是说这份数据集在交付前已经做过一轮增广每张增强图都有独立的标签文件不是简单复制原图。常见做法是拿到手后先确认三件事图片和标签是否同名同目录、class 文件里类别顺序是否和标签里的 class_id 对得上、训练集和验证集是否已经分好。我一般会先跑一段脚本统计而不是靠肉眼翻文件夹。import os from collections import Counter # 假设数据集根目录结构为 dataset/images 和 dataset/labels root dataset img_dir os.path.join(root, images) lbl_dir os.path.join(root, labels) img_files [f for f in os.listdir(img_dir) if f.lower().endswith((.jpg, .png, .jpeg))] lbl_files [f for f in os.listdir(lbl_dir) if f.lower().endswith(.txt)] # 检查图片和标签是否一一对应 img_stems {os.path.splitext(f)[0] for f in img_files} lbl_stems {os.path.splitext(f)[0] for f in lbl_files} print(图片数量:, len(img_stems)) print(标签数量:, len(lbl_stems)) print(有图无标签:, len(img_stems - lbl_stems)) print(有标签无图:, len(lbl_stems - img_stems)) # 统计每个类别的框数量 cls_counter Counter() for f in lbl_files: with open(os.path.join(lbl_dir, f), r) as fp: for line in fp: parts line.strip().split() if len(parts) 5: cls_counter[int(parts[0])] 1 print(类别分布:, dict(sorted(cls_counter.items())))这段脚本的逻辑很直白先做图片和标签的配对检查再做类别框数统计。参数上唯一需要改的是root路径指向你解压后的数据集根目录。如果有图无标签或有标签无图不为零说明数据组织有问题得先修再训。类别分布那行输出尤其重要——如果某一类只有几十个框训练时大概率会被其他类淹没后面调 loss 权重或者做重采样就有依据了。2.2 class 文件与 data.yaml 的对应关系数据集里那个 class 类别文本文件通常是一行一个类别名顺序就是标签里 class_id 的顺序。YOLO 训练不直接读这个文件而是读data.yaml。所以你要做的是把 class 文件的内容翻译成 yaml 里的names列表。# data.yaml path: /home/user/dataset # 数据集根目录绝对路径最稳 train: images/train # 训练集图片相对路径 val: images/val # 验证集图片相对路径 nc: 10 # 类别数必须和 class 文件行数一致 names: # 顺序必须和 class 文件完全一致 0: car 1: motorcycle 2: person 3: truck # ... 其余类别按 class 文件补全这里有个血泪经验names的顺序一旦和标签里的 class_id 错位训练 loss 会正常下降但推理时类别全乱而且这种错误在训练日志里看不出来。我一般会写个校验脚本随机抽 20 张图把框画出来肉眼确认类别标签和实际目标对得上。别嫌麻烦这一步省掉后面调半天模型都找不到原因。提示如果数据集已经分好 train/val 目录直接按实际目录名改train和val字段如果没分用脚本按 8:2 随机划分注意固定随机种子保证可复现。3. 用 YOLOv8 跑通第一轮训练参数怎么设、日志怎么看3.1 环境准备与最小训练命令这份数据集兼容 YOLO 全系列我拿 YOLOv8 举例因为它的训练接口最干净。环境上Python 3.9、PyTorch 2.0、ultralytics 包GPU 显存建议 8G 起步。俯拍图分辨率如果原图很大训练时统一缩到 640这是 YOLO 系列的默认输入尺寸也是精度和速度的平衡点。# 安装 ultralytics pip install ultralytics # 最小训练命令 yolo detect train \ datadata.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ device0 \ projectruns/traffic \ nameexp1参数逐个说modelyolov8n.pt是最小的 nano 版本先用它跑通流程确认数据和标签没问题再换 s/m/l 版本冲精度。batch16是 8G 显存的保守值显存够可以往上加但要注意 batch 太大时小目标梯度贡献被稀释。imgsz640不要轻易改改了要和后面推理、部署的输入尺寸保持一致。device0指定第一块 GPU多卡用device0,1。训练启动后重点看三个东西train/box_loss是否稳定下降、metrics/mAP50是否在涨、val/box_loss有没有在某个 epoch 后反弹。俯拍小目标多前 10 个 epoch mAP 低是正常的别急着停。3.2 数据增强参数与俯拍场景的适配数据集本身已经做过增广但 YOLO 训练时还会在 dataloader 里再做一轮在线增强。默认的mosaic、mixup、hsv对俯拍交通场景不一定都合适。比如mixup把两张图线性叠加俯拍图背景本来就杂叠完可能产生不存在的目标组合反而干扰训练。yolo detect train \ datadata.yaml \ modelyolov8s.pt \ epochs150 \ imgsz640 \ batch12 \ device0 \ mosaic0.8 \ mixup0.0 \ hsv_h0.015 \ hsv_s0.5 \ hsv_v0.4 \ degrees0.0 \ translate0.1 \ scale0.3 \ fliplr0.5 \ flipud0.0这里几个关键取舍mosaic0.8保留较高概率因为俯拍场景目标密集mosaic 能增加小目标出现频率mixup0.0直接关掉理由上面说了degrees0.0不做旋转俯拍视角的朝向信息有意义随便转可能让车辆朝向变得不合理flipud0.0不做上下翻转同理俯拍图上下翻转后透视关系不对。scale0.3保留一定缩放增强尺度鲁棒性。这些参数不是死的如果你的场景里车辆朝向不重要可以适当开degrees。但我的习惯是先按保守配置跑一版 baseline再逐项开增强做消融每次只改一个参数看验证集 mAP 的变化。3.3 训练日志里的关键指标与早停策略YOLOv8 默认patience50意思是验证指标 50 个 epoch 不提升就早停。俯拍数据集如果验证集样本少mAP 波动会比较大我一般把patience调到 30同时开save_period10定期存 checkpoint防止最佳权重被覆盖。yolo detect train \ datadata.yaml \ modelyolov8s.pt \ epochs200 \ patience30 \ save_period10 \ cos_lrTrue \ lr00.01 \ lrf0.01cos_lrTrue用余弦退火学习率比阶梯下降更平滑适合这种中等规模数据集。lr00.01是初始学习率lrf0.01是最终学习率系数实际最终 lr 是lr0 * lrf。如果训练前期 loss 震荡厉害先把lr0降到 0.005 试试。日志里还有一个容易被忽略的指标metrics/mAP50-95。俯拍小目标定位精度要求高mAP50 好看但 mAP50-95 低说明框的位置不够准这时候要考虑是不是标注框本身有偏差或者imgsz太小导致小目标特征丢失。4. 避坑与排查俯拍数据集训练最容易翻车的五件事4.1 现象训练 loss 正常下降但推理时框全偏了原因标签格式不是标准的 YOLO 归一化格式。YOLO 要求class_id x_center y_center width height且四个值都是相对图像宽高的归一化值0~1。如果标签里是绝对像素坐标训练时 loss 也能降但模型学到的位置关系是错的。解决写脚本检查标签值范围任何坐标大于 1 的行都说明格式不对。转换时用 PIL 或 OpenCV 读原图尺寸逐行除以宽高。from PIL import Image import os img_dir dataset/images lbl_dir dataset/labels for f in os.listdir(lbl_dir): if not f.endswith(.txt): continue img_path os.path.join(img_dir, f.replace(.txt, .jpg)) if not os.path.exists(img_path): continue w, h Image.open(img_path).size with open(os.path.join(lbl_dir, f)) as fp: for i, line in enumerate(fp): parts line.strip().split() if len(parts) 5: print(f格式错误: {f} 第{i1}行) continue vals list(map(float, parts[1:])) if any(v 1.0 for v in vals): print(f未归一化: {f} 第{i1}行 - {vals})4.2 现象某一类 mAP 始终为 0原因class 文件里的类别名和 data.yaml 的names顺序不一致或者某一类在训练集里样本极少。俯拍场景里“摩托车”和“汽车”容易混如果标注时把摩托车标成了汽车模型学到的就是错的。解决先跑 2.1 的类别统计脚本确认每类框数。少于 100 框的类别考虑合并到相近类或者用cls_pw类权重补偿。再抽查标签可视化确认类别标注正确。4.3 现象验证集 mAP 比训练集低很多原因训练集和验证集分布不一致。这份数据集如果增广图全堆在训练集验证集全是原图模型在验证集上就会表现差。另外俯拍高度、光照、道路类型如果 train/val 差异大也会导致这个问题。解决检查 train/val 划分是否随机。我一般用sklearn.model_selection.train_test_split按文件名随机分固定random_state42。如果已经分好统计两边的类别分布差异大的类做重采样。4.4 现象训练到一半显存爆了原因batch设太大或者imgsz调高了但没同步降 batch。YOLOv8 训练时显存占用和batch * imgsz^2成正比。解决用batch-1让 ultralytics 自动找最大 batch或者手动降。8G 显存跑 640 分辨率YOLOv8s 建议 batch 不超过 16。4.5 现象推理时小目标漏检严重原因俯拍图里行人和摩托车在 640 分辨率下可能只有 10~20 像素YOLO 的 P3 特征图下采样 8 倍后这些目标只剩 1~2 个像素特征几乎消失。解决训练时把imgsz提到 960 或 1280但显存和速度代价大。折中方案是用 YOLOv8 的rect推理模式或者换用带 P2 检测头的模型变体。另一个思路是切片推理把大图切成小块分别检测再合并适合无人机俯拍大图场景。5. 进阶技巧用切片推理把俯拍小目标召回率拉上来俯拍交通图有个特点单张图覆盖范围大目标相对整图很小。直接缩到 640 训练小目标信息损失严重。我试过一个很实用的技巧——训练时用 640 保证速度推理时用切片SAHI 思路把原图切成重叠子图分别检测再按置信度做 NMS 合并。这样不改训练流程只改推理端小目标召回率能明显改善。from ultralytics import YOLO import cv2 import numpy as np model YOLO(runs/traffic/exp1/weights/best.pt) def sliced_inference(img_path, slice_size640, overlap0.2): img cv2.imread(img_path) h, w img.shape[:2] step int(slice_size * (1 - overlap)) boxes_all [] for y in range(0, h, step): for x in range(0, w, step): patch img[y:yslice_size, x:xslice_size] if patch.shape[0] 32 or patch.shape[1] 32: continue results model(patch, verboseFalse)[0] for box in results.boxes: xyxy box.xyxy[0].cpu().numpy() xyxy[0] x xyxy[1] y xyxy[2] x xyxy[3] y boxes_all.append((*xyxy, float(box.conf[0]), int(box.cls[0]))) # 这里接一个 NMS 做跨切片合并可用 torchvision.ops.nms return boxes_all boxes sliced_inference(test.jpg) print(切片检测框数量:, len(boxes))这段代码的核心参数是slice_size和overlap。slice_size设成和训练imgsz一致保证模型看到的尺度分布不变overlap0.2是相邻切片的重叠比例防止目标正好卡在切片边界被切掉。切片越多推理越慢但小目标召回越高。实际部署时可以根据业务对延迟的容忍度调这两个值。跨切片合并那步别偷懒一定要做 NMS否则同一个目标会在多个切片里被重复检出。我一般用torchvision.ops.nmsIoU 阈值设 0.5 左右。另外切片推理的坐标偏移容易写错xyxy加偏移量时四个值都要加只加前两个是经典翻车点。还有一个验证技巧训练完后别只看 mAP 数字把验证集里 mAP 最低的那 20 张图导出来用切片推理跑一遍对比原推理结果。如果切片后这些图的检出框明显变多且合理说明小目标确实是瓶颈可以考虑在训练端也引入切片增广。从那以后我每次拿到俯拍数据集都强制先跑一遍切片推理对比再决定要不要调训练分辨率。希望帮到你。本文还有配套的精品资源点击获取
返回列表