E_bicycle2电动车数据集:994张xml标注,快速训练YOLOv5检测模型
简介本资源面向从事机器视觉与目标检测的开发者及学生聚焦非机动车违规停放场景下的电动车识别任务提供YOLOv5可直接训练使用的已标注数据集。压缩包内共1976个文件以994张jpg图片和982个xml标注文件为主图片用于模型输入xml对应VOC格式标注框整体约160.58MB解压后即可投入训练与验证。该批数据属于电动车E_bicycle2分类涵盖共享电动车等多种车型样本数量约994张标注完整、类别清晰可有效支撑违规停放检测、车辆类型识别等实验。目前已有211人学习下载适合需要快速搭建非机动车检测基线、验证YOLOv5训练流程或补充电动车样本的读者能省去自行采集与标注的时间成本直接用于模型调参与效果对比。1. 电动车违规停放识别为什么我盯上了这份 E_bicycle2 标注数据上个月帮朋友看一个园区非机动车违停抓拍的项目算法侧其实不复杂难的是数据。你要让模型分清“这辆电动车是停在框里还是横在消防通道上”首先得让模型认识电动车本身。翻了一圈公开数据集要么是 COCO 里那点零星的 bicycle/motorcycle 类别要么是街景里糊成一团的远景车流真正能拿来训 yolov5 的、已经标好 xml 的电动车数据少得可怜。这份 E_bicycle2 就是在这个背景下被我翻出来的——它是整个非机动车数据集里电动车大类的第二个子类994 张共享电动车图片配套完整的 xml 标注直接对应 yolov5 训练所需的 images labels 结构。适合谁做智慧园区、社区违停治理、共享单车运维识别的同学尤其是想跳过“自己标几千张图”这个苦力阶段、直接进入模型调优的人。它解决的不是算法问题是数据冷启动问题。2. 拆开 E_bicycle2994 张图与 xml 标注到底怎么组织2.1 目录结构与文件命名规律拿到压缩包先别急着解压到训练目录我一般会先在一个临时目录里铺开看结构。这份资源的组织方式很朴素图片和标注是分开的命名靠文件名对齐。典型结构长这样E_bicycle2/ ├── images/ │ ├── 共享电动车_777.jpg │ ├── 共享电动车_642.jpg │ ├── 共享电动车_114.jpg │ └── ...共 994 张 └── annotations/ ├── 共享电动车_777.xml ├── 共享电动车_642.xml ├── 共享电动车_114.xml └── ...共 994 个这里有个细节值得说文件名用的是中文“共享电动车_编号”而不是常见的 000001.jpg 这种纯数字。中文名在 Linux 下没问题但一旦你走 Docker 挂载或者某些老版本的 OpenCV 读取路径就可能踩到编码坑。我一般会在转换阶段顺手把文件名规范化成英文或纯数字后面省心。# 批量重命名把中文前缀去掉只保留编号 cd E_bicycle2/images for f in 共享电动车_*.jpg; do newname$(echo $f | sed s/共享电动车_//) mv $f $newname done这段脚本做的事很简单遍历所有以“共享电动车_”开头的 jpg把前缀替换掉。sed s/共享电动车_//是删除匹配到的中文前缀mv完成重命名。执行前建议先ls | head确认一下命名是否统一如果混入了别的命名格式脚本会漏掉那些文件。标注目录同理跑一遍保证 images 和 annotations 里的文件名严格一一对应这是后面转 YOLO 格式不出错的前提。2.2 xml 标注里到底存了什么xml 是 PASCAL VOC 格式用文本编辑器打开一个看看核心信息就几块filename对应图片名size记录宽高和通道数object里是类别名和bndbox的 xmin/ymin/xmax/ymax。这份数据里 object 的 name 基本就是“电动车”或类似标签具体以你解压后看到的为准。annotation filename共享电动车_777.jpg/filename size width640/width height480/height depth3/depth /size object nameebicycle/name bndbox xmin112/xmin ymin203/ymin xmax398/xmax ymax441/ymax /bndbox /object /annotation看 xml 的时候我习惯抽查三件事一是 bndbox 有没有超出图片宽高越界框会让训练直接报错二是 name 字段是否统一有的标注里混了大小写或中英文类别数会翻倍三是空标注文件没有 object 的 xml占比多少。994 张里如果有个位数空标注直接删掉对应图片即可如果几十张都空那这批数据可能有一部分是负样本得单独处理。2.3 为什么选 yolov5 而不是别的检测器有人会问现在检测器这么多为什么这份数据配的是 yolov5我的判断很实际yolov5 的工程化程度高数据格式转换脚本成熟社区里踩过的坑最多你遇到问题基本能搜到答案。更重要的是它对中小规模数据集友好994 张图做单类检测配合预训练权重迁移学习收敛很快。换成需要复杂 anchor 调优或者对标注格式挑剔的框架光数据适配就能耗掉你两天。这份数据的定位就是“拿来即训”yolov5 是阻力最小的路径。3. 从 xml 到 yolov5 训练格式转换与配置文件落地3.1 VOC 转 YOLO 的转换脚本yolov5 要的不是 xml是每张图对应一个 txt每行class_id x_center y_center width height且坐标要归一化到 0~1。这个转换我写过不下十遍下面这版是稳定能用的import os import xml.etree.ElementTree as ET # 类别映射按你实际 xml 里的 name 来改 classes [ebicycle] def convert_annotation(xml_path, label_path): tree ET.parse(xml_path) root tree.getroot() size root.find(size) w int(size.find(width).text) h int(size.find(height).text) with open(label_path, w) as out: for obj in root.iter(object): cls_name obj.find(name).text.strip() if cls_name not in classes: continue cls_id classes.index(cls_name) bndbox obj.find(bndbox) xmin float(bndbox.find(xmin).text) ymin float(bndbox.find(ymin).text) xmax float(bndbox.find(xmax).text) ymax float(bndbox.find(ymax).text) # 归一化并转为中心点宽高 x_center (xmin xmax) / 2.0 / w y_center (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h out.write(f{cls_id} {x_center:.6f} {y_center:.6f} {bw:.6f} {bh:.6f}\n) # 批量执行 xml_dir E_bicycle2/annotations label_dir E_bicycle2/labels os.makedirs(label_dir, exist_okTrue) for f in os.listdir(xml_dir): if f.endswith(.xml): name os.path.splitext(f)[0] convert_annotation( os.path.join(xml_dir, f), os.path.join(label_dir, name .txt) )逻辑说明先解析 xml 拿到图片宽高再遍历每个 object把 VOC 的左上右下坐标换算成 YOLO 的中心点加宽高并除以宽高做归一化。classes列表必须和 xml 里的 name 完全一致多一个空格都会导致类别匹配失败、该框被跳过。:.6f是保留六位小数精度足够也避免科学计数法。跑完之后建议抽查一个 txt用cat看一眼数值是否都在 0~1 之间出现大于 1 的基本就是坐标越界或宽高读错了。3.2 划分训练集与验证集994 张不算多验证集给 10% 到 15% 比较合适太少评估不稳太多训练样本不够。我一般用脚本按比例随机划分并保证图片和标签同步移动import os import random import shutil random.seed(42) # 固定随机种子保证可复现 img_dir E_bicycle2/images lbl_dir E_bicycle2/labels out_root dataset for split in [train, val]: os.makedirs(f{out_root}/images/{split}, exist_okTrue) os.makedirs(f{out_root}/labels/{split}, exist_okTrue) imgs [f for f in os.listdir(img_dir) if f.endswith(.jpg)] random.shuffle(imgs) val_count int(len(imgs) * 0.15) val_imgs imgs[:val_count] train_imgs imgs[val_count:] for split, files in [(train, train_imgs), (val, val_imgs)]: for f in files: name os.path.splitext(f)[0] shutil.copy(f{img_dir}/{f}, f{out_root}/images/{split}/{f}) shutil.copy(f{lbl_dir}/{name}.txt, f{out_root}/labels/{split}/{name}.txt)random.seed(42)是为了每次划分结果一致方便你复现实验。val_count按 15% 算994 张大概 149 张进验证集。复制而不是移动是为了保留原始数据万一划分有问题还能重来。跑完后检查 train 和 val 两个目录下 images 与 labels 的文件数量是否各自相等不等就说明有图片缺对应标签得回去查转换环节。3.3 data.yaml 与模型配置yolov5 训练靠一个 yaml 文件告诉它数据在哪、有几类、类名是什么path: ./dataset train: images/train val: images/val nc: 1 names: [ebicycle]path是数据集根目录train和val是相对 path 的路径。nc是类别数这份数据单类就是 1。names顺序必须和转换脚本里的classes一致否则类别 id 会对错。模型配置直接用 yolov5s.yaml 起步单类小数据集没必要上 l 或 xs 版本在精度和速度之间平衡得最好后续要提精度再换 m。3.4 启动训练与关键参数环境配好后训练命令本身不复杂关键是几个参数python train.py \ --data data/ebicycle.yaml \ --cfg models/yolov5s.yaml \ --weights yolov5s.pt \ --epochs 100 \ --batch-size 16 \ --img-size 640 \ --project runs/train \ --name ebicycle_exp--weights yolov5s.pt是加载官方预训练权重做迁移学习这一步对 994 张的小数据集几乎是必须的从零训会很难收敛。--epochs 100是起步值看验证集 mAP 曲线如果 60 轮后还在涨可以加到 150。--batch-size 16取决于显存8G 显存跑 640 尺寸基本能撑住爆显存就降到 8。--img-size 640是输入分辨率如果你的图片原始尺寸远大于 640可以适当调大但显存占用会平方级上升。训练日志里重点盯三个指标box_loss 是否稳定下降、mAP0.5 是否上升、有没有出现 loss 为 nan 的情况。4. 训练与推理环节的避坑排查4.1 类别名不匹配导致标签全被跳过现象转换脚本跑完labels 目录里全是空 txt或者训练时提示 “no labels found”。 原因xml 里的name字段和你脚本里classes列表不一致可能是大小写差异也可能是中英文混用比如 xml 里写的是“电动车”而你列表里写的是 “ebicycle”。 解决先跑一句统计把所有 xml 里的 name 去重打印出来再照着改classes。grep -rh name E_bicycle2/annotations | sort | uniq -c这条命令会把所有 name 标签连同出现次数列出来一眼就能看出有没有混入异常类别。4.2 坐标越界导致训练报错现象训练启动后报AssertionError或坐标超出范围的警告甚至直接中断。 原因xml 里个别 bndbox 的 xmax 大于图片宽度或者 xmin 为负数常见于标注时手抖或图片被裁剪过。 解决在转换脚本里加一层裁剪保护把坐标 clamp 到 [0, w] 和 [0, h] 之间同时过滤掉宽高小于 2 像素的无效框。xmin max(0, min(xmin, w)) xmax max(0, min(xmax, w)) ymin max(0, min(ymin, h)) ymax max(0, min(ymax, h)) if xmax - xmin 2 or ymax - ymin 2: continue4.3 中文路径引发的读取失败现象OpenCV 或 PIL 读图返回 None训练时提示找不到图片。 原因图片文件名含中文在某些环境下编码解析出错尤其是跨平台或容器内运行时。 解决按 2.1 的脚本把文件名统一改成纯数字或英文标注文件同步改名。改完记得重新跑一遍转换和划分别只改一半。4.4 验证集 mAP 虚高或为 0现象训练日志里 mAP0.5 一直是 0或者高得离谱接近 1。 原因mAP 为 0 通常是验证集标签路径没配对yolov5 找不到对应 txt虚高则可能是训练集和验证集有重复图片模型“背题”了。 解决检查 val 目录下 images 和 labels 数量是否一致用 md5 或文件名比对确认 train 和 val 没有交集。994 张里如果有极个别重复图划分时可能同时进了两边建议划分前先去重。4.5 显存溢出与 batch-size 调整现象训练刚开始就CUDA out of memory。 原因batch-size 或 img-size 设太大超出显卡容量。 解决优先降 batch-size 到 8 甚至 4再考虑降 img-size。yolov5 支持--batch-size -1自动估算但自动值有时偏激进我一般手动设一个保守值先跑通再逐步往上加。5. 把 E_bicycle2 用出更大价值扩展与验证技巧单类 994 张能训出一个可用的电动车检测器但如果你做的是违停识别光检测电动车还不够最终要判断它“停在哪”。我的做法是分两步先用这份数据训一个电动车检测模型再把检测框送进一个简单的空间逻辑模块判断框的中心点是否落在预设的禁停区域内。这样职责清晰检测模型只负责“找到电动车”违停判定交给规则后续换场景只改区域配置不用重训模型。验证模型是否真的可用别只看 mAP。我习惯抽 20 张验证集里没见过的图用detect.py跑一遍肉眼看漏检和误检python detect.py \ --weights runs/train/ebicycle_exp/weights/best.pt \ --source dataset/images/val \ --conf-thres 0.4 \ --save-txt--conf-thres 0.4是置信度阈值调低会召回更多但误检增加调高则相反实际部署时按场景取舍。--save-txt会把检测框坐标存下来方便你后续做违停区域判断。跑完重点看两类图电动车密集堆叠的场景有没有漏检以及背景里类似电动车的物体有没有被误检。如果误检多可以适当提高 conf-thres 或者补充负样本重训。还有一个容易被忽略的点这份数据是共享电动车子类颜色和车型相对集中。如果你的实际场景里混入了大量私家电动车、三轮车模型的泛化会打折。我的习惯是拿这份数据做基座再针对目标场景补拍几百张、标一遍做增量微调比从零标几千张省太多。从那以后我每次拿到一份标注数据都会先跑一遍类别统计和坐标合法性检查再动手训练——这个习惯帮我省下了至少三次通宵返工。希望帮到你。本文还有配套的精品资源点击获取