
简介面向煤矿智能化与选煤场景的检测需求这份数据集提供102张现场采集的原始图片覆盖煤炭、煤矸石与高岭石三种类别已按YOLOv8格式完成标注适用于目标检测模型的训练、验证与迁移学习也适合矿山自动化相关课题的算法验证与教学演示。压缩包体积仅2.26MB共包含205个文件其中102个jpg图像、102个txt标注文件及1个yaml配置文件txt文件严格对应每张图像中目标的类别与边界框坐标yaml文件定义类别名和数据集路径目录结构清晰可直接放入YOLOv8工程训练或二次开发。目前已有459人学习下载图片均为现场采集背景与光照贴近实际工况样本虽不算大却能为小样本检测、数据增强策略研究及预训练模型微调提供直观的练习数据尤其适合入门级目标检测项目快速上手。1. 煤矸石识别数据集只有102张现场图为什么反而够用选煤厂皮带上的矸石分选大部分时间还靠人站在手选带旁边用眼睛盯。这两年煤矿智能化提得多但真正拦住项目的不是算法而是数据公开的煤矸石识别数据集几乎没有网上能找到的图片大多是实验室里摆拍的干净煤块拿到皮带上一测就翻车。这个标题给的是一个非常诚实的起点——102张现场采集原始图片YOLOv8格式标注覆盖煤炭、煤矸石、高岭石三类。数量不大但它解决的是“手里连一张现场图都没有”的冷启动问题。反直觉的地方在于这种小数据集配合预训练权重和克制的增强策略足以把验证级模型跑起来也能把整个识别流程的真实坑位暴露出来。适合正在做选煤厂智能化的算法工程师、做机器视觉落地的外包团队以及想用YOLOv8做工业小目标检测的初学者——你不需要等一个十万张的完美数据集先把这102张用透比攒数据更重要。2. 煤矸石识别任务与YOLOv8格式标注三个类别怎么界定、标签怎么落到现场图上2.1 煤炭、煤矸石、高岭石三类目标视觉边界比想象中更模糊做这个数据集之前先把类别定义钉死。煤炭、煤矸石、高岭石在矿物学上是三种东西但在相机画面里它们的灰度差经常小到让人想摔键盘。我的经验是先建立一张特征对比表让标注员和后续训练的评估都有一个共同的“裁判标准”。类别颜色与光泽块体形态表面质地常见误判来源煤炭深黑玻璃光泽或沥青光泽多块状层理明显常有锐利棱角相对光滑断面平整逆光时局部过暗与阴影混在一起煤矸石灰黑至深灰光泽弱块状不规则常呈板状或粒状粗糙颗粒感强可见层理但较乱表面附着煤粉后颜色接近煤炭高岭石灰白、浅黄、浅灰色土状、致密块体少见锐利棱角细腻有滑腻感断口平坦光照过强时发白易与皮带托辊表面混视觉上最麻烦的是煤矸石表面沾了煤粉整体发黑深度学习模型会把它归到煤炭。高岭石在强光下反光强烈亮度接近皮带托辊又容易被漏检。这三个类别的区分不完全是颜色还要看纹理和块体的整体形状。所以标注时我一般要求框体贴合目标主体的可见轮廓不把阴影算进去如果一个目标被另一个目标遮挡超过50%就不单独标注避免给训练集注入半框噪声。102张原始图数量不大标注质量直接决定后面所有效果的上限宁可少框几个不要错框一堆。2.2 现场采集图片里的YOLOv8标注格式txt文件与归一化坐标YOLOv8的数据标注格式延续了YOLO系列的约定每张图片对应一个同名txt文件每一行描述一个目标类别序号、归一化后的中心点x、中心点y、框宽w、框高h。归一化是指除以图片本身的宽和高所以数值都在0到1之间。这种格式的好处是不管相机分辨率是两百万还是五百万像素训练时都不需要手动改坐标。一个典型的标签文件内容长这样0 0.518750 0.427083 0.112500 0.223958 1 0.739583 0.463542 0.095833 0.190625 2 0.263542 0.711458 0.127083 0.248958第一列0、1、2分别对应煤炭、煤矸石、高岭石后面四个数依次是x中心、y中心、宽度、高度都做了归一化。如果原图是一张4096×3072的现场照片某个煤炭块的中心在像素坐标(2125, 1312)宽460高688转换公式就是x_center2125/4096y_center1312/3072。手工算不现实常见做法是标注工具导出COCO或VOC格式再用脚本做一次坐标换算。import cv2 def voc_to_yolo(x1, y1, x2, y2, img_w, img_h): # VOC坐标是左上角和右下角YOLO需要中心点加宽高 x_center (x1 x2) / 2 / img_w y_center (y1 y2) / 2 / img_h w (x2 - x1) / img_w h (y2 - y1) / img_h return round(x_center, 6), round(y_center, 6), round(w, 6), round(h, 6)这段代码的输入来自标注工具导出的坐标框输出直接写入txt。转换时有两个细节容易出错一是标注工具的坐标有些是从0开始的有些从1开始转换后会出现毫米级的偏移对皮带场景影响不大但强迫症的可以统一减1二是图片标注时如果做过旋转、裁剪必须先还原到原图坐标再转YOLO格式否则框和图像对不上。我一般转换完会随机抽5张图做可视化校验把画了框的图和原图叠加肉眼确认没有错位再进入训练。2.3 102张原始图为什么“够用但不够好”现场采集的102张图和从搜索引擎抓下来的图片有本质区别。现场图带着固定的相机视角、固定的皮带背景、随机的煤流厚度和真实的光照变化这些恰恰是模型落地时真正需要学习的分布。我从这类小数据集上得到的经验是泛化能力不取决于图片数量而取决于图片是否覆盖了实际工况的变化范围。102张如果有80张是顺光拍的剩下逆光过曝的不到10张模型在逆光时就会明显变差。拿到数据集后做的第一件事不是训练而是统计每张图的类别实例数。常见做法是写个小脚本读一遍labels目录看每个类的目标框数量分布。假设102张图总共标注了约300个煤炭框、200个煤矸石框、50个高岭石框那高岭石就是短板类别后面的数据增强和损失函数调整都要向它倾斜。这个统计结果同样决定训练集和验证集的划分方式不能随意全局随机切分要按类别实例数做分层采样否则很容易出现验证集里根本没有高岭石的情况。2.4 标注质量检查先可视化再进训练YOLOv8训练对脏数据非常敏感。标签文件里如果有一个框的坐标超出0到1范围训练过程虽然能跑起来但那一批的损失会异常跳高。更隐蔽的问题是框比目标大一圈或者框住了两个目标的中间空隙。这些肉眼勉强能接受的误差会让模型的定位精度上不去。我习惯在训练前跑一遍可视化检查脚本把标签框叠加回原始图片。import cv2 import numpy as np from pathlib import Path img_paths list(Path(images/train).glob(*.jpg)) class_names [coal, gangue, kaolinite] colors [(0, 255, 0), (0, 0, 255), (255, 0, 0)] for img_path in img_paths[:10]: img cv2.imread(str(img_path)) h, w img.shape[:2] label_path Path(labels/train) / (img_path.stem .txt) with open(label_path) as f: for line in f: 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), colors[int(cls)], 2) cv2.putText(img, class_names[int(cls)], (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, colors[int(cls)], 2) cv2.imwrite(fcheck_{img_path.stem}.jpg, img)这段脚本干了三件事读取图像和对应的标签文件、把归一化坐标换算回像素坐标、在图上画框和类别名。参数上要注意的是img.shape[:2]拿到的是高度和宽度顺序不要搞反。如果发现框与目标轮廓明显偏移不要想着靠增强拉回来直接回头改标注文件。小数据集的容错率很低一个错框占全部样本的比例太高模型会认为是真实分布的一部分。3. 用YOLOv8跑通煤矸石识别的最小训练闭环从数据划分到看第一次预测结果3.1 环境安装与版本约束GTX 1660 Ti也能跑煤矸石识别不是高分辨率多目标竞赛YOLOv8n级别的模型在消费级显卡上就能完成。我在1660 Ti 6GB显存上跑过同样的数据集一个epoch的训练时间在几十秒级别200轮也就两三个小时完全能接受。环境安装不需要折腾太多ultralytics包已经封装了大部分训练逻辑。pip install ultralytics torch torchvisionfrom ultralytics import YOLO import torch print(torch.__version__) print(torch.cuda.is_available()) model YOLO(yolov8n.pt)参数说明yolov8n.pt是官方预训练权重n代表nano参数量最小适合小数据集和边缘设备。torch.cuda.is_available()返回True说明GPU可用。如果这里返回False大概率是PyTorch装了CPU版本需要重新安装对应CUDA版本的PyTorch。另外注意Python版本最好在3.9到3.11之间太老的版本跑不动ultralytics的新版API。3.2 数据划分与data.yaml配置分层采样保证高岭石不缺席102张图怎么划训练集和验证集直接决定你看到的训练曲线是不是假象。我之前踩过一次坑全局随机切分后验证集12张图里没有一张包含高岭石训练时高岭石mAP显示为0根本分不清是模型没学会还是验证集没样本。后来改成按类别实例数做分层采样保证验证集里每个类别至少出现一次。import random from pathlib import Path from collections import Counter import shutil random.seed(42) images list(Path(images).glob(*.jpg)) label_counts {} for img_path in images: label_path Path(labels) / (img_path.stem .txt) with open(label_path) as f: classes [line.split()[0] for line in f if line.strip()] label_counts[img_path.stem] classes # 按类别出现次数排序确保高岭石所在的图片优先进入训练集 test_ratio 0.15 n_test max(5, int(len(images) * test_ratio)) # 收集包含稀有类别的图片 rare_images [p for p in images if 2 in label_counts[p.stem]] common_images [p for p in images if 2 not in label_counts[p.stem]] random.shuffle(rare_images) random.shuffle(common_images) # 先从稀有类别里取一部分进验证集 val_images rare_images[: max(1, n_test // 2)] # 再补足剩余名额 val_images common_images[: n_test - len(val_images)] train_images [p for p in images if p not in val_images] print(验证集数量:, len(val_images)) print(训练集数量:, len(train_images))这段脚本的关键是先用包含高岭石类别的图片填充验证集名额。我的参数选择验证集比例15%102张图大约15张验证、87张训练。这里没有用常规的20%验证比因为样本太少验证集占比过高会让训练集进一步缩小。另外注意random.seed(42)固定随机种子保证每次跑出来的划分是一致的方便复现。我一般在划分后打印每个类在训练集和验证集中的实例数比例相差不大才继续。接下来在工作目录下写一个data.yaml文件path: C:/projects/gangue_dataset train: images/train val: images/val nc: 3 names: 0: coal 1: gangue 2: kaolinitepath是数据集根目录的绝对路径或相对路径。train和val的值是相对path的目录名目录里直接放图片就行。nc是类别数。names的索引顺序必须和标注文件的0、1、2完全对应顺序错了模型训练不会报错但预测结果会让煤矸石显示成煤炭这类错误很难排查所以我每次都会先跑一句model.names确认类别映射。3.3 训练命令与关键参数小数据集的理性选择训练命令本身不复杂参数选择才是决定成败的地方。yolo detect train datadata.yaml modelyolov8n.pt epochs200 imgsz640 batch16 device0 patience50modelyolov8n.pt从COCO预训练权重开始不是从零训练。对小数据集来说预训练权重相当于把“看形状”的能力提前装好了模型只需要适应煤矸石的具体纹理。epochs200102张图的数据量200轮足够收敛。配合patience50验证集指标连续50轮不提升就自动停止避免浪费时间。imgsz640YOLOv8默认输入尺寸。如果现场原图是几千万像素的高清工业相机640会丢失大量小目标细节后面会单独讲怎么调整。batch161660 Ti 6GB显存跑yolov8n没问题。如果训练中报CUDA out of memory先把batch降到8或4。训练过程中模型会在项目目录下生成runs/detect/train文件夹里面的results.png记录了loss曲线和mAP曲线。训练结束后的best.pt就是验证集上表现最好的权重后面所有预测、导出、部署都用它而不是最后一轮的last.pt。3.4 第一次训练完先看这四张图别急着欢呼训练完成不等于模型可用。我会按顺序检查四样东西results.png里训练损失和验证损失有没有同步下降出现明显背离就是过拟合confusion_matrix.png里高岭石和煤矸石有没有互相混淆PR_curve.png里三个类别的PR曲线下面积差距大不大最后用yolo predict在十来张没参与训练的现场图上跑一遍亲眼看看模型预测出来的框是不是贴在煤块上。yolo detect predict modelruns/detect/train/weights/best.pt sourceval_images device0 saveTrue conf0.25当验证集上煤矸石和煤炭的mAP50都超过0.85、高岭石超过0.7这个数据集就算被用到位了。如果高岭石远低于其他两类先检查验证集是不是又出现了类别缺失再检查标注框数量是否足够。接下来要做的不是盲目加epochs而是针对短板的类别做策略调整。4. 把102张图的潜力榨干数据增强、预训练权重与小数据集的训练策略4.1 数据增强的取舍皮带场景真的别乱开旋转YOLOv8默认开启一系列增强策略比如mosaic、hsv变化、随机平移和缩放。对小数据集来说增强是一把双刃剑用对了等于白捡几倍的训练样本用错了会让模型学到奇怪的分布。煤矸石在皮带上的姿态非常固定基本都是煤流自然堆叠下的随机角度。我在这个场景下关闭了degrees旋转增强或者只开到degrees5。原因很简单皮带上的煤块不会像货物检测那样横七竖八大角度旋转生成的训练样本在真实场景里不存在只会增加模型的学习负担。同样flipud上下翻转我也关掉因为相机视角固定翻转后的画面意味着煤块悬浮在皮带上方这个分布是假的。保留fliplr左右翻转是合理的煤流方向固定但同一块煤可能会在画面左侧或右侧出现。# augment.yaml 在训练命令中通过 augmentTrue 引用 degrees: 5.0 translate: 0.1 scale: 0.5 shear: 2.0 perspective: 0.0 flipud: 0.0 fliplr: 0.5 mosaic: 0.8 mixup: 0.2 hsv_h: 0.015 hsv_s: 0.4 hsv_v: 0.4这些参数可以直接加到训练命令里yolo detect train datadata.yaml modelyolov8n.pt epochs200 imgsz640 batch16 augmentaugment.yaml。关键参数说明mosaic: 0.8表示80%的概率把4张图拼成一张训练对小数据集非常友好等于模型每次能看到4倍的目标数量mixup: 0.2把两张图叠加混合适合样本量不足的场景hsv_v: 0.4是亮度扰动这个对煤矸石场景特别重要现场光照本来就波动大适当增强能提升鲁棒性。perspective: 0.0必须关掉透视变换会让煤块的形状发生不符合实际的形变严重影响对体积大小的判断。4.2 用预训练权重还是从头训练小数据集没有第二种选择同等条件下加载yolov8n.pt预训练权重比用yolov8n.yaml从零开始训练在mAP50上的提升往往是压倒性的。YOLOv8在COCO上见过数千万个目标已经学会了边缘、纹理、形状的通用表征。煤矸石虽然不在COCO类别里但“石头”“矿物”这类低层特征是可迁移的。# 方式一从预训练权重继续训练推荐 yolo detect train datadata.yaml modelyolov8n.pt epochs200 imgsz640 batch16 # 方式二从零训练不推荐用于102张图 yolo detect train datadata.yaml modelyolov8n.yaml epochs500 imgsz640 batch16方式一的训练会在预训练权重的基础上微调200轮基本够。方式二从零开始需要更多epochs才能收敛而且在数据量不够的情况下非常容易过拟合训练损失降到很低验证损失却纹丝不动。我用过几次方式二每次都翻车耗时长效果差。这里的教训是小数据集训练不是比拼训练技巧而是比拼迁移学习用得对不对。4.3 类别不均衡高岭石只有几十个框怎么办102张现场图里煤炭和煤矸石是绝对多数高岭石可能只出现在十几张图中。YOLOv8默认的类别损失是平等对待的样本多的类别梯度贡献大模型会倾向于把不确定的目标全部预测成煤炭或煤矸石。我见过最典型的结果高岭石的精确率极高但召回率极低因为它只在非常明显的浅色块体上才敢预测。解决思路分两步。第一步是损失函数层面配置focal_loss1.0。Focal Loss会降低置信度高的样本的损失权重让模型更关注那些分类困难的目标也就是高岭石。第二步是训练策略层面采用两阶段训练先用全量数据正常训练到基本收敛然后用包含高岭石的图片单独继续训练几十轮把模型的注意力强行拉回来。第二阶段训练时把学习率降到原来的十分之一防止破坏前面学到的特征。4.4 学习率、batch与imgsz的互相影响小数据集训练最怕学习率太大损失曲线像心电图一样上下乱跳。我一般把初始学习率设为0.001到0.002配合cosine学习率衰减。YOLOv8在训练时会自动根据batch大小调整学习率batch16时默认学习率是0.01对102张图来说偏大了。显式指定lr00.001会更稳。imgsz的选择要和现场部署的分辨率对齐。如果现场相机是4K高清且部署到RK3588这类边缘设备训练时用imgsz640推理时把输入切换到1280会出现明显的精度下降——模型没见过那么大尺寸下的目标形态。我的做法是训练时用imgsz1024或者imgsz1280虽然显存和训练时间增加但模型的泛化更贴近实际部署。显存不够时优先降低batch而不是降低imgsz因为输入尺寸对目标检测的影响远大于batch。5. 煤矸石识别数据集训练与标注的5条踩坑记录现象、原因与解决办法5.1 背景误检皮带托辊被当成煤矸石现象模型在验证集上mAP不错一旦把相机对准真实运行的皮带检测结果里频繁出现皮带托辊和支架的框置信度还有0.6以上。原因托辊是高亮圆弧面颜色和浅色煤矸石、高岭石非常接近。训练集里的负样本不够模型没机会学会“托辊不是目标”。102张现场图大多数时候皮带是空的或煤流较薄托辊大量暴露在画面中标注人员通常不会把背景单独标出来模型就只能把相似的物体当作目标。解决第一种做法是收集一批不包含目标的纯背景图放进训练集注意不要配套标注文件模型会自动把它们当作负样本第二种是训练完成后在部署时按场景过滤限定检测区域只在皮带宽度范围内皮带边缘的机械结构不做检测。我之前加了一个简单的ROI遮罩把图像上下各切掉一行像素误检数立刻下降一半以上。第三种做法是提高置信度阈值到0.4以上用阈值换误检率但会牺牲部分遮挡目标的召回。5.2 煤矸石表面附着煤粉被模型识别成煤炭现象训练时损失很低但模型输出里煤炭类别框的数量远高于煤矸石验证集上煤矸石的召回率始终上不去。原因煤矸石表面被煤粉覆盖后视觉特征和煤炭几乎一样标注员在处理这类图时也容易犹豫。模型并没有真正学会区分“表面纹理”只是学会了“颜色深的就预测煤炭”。标注时对这类目标的标签边界不一致有些图片标成煤矸石有些标成煤炭模型学到的特征更混乱。解决重新统一标注口径以块体的断面形态为准有层理、有棱角的深色块体即使表面有煤粉也标为煤炭表面粗糙、形态圆钝、无明显光泽的深色块体标为煤矸石。标注完成后做一次类别分布一致性检查挑出前后标注矛盾的样本进行二次复核。经过这个操作煤矸石召回率通常能提升10个百分点以上。5.3 损失曲线正常下降但mAP50卡在0.5不再上涨现象训练损失和验证损失都在下降看起来一切正常但验证集的mAP50始终在0.5左右徘徊甚至出现epoch越往后mAP越低。原因目标在画面中尺寸太小。现场图片分辨率高一个煤矸石块可能只有几十乘几十像素而YOLOv8在640输入尺寸下小目标会被下采样到很小的特征图上信息几乎丢光。mAP50对定位要求不严苛但对目标是否存在要求很高小目标漏检直接导致召回率上不去。解决把imgsz从640提高到1024或1280训练时间和显存占用会上升但小目标的特征保留效果好很多。如果显存不够另一个思路是使用SAHI切片推理把大图切成重叠小图分别检测再拼接结果。实测在4K原图上SAHI配合640训练的模型比直接用640全图推理的mAP50提升15个百分点。缺点是推理时间变长部署到RK3588时需要做权衡。5.4 验证集里高岭石数量太少指标波动像过山车现象每次训练完验证集的mAP50都不一样高岭石类别的指标忽高忽低有时0.9有时0.3完全无法判断模型到底学没学会。原因高岭石在验证集中只有几个实例一张包含高岭石的图片有没有被预测对就把指标拉高或拉低一截。这是小数据集的统计噪声不是模型能力问题。解决把按类别分层的约束从全局划分改成每折都做也就是用K折交叉验证。102张图划分成5折每折训练5次取mAP的均值和方差。方差大说明该类别样本不足训练不稳定均值高于0.7说明方向正确可以继续补充数据。注意交叉验证耗时是原来的5倍对102张图来说完全可接受。5.5 训练中途显存溢出或进程被kill现象训练跑到一半报CUDA out of memory或者整机内存被吃满训练进程直接消失。原因workers设置过大导致数据加载占满内存batch和imgsz组合超出显卡显存或者Windows平台上默认的pinned_memory机制和某些显卡驱动冲突。解决先把batch降到8workers设为2显存问题基本能解决。如果还溢出把imgsz从640降到512小数据集上这个操作对精度的损失通常不明显。device0显式指定单卡不要依赖默认设置。文本检测类的工业项目我一般开一个定时清理显存的脚本防止多次训练后显存碎片累积导致OOM。6. 最后一公里阈值调参、导出RK3588模型、补拍数据找后悔药训练完best.pt距离真正能用还差两步。第一步是用验证集做一次置信度阈值取样。默认conf0.25是COCO场景的经验值煤矸石现场图背景复杂煤矸石与煤炭之间视觉混淆严重0.25会产生大量低置信度误检。我一般跑一遍批量预测统计0.2到0.5区间内精确率和召回率的变化选两者交叉点做部署阈值常见结果是0.35到0.4之间。第二步是把模型导出成边缘设备能跑的格式。如果部署目标是RK3588这类NPU平台标准流程是先导出ONNX再转到RKNNyolo export modelbest.pt formatonnx opset12 imgsz640导出时opset12是个稳妥参数太高版本的opset在部分NPU工具链上不支持。imgsz必须和训练时一致或者取它的倍数RK3588上的RKNN转换工具通常要求输入尺寸为32的倍数640正合适。导出成功后先用onnxruntime在PC上验证一遍精度确认导出没有把模型结构搞坏再拿给工具链做量化。量化时优先用INT8精度损失一般在3个百分点以内换取的是推理速度质的提升。补数据这件事如果你只有102张图最好的策略不是盲目去现场再拍几千张而是先让现有模型在真实视频流里跑几天把预测错误的画面自动保存下来。这些“打脸图”才是模型真正的短板哪些光照角度会漏检哪些煤种变化会误检通过它们能看到模型的黑匣子里到底缺什么。我犯过的错误是早期直接拿合成图和网上图片扩充训练集结果模型在实验室指标好看到皮带上一测就露馅。现场图贵在真实不在数量——哪怕是和原图完全相同的场景换一个时间段的光照条件都比加100张网上图有用。希望这个102张的小数据集能成为你第一个可复现的起点把它的潜力吃干榨净再做增量迭代。希望帮到你。本文还有配套的精品资源点击获取