电动车摩托车违规检测YOLO数据集:从标注到训练落地
简介这是一份面向计算机视觉与智能交通方向学习者的YOLO格式目标检测数据集聚焦电动车、摩托车骑行中的违规行为识别可用于训练不戴头盔、骑行中使用手机等场景的检测模型适合课程设计、毕业项目或算法验证使用。压缩包共1883个文件包含940张jpg图像、941个txt标注文件以及1个可视化py脚本和1个png示例图整体约56.63MB按YOLOv5目录结构组织可直接投入训练。数据划分为训练集约700张、验证集约180张类别共5类具体类别名称可参考随附的classes文件。配套可视化脚本无需修改随机传入一张图片即可绘制边界框并保存到当前目录便于快速检查标注质量。目前已有531人学习下载资源还附带了YOLOv5改进实战系列文章入口方便进一步拓展模型优化思路。1. 电动车摩托车违规检测数据集从标注到 YOLO 训练的一条龙落地城市交通治理里电动车和摩托车的违规行为识别一直是个高频刚需闯红灯、逆行、不戴头盔、违规载人、占用机动车道这些场景在路口摄像头里每天都在发生。但真正动手做过的人都知道难点从来不在模型结构而在数据——你手上有没有一份标注规范、类别清晰、划分合理的 YOLO 数据集直接决定了后面训练是顺风顺水还是反复翻车。这个标题讲的正是这件事一份面向电动车、摩托车违规目标检测的 YOLO 数据集配套划分好的训练/验证/测试集、类别 class 文件以及一套数据可视化脚本让你拿到手就能看清数据长什么样、类别分布是否均衡、标注框有没有问题。它适合两类人一类是想快速跑通 YOLO 目标检测流程、又不想从零标注的算法工程师另一类是做智慧交通、园区安防、外卖骑手管理等场景的产品和开发需要判断这个方向值不值得投入。下面我按自己实际做这类项目的顺序把数据集结构、class 文件写法、可视化脚本、训练配置和踩坑点一层层拆开讲。2. 数据集结构与 class 文件先搞清楚你拿到的是什么2.1 目录布局与划分逻辑一份能直接用于 YOLO 训练的数据集目录结构通常长这样我一般会先tree一遍确认没有多余层级dataset/ ├── images/ │ ├── train/ # 训练集图片 │ ├── val/ # 验证集图片 │ └── test/ # 测试集图片 ├── labels/ │ ├── train/ # 训练集标注.txt │ ├── val/ │ └── test/ ├── classes.txt # 类别名一行一个 └── data.yaml # YOLO 训练入口配置这里的关键是images和labels必须严格镜像对应images/train/abc.jpg对应labels/train/abc.txt文件名不含扩展名完全一致。YOLO 在训练时是按文件名去匹配标签的一旦对不上那张图就会被当成无目标背景图训练日志里 loss 看着正常实际模型学不到东西这是最隐蔽的坑之一。划分比例上违规检测这类场景我一般用 7:2:1 或 8:1:1。原因是违规行为本身是长尾分布——不戴头盔的样本可能远多于违规载人验证集太小会导致 mAP 抖动剧烈你根本判断不了模型是真的变好还是随机波动。如果原始数据里某些类别样本极少宁可做过采样也不要硬凑划分。2.2 class 文件与 data.yaml 的写法classes.txt决定类别索引顺序这个顺序一旦定了就不能改因为所有.txt标签里的第一个数字就是类别索引。违规检测常见的类别定义如下helmet # 0 戴头盔 no_helmet # 1 未戴头盔 motorcycle # 2 摩托车 ebike # 3 电动车 illegal_passenger # 4 违规载人 red_light_violation # 5 闯红灯对应的data.yamlpath: /home/user/dataset # 数据集根目录绝对路径最稳 train: images/train val: images/val test: images/test nc: 6 # 类别数量必须和 classes.txt 行数一致 names: # 顺序必须和 classes.txt 完全一致 0: helmet 1: no_helmet 2: motorcycle 3: ebike 4: illegal_passenger 5: red_light_violation参数说明nc写错是最常见的低级错误写成 5 而实际有 6 类训练不会报错但最后一类永远学不出来names的键值顺序如果和标签索引错位模型会把「戴头盔」识别成「闯红灯」可视化时一眼能看出来但训练时毫无提示。我一般会在训练前跑一段校验脚本把标签里出现的最大类别索引和nc对比一遍。提示标签文件每行格式是class_id x_center y_center width height后四个都是归一化到 0~1 的相对值。如果你拿到的是像素坐标的标注必须先转换否则框会全部跑到图像外面。3. 数据可视化脚本训练前先让数据自己说话3.1 用脚本把标注框画回原图在把数据丢进训练之前我一定会先做可视化。原因很简单标注错误、类别错位、框跑偏这些问题肉眼看图三秒就能发现但靠训练 loss 可能要跑几个小时才暴露。下面这段脚本把 YOLO 格式的标签还原成框画在图上import cv2 import os import random # 类别名顺序必须和 classes.txt 一致 CLASSES [helmet, no_helmet, motorcycle, ebike, illegal_passenger, red_light_violation] # 每个类别一个颜色方便肉眼区分 COLORS [(0,255,0), (0,0,255), (255,0,0), (255,255,0), (255,0,255), (0,255,255)] def draw_boxes(img_path, label_path, save_path): img cv2.imread(img_path) h, w img.shape[:2] # 原图高宽用于反归一化 if os.path.exists(label_path): with open(label_path) as f: for line in f: cid, xc, yc, bw, bh map(float, line.split()) cid int(cid) # 归一化坐标还原成像素坐标 x1 int((xc - bw/2) * w) y1 int((yc - bh/2) * h) x2 int((xc bw/2) * w) y2 int((yc bh/2) * h) cv2.rectangle(img, (x1,y1), (x2,y2), COLORS[cid], 2) cv2.putText(img, CLASSES[cid], (x1, y1-5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, COLORS[cid], 2) cv2.imwrite(save_path, img) # 随机抽 20 张训练图做抽查 img_dir dataset/images/train lbl_dir dataset/labels/train os.makedirs(vis_out, exist_okTrue) samples random.sample(os.listdir(img_dir), 20) for name in samples: stem os.path.splitext(name)[0] draw_boxes(os.path.join(img_dir, name), os.path.join(lbl_dir, stem .txt), os.path.join(vis_out, name))逻辑说明核心是反归一化那四行xc, yc是框中心点bw, bh是框宽高都乘回原图尺寸才能得到像素坐标。参数上COLORS和CLASSES必须一一对应否则颜色和文字会错位。抽 20 张是经验值太少看不出分布问题太多浪费时间。3.2 类别分布统计与长尾排查光看图还不够违规检测最容易死在类别不均衡上。我一般再跑一段统计把每个类别的框数量打出来from collections import Counter counter Counter() for lbl in os.listdir(dataset/labels/train): with open(os.path.join(dataset/labels/train, lbl)) as f: for line in f: counter[int(line.split()[0])] 1 for cid, name in enumerate(CLASSES): print(f{name:22s}: {counter[cid]})如果发现no_helmet有 8000 个框而red_light_violation只有 200 个那训练时后者基本会被淹没。常见做法是对稀有类别做复制增强或者在 loss 里给类别加权。这里要提醒一句YOLO 的类别权重不像分类任务那么好调更稳的办法还是从数据侧补样本别指望靠调参救长尾。注意统计时如果某个类别数量为 0说明你的数据集里根本没有这类样本但data.yaml里却声明了它。这种情况训练不报错但该类 mAP 恒为 0别以为是模型不行是数据里就没有。4. 训练配置与参数让违规检测真正跑起来4.1 从预训练权重起步的训练命令违规检测数据量通常不大从零训练几乎必然过拟合标准做法是加载预训练权重做微调。以常见的 YOLOv8 训练入口为例yolo detect train \ datadataset/data.yaml \ modelyolov8n.pt \ # 轻量模型边缘部署友好 epochs100 \ imgsz640 \ batch16 \ lr00.01 \ # 初始学习率 patience20 \ # 20 轮无提升就早停 projectruns/violation \ nameexp1参数说明imgsz640是速度和精度的平衡点路口远景小目标多的话可以提到 960但显存和耗时都会涨batch要根据显存调爆显存就减半patience是后悔药防止你盯着一个已经不涨的模型白跑几十轮。model选 n/s/m 取决于你的部署端如果是 Jetson 或边缘盒子n 或 s 更现实。4.2 违规检测特有的增强与评估关注点通用增强里mosaic和mixup对小目标有帮助但违规检测有个特殊点戴不戴头盔、有没有载人这些是语义细节过度裁剪或缩放会把关键区域切掉反而让模型学偏。我的经验是把mosaic概率适当调低scale抖动范围收窄保证头盔、人体这些关键部位完整。评估时别只看总 mAP要分类别看。违规检测里no_helmet和helmet极易混淆因为两者外观高度相似差别只在头部那一小块区域。如果这两类 mAP 差距大优先回去看标注是否一致——同一个骑手有的标了no_helmet有的标了helmet模型直接懵。混淆矩阵在这里比 loss 曲线有用得多。提示训练中如果出现 BN 层相关报错或 loss 突然变 NaN先检查 batch 是不是太小小于 2 时 BN 统计不稳再检查学习率是不是过大。这类问题在违规检测小数据集上比通用检测更常见。5. 避坑与排查违规检测数据集最容易翻车的五个地方5.1 标签索引与 class 文件错位现象训练正常收敛但可视化预测结果时明明是不戴头盔却显示成电动车。原因classes.txt的顺序和生成标签时的顺序不一致或者中途改过类别顺序。解决类别顺序一旦确定就冻结任何改动都要重新生成全部标签并在训练前用校验脚本比对标签里的最大索引和nc。5.2 图片与标签文件名不匹配现象训练 loss 一直偏高且不下降验证集 mAP 极低。原因images和labels里存在文件名对不上的样本YOLO 把有图无标签的当成纯背景图训练。解决写一段脚本遍历两个目录找出差集缺标签的图要么补标要么删掉别留着当噪声。5.3 归一化坐标越界现象可视化时框跑到图像外面或者框只有一半。原因标注工具导出的是像素坐标被直接当成归一化坐标用了或者手工标注时坐标算错。解决训练前统一检查每行后四个值是否都在 0~1 之间越界的直接标红人工复核。5.4 类别极度不均衡导致稀有类失效现象总 mAP 看着还行但闯红灯、违规载人这类 mAP 接近 0。原因稀有类样本太少被高频类淹没。解决从数据侧补样本优先其次考虑过采样和增强别一上来就猛调 loss 权重容易把高频类也带崩。5.5 验证集与训练集场景重叠现象验证集 mAP 很高一上真实路口就拉胯。原因划分时按随机抽帧同一段视频的相邻帧同时进了训练和验证等于变相泄漏。解决按视频源或时间段划分保证验证集来自训练时没见过的场景这样评估出来的数字才可信。6. 把可视化脚本用成日常习惯一个我坚持了三年的小技巧做违规检测这几年我最大的教训不是模型选错而是太晚看数据。早期我总想着先把训练跑起来再说结果跑了一晚上发现标签全是错的那种感觉比调参调不动还难受。后来我养成了一个习惯任何新数据集到手第一件事不是配环境而是跑可视化脚本随机抽 30 张图把框和类别名画出来一张一张翻。这个动作花不了十分钟但能挡掉后面百分之八十的玄学问题。具体做法上我会把可视化脚本改成一个可复用的小工具支持三个模式单张抽查、批量抽样、按类别过滤。按类别过滤特别有用——比如我只想看no_helmet的样本就把该类别的图单独抽出来集中看标注一致性一眼就能判断。下面这个过滤逻辑我用了很久def filter_by_class(label_dir, target_cid): 找出包含指定类别的所有标签文件名 hits [] for lbl in os.listdir(label_dir): with open(os.path.join(label_dir, lbl)) as f: ids [int(line.split()[0]) for line in f] if target_cid in ids: hits.append(lbl) return hits # 例只看未戴头盔的样本 no_helmet_files filter_by_class(dataset/labels/train, 1) print(f未戴头盔样本数: {len(no_helmet_files)})这个函数返回的是标签文件名列表配合前面的draw_boxes就能把某一类样本全部可视化出来。参数target_cid就是classes.txt里的行号改一个数字就能切换类别。我一般会重点看两类数量最少的稀有类和最容易混淆的相似类比如戴头盔 vs 不戴头盔。前者决定模型能不能学到后者决定模型学得准不准。还有一个验证技巧训练完成后别只看验证集指标把测试集的可视化结果和真实标注并排画出来左边是 GT右边是预测。违规检测里经常出现「框对了但类别错了」的情况这种错误在 mAP 数字上体现不明显但并排一看就无所遁形。我靠这个办法揪出过好几次标注和预测的系统性偏差。说到底数据集和可视化脚本不是训练前的准备工作而是贯穿整个项目的习惯。模型结构可以换预训练权重可以换但你对数据的理解程度才是决定这个违规检测方案能不能真正落地的分水岭。希望帮到你。本文还有配套的精品资源点击获取