简介这份资源面向从事工业安全检测与计算机视觉的开发者提供煤矿传动带异物检测的YOLO系列目标检测数据集可直接用于模型训练与验证测试适配yolov5、yolov8、yolov9、yolov7、yolov10及yolo11等主流算法。压缩包共2000个文件以xml标注文件为主同时提供yolo格式txt与voc格式xml两套标签分别存放于独立文件夹yolo格式采用类别索引加归一化中心点与宽高的标准写法便于直接接入训练流程。资源包整体约240.41MB目录划分清晰已预先完成训练集与验证集切分省去自行整理与转换标注的环节。目前已有511人学习下载适合需要快速搭建煤矿传动带异物检测基线、验证算法效果或开展工业场景迁移学习的中高级读者参考使用。1. 煤矿传动带异物检测为什么 10584 张图像的数据集值得你花时间跑一遍煤矿传动带跑起来的时候锚杆、木块、铁丝、大矸石混在煤流里一旦卡进滚筒或撕裂皮带停机损失按小时算。传统做法靠人盯监控夜班疲劳、粉尘遮挡、光照突变漏检几乎是必然。YOLO 算法做传动带异物检测核心逻辑是把「检测什么」交给标注数据把「怎么检测」交给卷积网络端到端出框。这个标题里的 10584 张图像带标签数据集价值不在于数字大而在于它覆盖了井下真实工况的多样性——不同带宽、不同照度、不同异物形态。适合谁做工业视觉落地的算法工程师、想从公开数据集切入煤矿场景的研究生、以及需要快速验证 YOLO 在传送带场景是否可用的技术负责人。你不需要先建一个矿井但你需要知道这批数据怎么喂给 YOLO、参数怎么调、坑在哪。2. 从 10584 张图像到 YOLO 可读格式数据集的拆包与清洗2.1 先看清压缩包里到底有什么拿到煤矿传动带异物检测数据集-10584张图像带标签.zip别急着解压完就开训。常见做法是先列目录结构确认图像和标签是否一一对应。我一般会写个脚本统计文件数量、扩展名分布、标签格式是 VOC XML 还是 YOLO TXT 还是 COCO JSON。这一步决定了后面要不要写转换脚本。import os import zipfile from collections import Counter zip_path 煤矿传动带异物检测数据集-10584张图像带标签.zip ext_counter Counter() img_count 0 label_count 0 with zipfile.ZipFile(zip_path, r) as z: for name in z.namelist(): ext os.path.splitext(name)[1].lower() ext_counter[ext] 1 if ext in [.jpg, .jpeg, .png, .bmp]: img_count 1 if ext in [.txt, .xml, .json]: label_count 1 print(扩展名分布:, ext_counter) print(f图像总数: {img_count}, 标签文件总数: {label_count})逻辑说明这段代码不真正解压只读中央目录速度快。参数说明zip_path换成你本地的实际路径ext_counter用来判断标签是 TXT 还是 XML。如果图像数和标签数不一致说明有缺失或多余文件需要先对齐文件名再谈训练。2.2 标签格式转换VOC 转 YOLO 的四个边界坑如果标签是 XMLVOC 格式YOLO 需要的是归一化后的class_id x_center y_center width height。转换脚本网上一搜一大把但真正跑起来容易翻车的地方有四个图像尺寸读错、坐标越界、类别名大小写不一致、空标签文件没跳过。import xml.etree.ElementTree as ET from PIL import Image import os classes [anchor, wood, iron, rock] # 按你的实际类别改 class_map {name: idx for idx, name in enumerate(classes)} def voc_to_yolo(xml_path, img_dir, out_dir): tree ET.parse(xml_path) root tree.getroot() img_name root.find(filename).text img_path os.path.join(img_dir, img_name) if not os.path.exists(img_path): return with Image.open(img_path) as im: w, h im.size lines [] for obj in root.findall(object): cls_name obj.find(name).text.strip() if cls_name not in class_map: 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)) xmax max(0, min(xmax, w)) ymin max(0, min(ymin, h)) ymax max(0, min(ymax, h)) if xmax xmin or ymax ymin: continue xc (xmin xmax) / 2.0 / w yc (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{class_map[cls_name]} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}) if not lines: return out_path os.path.join(out_dir, os.path.splitext(img_name)[0] .txt) with open(out_path, w) as f: f.write(\n.join(lines))逻辑说明先读图像真实宽高再做归一化。参数说明classes列表必须和你的标注类别完全一致顺序决定class_idxmin等坐标做max(0, min(..., w))裁剪防止标注员手抖画出界空标签文件直接跳过否则 YOLO 训练时会报ZeroDivisionError或产生无效锚框。2.3 训练集/验证集划分别让同一段皮带的图像同时出现在两边10584 张图像如果随机按 8:2 划分同一段传动带、同一时刻的连续帧可能被拆到训练集和验证集导致验证指标虚高。常见做法是按视频片段或时间戳分组划分。如果数据集没有提供分组信息至少按文件名前缀聚类保证同一前缀的图像只进一个集合。import os import random from sklearn.model_selection import GroupShuffleSplit img_files sorted(os.listdir(images)) # 假设文件名格式为 belt01_20240101_001.jpg取 belt01 作为组 groups [f.split(_)[0] for f in img_files] gss GroupShuffleSplit(n_splits1, test_size0.2, random_state42) train_idx, val_idx next(gss.split(img_files, groupsgroups)) with open(train.txt, w) as f: for i in train_idx: f.write(os.path.abspath(os.path.join(images, img_files[i])) \n) with open(val.txt, w) as f: for i in val_idx: f.write(os.path.abspath(os.path.join(images, img_files[i])) \n)逻辑说明GroupShuffleSplit按组划分避免同一段皮带的图像泄漏。参数说明test_size0.2是验证集比例数据量少时可调到 0.15random_state固定后结果可复现。如果文件名没有分组信息退而求其次用train_test_split但要在报告里注明可能存在泄漏。3. YOLO 训练参数怎么设从预训练权重到学习率调度3.1 选 YOLOv8 还是 YOLOv5煤矿场景的取舍YOLOv8 的 anchor-free 头对小目标更友好传动带上的铁丝、小锚杆属于小目标我一般优先选 YOLOv8n 或 YOLOv8s。YOLOv5 的生态更成熟部署到 TensorRT 的教程多。如果你手头有yolo预训练模型下载的需求直接去 Ultralytics 官方仓库下yolov8n.pt或yolov5s.pt不要用来路不明的权重。煤矿场景图像偏暗、对比度低预训练权重能加速收敛但不要冻结全部主干否则模型学不到井下特征。# YOLOv8 训练命令示例 yolo detect train \ datacoal_belt.yaml \ modelyolov8s.pt \ epochs150 \ imgsz640 \ batch16 \ lr00.01 \ lrf0.01 \ patience30 \ device0 \ workers8 \ projectcoal_belt_runs \ nameexp01逻辑说明data指向数据集配置文件里面写train、val、nc、names。参数说明imgsz640是常见起点小目标多可升到 1280 但显存翻倍batch16在 8G 显存下跑 YOLOv8s 比较稳lr00.01是初始学习率lrf0.01是最终学习率因子余弦调度patience30表示 30 轮无提升就早停。workers设成 CPU 核心数的 70% 左右太高反而抢资源。3.2 数据增强煤矿粉尘和光照变化的模拟传动带场景的难点是粉尘、水雾、光照不均。YOLO 默认增强包括 HSV 抖动、随机翻转、 mosaic。我一般会额外加hsv_v0.5模拟暗光hsv_s0.7模拟粉尘导致的饱和度下降但不要开flipud因为传动带上下翻转不符合物理实际。# coal_belt.yaml path: /data/coal_belt train: train.txt val: val.txt nc: 4 names: [anchor, wood, iron, rock] # 增强参数在 train 命令里覆盖或写进 hyp hsv_h: 0.015 hsv_s: 0.7 hsv_v: 0.5 degrees: 5.0 translate: 0.1 scale: 0.5 shear: 2.0 perspective: 0.0 flipud: 0.0 fliplr: 0.5 mosaic: 1.0 mixup: 0.1逻辑说明hsv_v0.5让模型见过更暗的图像flipud0.0关闭上下翻转mixup0.1轻度混合防止过拟合。参数说明degrees旋转角度不要太大传动带异物方向有物理约束scale0.5允许缩放模拟不同距离。3.3 损失函数与正负样本YOLO 损失函数在异物检测中的表现YOLOv8 的分类损失用 BCE回归用 CIoU 加 DFL。传动带异物检测里背景占绝大多数正样本极少容易出现「全预测背景」的塌缩。我一般会检查cls_loss是否在早期就降到接近零如果是说明正样本权重不够或学习率太低。可以适当提高box损失权重或在数据层面做过采样把含异物的图像复制一份。# 统计正样本比例判断是否需要过采样 import os label_dir labels/train total_boxes 0 empty_files 0 for f in os.listdir(label_dir): with open(os.path.join(label_dir, f)) as fh: lines fh.readlines() if not lines: empty_files 1 total_boxes len(lines) print(f总标注框: {total_boxes}, 空标签文件: {empty_files}) print(f平均每图标注框: {total_boxes / (len(os.listdir(label_dir)) - empty_files):.2f})逻辑说明空标签文件多说明背景图多正样本稀疏。参数说明如果平均每图标注框小于 0.5建议过采样含异物的图像或在train命令里设cls1.5提高分类损失权重。4. 训练过程排查loss 不降、mAP 抖动、显存爆了怎么办4.1 现象loss 从第一轮就不降原因学习率太大、数据标签格式错、图像路径不对。解决先用 10 张图过拟合如果 loss 能降到接近零说明模型和代码没问题是数据量或学习率的问题。把lr0降到 0.001 再试同时检查train.txt里的路径是否真实存在。4.2 现象mAP 在 0.3 附近震荡不升原因验证集和训练集分布不一致或标注质量差。解决可视化验证集的预测框看是不是把粉尘当成异物或者漏标了部分异物。煤矿场景里锚杆和铁丝在低分辨率下几乎一样需要确认标注一致性。可以把imgsz从 640 升到 960 再训一轮对比。4.3 现象训练到一半显存爆了原因batch太大或workers太多导致内存泄漏。解决把batch减半workers降到 4开ampTrue混合精度。如果还爆检查是不是mosaic增强在后期产生了超大图像可以在最后 10 轮关掉mosaicclose_mosaic10。4.4 现象验证集 mAP 很高但实际推理漏检严重原因验证集泄漏同一段皮带的图像同时出现在训练和验证。解决回到 2.3 节按组重新划分。另外检查推理时的预处理是否和训练一致比如归一化参数、letterbox 填充方式。4.5 现象模型把传送带边缘当成异物原因标注时把皮带边缘的磨损也标成了异物或者负样本不足。解决清洗标注把非异物的边缘磨损删掉增加纯背景图像作为负样本比例控制在 10% 左右。5. 推理部署与效果验证从 PyTorch 到 TensorRT 的最后一公里5.1 用验证集跑一遍混淆矩阵别只看 mAPmAP 是综合指标但煤矿现场更关心漏检率。用 YOLO 的val模式生成混淆矩阵重点看anchor和iron是否被大量误判为背景。如果漏检集中在某一类回到训练集补该类样本。yolo detect val \ modelcoal_belt_runs/exp01/weights/best.pt \ datacoal_belt.yaml \ imgsz640 \ conf0.25 \ iou0.5 \ plotsTrue逻辑说明conf0.25是置信度阈值现场可调到 0.3 降低误报plotsTrue生成混淆矩阵和 PR 曲线。参数说明iou0.5是 NMS 的 IoU 阈值异物重叠少可保持默认。5.2 导出 ONNX 和 TensorRT注意动态轴和 FP16PyTorch 权重直接部署到工控机延迟高常见做法是导出 ONNX 再用 TensorRT 加速。导出时注意dynamic轴设置batch 维度动态宽高固定为 640。yolo export \ modelcoal_belt_runs/exp01/weights/best.pt \ formatengine \ imgsz640 \ halfTrue \ device0 \ dynamicFalse逻辑说明formatengine直接生成 TensorRT 引擎halfTrue用 FP16速度提升明显精度损失通常小于 1%。参数说明dynamicFalse固定 batch1适合单路视频流如果要多路并发设dynamicTrue并指定batch4或8。5.3 现场验证用一段真实视频跑推理看帧率和漏检拿一段井下传动带的真实视频用导出的引擎跑统计平均帧率和漏检次数。我一般会写个简单脚本把预测框画到视频上人工抽检 100 帧。如果帧率低于 25 FPS考虑降imgsz到 512 或换更小的模型。import cv2 from ultralytics import YOLO model YOLO(coal_belt_runs/exp01/weights/best.engine) cap cv2.VideoCapture(belt_video.mp4) fps_list [] while cap.isOpened(): ret, frame cap.read() if not ret: break results model(frame, conf0.3, verboseFalse) annotated results[0].plot() cv2.imshow(result, annotated) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()逻辑说明conf0.3比验证时略高减少误报verboseFalse关闭日志刷屏。参数说明best.engine是 TensorRT 引擎路径首次加载较慢后续推理快。5.4 一个具体技巧用软标签缓解类别混淆锚杆和铁丝在低照度下纹理接近硬标签容易让模型在两类之间反复横跳。我试过把标注的 one-hot 改成软标签比如锚杆 0.8、铁丝 0.2训练时用 KL 散度替代 BCE。YOLOv8 不直接支持但可以改损失函数里的cls_loss计算方式。这个技巧在类别边界模糊时能提升 2 到 3 个点的 mAP代价是训练代码要动刀。# 伪代码软标签分类损失 import torch.nn.functional as F def soft_cls_loss(pred, soft_target): log_prob F.log_softmax(pred, dim-1) return -(soft_target * log_prob).sum(dim-1).mean()逻辑说明soft_target是人工构造的软标签矩阵每行和为一。参数说明软标签的平滑系数建议 0.1 到 0.2太大反而模糊类别边界。我自己的习惯是每次训完先看混淆矩阵再看 20 张漏检图最后才决定要不要调参。数据集再好标注不一致也会让模型学偏。希望帮到你。本文还有配套的精品资源点击获取