简介:本资源为面向YOLO系列目标检测算法的工程机械数据集,包含自卸卡车、挖掘机、轮式装载机三类目标,适合从事施工场景识别、工地安全监控或车辆检测的开发者与研究者使用。压缩包共2000个文件,以VOC格式的xml标注文件为主,同时提供YOLO格式的txt标签,两种标注分别存放于独立文件夹,文件名末尾标注对应类别名称,便于按类别检索与核对。资源已按训练与验证需求划分完毕,并附带data.yaml配置文件,可直接适配YOLOv5、YOLOv7、YOLOv8、YOLOv9、YOLOv10及YOLO11等主流版本,省去格式转换与目录整理的重复工作。YOLO标签采用归一化中心点与宽高表示,坐标范围0到1,符合标准训练输入要求。压缩包整体约232MB,内含2656张图像及对应标签,目前已有82人学习下载,适合快速搭建工程机械检测基线模型并开展迁移学习实验。
1. 从一份 2656 张的挖掘机数据集说起:YOLO 工程机械检测到底难在哪
工地上同时出现挖掘机、自卸卡车、轮式装载机,这三种设备外形差异大、作业姿态多变,但真正做过工程机械检测的人都知道,难的不是把它们分开,而是让模型在尘土、逆光、遮挡和远距离小目标下依然稳定。这份 2656 张图像带标签的挖掘机数据集,覆盖了挖掘机、自卸卡车、轮式装载机三类目标,正好是一个典型的「少类别、强场景、高姿态变化」检测任务。它适合谁?适合想入门 YOLO 目标检测但不想从 COCO 那种通用数据集起步的工程师,也适合做智慧工地、土方量统计、设备调度、安全监控的从业者。你拿到的不是一份玩具数据,而是一个能直接跑通训练、验证、推理全流程的真实场景数据集。接下来的内容,我会按「数据怎么查、标签怎么转、YOLO 怎么训、参数怎么调、坑在哪」这条线,把整个落地路径拆开讲清楚。
2. 拿到数据集先别急着训:2656 张图像的标签体检与格式转换
2.1 先搞清楚标签格式:YOLO txt、VOC xml 还是 COCO json
工程机械数据集最常见的标签格式有三种:YOLO 的归一化 txt、Pascal VOC 的 xml、COCO 的 json。你拿到的这份数据集,从命名习惯看大概率是 YOLO txt 或 VOC xml。别急着写训练脚本,先花十分钟做一次标签体检,否则后面训练 loss 不降、mAP 为 0 的时候你会怀疑人生。
先看目录结构。常见做法是 images 和 labels 两个文件夹并列,labels 里每个 txt 对应一张图,每行是class_id x_center y_center width height,全部归一化到 0~1。如果是 VOC,则是 Annotations 里一堆 xml,JPEGImages 里一堆 jpg。用下面这段脚本快速统计类别分布和标签完整性:
import os from collections import Counter from pathlib import Path # 改成你的实际路径 label_dir = Path("labels") img_dir = Path("images") class_counter = Counter() missing_label = [] empty_label = [] bad_line = [] for img_path in img_dir.glob("*.jpg"): label_path = label_dir / (img_path.stem + ".txt") if not label_path.exists(): missing_label.append(img_path.name) continue lines = label_path.read_text().strip().splitlines() if len(lines) == 0: empty_label.append(img_path.name) continue for line in lines: parts = line.split() if len(parts) != 5: bad_line.append((label_path.name, line)) continue cls_id = int(parts[0]) class_counter[cls_id] += 1 # 检查归一化坐标是否越界 coords = list(map(float, parts[1:])) if any(c < 0 or c > 1 for c in coords): bad_line.append((label_path.name, line)) print("类别分布:", class_counter) print("缺标签图片数:", len(missing_label)) print("空标签图片数:", len(empty_label)) print("异常行数:", len(bad_line))这段脚本做了四件事:统计每个类别的框数量、找出没有对应标签的图片、找出空标签文件、检查坐标是否越界。类别分布直接决定你后面要不要用加权采样或 focal loss;缺标签和空标签图片如果太多,要么补标要么剔除;坐标越界说明标注工具导出时出了问题,必须修。
参数说明:label_dir和img_dir按你的实际目录改;如果你的图片是 png 或 jpeg,把 glob 的后缀换掉。跑完如果发现某一类只有几十个框,那这个类基本训不出来,需要考虑合并类别或补充数据。
2.2 把 VOC 转成 YOLO 格式:转换脚本与四个边界坑
如果体检发现是 VOC xml,就得转成 YOLO txt。转换逻辑不复杂,但边界坑很多。下面这个脚本我用了很多次,直接抄:
import xml.etree.ElementTree as ET from pathlib import Path from PIL import Image voc_dir = Path("Annotations") img_dir = Path("JPEGImages") out_dir = Path("labels_yolo") out_dir.mkdir(exist_ok=True) # 类别名到 id 的映射,按你的数据集改 classes = ["excavator", "dump_truck", "wheel_loader"] class_to_id = {name: i for i, name in enumerate(classes)} for xml_path in voc_dir.glob("*.xml"): tree = ET.parse(xml_path) root = tree.getroot() img_name = root.find("filename").text img_path = img_dir / img_name if not img_path.exists(): print("图片缺失:", img_name) continue w, h = Image.open(img_path).size lines = [] for obj in root.findall("object"): cls_name = obj.find("name").text.strip() if cls_name not in class_to_id: continue 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) # 边界裁剪,防止越界 xmin = max(0, min(xmin, w - 1)) ymin = max(0, min(ymin, h - 1)) xmax = max(0, min(xmax, w - 1)) ymax = max(0, min(ymax, h - 1)) if xmax <= xmin or ymax <= ymin: continue x_center = (xmin + xmax) / 2.0 / w y_center = (ymin + ymax) / 2.0 / h bw = (xmax - xmin) / w bh = (ymax - ymin) / h lines.append(f"{class_to_id[cls_name]} {x_center:.6f} {y_center:.6f} {bw:.6f} {bh:.6f}") if lines: (out_dir / (xml_path.stem + ".txt")).write_text("\n".join(lines))四个边界坑:第一,xmin/xmax 可能超出图片尺寸,必须裁剪;第二,有些标注框宽高为 0 或负数,直接跳过;第三,类别名大小写和空格不一致,比如 "Excavator" 和 "excavator ",要先 strip 再统一映射;第四,图片文件名和 xml 里的 filename 不一致,要以实际图片为准。转换完再跑一遍 2.1 的体检脚本,确认类别分布和坐标都正常。
2.3 划分训练集、验证集、测试集:别让同一场景的图同时出现在两边
2656 张图不算多,划分比例常见是 7:2:1 或 8:1:1。但工程机械数据有个特点:同一段视频抽帧出来的图片高度相似。如果你随机划分,训练集和验证集里会出现几乎一样的图,验证 mAP 虚高,上线就翻车。正确做法是按场景或按视频源划分,同一场景的图只进一个集合。
import random from pathlib import Path import shutil random.seed(42) img_dir = Path("images") label_dir = Path("labels") out_root = Path("dataset") for split in ["train", "val", "test"]: (out_root / "images" / split).mkdir(parents=True, exist_ok=True) (out_root / "labels" / split).mkdir(parents=True, exist_ok=True) all_imgs = sorted(img_dir.glob("*.jpg")) random.shuffle(all_imgs) n = len(all_imgs) n_train = int(n * 0.8) n_val = int(n * 0.1) splits = { "train": all_imgs[:n_train], "val": all_imgs[n_train:n_train + n_val], "test": all_imgs[n_train + n_val:] } for split, imgs in splits.items(): for img_path in imgs: shutil.copy(img_path, out_root / "images" / split / img_path.name) label_path = label_dir / (img_path.stem + ".txt") if label_path.exists(): shutil.copy(label_path, out_root / "labels" / split / label_path.name)如果你的图片文件名里带了场景编号或日期,按编号分组再划分,比纯随机靠谱得多。跑完检查三个集合的类别分布是否接近,如果某一类只在训练集出现,验证集就测不出这个类。
3. YOLO 训练挖掘机检测模型:从 data.yaml 到第一个 baseline
3.1 写对 data.yaml:三个类别名和路径的常见错误
YOLO 系列训练都靠一个 yaml 文件描述数据路径和类别。以 YOLOv8 为例,结构如下:
path: /home/user/dataset train: images/train val: images/val test: images/test names: 0: excavator 1: dump_truck 2: wheel_loader三个常见错误:第一,path用了相对路径,训练时工作目录一变就找不到;第二,train和val写成了绝对路径但path又拼了一次,导致路径重复;第三,names的 id 和标签里的 class_id 对不上,比如标签里 0 是挖掘机,names 里 0 写成了卡车,训练 loss 正常但预测全错。写完 yaml 后,用一行命令验证路径:
python -c "from ultralytics import YOLO; model=YOLO('yolov8n.pt'); model.train(data='data.yaml', epochs=1, imgsz=640, batch=4)"先跑 1 个 epoch,看能不能正常读图、正常反传。如果报 "No labels found",八成是路径或文件名对不上。
3.2 从 yolov8n 开始:第一个 baseline 的训练命令与参数含义
别一上来就上大模型。2656 张图,yolov8n 或 yolov8s 足够跑出可用的 baseline。命令如下:
yolo detect train \ data=data.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ batch=16 \ lr0=0.01 \ lrf=0.01 \ patience=20 \ device=0 \ project=runs/excavator \ name=baseline参数逐个说:imgsz=640是输入分辨率,工程机械目标通常较大,640 够用;如果小目标多,可以上 1280,但显存翻倍。batch=16看显存调,8G 显存跑 640 大概能到 16。lr0=0.01是初始学习率,YOLOv8 默认 0.01,数据量小可以降到 0.005。lrf=0.01是最终学习率系数,控制余弦退火终点。patience=20是早停耐心值,20 个 epoch 没提升就停。device=0指定第一块 GPU。
训练过程中重点看三个指标:box_loss是否稳定下降、mAP50是否上升、cls_loss是否震荡。如果 box_loss 不降,先检查标签格式;如果 mAP50 卡在很低的值,检查类别映射和验证集划分。
3.3 数据增强怎么开:Mosaic、MixUp 和 HSV 在工程机械场景的取舍
YOLO 默认开 Mosaic 和 HSV 增强。Mosaic 把四张图拼成一张,对小数据集很有效,能提升 batch 内的多样性。但工程机械场景有个问题:Mosaic 拼出来的图里,挖掘机可能被截断成半截,模型学到不完整的目标特征。我的经验是,前 80 个 epoch 开 Mosaic,最后 20 个 epoch 关掉,让模型在完整图上收敛。
HSV 增强调饱和度、明度、色调,对尘土和逆光场景有帮助。但如果你的数据本身色调单一,HSV 幅度别开太大,否则模型把颜色当噪声。MixUp 在工程机械上要慎用,两张图叠加后目标边界模糊,小目标容易消失。常见做法是 Mosaic=1.0、MixUp=0.0、HSV 默认,先跑一版看效果,再针对性调。
yolo detect train \ data=data.yaml \ model=yolov8s.pt \ epochs=120 \ imgsz=640 \ batch=12 \ mosaic=1.0 \ mixup=0.0 \ hsv_h=0.015 \ hsv_s=0.7 \ hsv_v=0.4 \ close_mosaic=20 \ device=0close_mosaic=20表示最后 20 个 epoch 关闭 Mosaic,这是 YOLOv8 的一个实用参数,很多人不知道。跑完对比 baseline,看 mAP50 和 mAP50-95 的变化,如果 mAP50 涨了但 mAP50-95 没动,说明框的位置还不够准,可以调框回归的 loss 权重。
4. 训练完别只看 mAP:挖掘机检测的排查与避坑清单
4.1 现象:mAP50 很高但实际推理漏检严重
原因:验证集和训练集场景太像,模型过拟合到特定背景。或者验证集里目标尺寸分布和实际部署场景不一致。解决:按场景重新划分验证集,加入不同光照、不同距离的图;推理时降低置信度阈值到 0.25 试试,看漏检是否减少;如果降低阈值后误检暴增,说明模型区分能力不够,需要补难例。
4.2 现象:自卸卡车和轮式装载机互相误检
原因:这两类设备在远距离或部分遮挡时外形相似,尤其是车斗和铲斗的轮廓。解决:检查标签里这两类的框是否有标错;在 data.yaml 里确认类别 id 没串;训练时对这两类加更高的分类 loss 权重,或者用更大的模型(yolov8m)提升特征区分度。如果数据里轮式装载机样本太少,考虑合并成「工程车辆」一类先跑通,再细分。
4.3 现象:训练 loss 正常但推理时框全偏了
原因:标签坐标归一化时用了错误的宽高,比如把 xml 里的宽高当成了 xmax/ymax。或者图片在训练时被 resize 但标签没同步。解决:用 2.1 的体检脚本检查坐标是否在 0~1 之间;随机抽几张图,用脚本把标签框画到图上,肉眼确认框的位置对不对。
import cv2 from pathlib import Path img_path = Path("images/train/001.jpg") label_path = Path("labels/train/001.txt") img = cv2.imread(str(img_path)) h, w = img.shape[:2] for line in label_path.read_text().strip().splitlines(): cls, xc, yc, bw, bh = map(float, line.split()) 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), (0, 255, 0), 2) cv2.imwrite("check.jpg", img)跑完打开 check.jpg,框如果偏了,就是标签问题,不是模型问题。
4.4 现象:显存溢出,batch 降到 4 还是炸
原因:imgsz 设太大,或者模型选太大,或者 dataloader 的 workers 太多导致内存泄漏。解决:先把 imgsz 降到 640,模型换 yolov8n,workers 设 4;如果还炸,用batch=2加梯度累积模拟大 batch;检查是否有图片尺寸异常大,比如 4000x3000 的图,先统一 resize 到长边 1280 再训。
4.5 现象:训练到一半 mAP 突然掉下去
原因:学习率太大导致震荡,或者数据里有脏标签在某个 epoch 被采样到。解决:看 loss 曲线,如果 cls_loss 突然飙升,大概率是脏标签;用 2.1 的脚本再扫一遍标签,重点看坐标越界和类别 id 异常的;把 lr0 降到 0.005,加 warmup epochs。
5. 把 2656 张用到极致:小数据集的进阶技巧与验证习惯
2656 张图在目标检测里属于小数据集,想榨出更高精度,有几个技巧我反复用过。第一,用预训练权重做迁移学习,yolov8n.pt 或 yolov8s.pt 都是在 COCO 上训过的,直接拿来微调比从头训快得多,mAP 也高。第二,用 K-fold 交叉验证代替单次划分,把 2656 张分成 5 折,每折都做一次验证,取平均 mAP,这样对模型真实能力的估计更稳。第三,对难例做针对性增强,比如把漏检的图挑出来,单独复制几份加不同增强再训一轮。
验证习惯上,我一般会做两件事:一是用测试集跑一次yolo detect val,看混淆矩阵,确认没有类别系统性混淆;二是用yolo detect predict跑一批实际场景图,肉眼数漏检和误检。混淆矩阵里如果挖掘机和背景的混淆很高,说明背景太杂,需要加负样本。下面这个命令导出混淆矩阵和 PR 曲线:
yolo detect val \ model=runs/excavator/baseline/weights/best.pt \ data=data.yaml \ split=test \ plots=True \ save_json=Trueplots=True会在 runs 目录下生成混淆矩阵、PR 曲线、F1 曲线。重点看混淆矩阵的对角线,如果某一类召回明显低,回去补这类样本。save_json=True导出 COCO 格式的预测结果,方便和其他模型对比。
最后一个习惯:每次改参数或改数据,只改一个变量,记录 mAP50 和 mAP50-95。我见过太多人一次改五个参数,结果涨了不知道哪个起作用,跌了不知道哪个背锅。小数据集训练玄学多,但可控的实验记录能让你少走很多弯路。希望帮到你。
本文还有配套的精品资源,点击获取