电动车摩托车违规检测数据集:YOLO训练与可视化实战

发布时间:2026/9/28 11:21:18
电动车摩托车违规检测数据集:YOLO训练与可视化实战 简介这份资源面向计算机视觉初学者与目标检测实战开发者聚焦电动车、摩托车骑行场景中的违规行为识别可用于课程设计、竞赛练手或算法验证。数据按YOLOv5目录结构组织可直接投入训练与推理无需额外整理。压缩包共1883个文件以940张jpg图像和941个txt标注文件为主体另附1个可视化py脚本与1个png示例图整体约56.63MB。类别共5类涵盖不戴头盔、使用手机等违规情形具体以classes文件为准训练集约700张、验证集约180张划分清晰。可视化脚本无需修改随机传入一张图片即可绘制边界框并保存到当前目录便于快速核验标注质量。目前已有531人学习下载适合希望低成本上手YOLO违规检测、快速搭建基线并迭代改进的读者参考使用。1. 电动车摩托车违规检测数据集从标注到可视化一套能直接开训的 YOLO 方案城市道路监控里最让算法工程师头疼的往往不是行人检测而是电动车和摩托车的违规行为识别。这类目标尺寸小、遮挡严重、姿态多变更麻烦的是数据集难搞——网上开源的多是通用 COCO 或 VOC真正带违规类别标注的少之又少。我手上这套方案核心就是解决「有模型没数据」的尴尬一份已经划分好训练集/验证集/测试集的电动车摩托车违规目标图像数据集配套类别 class 文件再加一个数据可视化脚本让你拿到手就能跑 YOLOv8 训练不用再花两周时间从零标注。适合正在做智慧交通、园区安防、外卖骑手管理这类项目的从业者也适合想拿真实场景练手 YOLO 训练流程的开发者。下面从数据集结构、class 文件写法、可视化脚本、训练参数到踩坑记录一步步拆开讲。2. 数据集目录结构与 class 文件YOLO 训练前必须对齐的三件事2.1 划分好的数据集长什么样一套能直接喂给 YOLOv8 的数据集目录结构必须严格遵循 Ultralytics 的约定。我见过太多人把图片和标签混在一起或者 train/val 的 images 和 labels 没有平行对应结果训练脚本报No labels found直接翻车。这套电动车摩托车违规数据集的标准结构如下dataset/ ├── images/ │ ├── train/ # 训练集图片jpg/png 格式 │ ├── val/ # 验证集图片 │ └── test/ # 测试集图片可选用于最终评估 ├── labels/ │ ├── train/ # 训练集标签txt 格式与图片同名 │ ├── val/ # 验证集标签 │ └── test/ # 测试集标签 └── data.yaml # 数据集配置文件关键点在于images/train/下的每一张abc.jpg必须在labels/train/下有一个同名的abc.txt。如果某张图没有对应标签YOLO 会把它当作负样本背景图处理这本身没问题但如果你本意是漏标了就会引入噪声。我一般会在训练前跑一个校验脚本统计图片数和标签数的差值超过 5% 就回去查标注。2.2 class 文件与 data.yaml 的写法标题里提到的「类别 class 文件」通常有两种形式一种是纯文本的classes.txt每行一个类别名另一种是直接写进data.yaml的names字段。YOLOv8 官方推荐后者因为一个文件搞定路径和类别少一个出错环节。这套数据集的类别定义我按违规检测场景拆成了 6 类# data.yaml path: ./dataset train: images/train val: images/val test: images/test nc: 6 names: 0: ebike_normal # 电动车正常行驶 1: ebike_violation # 电动车违规闯红灯/逆行/载人超员 2: motorcycle_normal # 摩托车正常行驶 3: motorcycle_violation # 摩托车违规 4: rider_no_helmet # 骑手未戴头盔 5: license_plate # 车牌区域辅助识别这里有个血泪经验类别顺序一旦定下训练中途绝对不能改。我见过有人训练到一半觉得「未戴头盔」应该放前面改了names顺序重新训结果模型把违规和正常完全搞反。因为 YOLO 的标签文件里存的是类别索引0,1,2...不是类别名。改names顺序等于把索引含义换了模型学到的映射全乱。要改就从头重训没有后悔药。2.3 标签格式YOLO txt 的五个数值每张图的标签 txt 里每一行代表一个目标格式是class_id x_center y_center width height五个值都是归一化到 0~1 的浮点数x_center和y_center是框中心点相对整图宽高的比例width和height是框宽高相对整图宽高的比例。举个例子一张 1920x1080 的图里有个电动车违规框在左上角 (100, 200) 到 (400, 500)那么1 0.1302 0.3241 0.1563 0.2778计算方式x_center (100400)/2/1920 0.1302y_center (200500)/2/1080 0.3241width (400-100)/1920 0.1563height (500-200)/1080 0.2778。注意如果你的标注工具导出的是 VOC 的 xml 或 COCO 的 json必须转成这种归一化 txt。转换脚本网上一搜一大把但一定要检查转换后的数值是否在 0~1 之间超出范围的框会在训练时被自动过滤等于白标。3. 数据可视化脚本训练前先看一眼别等 loss 不降才后悔3.1 为什么要自己写可视化YOLOv8 训练时会自动生成train_batch0.jpg这类可视化图但那是训练启动之后的事。如果你数据集有问题——比如标签全挤在左上角、类别索引写错、图片和标签错位——等你看到 loss 不降再回头查半天已经过去了。我习惯在训练前跑一个独立可视化脚本把带框的图抽样画出来肉眼扫一遍。这套方案里的可视化脚本就是干这个的基于 OpenCV 和 matplotlib不依赖 ultralytics跑起来快。3.2 可视化脚本完整代码import cv2 import os import random import matplotlib.pyplot as plt import matplotlib.patches as patches # 类别名与颜色映射和 data.yaml 保持一致 CLASS_NAMES { 0: ebike_normal, 1: ebike_violation, 2: motorcycle_normal, 3: motorcycle_violation, 4: rider_no_helmet, 5: license_plate } COLORS { 0: (0, 255, 0), # 绿色正常 1: (255, 0, 0), # 红色违规 2: (0, 200, 0), 3: (255, 50, 50), 4: (255, 165, 0), # 橙色未戴头盔 5: (0, 0, 255) # 蓝色车牌 } def visualize_sample(img_dir, label_dir, num_samples6): 随机抽样可视化检查标签与图片是否对齐 img_files [f for f in os.listdir(img_dir) if f.endswith((.jpg, .png))] samples random.sample(img_files, min(num_samples, len(img_files))) fig, axes plt.subplots(2, 3, figsize(18, 10)) axes axes.flatten() for ax, img_file in zip(axes, samples): img_path os.path.join(img_dir, img_file) label_path os.path.join(label_dir, img_file.rsplit(., 1)[0] .txt) img cv2.imread(img_path) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) h, w img.shape[:2] ax.imshow(img) if os.path.exists(label_path): with open(label_path, r) as f: for line in f.readlines(): parts line.strip().split() if len(parts) ! 5: continue cls_id int(parts[0]) xc, yc, bw, bh map(float, parts[1:]) # 反归一化到像素坐标 x1 (xc - bw / 2) * w y1 (yc - bh / 2) * h box_w bw * w box_h bh * h color COLORS.get(cls_id, (255, 255, 255)) rect patches.Rectangle( (x1, y1), box_w, box_h, linewidth2, edgecolor[c/255 for c in color], facecolornone ) ax.add_patch(rect) ax.text(x1, y1 - 5, CLASS_NAMES.get(cls_id, str(cls_id)), colorwhite, fontsize8, bboxdict(facecolor[c/255 for c in color], alpha0.7)) else: ax.set_title(f{img_file} - NO LABEL, colorred) ax.axis(off) plt.tight_layout() plt.savefig(visualization_check.jpg, dpi150) plt.show() print(可视化结果已保存为 visualization_check.jpg) if __name__ __main__: visualize_sample( img_dirdataset/images/train, label_dirdataset/labels/train, num_samples6 )逻辑说明脚本从训练集随机抽 6 张图读入对应标签把归一化坐标反算回像素坐标用 matplotlib 画框和类别名。颜色按类别区分正常行驶用绿色系违规用红色系未戴头盔用橙色车牌用蓝色。跑完会弹窗显示并保存一张visualization_check.jpg。参数说明num_samples控制抽样数量默认 6想看得更全可以调到 12 或 20img_dir和label_dir要指向同一划分train 对 trainval 对 val如果指错了会出现大量NO LABEL红字标题那就是路径配错了。3.3 看可视化图时重点查什么第一框的位置对不对。如果框整体偏移多半是标注工具导出时坐标系没统一有的用左上角原点有的用中心点。第二类别颜色对不对。电动车违规框应该是红色如果出现绿色说明类别索引写错了。第三有没有漏标。一张图里明显有电动车但没框回去补标。第四小目标框是不是太小。电动车在远景里可能只有 20x30 像素这种框如果太多训练时要把imgsz调大否则模型根本学不到。提示可视化脚本不要只跑训练集验证集也跑一遍。我遇到过训练集标签没问题、验证集标签整体错位的情况原因是划分数据时用脚本复制文件标签复制漏了重新生成坐标基准变了。这种问题不提前查训完 mAP 低得莫名其妙。4. YOLOv8 训练参数怎么设从 imgsz 到 batch 的实操建议4.1 环境配置与预训练模型选择训练前先把环境搭好。YOLOv8 用 ultralytics 包一条命令装完pip install ultralytics如果你有 NVIDIA 显卡确认 CUDA 可用python -c import torch; print(torch.cuda.is_available())输出True才能用 GPU 训。预训练模型我一般选yolov8s.pt或yolov8m.pt。电动车摩托车这类目标不算特别小但违规行为需要看细节比如有没有戴头盔yolov8s在精度和速度之间比较平衡显存 8G 以上就能跑。如果显存只有 6G用yolov8n.pt但 mAP 会掉几个点。yolov8l和yolov8x精度更高但训练慢适合最终交付版本。4.2 关键训练参数逐项说明启动训练的命令行方式yolo detect train \ datadataset/data.yaml \ modelyolov8s.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ device0 \ projectruns/train \ nameebike_violation_v1逐项拆解imgsz640是输入分辨率。电动车在监控画面里往往只占几十像素640 够用但如果你的数据里目标普遍偏小调到 960 或 1280代价是显存翻倍、速度变慢。我一般先用 640 跑一轮看 mAP不够再升。batch16是批大小。8G 显存跑 640 分辨率yolov8s用 16 比较稳。如果报CUDA out of memory先降到 8再不行降到 4。不要盲目开梯度累积来模拟大 batchYOLO 的 BN 层对 batch 大小敏感太小会导致 BN 统计不准训练崩溃。lr00.01是初始学习率。YOLOv8 默认用 SGD 优化器时 lr00.01用 AdamW 时建议降到 0.001。如果你发现 loss 前期震荡厉害先降 lr0 到 0.005 试试。patience20是早停耐心值。20 个 epoch 验证集 mAP 不升就停省时间。但如果你数据量小比如几千张建议设到 30 或 50给小数据集更多收敛机会。epochs100是最大轮数。实际跑下来这套数据集在 60~80 epoch 左右 mAP 就趋于稳定。100 是上限有 patience 兜底不会白跑。4.3 训练过程看什么指标训练启动后终端会打印每个 epoch 的 box_loss、cls_loss、dfl_loss 和 mAP50、mAP50-95。重点看三个box_loss 持续下降说明框回归在学如果 box_loss 不降反升检查标签坐标是不是有问题。cls_loss 下降说明分类在学如果 cls_loss 一直很高可能是类别不平衡——违规样本远少于正常样本这时候要在 data.yaml 里加类别权重或者对违规类别做过采样。mAP50 是 IoU0.5 时的平均精度电动车检测一般能到 0.85 以上算不错mAP50-95 更严格能到 0.6 以上说明框的位置很准。训练完在runs/train/ebike_violation_v1/下会生成weights/best.pt和weights/last.pt。用 best.pt 做推理yolo detect predict \ modelruns/train/ebike_violation_v1/weights/best.pt \ sourcetest_images/ \ conf0.4 \ saveTrueconf0.4是置信度阈值。违规检测场景我建议设 0.4~0.5宁可漏检也不要误报——把正常行驶的电动车误判成违规比漏掉一个违规更让人头疼。如果做的是抓拍取证可以降到 0.3 提高召回但后面要加人工复核。5. 避坑与排查电动车违规检测训练中最容易翻车的 5 个点5.1 现象训练 loss 正常下降但 mAP 一直是 0原因标签文件里的类别索引超出了nc定义的范围。比如data.yaml写了nc: 6但某个标签 txt 里出现了6或更大的数字YOLO 会忽略这个框如果大部分框都这样mAP 就是 0。解决跑一行命令检查所有标签的最大类别索引cat dataset/labels/train/*.txt | awk {print $1} | sort -n | uniq输出应该只有 0 到 5。出现 6 以上就找到对应文件改掉。5.2 现象训练到一半 loss 突然变成 NaN原因学习率太大或者某个 batch 里出现了宽高为 0 的框。宽高为 0 的框在计算 IoU 时会产生除零梯度爆炸。解决先降 lr0 到 0.001 重跑。如果还 NaN用脚本过滤掉宽高小于 0.001 的框import os def clean_labels(label_dir): for fname in os.listdir(label_dir): if not fname.endswith(.txt): continue path os.path.join(label_dir, fname) valid_lines [] with open(path, r) as f: for line in f: parts line.strip().split() if len(parts) ! 5: continue _, _, _, bw, bh map(float, parts) if bw 0.001 and bh 0.001: valid_lines.append(line) with open(path, w) as f: f.writelines(valid_lines) clean_labels(dataset/labels/train) clean_labels(dataset/labels/val)5.3 现象验证集 mAP 比训练集低很多差距超过 0.2原因过拟合或者训练集和验证集分布不一致。常见于划分数据时没有随机打乱训练集全是白天、验证集全是夜晚。解决重新划分数据确保 train/val 的类别分布和场景分布接近。用sklearn的train_test_split按类别分层抽样from sklearn.model_selection import train_test_split import os all_imgs [f for f in os.listdir(dataset/images/all) if f.endswith(.jpg)] # 按文件名前缀或场景标签分层这里简化为随机 train, val train_test_split(all_imgs, test_size0.2, random_state42)5.4 现象模型把电动车和摩托车搞混原因这两类目标外观相似尤其远景下轮廓几乎一样。类别定义时如果只靠形状区分模型很难学。解决在类别定义上做区分——电动车看踏板和车牌颜色绿牌摩托车看油箱和排气管。如果数据里这些特征不明显考虑合并成「两轮车」一个大类再单独训一个违规行为分类模型。我一般建议先合并训检测再对检测框做二次分类比强行分两类效果好。5.5 现象推理时框重叠严重同一个目标出好几个框原因NMS非极大值抑制的 IoU 阈值设太高或者模型对同一目标产生了多个高置信度预测。解决推理时加iou参数yolo detect predict modelbest.pt sourcetest/ iou0.5 conf0.4iou0.5是默认值重叠框多就降到 0.4 或 0.3。但注意降太低会把相邻的两个电动车合并成一个框要根据实际画面调。6. 进阶技巧用可视化脚本反查标注质量把 mAP 再提 3 个点训练完一轮后别急着调参。我习惯把可视化脚本改一改让它同时画出模型预测框和真实标签框对比着看。预测框用实线标签框用虚线颜色区分。这样一眼就能看出模型在哪里犯错是漏检了违规电动车还是把正常行驶误判成违规。具体做法是在可视化脚本里加载best.pt对每张抽样图跑一次推理拿到预测结果后和标签一起画。核心代码片段from ultralytics import YOLO model YOLO(runs/train/ebike_violation_v1/weights/best.pt) results model(img_path, conf0.4) # results[0].boxes.xyxy 是预测框像素坐标 # results[0].boxes.cls 是预测类别 # results[0].boxes.conf 是置信度把预测框画成实线标签框画成虚线重叠在一起看。如果某个违规电动车标签框在但预测框没有说明模型漏检——回去看这类样本是不是太少做针对性补充。如果预测框有但标签没有可能是漏标也可能是模型误报——结合画面判断。这个反查流程我跑了十几套数据集平均能找出 5%~10% 的标注问题。修完再训一轮mAP 通常能提 2~3 个点。比盲目调学习率、换模型结构有效得多。还有一个习惯每次训练完把best.pt在测试集上跑一遍用yolo detect val生成混淆矩阵。重点看「ebike_violation」和「ebike_normal」之间的混淆——这两个类最容易串。如果混淆矩阵显示违规被大量判成正常说明违规样本的特征不够突出要么补数据要么在损失函数里给违规类加权。yolo detect val \ modelruns/train/ebike_violation_v1/weights/best.pt \ datadataset/data.yaml \ splittest \ plotsTrueplotsTrue会生成混淆矩阵、PR 曲线、F1 曲线存在runs/val/下。这些图比数字更直观尤其 PR 曲线能看出每个类别的召回和精度平衡点在哪。电动车违规检测这种场景我一般要求违规类的召回不低于 0.8精度不低于 0.7达不到就继续补数据。这套流程走下来从拿到数据集到出一个能用的违规检测模型大概两三天。关键不在模型多复杂而在数据质量查得够不够细。我踩过的坑基本都写在上面了希望帮到你。本文还有配套的精品资源点击获取