简介这是一份面向计算机视觉与深度学习方向的目标检测数据集聚焦卡车倾倒建筑垃圾这一特定场景适合训练和评估YOLOv7等检测模型服务于智能监控、建筑工地管理与环保监测等应用。压缩包共1023个文件以569张jpg、106张png、39张jpeg图像为主另含309个xml标注文件整体约115.49MB图像覆盖不同角度、光照与倾倒阶段标注文件提供边界框坐标与类别标签可直接用于监督学习训练。目前已有240人学习下载。借助该数据集读者可完成从图像预处理、标注解析到模型训练与验证的完整流程并参考mAP 0.85的检测表现快速复现高精度识别效果为非法倾倒行为的自动化检测提供数据基础与调优思路。1. 从 714 张工地实拍里拆出「卡车倾倒建筑垃圾」这个检测任务城市建筑垃圾的非法倾倒难就难在「抓现行」——车斗一抬、垃圾一落前后不过十几秒靠人盯监控基本是碰运气。这份「卡车倾倒建筑垃圾检测数据集」就是冲着这个场景来的714 张实拍图覆盖不同角度、光照、背景和倾倒阶段专门用来训练 YOLOv7 这类目标检测模型把「卡车」和「倾倒行为」从画面里框出来。它适合两类人一类是想找一个真实、脏、有挑战的工业级检测任务练手的算法工程师另一类是做智慧工地、环保监测、城市管理方向需要快速验证「能不能自动识别违规倾倒」的产品同学。数据集本身不承诺开箱即用但它的价值在于——你拿到的是一批已经踩过现实复杂度的图而不是实验室里摆拍的干净样本。2. 先搞懂标注格式和目录结构别拿到图就急着喂模型2.1 这批图到底长什么样为什么文件名这么乱打开压缩包你会看到一堆命名风格完全不统一的文件gwar-two-trucks.jpeg、1ee3c9e5-ebef-4014-b094-001188f035c7.42f9d8d569fde385b3791df4b19e6e8e.jpeg、image19.jpeg、image17 (2).jpeg……这不是作者偷懒而是典型的「多来源采集」痕迹——有的来自公开图库有的来自视频抽帧有的是手机随手拍。文件名里的 UUID 和哈希值说明部分图片经过了去重或溯源处理imageXX系列则大概率是批量导出的帧序列。这种命名混乱在真实项目里非常常见但直接拿去训练会出问题YOLO 的数据加载器虽然不关心文件名但你在做训练集/验证集划分、错误样本回溯、增量数据合并时没有统一命名会让你痛不欲生。我一般拿到这种数据集第一步不是看标注而是先做文件名规范化。# 把当前目录下所有 jpeg 统一重命名为 truck_dump_0001.jpeg 格式 # 先预览确认没有重名冲突 ls *.jpeg | wc -l # 714 张符合预期 # 用 rename 批量处理Linux/macOS i1 for f in *.jpeg; do newname$(printf truck_dump_%04d.jpeg $i) mv $f $newname i$((i1)) done这段脚本做的是「顺序编号重命名」%04d保证编号固定四位排序时不会出现10排在2前面的问题。执行前建议先备份原始文件名列表ls *.jpeg original_names.txt万一后面发现某张图标注有问题还能靠原始名回溯。注意重命名只改文件名不动图片内容也不影响后续标注文件的匹配——前提是你的标注文件是按同名.txt或.xml对应的如果标注文件里引用了原文件名那得同步改标注里的filename字段。2.2 标注格式决定你后面怎么转 YOLO数据集正文里提到标注文件「一般为 XML 或 JSON 格式」这是比较保守的说法。实际拿到手大概率是以下三种之一Pascal VOC 的 XML、COCO 的 JSON或者已经转好的 YOLO txt。你得先确认是哪一种因为转换脚本完全不同。判断方法很简单看标注文件的后缀和内容结构。# 查看标注文件类型分布 find . -name *.xml | head -3 find . -name *.json | head -3 find . -name *.txt | head -3 # 如果是 XML看一个样本的结构 head -30 annotations/xxx.xmlPascal VOC 的 XML 里会有objectnametruck/namebndboxxmin...这样的层级COCO 的 JSON 则是一个大文件里包含images、annotations、categories三个主键YOLO txt 最简每行class_id x_center y_center width height全是归一化到 0~1 的浮点数。这个数据集的任务是「卡车倾倒建筑垃圾」类别设计上通常有两种方案一种是只标truck和dump倾倒行为两类另一种是标truck、garbage、dumping三类。从 714 张图的规模和 mAP 0.85 的目标来看类别不会太多否则小样本下很难训到这么高。我倾向于认为它是「卡车 倾倒区域」的二元或三元标注。你拿到标注后先统计一下类别分布import os import xml.etree.ElementTree as ET from collections import Counter # 统计 Pascal VOC 格式下的类别分布 class_counter Counter() for xml_file in os.listdir(annotations): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(annotations, xml_file)) for obj in tree.findall(object): class_counter[obj.find(name).text] 1 print(class_counter) # 预期输出类似Counter({truck: 680, dump: 420})这段代码遍历所有 XML用Counter统计每个类别出现的次数。如果发现某个类别只有几十个框那训练时就得考虑类别不平衡的问题——要么过采样要么在 loss 里给稀有类别加权。参数上os.listdir的顺序不保证稳定但统计结果不受影响ET.parse对格式错误的 XML 会直接抛异常建议加try/except跳过坏文件别让一个坏标注卡住整个流程。3. 转成 YOLOv7 能吃的格式坐标归一化和类别映射的四个细节3.1 从 VOC XML 到 YOLO txt 的完整转换脚本YOLOv7 默认读的是 YOLO 格式的 txt每张图对应一个同名 txt每行五个值——class_id x_center y_center width height后四个都是相对于图片宽高的归一化值0~1。如果你拿到的是 VOC XML转换逻辑就是读图片尺寸 → 读 bndbox 的xmin/ymin/xmax/ymax→ 算中心点和宽高 → 除以图片宽高 → 按类别映射表转成整数 id。import os import xml.etree.ElementTree as ET from PIL import Image # 类别映射根据你的实际标注调整 CLASS_MAP {truck: 0, dump: 1} def voc_to_yolo(xml_path, img_dir, out_dir): tree ET.parse(xml_path) root tree.getroot() filename root.find(filename).text img_path os.path.join(img_dir, filename) # 用 PIL 读图片尺寸比从 XML 的 size 字段读更可靠 with Image.open(img_path) as img: w, h img.size lines [] for obj in root.findall(object): cls_name obj.find(name).text if cls_name not in CLASS_MAP: continue # 跳过不需要的类别 cls_id CLASS_MAP[cls_name] bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 归一化并转成 YOLO 的中心点格式 x_center (xmin xmax) / 2.0 / w y_center (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h # 裁剪到 [0,1]防止标注越界 x_center min(max(x_center, 0), 1) y_center min(max(y_center, 0), 1) bw min(max(bw, 0), 1) bh min(max(bh, 0), 1) lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {bw:.6f} {bh:.6f}) out_path os.path.join(out_dir, filename.replace(.jpeg, .txt)) with open(out_path, w) as f: f.write(\n.join(lines)) # 批量执行 for xml_file in os.listdir(annotations): if xml_file.endswith(.xml): voc_to_yolo( os.path.join(annotations, xml_file), images, labels )这段脚本的关键点有三个。第一图片尺寸用PIL.Image.open实时读取而不是信 XML 里的size字段——我踩过太多次坑XML 里的尺寸和实际图片对不上导致归一化后框全飘了。第二min(max(...))的裁剪是必要的有些标注框会超出图片边界比如xmax大于图片宽度不裁剪的话 YOLO 训练时虽然不会报错但 loss 会异常。第三:.6f保留六位小数YOLO 官方实现里默认精度够用再高没必要。3.2 类别映射和空标注文件的处理类别映射表CLASS_MAP必须和你的data.yaml里的names顺序严格一致。YOLOv7 训练时class_id是索引不是名字映射错了模型学出来的东西完全是乱的。常见做法是先跑一遍统计脚本把所有出现的类别名列出来再手动定映射。另一个容易被忽略的点是空标注文件。有些图片里可能没有目标比如纯背景图转换后会生成一个空的 txt。YOLOv7 默认会跳过空 txt 对应的图片但如果你用的是自定义 dataloader空文件可能导致ZeroDivisionError。我一般会在转换后检查一遍# 统计空标注文件数量 find labels -name *.txt -empty | wc -l # 如果数量不多直接删掉对应的图片和空标注 find labels -name *.txt -empty -delete删空标注之前先确认这些图确实没有目标。如果数据集里故意放了负样本纯背景那应该保留图片但删掉空 txt让模型学会「没有目标时输出全零」。这个策略取决于你的任务需求——对于「卡车倾倒」这种二分类检测负样本有助于降低误报。3.3 data.yaml 怎么写路径和类别名别搞反YOLOv7 训练需要一个data.yaml里面指定训练集、验证集、测试集的路径以及类别数和类别名。这个文件写错训练直接起不来。# data.yaml train: ./dataset/images/train val: ./dataset/images/val test: ./dataset/images/test nc: 2 names: [truck, dump]nc是类别数必须和names的长度一致。names的顺序就是class_id的顺序——truck是 0dump是 1。路径可以是绝对路径也可以是相对于训练脚本的路径但建议用绝对路径省得后面换工作目录时找不到文件。另外YOLOv7 的train和val指向的是图片目录不是标注目录标注目录默认是图片路径里的images替换成labels。所以你的目录结构应该是dataset/ images/ train/ val/ test/ labels/ train/ val/ test/图片和标注文件名必须一一对应除了后缀不同。truck_dump_0001.jpeg对应truck_dump_0001.txt放在对应的images和labels子目录里。4. 训练 YOLOv7 时的参数设置和显存控制4.1 从预训练权重起步别从零训714 张图不算多从零训练 YOLOv7 几乎必然过拟合。标准做法是加载 COCO 预训练权重冻结 backbone 先训几轮再解冻全量微调。YOLOv7 官方仓库提供了yolov7.pt和yolov7-tiny.pt等权重后者更适合显存有限的场景。# 单卡训练batch size 根据显存调整 python train.py \ --weights yolov7.pt \ --cfg cfg/training/yolov7.yaml \ --data data.yaml \ --hyp data/hyp.scratch.p5.yaml \ --epochs 100 \ --batch-size 16 \ --img-size 640 640 \ --device 0 \ --workers 4 \ --name truck_dump_exp参数逐个说--weights指定预训练权重不写就是从零开始--cfg是模型结构文件YOLOv7 和 YOLOv7-tiny 用的不是同一个--hyp是超参文件hyp.scratch.p5.yaml适合从预训练微调如果从零训要用hyp.scratch.p6.yaml或自定义--batch-size 16在 8GB 显存上跑 640 分辨率大概能撑住显存不够就降到 8 或 4--img-size是训练分辨率640 是 YOLO 系列的经典值再大显存吃不消再小精度掉得厉害。4.2 学习率、warmup 和早停的实际取值YOLOv7 的默认学习率策略是余弦退火 warmup。在hyp.scratch.p5.yaml里lr0是初始学习率默认 0.01lrf是最终学习率系数默认 0.1也就是最终学习率是lr0 * lrf 0.001。对于 714 张图的小数据集我一般会把lr0降到 0.005 甚至 0.001避免初期震荡太大。warmup 的轮数由warmup_epochs控制默认 3。小数据集上可以保持默认或者降到 1~2因为数据量少模型很快就能过一遍。早停靠--patience参数默认 50意思是验证集 mAP 连续 50 轮不提升就停。714 张图训 100 轮足够了如果 50 轮还没到 0.8 的 mAP大概率是标注有问题或者类别映射错了别硬等。# hyp.scratch.p5.yaml 里需要关注的几个值 lr0: 0.005 # 初始学习率小数据集建议降低 lrf: 0.1 # 最终学习率系数 momentum: 0.937 weight_decay: 0.0005 warmup_epochs: 2 warmup_momentum: 0.8 box: 0.05 # box loss 权重 cls: 0.5 # 分类 loss 权重 obj: 1.0 # 目标性 loss 权重box、cls、obj三个 loss 权重决定了模型更关注定位还是分类。对于「卡车倾倒」这种目标明确的任务obj保持 1.0cls可以适当调高到 0.6~0.8因为倾倒行为本身的类间差异比定位更难学。4.3 验证集 mAP 0.85 意味着什么怎么复现数据集正文提到训练后 mAP 达到 0.85这个数字在目标检测里算相当高了。但要注意mAP 的计算方式有多种VOC 的 mAP0.5、COCO 的 mAP[0.5:0.95]两者差距很大。0.85 大概率是 mAP0.5也就是 IoU 阈值 0.5 时的平均精度。如果你用 COCO 的评估标准同样的模型可能只有 0.6 左右。复现这个指标除了数据本身的质量训练时的数据增强策略也很关键。YOLOv7 默认开启了 mosaic、mixup、随机缩放等增强这些对小数据集尤其重要。但 mosaic 在训练后期可能会干扰收敛常见做法是最后 10~15 轮关掉 mosaic# 在 train.py 里找到 mosaic 相关参数或者通过命令行覆盖 --mosaic 0 # 最后几轮关闭实际训练时我一般会在第 80 轮之后把mosaic设为 0让模型在真实分布上做最后的微调。这个技巧在 YOLOv5/v7 社区里叫「close mosaic」对最终 mAP 通常有 1~2 个点的提升。5. 避坑与排查标注、显存、过拟合的五个血泪教训5.1 现象训练 loss 正常下降但验证 mAP 始终为 0原因类别映射错了。data.yaml里的names顺序和标注转换时的CLASS_MAP不一致导致模型学的是「0 号类是 dump」但验证时按「0 号类是 truck」去算全错。解决打印训练时 dataloader 返回的cls值分布和data.yaml里的names对照。最直接的办法是拿一张训练图跑推理看输出的类别 id 和框的位置是否合理。5.2 现象训练到一半突然 CUDA out of memory原因YOLOv7 的 mosaic 增强会拼接四张图等效 batch size 翻四倍。如果--batch-size 16实际显存占用接近 64。另外验证时的--img-size如果和训练不一致也会导致显存峰值。解决把--batch-size降到 8或者用--accumulate做梯度累积。YOLOv7 支持--accumulate 2等效 batch size 不变但显存减半。验证时确保--img-size和训练一致。5.3 现象训练集 mAP 0.95验证集 mAP 0.6差距巨大原因过拟合。714 张图对 YOLOv7 来说太少了模型把训练集背下来了。常见诱因是数据增强太弱或者weight_decay设得太小。解决加强增强开启 mixup、cutout提高weight_decay到 0.001降低lr0增加早停耐心值。如果还不行考虑用 YOLOv7-tiny 这种小模型参数量少过拟合风险低。5.4 现象推理时框的位置整体偏移原因训练时的--img-size和推理时的--img-size不一致或者图片预处理时没有保持长宽比。YOLO 默认会把图片 resize 到正方形如果原图是 16:9直接拉伸会导致目标变形框的位置自然偏。解决推理时用--img-size和训练一致并且在 dataloader 里开启rectTrue保持长宽比的 padding这样不会变形。YOLOv7 的detect.py默认就是 letterbox 处理但如果你自己写推理脚本记得手动实现。5.5 现象某些类别的 AP 特别低比如 dump 只有 0.3原因类别不平衡。truck 在每张图里几乎都有但 dump倾倒行为可能只在部分图里出现样本量差了一个数量级。解决在 loss 里给稀有类别加权或者对包含 dump 的图片做 oversampling。YOLOv7 的hyp文件里没有直接的类别权重参数需要改loss.py里的BCEWithLogitsLoss传入pos_weight。另一个办法是数据层面把包含 dump 的图复制几份混进训练集。6. 用 TensorRT 加速推理把 714 张图的验证跑进 30 秒训练完拿到best.pt之后如果只是做离线验证PyTorch 原生推理也能跑但 714 张图在 640 分辨率下大概要 2~3 分钟。实际部署到工地边缘设备时这个速度不够看。我一般会转成 TensorRT 引擎推理速度能提升 3~5 倍。转换流程分两步先导出 ONNX再用trtexec转 TensorRT。# 导出 ONNX注意 opset 版本和动态 batch python export.py \ --weights runs/train/truck_dump_exp/weights/best.pt \ --img-size 640 640 \ --batch-size 1 \ --dynamic \ --simplify \ --opset 12 # 用 trtexec 转 TensorRTFP16 精度 trtexec \ --onnxbest.onnx \ --saveEnginebest.trt \ --fp16 \ --workspace4096 \ --minShapesimages:1x3x640x640 \ --optShapesimages:1x3x640x640 \ --maxShapesimages:1x3x640x640--dynamic允许动态 batch--simplify会调用 onnx-simplifier 去掉冗余节点--opset 12是 YOLOv7 导出比较稳的版本。trtexec的--fp16开启半精度精度损失通常在 0.5 个点以内但速度翻倍。--workspace4096是显存工作空间单位 MB4096 够用。转完之后用 TensorRT 的 Python API 加载引擎跑推理单张图在 T4 上大概 8~12ms714 张图 10 秒内跑完。验证 mAP 时把 TensorRT 的输出和 PyTorch 的输出对比一下如果 mAP 掉了超过 1 个点检查是不是 FP16 溢出导致的可以换--fp32再试。从那以后我每次拿到新数据集都强制先跑一遍「标注可视化 类别统计 空文件检查」三件套确认数据干净了再开训。这份卡车倾倒数据集的价值不在于它有多大而在于它把「非法倾倒」这个真实场景的复杂度带进了训练集——光照变化、遮挡、不同倾倒阶段这些才是模型落地时真正要面对的。希望帮到你。本文还有配套的精品资源点击获取