
简介本资源为面向YOLO系列目标检测算法的工程机械数据集聚焦自卸卡车、挖掘机与轮式装载机三类目标适合从事智慧工地、矿山监控、工程车辆识别等方向的研究者与开发者用于模型训练与验证。压缩包共2000个文件以xml标注文件为主同时提供YOLO格式txt与VOC格式xml两套标签分别存放于独立文件夹文件名末尾标注对应类别名称并附带data.yaml配置文件可直接适配yolov5、yolov8、yolov9、yolov7、yolov10及yolo11等主流版本。YOLO标签采用类别索引与归一化中心点、宽高比例的标准格式便于快速接入训练流程。资源包整体约232.47MB目录划分清晰已预先完成训练集与验证集切分省去自行整理与转换标注的环节。目前已有80人学习下载适合需要快速搭建工程机械检测基线、验证算法效果或进行迁移学习的读者参考使用。1. 从 2656 张工地图像说起这套挖掘机数据集到底能干什么工地上三班倒的土方作业挖掘机、自卸卡车、轮式装载机来回穿梭调度员靠对讲机喊话确认车辆位置效率低还容易出错。如果你正在做工程机械的视觉识别项目或者想用 YOLO 训练一个能识别工地车辆的模型手里却没有合适的数据集那这套 2656 张图像带标签的挖掘机数据集就是为你准备的。它覆盖挖掘机、自卸卡车、轮式装载机三类目标标注格式适配 YOLO 系列拿来就能直接进入训练流程。这个数据集解决的核心问题是省去从零采集和标注的时间。做过目标检测的人都知道标注 2000 多张图至少需要一周的重复劳动而且工地场景的光照变化、遮挡、尘土干扰都很考验标注一致性。这套数据已经完成了标注你拿到手之后的主要工作是验证标注质量、划分训练验证集、配置 YOLO 训练参数。适合的人群包括做智慧工地车辆调度的算法工程师、研究工程机械检测的学生、需要快速验证 YOLO 改进方案的研究者。如果你只是想跑通 YOLO 训练流程这套数据也够用因为三类目标的区分度明显不会因为类别混淆导致训练失败。2. 数据集拆包与标注格式验证2656 张图到底怎么组织2.1 解压后的目录结构与类别分布拿到压缩包后第一件事不是急着写训练脚本而是把目录结构摸清楚。常见的组织方式有两种一种是 images 和 labels 分开存放另一种是每张图对应一个同名 txt 文件放在一起。我一般会先跑一段脚本统计文件数量和类别分布确认没有缺图或空标签的情况。import os from collections import Counter # 假设解压后的根目录为 dataset_root dataset_root ./excavator_dataset images_dir os.path.join(dataset_root, images) labels_dir os.path.join(dataset_root, labels) # 统计图像和标签文件 image_files [f for f in os.listdir(images_dir) if f.endswith((.jpg, .png, .jpeg))] label_files [f for f in os.listdir(labels_dir) if f.endswith(.txt)] print(f图像总数: {len(image_files)}) print(f标签文件总数: {len(label_files)}) # 检查是否有图像缺少对应标签 missing_labels [] for img in image_files: base os.path.splitext(img)[0] if f{base}.txt not in label_files: missing_labels.append(img) print(f缺少标签的图像数: {len(missing_labels)}) # 统计各类别目标数量YOLO 格式第一列为类别索引 class_counter Counter() for lbl in label_files: with open(os.path.join(labels_dir, lbl), r) as f: for line in f: parts line.strip().split() if len(parts) 5: class_counter[int(parts[0])] 1 print(各类别目标数量:, dict(class_counter))这段脚本的逻辑很直接先确认图像和标签文件数量是否匹配再逐行读取 YOLO 格式的标签文件统计每个类别的目标框数量。参数方面dataset_root需要改成你实际解压的路径。如果输出显示图像总数是 2656 而标签文件数明显偏少说明有图像没标注需要决定是丢弃还是补标。类别索引 0、1、2 分别对应挖掘机、自卸卡车、轮式装载机具体映射关系要看数据集附带的 classes.txt 或 data.yaml 文件。2.2 YOLO 标注格式的字段含义与常见异常YOLO 格式的每行标注是class_id x_center y_center width height后四个值都是相对于图像宽高的归一化坐标范围在 0 到 1 之间。这个格式看起来简单但实际检查时经常遇到几类异常坐标值超出 [0,1] 范围、宽度或高度为 0、同一行字段数不足 5 个。这些异常如果不提前清理训练时会出现 loss 变成 NaN 或者模型完全不收敛的情况。# 检查标注异常 abnormal [] for lbl in label_files: with open(os.path.join(labels_dir, lbl), r) as f: for i, line in enumerate(f): parts line.strip().split() if len(parts) ! 5: abnormal.append((lbl, i, 字段数不对)) continue cls, x, y, w, h parts vals [float(x), float(y), float(w), float(h)] if any(v 0 or v 1 for v in vals): abnormal.append((lbl, i, 坐标越界)) if float(w) 0 or float(h) 0: abnormal.append((lbl, i, 宽高非正)) print(f异常标注行数: {len(abnormal)}) for item in abnormal[:10]: print(item)检查逻辑是逐行解析先看字段数是否为 5再判断坐标是否在合法范围内。如果异常行数占比很低比如不到 1%可以直接删除这些行如果占比超过 5%需要回头检查标注工具是否配置正确。我一般会把异常行单独导出到一个文件人工确认后再决定处理方式。这一步花十分钟能省掉训练时几个小时的排查时间。2.3 划分训练集、验证集和测试集2656 张图不算多划分比例建议 8:1:1即训练集约 2125 张、验证集约 265 张、测试集约 266 张。划分时要保证三类目标在三个子集中的分布大致均衡避免某个子集里缺少某一类。常见做法是按图像级别随机划分同时检查每个子集的类别计数。import random import shutil random.seed(42) all_images sorted(image_files) random.shuffle(all_images) n len(all_images) train_end int(n * 0.8) val_end int(n * 0.9) splits { train: all_images[:train_end], val: all_images[train_end:val_end], test: all_images[val_end:] } for split_name, files in splits.items(): img_out os.path.join(dataset_root, splits, split_name, images) lbl_out os.path.join(dataset_root, splits, split_name, labels) os.makedirs(img_out, exist_okTrue) os.makedirs(lbl_out, exist_okTrue) for img in files: base os.path.splitext(img)[0] shutil.copy(os.path.join(images_dir, img), os.path.join(img_out, img)) lbl_name f{base}.txt if os.path.exists(os.path.join(labels_dir, lbl_name)): shutil.copy(os.path.join(labels_dir, lbl_name), os.path.join(lbl_out, lbl_name)) print(划分完成)random.seed(42)保证每次运行划分结果一致方便复现。划分完成后建议再跑一次类别统计脚本确认三个子集的类别分布没有明显偏斜。如果验证集中某一类目标数量为 0需要调整随机种子或改用分层抽样。这个目录结构可以直接对接 YOLOv8 的data.yaml配置。3. 用 YOLOv8 跑通第一轮训练环境、配置与启动命令3.1 Anaconda 环境配置与 ultralytics 安装YOLOv8 的训练依赖 ultralytics 包环境配置是新手最容易翻车的地方。我一般用 Anaconda 建一个独立环境Python 版本选 3.9 或 3.10这两个版本和 PyTorch 的兼容性最稳。显卡驱动和 CUDA 版本需要提前确认nvidia-smi能正常输出就说明驱动没问题。conda create -n yolo_train python3.10 -y conda activate yolo_train pip install ultralytics pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118第一行创建环境第二行激活第三行安装 ultralytics第四行安装带 CUDA 11.8 支持的 PyTorch。如果你的显卡驱动对应的是 CUDA 12.x把cu118改成cu121。安装完成后跑yolo checks可以查看环境是否正常重点看 CUDA 是否可用。如果显示 CPU only说明 PyTorch 版本和驱动不匹配需要重新安装。3.2 data.yaml 的字段填写与路径陷阱YOLOv8 训练需要一个data.yaml文件来描述数据集路径和类别信息。这个文件看着简单但路径写错是最高频的翻车点。常见错误包括用了相对路径但工作目录不对、Windows 下反斜杠转义、类别名称和索引顺序不一致。path: /home/user/excavator_dataset/splits train: train/images val: val/images test: test/images names: 0: excavator 1: dump_truck 2: wheel_loaderpath是数据集根目录train、val、test是相对于path的子路径。names里的索引必须和标注文件中的 class_id 一一对应。如果标注时挖掘机是 0、自卸卡车是 1、轮式装载机是 2这里就不能写反。我见过有人把 names 写成列表形式导致训练时报 key 错误YOLOv8 要求 names 是字典格式键是整数索引。3.3 启动训练命令行参数与首轮结果解读配置好 data.yaml 之后训练命令本身不复杂关键是参数怎么设。第一次训练建议用 yolov8n.pt 预训练权重输入尺寸 640batch size 根据显存调整8GB 显存用 16 比较稳。yolo detect train \ modelyolov8n.pt \ data./data.yaml \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ project./runs \ nameexcavator_v1model指定预训练权重data指向配置文件epochs是训练轮数imgsz是输入图像尺寸batch是批大小lr0是初始学习率patience是早停耐心值project和name控制输出目录。训练启动后重点关注三个指标box_loss 是否稳定下降、mAP50 是否逐步上升、cls_loss 是否出现震荡。如果 box_loss 在前几个 epoch 就变成 NaN大概率是标注里有越界坐标或宽高为 0 的行回到第 2 章检查标注异常。首轮训练结束后runs/excavator_v1/weights/目录下会生成best.pt和last.pt。best.pt是验证集 mAP 最高的权重后续推理和部署都用它。如果 mAP50 在 0.6 以下先别急着调模型结构检查验证集标注是否准确、类别是否均衡。4. 训练效果不达标时的排查顺序从数据到参数的逐层定位4.1 先看数据标注质量比模型结构更影响结果模型训练效果差八成问题出在数据上。我习惯按这个顺序排查先可视化一批标注框确认框的位置和类别是否正确再统计各类别的目标数量看是否存在严重不均衡最后检查训练集和验证集的分布是否一致。可视化可以用 ultralytics 自带的工具也可以自己写脚本把标注框画到原图上。import cv2 def draw_yolo_label(img_path, lbl_path, save_path): img cv2.imread(img_path) h, w img.shape[:2] with open(lbl_path, r) as f: for line in f: parts line.strip().split() if len(parts) ! 5: continue cls, x, y, bw, bh map(float, parts) x1 int((x - bw / 2) * w) y1 int((y - bh / 2) * h) x2 int((x bw / 2) * w) y2 int((y bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, str(int(cls)), (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) cv2.imwrite(save_path, img)这段代码把归一化坐标还原成像素坐标再画框和类别索引。随机抽 20 张图跑一遍肉眼确认框是否贴合目标。如果发现大量框偏移或类别标错说明标注质量有问题需要重新标注或清洗。这一步虽然笨但比盲目调参有效得多。4.2 再调参数学习率、batch size 和输入尺寸的联动数据没问题的情况下再考虑调参。学习率是最敏感的参数lr00.01是 YOLOv8 的默认值但如果你的数据集较小2656 张属于小数据集可以降到 0.005 甚至 0.001避免训练初期震荡。batch size 受显存限制但太小会导致梯度估计不准建议至少 8。输入尺寸imgsz从 640 提到 1280 能提升小目标检测效果但显存占用会翻倍需要同步降低 batch size。参数默认值小数据集建议值影响lr00.010.005学习率过高导致 loss 震荡batch168 或 16过小导致梯度估计不准imgsz640640 或 1280增大提升小目标召回但显存翻倍patience5020小数据集早停避免过拟合epochs100100-200配合早停使用调参时每次只改一个变量记录 mAP50 和 mAP50-95 的变化。如果改了学习率但效果没变说明瓶颈不在学习率回到数据层面继续查。4.3 最后看模型预训练权重和网络规模的选型YOLOv8 提供 n、s、m、l、x 五个规模参数量从 300 万到 6800 万不等。2656 张图的数据量用 yolov8n 或 yolov8s 就够了用更大的模型反而容易过拟合。如果 yolov8n 的 mAP50 已经到 0.85 以上换 yolov8s 可能提升 1-2 个点但推理速度会下降。我一般先用 yolov8n 跑基线确认数据没问题后再尝试 yolov8s对比验证集指标决定是否升级。5. 避坑记录标注、路径和显存这三类问题最耗时间5.1 标注文件里的类别索引和 names 对不上现象训练启动后 cls_loss 一直很高mAP50 接近 0。原因标注文件里的 class_id 和 data.yaml 中 names 的键不一致比如标注用的是 1、2、3 而 names 写的是 0、1、2。解决用第 2 章的统计脚本打印实际出现的 class_id 集合和 names 的键做对比改成一致后重新训练。5.2 Windows 路径反斜杠导致 data.yaml 解析失败现象训练报错FileNotFoundError但路径在文件管理器里能打开。原因Windows 下复制路径带反斜杠YAML 把\当转义字符。解决把路径里的\全部改成/或者用双反斜杠\\。更稳妥的做法是把数据集放在纯英文无空格的路径下避免编码问题。5.3 显存不足导致训练中途崩溃现象训练跑了几个 epoch 后报 CUDA out of memory。原因batch size 或 imgsz 设得太大或者没有及时释放缓存。解决把 batch 降到 8imgsz 保持 640在训练脚本开头加torch.cuda.empty_cache()。如果还不行用yolo detect train ... ampFalse关闭混合精度能省一部分显存但训练会慢一些。5.4 验证集 mAP 波动大怀疑标注不一致现象每个 epoch 的 mAP50 上下跳动超过 5 个点。原因验证集样本太少或标注质量参差不齐。解决把验证集比例从 10% 提到 15%同时用 4.1 的可视化脚本抽查验证集标注把明显错误的框修正或删除。小数据集上 mAP 波动是正常的但波动过大通常意味着标注有问题。5.5 训练完推理时检测框重叠严重现象推理结果里同一个目标出现多个重叠框。原因置信度阈值和 NMS IoU 阈值不匹配。解决推理时调整conf和iou参数conf0.25、iou0.45是常用起点。如果目标密集把 iou 降到 0.3 能减少重叠框但可能漏检相邻目标。6. 从能跑到好用置信度门限调优与推理脚本的工程化训练出 best.pt 只是第一步真正落地时推理脚本的鲁棒性决定了这套方案能不能用。我一般会在推理脚本里加三个东西置信度门限可配置、结果保存带原图和时间戳、批量推理时打印每张图的检测耗时。置信度门限的调整没有固定公式需要根据业务场景试。工地车辆调度场景下漏检比误检代价高所以 conf 可以降到 0.2如果是统计报表场景误检会污染数据conf 提到 0.4 更合适。from ultralytics import YOLO import time import os model YOLO(./runs/excavator_v1/weights/best.pt) def infer_batch(image_dir, conf_thres0.25, iou_thres0.45): results [] for img_name in sorted(os.listdir(image_dir)): if not img_name.endswith((.jpg, .png)): continue img_path os.path.join(image_dir, img_name) t0 time.time() preds model.predict(img_path, confconf_thres, iouiou_thres, verboseFalse) dt (time.time() - t0) * 1000 boxes preds[0].boxes n len(boxes) if boxes is not None else 0 results.append((img_name, n, round(dt, 1))) print(f{img_name}: {n} 个目标, 耗时 {dt:.1f} ms) return results infer_batch(./splits/test/images, conf_thres0.25, iou_thres0.45)这段脚本遍历测试集图像逐张推理并打印目标数量和耗时。conf_thres和iou_thres作为参数传入方便快速对比不同门限下的结果。verboseFalse关掉 ultralytics 的默认日志输出让控制台只显示我关心的信息。实际部署时我会先用一批典型场景图跑一遍把 conf 从 0.1 到 0.5 按 0.05 步长扫一遍记录每个门限下的检出数量和误检情况选一个业务上可接受的平衡点。还有一个容易被忽略的点推理时的输入尺寸要和训练时一致。训练用imgsz640推理时如果传入 1280 的图ultralytics 会自动缩放但小目标的召回会变化。我一般会在推理脚本里显式指定imgsz640保证和训练对齐。如果业务场景里目标普遍较小训练和推理都提到 1280但需要重新评估显存和速度。最后说一个血泪教训不要等到训练完才去检查测试集。我习惯在划分完数据后先跑一遍测试集的标注可视化确认测试集里的目标类别和训练集一致。有一次测试集里混进了几张没有标注的图推理时模型输出一堆低置信度框排查了半天才发现是数据划分的问题。现在我的习惯是划分完数据先可视化训练完先看验证集混淆矩阵推理完先抽查 20 张结果图。这三步做完心里才有底。希望帮到你。本文还有配套的精品资源点击获取