ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于YOLOv8的煤矸石识别数据集:小样本目标检测实战要点

基于YOLOv8的煤矸石识别数据集:小样本目标检测实战要点 简介面向煤矿智能分选与视觉检测场景的YOLOv8格式识别数据集围绕煤炭、煤矸石、高岭石三类目标提供现场采集的原始图像与标注文件适合目标检测初学者、算法工程师以及煤矿智能化项目团队用于模型训练、验证和算法调研。数据包共205个文件包含102张现场jpg图片、102个对应的txt标签文件以及1个yaml类别配置文件整体压缩后仅2.26MB轻量易用可在本地快速跑通YOLOv8训练流程不必等待大体积数据集下载。目前已有459人学习浏览属于典型的小样本真实场景数据集。透过内容预览可见图片命名保留了原始采集编号与标注来源便于按批次筛选和检查标注质量将yaml配置与txt标注直接放入YOLOv8工程即可开始训练也可结合数据增强扩展样本规模用于验证小样本条件下煤矸石检测的可行性。这份资源适合需要快速搭建煤矸石识别原型或进行预实验的开发者参考使用。1. 煤矸石识别数据集为什么这 102 张现场图比几千张网图更值得用做选煤厂视觉分选或者矸石山监测的算法工程师大概率都经历过这种尴尬跑通的模型在演示视频里一切正常一到现场换条皮带、换个光照就掉点。煤矸石识别数据集这个项目正好卡在这个痛点上——它不是从网上爬的合成图而是 102 张现场采集的原始图片已经按 yolov8 格式标注好煤炭、煤矸石、高岭石三类目标拿来就能跑训练流程。102 张听起来很少但现场图的价值在于背景、光照、粉尘干扰都是真实的做迁移学习的底子比几千张干净网图扎实。适合两类人一类是刚接触 yolov8、想用一套真实数据走通完整流程的开发者另一类是需要快速验证「厂区视觉分选到底可不可行」的预研工程师。如果你是冲着「下载即得工业级模型」来的建议先看完后面几章——小样本数据集的坑一个都不会少。2. 看懂这套 yolov8 格式标注三类目标的视觉边界与文件结构2.1 煤炭、煤矸石、高岭石现场视觉上怎么区分拿到数据集先别急着训练先搞清楚这三类目标在图像里到底长什么样。这里的分类不是矿物学意义上的严格区分而是视觉分选意义上的定义——模型学的是颜色、纹理、形状这些表观特征不是化学成分。煤炭在可见光下表面呈黑色到深黑褐色块状断口处有贝壳状纹理新鲜断面有光泽整体形状相对规则。煤矸石的颜色跨度很大从灰黑色到灰白色都有质地更硬边缘更尖锐表面粗糙没有煤炭那种油润光泽。高岭石则是灰白到白色细粒状容易破碎表面有细腻的粉感和浅色煤矸石的区分点是颗粒更细、颜色更白更均匀。听起来边界清晰现场图不是实验室图。暗色煤矸石在阴影里和煤炭非常接近白色高岭石在强光下会和浅色矸石混在一起。所以看标注的时候要注意标注方对边界是怎么定的——这决定了你自己补充数据时能不能保持一致。一般现场采集数据的标注规范会写「以人工分选结果为准」意思是标注员是见过实物或者跟着选煤厂工人确认过的不是纯看图猜的。2.2 yolov8 格式标注的文件结构一张图对应一个 txtyolov8 格式的标注核心就是 YOLO 的 txt 标注文件每个 txt 文件名和对应的图片名一致放在 labels 目录下图片放在 images 目录下。txt 里的每一行代表一个目标框五个值分别是类别 id、归一化中心点 x、归一化中心点 y、归一化宽、归一化高。比如一张 1920x1080 的现场图里有个煤矸石目标框的左上角是 (960, 300)右下角是 (1200, 600)那么标注行就是1 0.5625 0.4167 0.125 0.2778。类别 id 从 0 开始常见的映射是 0煤炭、1煤矸石、2高岭石但不同数据集的映射可能不一样训练前先确认自己的 data.yaml 里的类别顺序不然会出「模型把煤认得特别准因为标注全串了」这种低级翻车。拿到数据之后我一般第一步不是训练而是把标注文件全部读一遍确认边界框有没有越界、宽高有没有变负数、类别 id 有没有超出数量。写个脚本几分钟就能跑完省得后面训练时冒出一堆 nan loss 还不知道为什么。import os from pathlib import Path label_dir Path(datasets/coal_gangue/labels/train) img_w, img_h 1920, 1080 # 按数据集的原始分辨率填 problems [] for txt_path in label_dir.glob(*.txt): for line_idx, line in enumerate(txt_path.read_text().strip().splitlines()): parts line.split() if len(parts) ! 5: problems.append(f{txt_path.name}:{line_idx} 字段数不对) continue cls_id, cx, cy, w, h parts cx, cy, w, h float(cx), float(cy), float(w), float(h) if not (0 int(cls_id) 2): problems.append(f{txt_path.name}:{line_idx} 类别越界 {cls_id}) if w 0 or h 0 or w 1 or h 1: problems.append(f{txt_path.name}:{line_idx} 框尺寸异常) if not (0 cx 1 and 0 cy 1): problems.append(f{txt_path.name}:{line_idx} 中心点越界) print(f检查 {len(list(label_dir.glob(*.txt)))} 个文件 f发现 {len(problems)} 个问题) for p in problems[:20]: print(p)代码逻辑很直接遍历标签目录下每个 txt按行解析五个字段逐一校验类别 id 范围、框宽高、归一化坐标。归一化坐标理论上必须在 0 到 1 之间如果源标注是基于某个裁切过的图片做的但忘了同步更新这里就能发现。这个脚本跑完没问题再往下走。2.3 数据体检类别分布、目标尺度和框密度102 张图不是均匀分布三类目标的。矸石山场景里煤矸石可能占了大部分高岭石可能只有十几张图里有。这种类别不平衡如果不提前知道训练时会发现高岭石的 mAP 一直上不去不是你参数调得不好是从根上数据就偏。我一般会写一个统计脚本把所有标注的类别数量、框的宽高分布、单张图的目标数量都压出来。目标尺度尤其重要——如果绝大多数框的宽高都在整张图的 5% 以下那么训练时 imgsz 设置成 640 可能不够用得考虑提到 1280或者接受小目标漏检的现实。import numpy as np from pathlib import Path label_dir Path(datasets/coal_gangue/labels/train) stats {0: [], 1: [], 2: []} # cls_id - 框的相对面积列表 for txt_path in label_dir.glob(*.txt): for line in txt_path.read_text().strip().splitlines(): parts line.split() cls_id int(parts[0]) w, h float(parts[3]), float(parts[4]) stats[cls_id].append(w * h) # 归一化面积 for cls_id, areas in stats.items(): areas np.array(areas) print(f类别 {cls_id}: 框数 {len(areas)}, f归一化面积 中位数 {np.median(areas):.5f}, f最小 {areas.min():.5f}, 最大 {areas.max():.5f})参数和逻辑说明这里统计的是每个目标框相对整图面积的占比0.01 就代表框只占图的 1%属于典型的小目标。对煤矸石分选场景目标往往贴在皮带上、互相遮挡框面积普遍偏大但重叠严重所以这个指标能直接告诉你模型需要多大的特征分辨率才能「看清」目标。数据体检做完心里有底了再进训练环节。3. 用 yolov8 跑通三类目标检测数据集组织、训练参数与增强策略3.1 数据集目录组织与 data.yaml 配置yolov8 官方仓库对数据集目录的约定是 images 和 labels 分开训练集、验证集可以按子目录分也可以用 txt 文件列举图片路径。102 张图本来就少不建议再按 80/20 硬切——后面避坑章节会细说。这里先按最标准的目录结构摆好。datasets/ coal_gangue/ images/ train/ img_001.jpg img_002.jpg ... val/ img_091.jpg ... labels/ train/ img_001.txt ... val/ img_091.txt ...对应的 data.yaml 内容path: datasets/coal_gangue train: images/train val: images/val nc: 3 names: 0: coal 1: gangue 2: kaolinite注意path建议用相对路径或者直接用绝对路径别用../这种相对写法依赖当前工作目录——换台机器跑直接报错找不到数据集我踩过这种坑。names的顺序必须和标注 txt 里的 class id 一致之前提过。3.2 训练参数设多少102 张小数据集的调参逻辑大多数人第一次跑 yolov8 都是直接敲yolo detect train data... modelyolov8n.pt epochs100对着默认参数开训。默认参数是大数据集调出来的小数据集上照搬会出问题。先说结论再解释为什么。我一般用这个组合yolo detect train \ modelyolov8n.pt \ datadatasets/coal_gangue/data.yaml \ epochs300 \ batch16 \ imgsz640 \ workers4 \ optimizerSGD \ lr00.01 \ mosaic0.5 \ close_mosaic20 \ patience50 \ device0 \ projectruns/detect \ namecoal_gangue_102参数说明yolov8n是 nano 版本参数最少、最快小数据集上先用小模型把流程跑通别一上来就yolov8x——102 张图喂大模型100% 过拟合。epochs300看起来多但配合patience5050 个 epoch 验证集指标不涨就提前停实际不会跑满这是用小数据集训练的关键。mosaic0.5是 mosaic 增强启用概率前 100 个 epoch 有一半的 batch 会做 mosaic 拼接后 20 个 epoch 完全关闭close_mosaic20让模型在正常分布上微调收敛。SGD lr00.01是小数据集上最稳的组合Adam 系收敛快但容易在小样本下跑飞。batch16这个值要看显卡显存1660Ti 6G 跑 640 分辨率、nano 模型16 是安全的8G 以上显存可以加到 32。如果显存紧张优先调小 batch 而不是调小 imgsz——图片分辨率直接决定小目标能不能被检测到。3.3 训练过程怎么看损失、验证指标与过拟合信号训练启动之后不要干等。打开runs/detect/coal_gangue_102/目录下的results.png里面画了 train/val 的 box loss、cls loss 和 mAP 曲线。前 50 个 epoch 里 val loss 下降是正常的如果 train loss 一直在降但 val loss 在 100 epoch 后开始反弹说明已经过拟合了这时候看weights/last.pt和weights/best.pt的差距——两个文件差很多说明最佳模型出现在训练中段后面全在硬背训练集。from ultralytics import YOLO # 训练完成后加载 best.pt跑验证集并输出每类指标 model YOLO(runs/detect/coal_gangue_102/weights/best.pt) results model.val( datadatasets/coal_gangue/data.yaml, splitval, imgsz640, conf0.25, iou0.5, )代码逻辑model.val()用的就是 data.yaml 里指定的 val 集。conf0.25是置信度阈值iou0.5是 NMS 的 IoU 阈值这两个只是推理参数不影响已经训练好的权重。输出的results.results_dict里有mAP50和mAP50-95但更要看 per-class 的 AP——如果 coal 的 AP 有 0.8、gangue 只有 0.3那问题不在整体训练在数据或标注本身得回到第 2 章的统计结果去查。到这里训练闭环已经通了。但 102 张图的数据集光会跑通不够还得知道哪些地方会翻车。4. 小样本目标检测必踩的 5 个坑现象、原因与解法4.1 高岭石类别 AP 极低类别不平衡比你想象的更严重现象训完看 per-class APcoal 和 gangue 都能到 0.7 以上kaolinite 只有 0.1 甚至更低换任何增强参数都救不回来。原因102 张图里高岭石只在十几张中出现且每张只有一两个目标。yolov8 的损失函数里类别损失按样本数量加权占比小的类别梯度贡献微弱模型倾向于把所有目标都预测成占多数的类别。解决先统计各类别框的数量用第 2.3 节的脚本如果差距超过 5 倍考虑对高岭石图片做离线增强——复制高岭石的标注并加载到背景图上生成额外样本注意别让同一张图的增强版本同时出现在训练集和验证集。另一个做法是提高cls_pw这个类别的正样本权重但这种操作要小心调过头导致其它类别 AP 下跌。4.2 标注边界争议煤炭和暗色煤矸石肉眼不可分现象训练 loss 正常下降但 val 的混淆矩阵里 coal 和 gangue 互相错认的比例特别高。原因在弱光或粉尘遮挡下暗色煤矸石和煤炭在视觉上本来就难分。如果标注规范不明确不同标注员甚至同一个标注员前后标准不一致模型学到的是一个矛盾的边界自然没法稳定区分。解决回到标注数据上把预测错误最多的图片抽出来看模型哪些框预测成了另一类。如果连人都很难通过视觉确认就去找现场工人核对样本——他们用手掂一下、敲一下就能判断。确认错的标注后修正 txt 里的 class id这个工作没有捷径属于数据集质量的必经投入。4.3 mosaic 增强在小数据集上的虚影问题现象训练 loss 收敛很快但模型对紧挨在一起的目标会漏检或者框偏。原因mosaic 把 4 张图拼接在一起训练目标是模拟目标密集的场景。但数据集只有 102 张拼接后大量目标被裁切产生大量只有半个目标、没有完整特征的「虚影标注」。模型学会了「半截目标也能是目标」实际推理时反而对完整目标犹豫。解决把小数据集下的mosaic0或者0.25同时把close_mosaic保留在最后 20 个 epoch。如果场景里本身就有密集遮挡需要模拟密集目标可以用copy_paste增强——把一个图里的目标实例复制到另一张图里但这是高级技巧先用关闭 mosaic 来治虚影问题。4.4 切分验证集随缘高岭石全进了训练集或验证集现象训练完 val 指标很好看但实际部署一测高岭石一个都检不出来。原因做数据集切分的时候用了随机划分而高岭石图片只有十几张随机划分时可能全部落进训练集验证集里一张高岭石都没有val 指标自然好看但失去了意义。解决切分之前先按类别分布做分层采样最粗暴的做法是手动确认验证集里每类都有样本且占比和整体分布接近。我通常的做法是先把包含高岭石的图片挑出来单独编号抽 15% 到 20% 进验证集剩下的其它类别再随机补。这是数据切分里最不值得省的时间省了后面全在返工。4.5 光照和角度变化导致泛化崩塌现象模型在数据集的图片上表现不错拿到现场新拍的图同样的目标检不出来或者大量误检。原因102 张图很可能来自同一天、同一个机位、同一种光照条件。yolov8 会在背景纹理上过拟合——模型可能记住了「左上角那团阴影」而不是「黑色的块状物体」。解决训练前期的数据增强里把光照相关项拉高hsv_h0.05、hsv_s0.5、hsv_v0.5同时适度加degrees5小幅旋转和translate0.1小幅平移。更重要的是采集策略如果可能再补几批不同时间段的现场照片哪怕每批只有 30 张对泛化能力的提升比增加 100 张同条件图片都明显。5. 从训练到能用验证指标的正确打开方式与部署到边缘设备的路径训练结束、坑也踩完一轮之后最后一步是把这个模型真正用起来。先说实话在 102 张图上训练出来的模型验证集 mAP 到 0.8 以上只能说明「这个数据集上还行」离「选煤厂可靠运行」还有距离。真正决定能不能用的是混淆矩阵和实际场景的抽测。看混淆矩阵的时候重点看 off-diagonal——coal 被预测成 gangue 的比例超过 5% 就要警觉矸石混入煤炭和煤炭混入矸石的经济后果完全不同分选场景里错分率比 mAP 更重要。部署到边缘设备的话rk3588 是当前性价比很高也常被点名的选择。yolov8n 训练完的权重是 PyTorch 格式先导出 ONNX。yolo export modelruns/detect/coal_gangue_102/weights/best.pt formatonnx opset12 imgsz640导出后用onnx2rknn工具转成 RKNN 格式这一步需要在 x86 机器上装 rknn-toolkit2转换完成后在板端用 rknn-toolkit-lite2 做推理。实际部署时注意三个细节一是 RKNN 转换时量化方式选hybrid而不是全int8小模型全量化掉点很明显二是板端推理时预处理不要做太多归一化操作RKNN 输入对齐好数据集的预处理逻辑三是输入分辨率尽量和训练一致rk3588 用imgsz640跑 nano 模型可以实时提到 1280 会掉帧严重。最后聊一点实战习惯。我拿到任何小样本检测任务都不会只用一轮训练就完事——训练完先让模型推理全部 102 张图把置信度低但肉眼确定的目标找出来修正标注或者补充标注然后再训一轮。这个过程叫自举一轮下来数据质量会有实质提升。另外一个小技巧训练时给同一份数据准备两个随机种子跑两遍对比 loss 曲线。如果两次训练的最佳 mAP 差异超过 0.1说明当前数据量下模型强烈依赖随机初始化再多的调参都治标不治本优先加数据而不是换模型结构。最后是一点教训一开始做类似数据集的时候我迷信「模型越大越好」直接上 yolov8x结果 100 多张图训出来的模型过拟合到惨不忍睹。后来换 yolov8n 先把流程和数据质量摸清楚效果反而翻倍。小样本场景先小模型、强增强、盯混淆矩阵这条路走得通。希望帮到你。本文还有配套的精品资源点击获取
返回列表