基于YOLOv5的煤矿大块煤识别数据集构建与训练实践

基于YOLOv5的煤矿大块煤识别数据集构建与训练实践
简介本资源是面向煤矿智能化检测与工业视觉识别领域的专业数据集专为YOLOv5等PyTorch框架下的目标检测模型训练与验证设计解决大块煤在复杂煤堆场景中精准识别与尺寸判别难题适用于算法工程师、矿业AI应用开发者及计算机视觉初学者开展实战建模。压缩包共2000个文件含1767张煤矿现场实采图像JPG格式、对应YOLOv5标准格式的标注TXT文件每图一标含归一化坐标与类别ID以及统一配置的data.yaml元信息文件整体体积39.15MB结构规范、开箱即用。目前已有452人学习下载数据覆盖多光照、多角度、多堆积形态的真实工况所有图像均经人工复核标注可直接用于模型训练、mAP评估及工业部署前的数据增强实验。 煤矿现场的监控画面我盯过很久说真的让一个人连续盯着皮带上的煤流找大块煤十五分钟之后注意力就很难保证了。但大块煤一旦漏过去轻则堵溜槽重则卡破碎机皮带跑偏撕裂也是常见的连锁事故。所以这两年煤矿智能化项目里“大块煤识别”几乎成了标配需求而实现这个功能的底层支撑就是一套靠谱的目标检测数据集。我这边整理了一套煤矿现场采集的大块煤识别数据集总共1767张现场图片已经按YOLOv5的PyTorch训练格式全部标注完成专门用于训练大块煤检测模型。坦白讲1767张图放在公开数据集里不算多但对于煤矿现场这种场景相对固定、目标外观变化有限的工业项目来说这个量级完全够用关键要看数据怎么做。这篇文章我就把整套流程拆开讲清楚从采集思维、清洗标准、标注规范到YOLO txt格式制作、训练环境配置、常见坑点排查全部过一遍。不管你是刚接触目标检测还是已经在做工业视觉项目都可以把这篇文章当成一份可复用的操作手册。1. 项目背景为什么煤矿现场要识别大块煤1.1 大块煤识别的真实痛点“大块煤”这个说法在选煤厂、装车站、井下运输巷道里经常出现但严格定义并不完全统一。有的煤矿把大于300mm粒径的叫大块煤有的把大于500mm的叫大块煤阈值取决于破碎机入口尺寸、筛分设备孔径和后续工艺的承受能力。不管阈值定多少业务需求都差不多从运动的煤流里把超粒径的煤块找出来然后触发破碎、分流或者人工清理的动作。不做这件事会有什么后果选煤环节中大块煤进入破碎机容易卡死转子一次卡停至少耽误半小时生产运输环节里大块煤在皮带上容易造成跑偏严重的会撕裂皮带一条皮带的更换成本动不动就是几十万。装车环节更直接如果大块煤混进商品煤里煤质指标会出问题下游客户投诉和扣款都是真金白银的损失。所以很多煤矿宁可多上一套视觉识别系统也不愿意靠人工盯监控。而视觉方案之所以流行是因为现场环境太恶劣雷达、红外这类传感器对粉尘和角度都比较敏感工业摄像头加目标检测模型反而是成本低、响应快、可复制的方案。1.2 1767张图像应该覆盖哪些现场场景一套数据能不能撑起模型光看数量是不够的。我对比过不少数据集有些总量看着很大但2000张图里有1600张是同一个皮带同一角度的连续帧模型训练完换一个现场点位就拉胯。1767这个数量放到工业视觉里不算大规模但如果采集的时候有意识地覆盖了不同位置、不同角度、不同光照它的“有效多样性”反而比那种同质化堆量的数据强很多。具体到煤矿现场常见采集点位大概有这么几类皮带运输机上方的俯拍视角这是最主流的角度煤流从镜头下方高速通过溜槽或者落料口旁边的侧拍视角目标会出现堆叠、遮挡难度更高堆场或煤仓的远距离视角煤堆层叠大块煤混在里面不那么显眼振动筛筛面附近的平视视角煤块在振动状态下边界会有拖影。每类场景下还要尽量覆盖不同光照白天自然光、夜间补光灯、粉尘浓度高的时段、刚洒水完煤流表面反光明显的时段。这样组合下来模型能接触到的大块煤外观变化才够完整训练出来的检测器在现场才敢用。2. 数据准备采集、清洗与标注规范2.1 现场图像采集的两种方式和关键参数煤矿现场图像的获取通常有两种方式。一种是直接用现场已有的监控录像抽帧这是最省事的做法。监控系统一般24小时开着把视频导出来之后按时间间隔抽帧就行比如每3秒取1帧或者按关键帧取避免相邻帧内容太接近。另一种是有条件的新点位用工业相机专门拍摄建议分辨率不低于1920×1080如果资金允许直接上500万像素的相机画面里小目标保留的细节会更多。不管哪种方式有几个参数要特别留意。压缩码率不能太低H.264编码如果码率给得太低画面里小煤块的边缘会发糊标注的时候边界不好判断模型学到的特征也是脏的。拍摄角度尽量固定巡检人员手持手机临时拍几张也能用但如果同一个点位能固定安装摄像头得到的视频连续性强抽帧后目标尺寸变化更自然训练效果通常更好。另外帧率和快门速度也要匹配煤流速度煤流跑得快的时候如果快门速度太低画面里全是运动模糊这种图标了也没意义。2.2 图像清洗筛选标准哪些图必须扔掉很多人做数据集时容易忽略清洗这一步觉得拍回来的图都能用其实这是大错特错。标注一个模糊框不仅浪费人工还会给训练引入噪声框和目标的边界对不上模型收敛都会受影响。我实际操作时一般按下面这套标准筛图图像问题处理方式原因严重运动模糊、失焦直接剔除目标和背景边界无法准确判断连续帧高度重复每3到5秒抽1帧保留有效信息避免训练集冗余曝光过度或严重反光剔除轻微欠曝可保留过曝会让煤块细节完全丢失分辨率过低、压缩痕迹明显剔除小目标像素太少无法有效学习目标几乎不可辨识剔除人工硬标会教坏模型这套标准执行下来1767张图可能要从原始素材中筛掉一两成这很正常。目标检测数据集的常见误区是“差不多就行”但框歪了、面积带大了、类别边界的煤块也标进去了这些噪声累积起来会直接反映在mAP上而且后期排查起来非常消耗耐心。2.3 类别定义与标框策略单类别也不简单类别定义方面初始数据集建议只设一个类别名字可以叫“large_coal”或者“big_coal”。有人会问要不要把小块煤也标上做负样本我的建议是不要。YOLOv5训练时背景本身就会作为负样本参与学习不需要人为额外标注背景类别。如果后续工艺需要区分“超大块”和“一般大块”再追加类别训练也不迟但首次训练请保持简单类别越多初期标注不一致带来的问题就越多。标框策略是大块煤数据集真正考验人的地方。YOLOv5用的是水平矩形框不支持旋转框所以目标再长再斜也只能用矩形贴住这要求标注员对“紧贴可见边缘”有统一的理解。我整理了几条标框原则水平框尽量紧贴目标可见边缘宁紧勿松框太松会把背景煤粉学进去多个煤块粘连时按视觉上可区分的边界拆开标如果实在分不开就整体框一个但要做好记录目标被遮挡超过一半的不标遮挡面积小的话标可见部分在图像边界的截断目标可见面积超过1/3就标太小直接忽略同一张图里如果目标很少不要为了凑数硬标保持真实分布。这些原则看起来简单实际执行起来最大的敌人是“手懒”。特别是那种边缘模糊的煤流图标几个框顺手一拉框比煤块大了一圈叠加上千张图之后模型学到的位置误差就非常明显了。3. 标注与格式转换做成YOLOv5能直接用的数据集3.1 标注工具选择与操作流程标注工具这一块我试过不少最终在本地环境里还是最常用LabelImg。它是传统的桌面标注工具轻量、启动快、对单类别标注完全够用也支持直接导出YOLO格式。安装方式很简单pip install labelImg labelImg启动之后左侧选择Open Dir加载图片目录右侧选择Change Save Dir设置标签存放目录顶部菜单把保存格式切换成YOLO。快捷键W是画框A和D切换上一张下一张CtrlS保存当前标注一个人标单类别数据大概能维持每分钟3到5张的速度。如果有一定基础也可以试试X-AnyLabeling它内置了一些自动标注模型可以先用模型跑一遍预标注再人工修正。但第一次做数据我不建议过度依赖自动标注因为初期的标注错误会被模型学进去后面再想纠正就要重新洗数据。手工标一遍虽然累但你知道每个框是用什么标准画出来的后续训练出问题也好从数据维度排查。3.2 YOLOv5数据格式详解一张图对应一个txt严格来说YOLOv5的标注文件是纯文本的YOLO格式PyTorch是模型训练框架二者不是同一层的东西。标题里写“yolov5pytorch格式”实际含义就是这份数据集可以直接拿给基于PyTorch的YOLOv5仓库去训练。新手不用被这个组合词吓到它本质上就是三样东西图像文件夹、同名txt标签文件夹、一个data.yaml配置文件。标准的目录结构是这样coal_dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yaml每张图像对应一个同名的txt文件比如IMG_0001.jpg对应IMG_0001.txt。txt里每一行代表一个目标格式固定为5个字段class_id x_center y_center width height特别注意所有坐标都是归一化后的数值范围在0到1之间用像素坐标除以图像宽高得到。举个例子假设图像宽度是1920高度是1080某个大块煤的左上角像素坐标是(480, 270)右下角是(720, 540)那么计算过程是x_center ((480 720) / 2) / 1920 0.3125y_center ((270 540) / 2) / 1080 0.375width (720 - 480) / 1920 0.125height (540 - 270) / 1080 0.25所以这一行就是0 0.3125 0.375 0.125 0.25。单个txt文件里有几行就代表这张图里有几个大块煤目标。如果某张图没有目标txt文件应该留空或者直接不创建但YOLOv5在训练时会对空标签做特殊处理建议目录里保留一个空txt不要完全缺失避免文件名匹配逻辑产生意外问题。还要注意一个细节YOLOv5加载数据时会自动把图像路径里的images替换成labels去找对应标签所以目录命名一定要按约定来images和labels这两个文件夹名字不能改否则训练时百分之百报错。3.3 训练集与验证集划分不要踩数据泄露的坑很多人在划分训练集和验证集时习惯直接随机打散对一般数据问题不大但对煤矿现场抽帧得到的图片来说这里藏着一个坑如果同一段视频的连续帧同时出现在训练集和验证集里模型其实已经“见过”验证集的图像了验证集评估出来的指标会虚高现场部署后一遇到新的角度就露馅。稳妥的做法是划分之前先按场景分组确保同一条皮带、同一台相机的画面尽量全部进入同一个集合。比如有3个点位的监控画面可以按点位划分点位1和点位2的图片进训练集点位3进验证集这样验证集才真正模拟了“没见过的场景”。如果点位不够退一步也应该按时间区间划分前几天的视频帧进训练集后几天的进验证集。下面是我常用的划分脚本固定随机种子保证可复现import os import random import shutil random.seed(42) img_src all_images label_src all_labels train_ratio 0.9 imgs [f for f in os.listdir(img_src) if f.endswith(.jpg)] random.shuffle(imgs) val_count int(len(imgs) * (1 - train_ratio)) val_imgs imgs[:val_count] train_imgs imgs[val_count:] for split, split_imgs in [(train, train_imgs), (val, val_imgs)]: os.makedirs(fimages/{split}, exist_okTrue) os.makedirs(flabels/{split}, exist_okTrue) for img in split_imgs: shutil.copy(os.path.join(img_src, img), fimages/{split}/{img}) label_file img.rsplit(., 1)[0] .txt label_path os.path.join(label_src, label_file) if os.path.exists(label_path): shutil.copy(label_path, flabels/{split}/{label_file})这段脚本会把90%的图片复制到训练集10%到验证集。如果你的数据不是按场景分好组的建议在上面代码之前先按目录把图片分组再把组级数据划分到不同集合而不是对单张图片做随机划分。3.4 编写data.yaml配置文件YOLOv5训练时必须给一个data.yaml文件描述数据集路径和类别信息。我的配置是这样的path: D:/datasets/coal_dataset train: images/train val: images/val nc: 1 names: [large_coal]各字段含义很直观path是数据集的根目录绝对路径或者相对路径train和val是相对于根目录的训练和验证图片文件夹nc是类别数量names是类别名称列表顺序和标注txt里的类别编号一一对应。需要注意names列表的下标从0开始所以只有names[0]也就是large_coal对应标注文件里的0。这里有个小坑path字段在YOLOv5不同版本里的作用有细微差别老版本可能没有path字段而是直接在train和val里写完整路径。如果你用的是新版本建议写相对路径加path的组合方式如果训练时提示找不到图片路径改成在train和val里填绝对路径问题一般就解决了。3.5 标注质量自动校验脚本1767张图手工标注下来难免有漏网之鱼。有的图可能保存成了Pascal VOC格式有的坐标没归一化有的类别编号写错了直接在训练时才报错会很被动。所以在训练前我强烈建议先跑一遍标注校验脚本把所有标签文件扫一遍import os label_dir labels/train errors [] for f in sorted(os.listdir(label_dir)): if not f.endswith(.txt): continue with open(os.path.join(label_dir, f)) as fp: lines fp.readlines() for line_no, line in enumerate(lines, 1): parts line.strip().split() if len(parts) ! 5: errors.append(f{f}:{line_no} 字段数不对) continue cid, x, y, w, h parts if not cid.isdigit() or int(cid) 1: errors.append(f{f}:{line_no} 类别编号异常) try: x, y, w, h map(float, [x, y, w, h]) except ValueError: errors.append(f{f}:{line_no} 坐标不是数字) continue if not (0 x 1 and 0 y 1 and 0 w 1 and 0 h 1): errors.append(f{f}:{line_no} 坐标越界) if errors: print(发现, len(errors), 个问题) for err in errors[:20]: print(err) else: print(标签校验通过)这段脚本检查三个点字段数是不是5个、类别编号是不是从0开始、坐标是不是都在0到1之间。跑完没有问题再进训练流程能省很多折腾时间。4. 环境搭建与训练参数配置4.1 PyTorch安装的版本搭配思路YOLOv5是构建在PyTorch之上的所以环境搭建的第一步是装好PyTorch。很多新手在这一步卡住多数是因为版本搭配出了问题。我的原则是先看显卡驱动支持的CUDA版本再选择匹配的PyTorch版本不要盲目追新。打开终端执行nvidia-smi看右上角CUDA Version这个数值表示驱动支持的最高CUDA版本。假设显示的是11.8或者12.1那就选择对应版本的PyTorch。以CUDA 11.8为例推荐用conda建环境再装conda create -n yolo python3.9 -y conda activate yolo pip install torch2.0.1 torchvision0.15.2 --index-url https://download.pytorch.org/whl/cu118如果没有NVIDIA独立显卡直接装CPU版本就能跑通训练流程只是速度会慢很多pip install torch torchvision版本匹配原则浓缩成一句话不要追新稳定优先。YOLOv5官方仓库对PyTorch 2.0这个版本兼容性很好踩过的坑最少新手用这套组合比较稳妥。4.2 获取YOLOv5代码并安装依赖PyTorch装好之后拉取YOLOv5代码并安装依赖git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txtrequirements.txt里包含了训练需要的所有Python包包括numpy、opencv-python、matplotlib、tensorboard这些。如果网络慢导致pip安装超时可以临时换用国内镜像源比如pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple装好之后可以顺手跑一句python train.py --help看看命令是否正常输出如果正常说明环境基本通了。4.3 关键训练超参数怎么选训练超参数直接影响训练效率和最终效果这几个参数我每次都会认真调--img输入图像尺寸默认640。大块煤在画面中如果偏大640够用如果目标偏小可以试试1280但显存占用会明显上升。--batch批大小由显存决定。8GB显存用16或3224GB显存可以用64。YOLOv5也支持--batch -1让程序自动探测最大可用批大小。--epochs迭代轮数建议300起步。工业数据集不大300轮基本能看到收敛配合早停机制防止过拟合。--weights预训练权重。默认用yolov5s.pt速度最快追求更高精度可以换yolov5m.pt或yolov5l.pt。我训练这块数据的典型命令是python train.py --data coal.yaml --weights yolov5s.pt --img 640 --batch 16 --epochs 300 --device 0如果只想快速验证数据链路是否通畅可以先用--epochs 5跑一个小轮次确认loss在下降、验证集能正常评估再跑完整的300轮这样可以避免因为数据配置错误白等好几个小时。5. 训练过程与问题排查实录5.1 启动训练并读懂loss曲线训练启动后终端会持续输出每一轮的训练日志包括box_loss、obj_loss、cls_loss、precision、recall、mAP等指标。我刚接触YOLOv5时盯着这些数字一脸懵后来明白了一个大概的判断逻辑box_loss表示预测框和真实框的误差obj_loss表示目标置信度误差cls_loss是分类误差。对于单类别大块煤识别cls_loss参考价值不大重点看box_loss和obj_loss有没有稳定下降。正常情况下train loss应该在前面几轮快速下降然后逐渐平缓val loss也会同步下降但会有波动。如果train loss持续下降而val loss到了某一轮开始反弹说明模型开始过拟合了训练集背得太熟验证集上泛化变差。通常的解决办法是降低epochs、增大训练数据或增加数据增强。YOLOv5默认开启了早停机制也就是--patience参数默认100轮内验证指标没有改善就自动停止这个机制我建议保持开启。5.2 标注格式错误是最常见的训练报错来源训练时最常见的问题往往不是模型本身而是数据标注格式出错。我遇到过三类典型错误第一类别编号从1开始。很多人受习惯影响把第一个类别编号标成1但YOLOv5要求从0开始。单类别数据如果标成1训练时类别索引越界会直接报错。校验脚本里检查int(cid) 1能提前发现这个问题。第二坐标没有归一化。手动标注时如果不小心把像素坐标直接写进了txt训练时YOLOv5会把上千像素的值当作0到1的归一化值解析导致anchor匹配全部错乱loss异常大且不稳定。校验脚本里的0到1范围检查就是为了抓这个问题。第三标签文件名和图像文件名不匹配。比如图像是IMG_0001.jpg标签文件是IMG_0001.txt如果多一个空格或者扩展名不一致训练时会提示找不到标签。这类问题用一个文件对应关系检查脚本很容易发现也可以用os.listdir对比两个目录下的文件名。5.3 目标小、数量不均导致的漏检问题大块煤在画面里占的像素面积如果很小模型可能一直漏检。这种情况在远距离堆场视角比较常见煤堆上的一大块煤可能只占图像宽度的1/10不到。我的经验是优先尝试这几种方法提高训练分辨率比如从640改成1280让小目标在输入图像里占更多像素增大Mosaic增强的贡献YOLOv5默认开启了Mosaic增强会把4张图拼在一起训练偏小的目标更容易被采样到针对性地补充近景或特写样本让样本里出现更多“大尺寸外观”的大块煤。还有一个容易被忽视的问题如果整张图里只有零星的几个大块煤背景占比极大模型会倾向于把所有区域预测成背景。这时候可以检查一下训练集里的标签密度如果发现大量图像只有1到2个目标可以考虑在采集时多拍一些目标密集的画面来平衡分布。5.4 背景与目标对比度低时的优化方向煤块在煤粉皮带上的对比度本来就不高特别是皮带上的煤粉和煤块都是黑色系模型很容易把堆积的料流整体识别成一个大目标或者漏掉真正的边界。解决这个问题的两个方向是图像层面和标注层面。图像层面可以在数据增强里提高亮度、对比度的扰动强度或者采集时增加侧光和补光条件让煤块的立体轮廓更明显。标注层面我发现很多误检其实是标注框太松导致的。画框时如果把煤块边缘的阴影和煤粉带都包进去了模型就会学着把阴影当目标。回到标注时要求“紧贴可见边缘”这一步对对比度低的目标尤其重要。我整理了一份常见问题速查表训练时遇到对应现象可以快速定位现象可能原因处理建议训练直接报错标签文件找不到文件命名或目录结构不规范检查images和labels同名对应按第3.2节结构重建训练启动后loss异常大且波动剧烈标注坐标未归一化、类别编号错误跑一遍第3.5节的校验脚本验证集mAP高但现场实测漏检多数据泄露验证集和训练集包含同一来源画面按场景/时间分组重新划分小目标普遍漏检目标像素占比太小或样本不足提高训练分辨率补充近景样本误把煤粉堆识别成大块煤标注框过松把背景包进去了重新检查标注框紧贴目标边缘5.5 一点额外提醒PyTorch版本升级带来的加载变化如果你用的PyTorch版本比较新比如2.6以上在自定义脚本里用torch.load加载权重文件时要注意新版把weights_only参数的默认值从False改成了True导致一些老权重文件里的非张量对象加载失败。YOLOv5训练本身有封装好的加载逻辑影响不大但如果你写完推理脚本直接调用torch.load遇到类似于“Weights only load failed”的报错记得手动加上weights_onlyFalse。6. 数据集的持续迭代与个人经验6.1 从单类别到多类别的扩展这套数据集虽然目前只有大块煤一个类别但后续很自然会遇到扩展需求。比如有的现场想区分“超大块”和“一般大块”有的想同时识别“大块煤”和“锚杆、托辊等异物”这些都属于多类别检测。扩展的时候不要重新标全量数据只需要在现有数据基础上追加新类别的标注然后调整data.yaml里的nc和names即可。如果新类别样本数量不够可以用已有的单类别模型做预标注再用人工修正的方式快速铺量也就是半自动标注的路子。6.2 关于标注质量和迭代闭环的几点经验最后说几条我自己踩过坑之后沉淀下来的经验。标注过程中最怕的是多人标准不统一。一个人标的话框的松紧风格基本一致多人协作时如果没有一个明确的标框规范同一块煤在不同人手里画出来的框可能差出10%到20%的面积。这种情况下模型学到的边界就变成了一种“平均风格”精度天花板会被拉低。所以要么一个人标到底要么多人标完之后集中review一轮。另外数据集不能一次性做完就扔在那而是要跟着现场误报和漏报持续迭代。模型部署上线后每次现场出现的典型漏报图、误报图都应该回灌到训练集里重新标注、增量训练这样才能慢慢覆盖掉新场景的分布。实际项目里模型上线三个月之后效果还在稳步提升靠的就是这套回灌机制。最后再分享一个小技巧标框的时候可以顺手记录一下每张图的拍摄点位和时段写到文件名前缀里。这样后续做分组划分、排查数据泄露、定位某一类场景的误报时会非常方便。反向踩坑的经历告诉我前期多花十分钟做记录后期能省出好几个小时的排查时间。数据集的本质就是“组织好的经验”组织得越有条理训练出来的模型就越可靠。本文还有配套的精品资源点击获取

最新新闻

日新闻

周新闻

月新闻