
简介面向目标检测与智慧交通场景的数据集聚焦电动车/摩托车非法加装遮阳篷的识别任务包含motor、motor-jz、motor-z三类标注共846张图片、1033个标注框。压缩包共2000个文件以jpg图片、VOC格式xml标签和YOLO格式txt标签为主整体大小41.64MB可直接投入YOLO系列或Faster R-CNN等模型训练。已有244人学习下载适合算法工程师、科研人员及竞赛团队用于真实违规场景的模型调优与效果验证。数据图片与标注一一对应且同时提供Pascal VOC与YOLO两种格式省去人工转换成本便于快速开展非法加装遮阳篷检测项目。1. 目标检测数据集新选择846 张非法加装遮阳篷双格式直接进训练做交通场景目标检测的人最缺的往往不是算法而是对口的训练数据。这套电动车摩托车非法加装遮阳篷数据集共 846 张图片每一张都带 VOC 与 YOLO 两套标注解压后可以直接进 YOLO 训练流程。它能解决一个很具体的需求识别电动自行车、摩托车上后期加装的遮阳篷、雨篷这类违规物件这也是交警巡查、社区安防和城市管理里最常见的一类检测目标。适合刚入门目标检测、想拿真实场景数据跑通全流程的新手也适合做交通安全监管项目的熟手拿来当预训练底料或验证集。这篇笔记从目录结构、格式转换、训练参数到常见坑位一条线走完。2. 数据集内容拆解目录结构、标注字段与两套格式的选型逻辑2.1 解压后先对一遍目录结构我拿到这类双格式数据集第一步不是急着配环境而是先花两分钟确认目录。VOC 和 YOLO 的目录习惯差异不小常见的组织方式是压缩包里同时放两套标注解压后大致是这个形态vehicle_umbrella/ ├── annotations/ # VOC 格式的 XML 标注 │ ├── 0001.xml │ └── ... ├── images/ # 原始图片 │ ├── 0001.jpg │ └── ... ├── labels/ # YOLO 格式的 TXT 标注 │ ├── 0001.txt │ └── ... ├── classes.txt # 类别清单一行一个类 ├── train.txt # 训练集图片路径清单 └── val.txt # 验证集图片路径清单VOC 那半部分JPEGImages 放原图Annotations 放同名 XMLImageSets/Main 下一般会有 train.txt、val.txt 这类划分清单。YOLO 那半部分简单得多images 和 labels 同级同名图片和文本一一对应classes.txt 决定 class_id 的顺序——这个顺序从头到尾不能变变了就是事故。所以拿到手先打开 classes.txt确认到底标了几个类别、名称是什么。单类数据集最怕的不是类别少而是 labels 里的 class_id 和 classes.txt 的顺序对不上。我自己习惯把 classes.txt 第一行当成 0第二行当成 1逐个对着 labels 里的数字过一遍确认没串位再往下走。注意这里有个容易看漏的点train.txt 和 val.txt 里写的路径是以压缩包根目录为基准还是以 images 目录为基准不同来源的数据集写法不一样。脚本处理的时候先读一个文件看看如果路径带了 images/ 前缀后面做数据划分时要记得统一处理。2.2 VOC 与 YOLO 两套标注的字段差异VOC 的 XML 里每个 object 节点带 name 和 bndboxbndbox 内是 xmin、ymin、xmax、ymax 四个像素绝对值YOLO 的 TXT 里一行一个目标格式是 class_id x_center y_center width height后四个值都是相对图片宽高的归一化比例。两套体系差异集中在三个地方坐标参考系、类别标识方式、存储粒度。为了看得更明白我列了一个对比表对比项VOC 标注YOLO 标注存储形式XML一个文件装一张图的所有目标TXT每行一个目标坐标体系像素绝对值 xmin/ymin/xmax/ymax归一化中心点加宽高类别标识object 节点内的 name 字符串class_id 数字依赖 classes.txt 顺序可视化labelImg 直接打开需要指定类名文件或转回 VOC 再开训练接入需要先转换YOLO 系列原生读取字段层面还有一个细节VOC 的 XML 里 size 节点记录了图片的真实宽高这个值既是转换 YOLO 格式时的分母也是判断标注有没有越界的依据。如果某张图的 bndbox 出现了 xmax 大于 size.width说明标注当时就出了问题趁早筛掉别让这种脏数据混进训练集。YOLO 的 TXT 里所有坐标都是 0 到 1 之间的浮点数一旦出现负值或大于 1 的值大概率是转换脚本写错了这类数据会直接把损失函数搞乱。2.3 选型逻辑什么时候用 VOC什么时候直接上 YOLO选哪套格式取决于下游要干什么。如果后续要把数据转成 COCO 格式或者要接入 Detectron2、mmdetection 这类框架VOC 的 XML 解析起来信息更完整XML 里除了 bndbox 还能存 truncated、occluded、difficult 这些附加属性对复杂标注场景更友好。如果是要立刻跑 ultralytics 的 YOLOv8、YOLO11 系列YOLO 格式是原生态直接把 labels 目录指给训练脚本就能跑省掉转换这一层。这份数据同时给了两套其实是想让你两头都不耽误。但正因为如此更得小心训练时 labels 目录和 images 目录必须一一对应图片没有对应的 TXT 文件会报错TXT 和图片同名但内容为空倒是合法的代表这张图没有目标。还有一个常见的坑有人图省事拿着 VOC 的 train.txt 去训练结果发现脚本找不到图片因为那张清单里写的是相对路径得先重写成你自己的绝对路径。我一般会写一段小脚本统一处理路径而不是手动改清单。3. 把 VOC 转成 YOLO 格式转换脚本与四个边界坑3.1 双格式数据集还要不要自己转换这份数据本身已经带 YOLO 标注理论上拿到手直接就能训不需要转。但我还是建议把转换逻辑完整走一遍原因有两个一是你之后大概率还会遇到只有 VOC 标注的开源数据集社区里老数据不少转格式是绕不过去的坎二是转换脚本本身就是对 bbox 坐标体系最直接的校验方式能把「归一化」这件事彻底吃透。下面这个脚本我在本地跑过很多次适用于 labelImg 产出的标准 VOC XML也兼容大多数标注工具导出的格式。3.2 voc2yolo 转换脚本与参数说明# voc2yolo.py # 作用把 VOC 格式的 XML 标注转成 YOLO 需要的 TXT 标注 # 用法python voc2yolo.py --xml_dir annotations --out_dir labels import argparse import xml.etree.ElementTree as ET from pathlib import Path # 类别映射只能出现这里定义过的类其他类会被跳过 # 顺序必须和 classes.txt 完全一致0 对应第一行1 对应第二行 CLASS_MAPPING { sunshade: 0, } def convert_one(xml_path: Path, out_dir: Path): tree ET.parse(xml_path) root tree.getroot() # 注意宽度高度以 XML 里的 size 节点为准不要用 PIL 重新读图 size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) out_txt out_dir / (xml_path.stem .txt) lines [] for obj in root.iter(object): name obj.find(name).text if name not in CLASS_MAPPING: continue box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) # 处理部分工具会给出的反向坐标即 xmin xmax xmin, xmax min(xmin, xmax), max(xmin, xmax) ymin, ymax min(ymin, ymax), max(ymax, ymax) # 归一化中心点加宽高四个值都要除以对应边长 x_center (xmin xmax) / 2 / img_w y_center (ymin ymax) / 2 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{CLASS_MAPPING[name]} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) # 空标注也必须导出空文件否则 YOLO 训练时对不上号 out_txt.write_text(\n.join(lines) \n if lines else ) if __name__ __main__: parser argparse.ArgumentParser() parser.add_argument(--xml_dir, typePath, defaultPath(annotations)) parser.add_argument(--out_dir, typePath, defaultPath(labels)) args parser.parse_args() args.out_dir.mkdir(parentsTrue, exist_okTrue) for xml_path in sorted(args.xml_dir.glob(*.xml)): convert_one(xml_path, args.out_dir) print(转换完成生成文件数, len(list(args.out_dir.glob(*.txt))))脚本逻辑不复杂先解析 XML 的 size 节点拿宽高再遍历所有 object把 bndbox 四个值取出来按中心点加宽高的公式归一化最后写 TXT 文件。参数上--xml_dir 指向 VOC 标注目录--out_dir 是输出目录--img_dir 在这个脚本里不需要因为宽高直接从 XML 里取。CLASS_MAPPING 必须是唯一权威映射不要用 enumerate 之类动态生成逻辑否则类别顺序一乱整个训练就废了。提示跑之前先确认 classes.txt 的类别顺序再把 CLASS_MAPPING 改成和它一致。这里示例里用了 sunshade 作为类别名实际以压缩包内 classes.txt 的内容为准。归一化坐标保留 6 位小数就够再多对训练没有意义。分辨率为 1920 的图1 个像素换算成归一化值是 0.0005 左右6 位小数已经能表达亚像素级的精度。3.3 转换必踩的四个边界坑第一个坑归一化分母用错。现象是转出来的框整体偏移目标中心点和标注框对不上。原因是有人图省事用 PIL 读图片尺寸做分母但标注工具的 size 节点和 PIL 读到的宽高在某些场景下不一致典型的是 JPEG 的 EXIF 旋转信息导致宽高互换。解决办法是统一从 XML 的 size 节点取宽高不再二次读图。第二个坑类别 id 错位。现象是训练能跑、损失也在降但混淆矩阵一塌糊涂。原因是转换脚本里用 os.listdir 的遍历顺序当 class_id 的索引而 listdir 返回顺序是不保证稳定的。解决办法是显式写死类别映射字典用类名做 keyid 做 value顺序以 classes.txt 为准。第三个坑反向坐标。现象是转出来的 w 或 h 为负值检测框直接消失。原因是部分标注工具在导出时会把 xmin 和 xmax 写反尤其手工编辑过 XML 的数据更容易出现。解决办法是计算前先做一次 min/max 交换把坐标归正宁可多写两行代码不要赌数据全是对的。第四个坑空标注文件缺失。现象是训练时出现 FileNotFoundError或数据集样本数量对不上。原因是 YOLO 读取数据时按图片索引找同名 TXT有些标注工具对无目标的图不生成 XML导致转换后缺文件。解决办法是脚本里对无目标的 XML 也生成同名空 TXT这一步不能省。4. YOLO 训练避坑与参数实战小数据集也能训出可用检测器4.1 模型选型为什么小数据集先上轻量模型846 张的单类数据集体量不算大模型首选轻量级。Ultralytics 全家桶里YOLOv8n 和 YOLO11n 都是 nano 级别参数量只有几百万单类目标检测完全够用显存占用小训练速度快。不要一上来就跑 yolo11x 这类大模型训练时间翻好几倍在单类小数据集上的收益基本看不出来反而更容易过拟合。如果机器只有 CPUn 系列也能勉强撑住训练只是时间会长一些但总比跑不动强。模型选型之外另一个容易忽略的是数据划分方式。同一个视频里抽帧出来的图高度相似直接随机划分 train 和 val会导致验证集虚高——模型很可能只是记住了场景而不是学会了检测目标。我一般会先按场景或时间戳把图片分桶再按桶来划分训练集和验证集这样验证集才能反映真实分布。这份数据集来源未知但你自己处理同类数据时记得先把这层做好。4.2 数据划分、yaml 配置与训练命令拿到数据后先把目录整理成 YOLO 训练的规范结构。把 images 和 labels 分别拆成 train、val 两个子目录比例按 8:2 左右划分。拆完后目录结构是这样的vehicle_umbrella/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── vehicle_umbrella.yaml然后写数据配置文件。这一步决定了训练脚本能不能找到你的图片和标注# vehicle_umbrella.yaml path: /data/vehicle_umbrella # 改成你自己的绝对路径不要用相对路径 train: images/train val: images/val names: 0: sunshade # 以压缩包 classes.txt 实际内容为准训练命令直接用 ultralytics 的命令行入口参数我拆开写方便逐个理解yolo detect train \ datavehicle_umbrella.yaml \ modelyolo11n.pt \ epochs100 \ imgsz640 \ batch16 \ patience20 \ device0 \ ampTrue \ projectruns \ nameshade_exp各参数的含义是这样的model 用 yolo11n.pt首次训练会自动下载预训练权重这个权重来自 COCO迁移到遮阳篷检测上能省不少训练时间epochs 设置 100单类数据集不用贪多50 到 100 之间通常就够了imgsz 设 640这是速度和精度的平衡点显存不够可以降到 416batch 大小取决于显存16G 显存跑 batch 16 问题不大8G 就跑 8patience 是早停参数验证集指标连续多少轮不涨就停止训练小数据集可以设大一点到 20防止验证集抖动导致的误停。提示第一次跑训练之前先看一眼 labels 目录里有没有空 TXT 文件。如果某个 TXT 不存在而图片存在训练会直接报错这个问题在第 3 章里强调过。4.3 关键参数怎么调不翻车小数据集调参最怕的是来回乱改。我一般先把固定参数定下来再动训练参数。下面这几个参数是踩过坑之后总结的参考范围参数参考值调参方向imgsz640小目标多就提到 768 或 896显存不够就降到 416batch8 到 32显存不够优先降 batch比降 imgsz 对精度影响小epochs80 到 150单类 100 够用观察 loss 曲线再决定加不加patience15 到 30小数据集验证波动大设太小会提前停lr00.01 默认过热就降到 0.005收敛慢就回升到 0.02mosaic1.0 默认最后 10 个 epoch 可以关掉让模型学真实分布ampTrue显存紧张时能省 3 成左右显存精度损失可忽略关掉 mosaic 这个操作很多人不知道。mosaic 在训练前中期能增强模型泛化能力但最后几个 epoch 它会让模型始终看到拼接图和真实场景有偏差。我一般会通过 ultralytics 的配置项把 mosaic 在最后 10 到 15 个 epoch 置为 0验证集 mAP 会有可见提升。4.4 常见问题排查记录第一个训练结束后没有 best.pt只有 last.pt。现象是 runs 目录下找不到 best 权重或者 best 出现在前几个 epoch。原因是 patience 设得太小验证集指标正常波动就触发了早停。解决方法是把 patience 调大到 20 以上或者干脆设成 0 关掉早停训练完再手动选权重。第二个验证集 mAP 正常实际场景漏检一堆。现象是 val 上跑出来 0.8 的 mAP拿到真实街景里一测各种漏。原因是训练集和验证集太相似随机划分导致同场景图片两边都有。解决方法是按场景分桶划分validation 里只放模型没见过的场景宁可 mAP 低一点数据才真实。第三个CUDA error 或训练悄悄退回 CPU。现象是启动训练时报 out of memory或者日志里 device 变成了 cpu。原因是 torch 版本和 CUDA 驱动不匹配或者 batch 设得太大。解决方法是先跑nvidia-smi看驱动支持的最高 CUDA 版本再用 conda 装对应版本的 torch显存不够就把 batch 降到 8别硬撑。第四个loss 一直降但检测框偏移严重。现象是训练过程正常预测时框和真实目标明显错位。原因多半是标注坐标出了问题某些图片归一化坐标算错了。解决方法是随机抽 20 张图把标注框画回图上肉眼过一遍这招比任何指标都直观直接能定位到问题图片。第五个白天识别正常傍晚就开始瞎检。现象是夜间或逆光场景误检率暴增。原因是数据集里暗光图片占比不足模型没学到这个分布。解决方法是先统计图片亮度分布确认一下数据集覆盖如果缺太多光照场景跑一个简单的曝光增强做数据扩充比调参有用得多。5. 验证与复用技巧用难例挖掘补齐单类数据集的短板训练完的权重不要急着收工先跑一遍完整的验证流程把模型的行为摸清楚。用这条命令能一次性产出混淆矩阵、PR 曲线和几张带预测框的样本图yolo detect val \ modelruns/shade_exp/weights/best.pt \ datavehicle_umbrella.yaml \ plotsTrueplotsTrue 会在 runs 目录下生成 confusion_matrix.png 和 PR_curve.png。单类数据集看 PR 曲线不如看混淆矩阵有用混淆矩阵里的 False Negative 才是漏检的重灾区——遮阳篷被背景淹没、被车身遮挡、或者角度太刁钻这些模型没检出来的框才是补数据的线索。更实用的做法是难例挖掘。把 val 集里预测置信度在 0.3 到 0.7 之间的图片全部导出人工扫一遍。置信度低不代表模型一定错了但低置信度说明模型对这个样本的特征表达很犹豫。这些图里有相当一部分是遮挡、逆光、形变这类困难样本把它们挑出来加进训练集比随机补几十张普通图有效得多。单类数据集的短板就在于类内差异可能很大——同样是遮阳篷三轮车上的和两轮车上的外形完全不同模型很容易只学会其中一种难例挖掘专治这个问题。数据增强上小数据集先别上花活。mosaic、HSV 扰动、随机透视这三样够用了重点是把增强概率控制在合理范围不要在训练后期让模型一直看变形图。如果你的目标偏向小目标可以额外关注针对小目标的损失改进但在 846 张的基础规模上先把数据划分和难例补充做扎实收益会明显得多。我有一回为了省时间跳过混淆矩阵只看整体 mAP 就草率收工。后来发现模型把车尾绑的行李当成遮阳篷PR 曲线看起来还行是因为正样本本来就少误检被摊薄了。从那以后我每次拿到小数据集都强制走一遍「按场景分桶划分 训练 混淆矩阵 置信度 0.3 到 0.7 难例抽取」这个流程全部过完才开始调参。这套流程也推荐你用在这份数据上希望帮到你。本文还有配套的精品资源点击获取