简介:这份摩托车与行人目标检测数据集面向交通监控、自动驾驶感知及智慧城市方向的算法开发者与研究人员,聚焦道路场景中摩托车与行人两类关键目标的识别需求。资源包共2000个文件,以1095个YOLO格式txt标注文件、903张JPEG道路监控图片为主,另含1个yaml配置文件与1份docx说明文档,压缩包约62.91MB,其中训练集937张、验证集158张,标注采用归一化边界框坐标,兼容YOLOv5/v7/v8等主流框架,可快速投入模型训练。数据集覆盖多种光照与视角条件,目标定位精准、场景针对性强,适用于交通流量统计、危险行为预警、行人聚集识别及摩托车与行人互动行为研究等任务。目前已有124人学习下载,适合需要即用型工业级目标检测数据的中高级开发者参考使用。
1. 摩托车与行人目标检测数据集:1095 张道路监控图能直接喂给 YOLO 吗
拿到一个标注好的数据集,第一反应往往不是"太好了",而是"这玩意儿能不能直接跑"。这份摩托车与行人目标检测数据集就是典型的道路监控场景资源:训练集 937 张、验证集 158 张,合计 1095 张 JPEG 图片,标注走的是 YOLO 格式,类别只有两个——摩托车(motorcycle)和行人(pedestrian)。它解决的不是"从零标注"的问题,而是"我有个交通监控相关的检测需求,但不想花两周标数据"的问题。适合谁?做交通流量统计、危险行为预警、自动驾驶感知模块预研,或者单纯想拿一份小规模、类别干净的数据集把 YOLOv5/v7/v8 训练流程跑通的人。1095 张不算大,但两类目标、真实道路场景、多光照多视角,作为验证 pipeline 和做 baseline 是够用的。真正要关心的是:标注质量、类别平衡、以及 YOLO 格式的目录结构能不能被你的训练脚本直接吃进去。
2. YOLO 格式拆解:从标签文件到 data.yaml 的完整链路
2.1 为什么是 YOLO 格式,而不是 COCO 或 VOC
目标检测数据集的标注格式直接决定你前期要花多少时间在转换上。COCO 用 JSON 存所有图片的标注,VOC 用 XML 一图一文件,YOLO 则是每张图对应一个.txt,每行一个目标,格式是class_id x_center y_center width height,坐标全部归一化到 0~1。这份数据集选 YOLO 格式,好处很直接:YOLOv5/v7/v8 以及后续的 v11 系列,训练时默认读的就是这种结构,不需要写转换脚本。常见做法是拿到 COCO 格式后先转 YOLO,但这里省掉了那一步。
归一化坐标的含义要清楚:x_center是边界框中心点的 x 坐标除以图片宽度,y_center同理,width和height是框的宽高分别除以图片宽高。这样做的原因是图片尺寸不一致时,归一化坐标可以直接缩放,不用每张图单独算。类别 id 从 0 开始,这份数据集里 0 对应 motorcycle,1 对应 pedestrian,具体顺序要以你拿到的classes.txt或data.yaml为准,不能凭感觉猜。
2.2 目录结构怎么摆才能被训练脚本识别
YOLO 训练对目录结构有约定,摆错了不会报"格式错误",而是直接找不到图或者标签对不上。标准结构是这样:
dataset/ ├── images/ │ ├── train/ # 937 张训练图 │ └── val/ # 158 张验证图 ├── labels/ │ ├── train/ # 与训练图同名的 .txt │ └── val/ # 与验证图同名的 .txt └── data.yaml关键点是images/train下的image-572.jpg必须对应labels/train/image-572.txt,文件名(不含扩展名)要完全一致。YOLO 在加载时会用图片路径替换images为labels、替换扩展名为.txt去找标签,找不到就跳过这张图,训练时你只会看到实际参与训练的图片数变少,不会报错。这是个隐蔽的坑,后面避坑章节会细说。
2.3 data.yaml 的字段含义与写法
data.yaml是训练入口,告诉 YOLO 去哪找图、有几类、类名是什么。写法如下:
# data.yaml path: ./dataset # 数据集根目录 train: images/train # 相对 path 的训练图路径 val: images/val # 相对 path 的验证图路径 nc: 2 # 类别数 names: # 类别名,顺序必须与标注里的 class_id 对应 0: motorcycle 1: pedestrianpath可以是绝对路径也可以是相对路径,相对路径是相对于你执行训练命令时的工作目录,不是相对于 yaml 文件位置,这点容易搞混。nc和names的键值对数量必须一致,names的顺序就是 class_id 的顺序。如果标注里 motorcycle 是 0、pedestrian 是 1,这里写反了,模型会把摩托车学成行人,训练 loss 照样下降,但推理结果全错。验证方法很简单:训练前用脚本统计一下标签文件里每个 class_id 出现的次数,和names对一遍。
2.4 用脚本快速校验标注完整性
在正式训练前,跑一个校验脚本能省掉大量排查时间。下面这段代码检查三件事:图片和标签是否一一对应、标签行格式是否合法、每个类别的框数量分布。
import os from pathlib import Path from collections import Counter def validate_yolo_dataset(root): root = Path(root) for split in ['train', 'val']: img_dir = root / 'images' / split lbl_dir = root / 'labels' / split imgs = {p.stem for p in img_dir.glob('*.jpg')} lbls = {p.stem for p in lbl_dir.glob('*.txt')} # 1. 图片与标签配对检查 only_img = imgs - lbls only_lbl = lbls - imgs print(f'[{split}] 图片 {len(imgs)} 张, 标签 {len(lbls)} 个') if only_img: print(f' 有图无标签: {len(only_img)} 个, 示例 {list(only_img)[:3]}') if only_lbl: print(f' 有标签无图: {len(only_lbl)} 个, 示例 {list(only_lbl)[:3]}') # 2. 标签格式与类别分布 cls_counter = Counter() bad_lines = 0 for lbl in lbl_dir.glob('*.txt'): for line in lbl.read_text().strip().splitlines(): parts = line.split() if len(parts) != 5: bad_lines += 1 continue cls_id = int(parts[0]) coords = [float(x) for x in parts[1:]] # 归一化坐标应在 0~1 之间 if not all(0 <= c <= 1 for c in coords): bad_lines += 1 continue cls_counter[cls_id] += 1 print(f' 类别分布: {dict(cls_counter)}, 异常行: {bad_lines}') validate_yolo_dataset('./dataset')逻辑说明:先按 split 分别取图片和标签的文件名集合(用stem去掉扩展名),做差集就能看出配对情况。标签格式检查里,一行必须是 5 个字段,坐标必须在 0~1 之间,超出范围说明标注时算错了或者图片尺寸记录有误。类别分布用Counter统计,如果某一类数量极少(比如行人只有几十个框),训练时这一类基本学不好,需要考虑过采样或调整 loss 权重。参数方面,root指向数据集根目录,脚本假设图片是.jpg,如果你的数据里有.png或.jpeg,把glob('*.jpg')改掉即可。
3. 训练参数怎么设:从 yolov8n 起步到收敛判断
3.1 模型选型:为什么先用 nano 版本跑通
这份数据集只有 1095 张图、2 个类别,属于小规模任务。常见做法是先用yolov8n.pt(nano)跑一遍,确认数据 pipeline 没问题、loss 能正常下降,再换yolov8s或yolov8m看精度有没有提升。nano 版本参数量小,单卡甚至 CPU 都能跑,一轮 epoch 几秒钟,适合快速验证。直接上大模型的问题是:如果数据有问题,大模型训练慢,你等半小时才发现 loss 不降,排查成本高。
选型判断标准:如果 nano 训练 50 epoch 后 mAP@0.5 能到 0.6 以上,说明数据质量可以,换更大模型有提升空间;如果 nano 怎么训都上不去,先回头查标注,别急着换模型。
3.2 关键训练命令与参数逐项说明
用 Ultralytics 的 YOLOv8 训练,命令如下:
yolo detect train \ data=./dataset/data.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ batch=16 \ lr0=0.01 \ patience=20 \ project=runs/train \ name=moto_pedestrian逐项说明:data指向 yaml 文件;model是预训练权重,用yolov8n.pt做迁移学习比从零训收敛快得多;epochs=100对小数据集够用,配合patience=20做早停——20 轮内验证指标没提升就停,避免过拟合;imgsz=640是输入分辨率,如果你的原图分辨率远大于 640,缩小后小目标(远处行人)可能丢细节,可以试imgsz=960,但显存占用会上升;batch=16看显存调,8G 显存跑 640 分辨率一般能到 16;lr0=0.01是初始学习率,迁移学习常用 0.01,从零训可以降到 0.001。
训练过程中重点看三个指标:box_loss和cls_loss是否稳定下降、mAP@0.5是否上升、验证集的precision和recall是否平衡。如果 loss 震荡厉害,把lr0调小;如果 recall 远低于 precision,说明漏检多,可能是小目标或者标注框偏小。
3.3 数据增强参数:小数据集的救命稻草
1095 张图训检测模型,过拟合是大概率事件。YOLOv8 默认开了 mosaic、HSV 增强、随机翻转等,但默认参数不一定适合道路监控场景。几个值得调的:
yolo detect train \ data=./dataset/data.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ hsv_h=0.015 hsv_s=0.7 hsv_v=0.4 \ degrees=0.0 \ translate=0.1 \ scale=0.5 \ fliplr=0.5 \ mosaic=1.0 \ mixup=0.1hsv_h/s/v控制色调、饱和度、亮度扰动,道路监控场景光照变化大,hsv_v=0.4让模型对明暗变化更鲁棒。degrees=0.0是因为道路场景里摩托车和行人基本是正立的,旋转增强反而引入不真实样本。fliplr=0.5左右翻转,行人左右翻转合理,但要注意如果场景里有文字标识(比如车牌),翻转后文字反了,不过这份数据集只有两类目标,影响不大。mosaic=1.0是四图拼接,小数据集上很有效,但训练后期可以关掉(设 0)让模型适应真实分布。mixup=0.1做图像混合,进一步抑制过拟合,但太高会让训练变慢。
3.4 训练结果怎么看:mAP 曲线与混淆矩阵
训练完在runs/train/moto_pedestrian/下会生成一堆文件,重点看两个:results.png里的 mAP 曲线,和confusion_matrix.png。mAP 曲线如果在后期还在上升,说明 epoch 不够;如果验证 mAP 开始下降而训练 mAP 还在升,就是过拟合,该早停或加增强。混淆矩阵能看出两类是否互相误判——如果 motorcycle 被大量判成 pedestrian,说明特征区分度不够,可能是标注框把两类混了,或者图片里两类目标重叠严重。
4. 避坑与排查:标注、路径、显存三个高频翻车点
4.1 现象:训练日志里图片数比实际少
原因:images和labels文件名没对上,或者标签文件扩展名不是.txt。YOLO 加载时静默跳过找不到标签的图片,不报错。
解决:跑 2.4 节的校验脚本,看"有图无标签"的数量。如果是 0 但训练数还是少,检查data.yaml里的train路径是不是写成了绝对路径但实际是相对路径,或者path字段拼出来的路径不对。另一个隐蔽情况:图片是.jpeg但脚本里 glob 的是.jpg,YOLO 内部按扩展名匹配,.jpeg可能不被识别,统一改成.jpg最稳。
4.2 现象:训练 loss 一直是 nan 或者不下降
原因:标签坐标超出 0~1 范围,或者某行字段数不对。YOLO 对异常标签的容忍度有限,一个坏标签可能让整个 batch 的 loss 炸掉。
解决:用校验脚本里的bad_lines计数,定位到具体文件。常见的是标注工具导出时坐标没归一化,或者图片旋转后坐标没重算。把异常行删掉或修正后重新训。另外检查data.yaml里nc和names数量是否一致,不一致会直接报错,但报错信息不一定直观。
4.3 现象:显存溢出(CUDA out of memory)
原因:batch或imgsz设太大,或者mosaic增强在后期占用额外显存。
解决:先把batch降到 8 或 4,再考虑降imgsz。如果还不行,开amp=True(自动混合精度),能省不少显存。另一个技巧是cache=False,不把图片缓存到内存,用时间换空间。训练后期如果 OOM,可以把mosaic=0.0关掉,mosaic 拼接会生成更大的临时图。
4.4 现象:验证集 mAP 很高但实际推理效果差
原因:验证集和训练集分布太接近,或者验证集太小(158 张)导致指标波动大。另外如果验证集里某些场景(比如夜间)没有覆盖,模型在那些场景下表现会差。
解决:手动抽几张验证集外的道路监控图做推理测试,看实际效果。如果差得多,说明数据分布不够广,需要补充更多场景的图。另一个检查点是推理时的conf阈值,训练默认用 0.25,实际部署可以调到 0.4~0.5 减少误检。
4.5 现象:两类目标数量差异大导致某一类学不好
原因:这份数据集里摩托车和行人的框数量可能不均衡,比如行人框远多于摩托车框,模型会偏向多数类。
解决:先统计类别分布(2.4 节脚本会输出)。如果差异超过 5:1,可以考虑对少数类过采样,或者在 loss 里给少数类更高权重。YOLOv8 本身没有直接的类别权重参数,但可以通过复制少数类图片到训练集来平衡。另一个办法是调整clsloss 的增益,不过这个要改源码,不太推荐新手操作。
5. 进阶技巧:用这份数据集做迁移学习和推理验证
5.1 迁移学习:从通用权重到交通场景微调
yolov8n.pt是在 COCO 上训的,COCO 里本来就有 motorcycle 和 person 类,所以迁移到这份数据集上收敛会很快。但要注意类别映射:COCO 的 person 类 id 是 0,motorcycle 是 3,而这份数据集里 motorcycle 是 0、pedestrian 是 1。直接用 COCO 权重时,模型最后一层的分类头会按新数据集的nc=2重建,前面的特征提取层复用。如果想更充分利用 COCO 的 person 知识,可以在data.yaml里把 pedestrian 的 id 设成和 COCO 一致,但没必要,因为分类头会重训。
微调策略:先冻结 backbone 训 10 个 epoch,再解冻全量训。YOLOv8 里用freeze=10参数冻结前 10 层。这样做的原因是随机初始化的分类头一开始梯度大,全量训容易把预训练特征带偏。冻结阶段让分类头先稳定,再解冻微调。
5.2 推理验证:用训练好的权重跑单图和批量测试
训练完用best.pt做推理:
# 单图推理 yolo detect predict \ model=runs/train/moto_pedestrian/weights/best.pt \ source=./test_images/ \ conf=0.4 \ save=True # 批量测试并输出统计 yolo detect predict \ model=runs/train/moto_pedestrian/weights/best.pt \ source=./test_images/ \ conf=0.4 \ save_txt=True \ save_conf=Trueconf=0.4比默认 0.25 高,减少误检。save_txt=True会把检测结果按 YOLO 格式存成 txt,方便后续做统计(比如统计一帧里有多少行人)。save_conf=True在 txt 里带上置信度,可以按置信度过滤。推理结果图在runs/detect/predict/下,重点看漏检和误检:漏检多就降conf,误检多就升conf,但根本问题还是数据分布和标注质量。
5.3 一个具体技巧:用验证集反推标注问题
验证集 158 张,训练时模型在验证集上的表现能反推标注质量。具体做法:训练完后用best.pt在验证集上推理,把预测结果和原始标注对比,找出那些"模型预测框和标注框 IoU 很低"的图。这些图要么是标注框画歪了,要么是模型没学好。如果是前者,修正标注后重新训;如果是后者,看是不是这类场景在训练集里太少。
from ultralytics import YOLO import cv2 from pathlib import Path model = YOLO('runs/train/moto_pedestrian/weights/best.pt') val_imgs = Path('./dataset/images/val').glob('*.jpg') for img_path in val_imgs: results = model(str(img_path), conf=0.25, verbose=False) # 读取原始标注 lbl_path = Path(str(img_path).replace('images', 'labels').replace('.jpg', '.txt')) if not lbl_path.exists(): continue gt_boxes = [] for line in lbl_path.read_text().strip().splitlines(): parts = line.split() gt_boxes.append([float(x) for x in parts[1:]]) # 对比预测框和标注框数量,差异大的图重点看 pred_count = len(results[0].boxes) if results[0].boxes else 0 if abs(pred_count - len(gt_boxes)) > 2: print(f'{img_path.name}: 标注 {len(gt_boxes)} 框, 预测 {pred_count} 框')这段代码不直接算 IoU,而是用框数量差异做粗筛。差异大的图人工看一眼,大概率能发现标注问题。参数上conf=0.25是推理阈值,调低能召回更多框,但也会引入误检,粗筛阶段用默认值就行。
从那以后我每次拿到新数据集,都强制先跑一遍校验脚本再开训,宁可花十分钟查标注,也不愿等两小时发现 loss 不降。希望帮到你。
本文还有配套的精品资源,点击获取