ARTICLE DETAIL

资讯详情

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

YOLO工业油污缺陷检测数据集:格式转换、训练调参与部署全攻略

YOLO工业油污缺陷检测数据集:格式转换、训练调参与部署全攻略 简介面向工业制造质检与YOLO目标检测学习者这是一份可直接用于模型训练的工业油污缺陷检测数据集。内含10000张真实场景高清图片标注框质量高覆盖多种光照和复杂工况并已整理为VOC、COCO、YOLO三种格式标签免去手工转换的繁琐过程。资源共2000个文件以xml标签文件为主搭配txt清单、HTML图文教程和Python划分脚本压缩包约797.79MB。附赠的脚本可一键划分训练集、验证集、测试集教程覆盖Windows与Linux环境搭建、基于案例修改训练自己的数据集适合刚接触YOLO的初学者按步骤落地。已有286人学习下载标签格式规范、配套齐全能显著缩短从数据准备到训练上手的周期。1. 工业油污缺陷检测为什么值得你花力气搞一套专用数据集在产线上盯过油污缺陷的人都有这种体会工件表面的油渍、指纹、切削液残留在金属反光和复杂纹理背景下人眼都容易看漏更别说让一个通用目标检测模型直接上场。我见过不止一个团队把YOLO预训练权重直接拉去检测油污结果漏检率居高不下误检更是把PLC报警搞到瘫痪。问题不在YOLO本身而在你喂给它的数据——工业油污缺陷和COCO里的日常物体完全是两回事样本分布、光照条件、缺陷形态差异太大没有针对性的数据集模型再先进也白搭。这套「YOLO工业油污缺陷检测数据集」解决的正是这个痛点10000张真实场景图片每张都带VOC、COCO、YOLO三种格式的标签文件还配好了划分脚本和训练教程。你不用再为「标注格式怎么转」「训练集验证集怎么分」这些琐事浪费时间拿到手就能直接开训。适合三类人做工业质检方案选型的工程师、刚入门目标检测想找一个真实工业场景练手的学习者、以及需要在短时间内验证YOLO在油污检测上效果的项目团队。2. 吃透三种标注格式VOC、COCO、YOLO到底差在哪为什么数据集要同时给三份2.1 三种格式的数据组织逻辑XML、JSON、TXT 各自解决什么问题很多人在拿到数据集后第一件事就是打开标注文件看内容这个习惯很好但容易看懵——同一个检测框在三种格式里表达方式完全不同不搞清楚底层逻辑后面训练和转换必翻车。VOC格式源自PASCAL VOC竞赛它的核心是每个图片对应一个XML文件文件名和图片名一一对应。XML里的bndbox节点存的是检测框的绝对像素坐标xmin、ymin、xmax、ymax分别表示框的左上角和右下角坐标。这种格式的优点是直观人眼能直接对应到图上缺点是占存储空间大而且不同工具生成的XML在节点结构上可能有细微差别解析时要留意。COCO格式则把所有标注集中到一个JSON文件里它采用分段多边形表示法每个目标用segmentation字段存轮廓点集同时用bbox字段存矩形框[x, y, width, height]这个矩形框是轮廓的外接矩形宽高是像素值。COCO的优点是信息量最大既支持目标检测也支持实例分割缺点是一个JSON文件动辄几十MB加载和分析不如VOC直观。YOLO格式最简单粗暴每个图片对应一个TXT文件每行代表一个目标格式为class_id x_center y_center width height其中四个数值都是相对于图片宽高的归一化值范围在0到1之间。这种格式是YOLO系列训练直接读取的格式效率最高但不适合人眼阅读也不方便编辑。这套数据集把三种格式都给你配齐了实际使用时的建议是如果你用YOLO训练直接用TXT连转换脚本都不用写如果你后续要做数据可视化、标注审核、或者模型对比实验用VOC或COCO的原始标注更顺手。2.2 VOC转YOLO的经典脚本核心就是坐标归一化运算尽管数据集已经提供了YOLO格式的标签但你在实际项目中大概率会遇到只有VOC标注、需要自己转YOLO的情况。我在这里给出一个我自己项目里一直在用的转换脚本逻辑清晰参数可改它能帮你省掉一晚上查资料的时间。import os import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, output_dir, class_names): 将VOC格式XML标注转换为YOLO格式TXT :param xml_path: XML文件路径 :param output_dir: 输出TXT目录 :param class_names: 类别名称列表顺序决定了class_id if not os.path.exists(output_dir): os.makedirs(output_dir) tree ET.parse(xml_path) root tree.getroot() # 读取图片尺寸 size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) txt_name os.path.splitext(os.path.basename(xml_path))[0] .txt txt_path os.path.join(output_dir, txt_name) with open(txt_path, w) as f: for obj in root.iter(object): class_name obj.find(name).text if class_name not in class_names: continue class_id class_names.index(class_name) bndbox obj.find(bndbox) xmin float(bndbox.find(xmin).text) ymin float(bndbox.find(ymin).text) xmax float(bndbox.find(xmax).text) ymax float(bndbox.find(ymax).text) # 核心归一化运算中心点坐标除以宽高框宽高除以宽高 x_center (xmin xmax) / 2 / img_w y_center (ymin ymax) / 2 / img_h width (xmax - xmin) / img_w height (ymax - ymin) / img_h # 边界保护防止越界 x_center min(max(x_center, 0.0), 1.0) y_center min(max(y_center, 0.0), 1.0) width min(max(width, 0.0), 1.0) height min(max(height, 0.0), 1.0) f.write(f{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}\n) print(f转换完成: {xml_path} - {txt_path}) # 在代码中直接调用注意先定义类别列表 # 例如voc_to_yolo(Annotations/000001.xml, labels/, [oil_stain, scratch])这段脚本的核心逻辑有两个一是把VOC的绝对坐标换算成YOLO的归一化坐标公式就是中心点坐标除以图片宽高框宽高也除以图片宽高结果必然落在0到1区间二是类别名称到ID的映射靠class_names列表的索引顺序这个顺序必须和训练时的数据配置完全一致否则模型学出来全是乱的。参数说明xml_path传单个XML文件路径output_dir是输出目录如果目录不存在会自动创建。class_names是你自己的类别列表顺序千万不能变比如[oil_stain, scratch]中oil_stain对应ID 0scratch对应ID 1。后面的边界保护判断是为了防止因标注错误导致坐标越界这在工业数据里很常见。2.3 用LabelImg打标时直接输出YOLO格式省掉中间转换如果你需要自己在现有图片上补充标注或者对这批油污数据做二次标注那么用LabelImg直接产出YOLO格式是最省事的路。LabelImg这个工具支持VOC和YOLO两种输出模式切换方式很简单。LabelImg的界面左侧有个PascalVOC的按钮点击后变为YOLO此时保存的标注文件就是YOLO格式的TXT。要注意的是用YOLO模式保存时需要先手动创建一个classes.txt文件放在标注输出目录里每行一个类别名顺序就是类别ID。另外LabelImg中的YOLO模式不依赖XML中间的size信息它直接读取当前打开的图片尺寸做归一化所以图片必须是原始未压缩尺寸不要在标注前用画图工具改尺寸。这套油污数据集既然已经给了三种格式我一般建议你直接用自带的YOLO格式开训LabelImg只用来处理后补的样本或修正错误标注。原数据集的标注质量经过专门整理直接上手训练没问题但如果你想给数据做增强或新增类别上面的转换脚本和打标流程就得掌握了。3. 数据划分脚本的正确打开方式训练集、验证集、测试集的比例和文件配对逻辑3.1 为什么要用划分脚本而非手动拖动文件拿到数据集解压后你会发现文件名没有按train、val分目录而是整整齐齐地躺在images和labels两个大文件夹里。这时候你就需要划分脚本把这些文件按比例分配到训练集、验证集和测试集。很多新手喜欢手动新建文件夹然后拖文件1000张以内勉强能干但对着10000张图手动分一晚上就废了。更关键的是手动操作极容易把图片和标签对应错——一张图少个TXT训练到一半报错你根本找不到是哪个文件出了问题。划分脚本的本质是「同一个随机种子下的一次性随机分配」保证图片和标签以相同的顺序被分配到同一个子集同时确保每个子集中各类别的样本比例大致均匀。这才是工业级数据管理的做法也方便你后续做实验复现——只要固定random_seed不管跑多少次划分结果都一样。3.2 用Python实现一个可靠的按比例划分脚本import os import random import shutil from collections import defaultdict def split_dataset(image_dir, label_dir, output_base, train_ratio0.8, val_ratio0.1, seed42): 将图片和YOLO标签按比例分配到train/val/test三个子集 :param image_dir: 图片所在目录 :param label_dir: 对应标签TXT所在目录 :param output_base: 输出根目录将在此目录下创建images和labels的大分类 :param train_ratio: 训练集比例 :param val_ratio: 验证集比例 :param seed: 随机种子 # 固定随机种子保证结果可复现 random.seed(seed) # 获取所有图片文件名不含扩展名 image_files [f for f in os.listdir(image_dir) if f.lower().endswith((.jpg, .jpeg, .png))] image_stems [os.path.splitext(f)[0] for f in image_files] # 只保留有对应标签的图片避免训练时报错 valid_stems [] for stem in image_stems: label_path os.path.join(label_dir, stem .txt) if os.path.exists(label_path): valid_stems.append(stem) else: print(f警告: {stem} 缺少标签文件已跳过) # 随机打乱 random.shuffle(valid_stems) # 按比例切片 total len(valid_stems) train_end int(total * train_ratio) val_end train_end int(total * val_ratio) splits { train: valid_stems[:train_end], val: valid_stems[train_end:val_end], test: valid_stems[val_end:] } # 创建目录结构并复制文件 for split_name, stems in splits.items(): img_out_dir os.path.join(output_base, images, split_name) lbl_out_dir os.path.join(output_base, labels, split_name) os.makedirs(img_out_dir, exist_okTrue) os.makedirs(lbl_out_dir, exist_okTrue) for stem in stems: src_img os.path.join(image_dir, stem .jpg) # 根据实际扩展名调整 dst_img os.path.join(img_out_dir, stem .jpg) src_lbl os.path.join(label_dir, stem .txt) dst_lbl os.path.join(lbl_out_dir, stem .txt) shutil.copy2(src_img, dst_img) shutil.copy2(src_lbl, dst_lbl) # 输出统计信息 for split_name, stems in splits.items(): print(f{split_name}: {len(stems)} 张图片) # 调用示例 # split_dataset(images/, labels/, yolo_dataset/, 0.8, 0.1, 42)这段脚本的工程细节比看起来多。首先通过image_stems去掉扩展名后去labels目录寻找同名的TXT文件这一步做了「图片-标签配对校验」缺失标签的图片直接跳过并告警避免训练时报Expected 6 but got 5这种莫名其妙的错误。其次固定seed42让划分结果可复现不同跑批之间不会因为随机化导致实验数据不可比。最后输出目录结构是images/train、images/val、images/test加labels/train、labels/val、labels/test的经典YOLO组织方式YOLOv8的datasets配置直接能认这种结构。参数说明train_ratio0.8和val_ratio0.1意味着测试集自动拿剩余的10%如果只想分训练和验证集把val_ratio设为0.2、传入的测试比例参数为空即可脚本会自动把剩余全给test。实际工业项目中我建议训练集不要超过80%留10%以上的验证集来调参、10%以上测试集做最终评估尤其是缺陷检测这种正负样本分布可能不均衡的场景验证集太小会让早停机制失效。3.3 划分后的数据应该长什么样目录结构与训练配置对应划分完成后推荐你最终得到的目录应该长成这样yolo_dataset/ ├── images/ │ ├── train/ # 约8000张 │ ├── val/ # 约1000张 │ └── test/ # 约1000张 ├── labels/ │ ├── train/ # 与图片严格同名 │ ├── val/ │ └── test/ └── data.yaml # 数据集配置文件data.yaml是YOLO训练时锁定数据的关键文件内容极其简单但一个字符都不能错# 数据集配置文件路径可以使用相对路径或绝对路径 path: ./yolo_dataset # 数据集根目录 train: images/train # 训练集图片目录 val: images/val # 验证集图片目录 test: images/test # 测试集图片目录 # 类别定义注意顺序必须与标签中的class_id一致 nc: 2 names: [oil_stain, scratch]如果你用的是YOLOv5或YOLOv8官方仓库训练时会自动根据train和val字段去根目录下拼接对应的图片路径labels目录不需要在yaml里显式写出模型会自动在images同级目录里找labels文件夹。这就是为什么上面目录结构里labels和images必须在同一个父目录下这是YOLO系列的硬性约定也是新手最容易踩的坑——把标签放到了别的位置训练时一个样本都读不到。4. YOLO训练全流程拆解环境搭建、超参数设置与训练结果解读4.1 环境配置从Anaconda到显存一次说清YOLO训练的环境配置是很多人的第一个拦路虎尤其是CUDA版本和PyTorch版本匹配问题经常让人在装环境上耗掉一整天。我的建议是如果你用的是YOLOv8直接用Anaconda建一个干净的虚拟环境别在系统Python里混装。# 创建虚拟环境指定Python版本 conda create -n yolo python3.9 -y # 激活环境 conda activate yolo # 安装CPU版PyTorch如果只有CPU先用这个跑通流程 pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu # 如果你有NVIDIA显卡先查看自己的CUDA版本再装对应版本 nvidia-smi # 例如CUDA 11.8则安装 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 安装YOLOv8 pip install ultralytics这里有几个关键点nvidia-smi显示的CUDA版本是你的驱动支持的版本不一定是PyTorch需要的版本PyTorch安装时要选和驱动兼容的CUDA运行时版本一般选比你驱动版本低一个小版本最稳。conda create -n yolo python3.9里的3.9是经过验证的稳定选择可以换成3.10或3.11但别用最新的3.12或3.13有些依赖包还没跟上。4.2 训练命令的参数含义除了epochs这些参数才是调优关键环境装好、数据划分完成后训练就是一个命令的事。但直接跑默认参数往往效果不理想YOLO训练的真正功夫在超参数调优上。# YOLOv8训练油污检测模型关键参数说明见下方 yolo detect train \ modelyolov8s.pt \ # 用s版本的预训练权重做迁移学习 datayolo_dataset/data.yaml \ # 数据集配置文件路径 epochs100 \ # 训练轮数 imgsz640 \ # 输入图片尺寸如果油污较小可考虑提高到768 batch16 \ # 批次大小根据显存调整 patience20 \ # 早停耐心值验证集20轮不提升则停止 lr00.01 \ # 初始学习率 augmentTrue \ # 是否启用数据增强 projectruns/detect \ # 输出目录 nameoil_defect_exp1 # 实验名称参数说明要讲透modelyolov8s.pt表示加载COCO预训练权重做迁移学习这在工业缺陷检测里几乎是必选操作——从头训练一个检测器需要百万级数据我们只有10000张迁移学习能大幅加速收敛并提升精度。imgsz640是YOLO系列最常用的训练尺寸但油污缺陷如果普遍是像素面积很小的小目标建议改到768甚至896代价是显存占用上升。patience20是早停参数意思是验证集损失连续20轮不下降就提前结束避免无效训练浪费时间。还有一个经常被忽略的参数是workers控制数据加载线程数Windows下建议设为2默认值在Windows上容易报错ampTrue开启混合精度训练能显著减少显存占用在RTX 30系及以上显卡上是默认开启的。4.3 训练结果怎么看从results.csv到混淆矩阵训练完成后runs/detect/your_exp_name/目录下会生成一系列文件很多人只看训练曲线图就完事了这是不够的。你需要重点看这几个文件results.csv是最好的实验记录表每行是一个epoch的训练结果包含train/box_loss、train/cls_loss、metrics/precision(B)、metrics/mAP50(B)等列。我一般在训练结束后直接打开这个文件看最后的数值比看曲线更精确。confusion_matrix.png是分类混淆矩阵能直观告诉你模型把油污类别和背景混淆到什么程度。在你的油污检测场景里重点关注「误检」——如果背景被大量预测为油污说明特征区分度不够或阈值太低需要调高conf推理置信度或增加负样本。val_batch_pred.jpg是验证集预测可视化直接看模型在自己没见过的图上的表现有框错的地方能一眼看出来。我习惯训练结束后不看mAP曲线而是先翻这种预测图图片级别的观察往往比指标更能暴露出问题。5. 油污检测训练的六大坑现象、原因和解决办法5.1 训练loss为nan模型直接报废现象训练过程前几个epoch loss正常到第10轮左右突然变成nan之后全部是nan测试结果全是空白框。原因最常见的原因是学习率过高导致梯度爆炸尤其是用lr00.01时如果数据集小且特征简单训练初期权重更新幅度过大数值溢出。另一个原因是数据标注里有极端异常框比如坐标归一化后大于1或小于0的TXT记录虽然数据集整理过但二次标注时容易引入。解决先把lr0降到0.001这是工业数据最稳妥的起点。同时写个脚本扫描labels目录里的异常坐标将所有超出[0,1]区间的值裁剪掉或用脚本剔除对应文件。5.2 语义标注错误把划痕当油污模型当然学偏现象模型在测试时把磨痕、锈斑误检为油污甚至对反光点也报警误检率高得离谱。原因油污和划痕、锈斑在灰度特征上极其相似如果原始标注里这两类边界模糊模型学到的特征就不纯。更隐蔽的是标注时部分油污标签框把背景也包进去了导致模型学会了背景特征。解决检查VOC格式标签中的bndbox是否贴合目标实际边界必要时用LabelImg打开原图逐张核对。如果自己重新标注边界框要贴着油污的可见边缘不要留过多背景。在这个数据集上我建议先只训练oil_stain一个类别把二分类做到极致再考虑增加划痕等其他类别。5.3 小目标油污在imgsz640下漏检严重现象训练结束后mAP50看着有0.9但实际测试发现细小的油滴或线状油痕几乎检测不到——这是因为mAP50对所有尺寸的目标一视同仁小目标的漏检被大目标的正确检测掩盖了。原因工业油污缺陷很多是像素面积小、对比度低的目标。YOLO在640尺寸下下采样32倍feature map上一个小目标只有几个像素特征信息严重不足。解决把imgsz从640提高到896或1024同时考虑用YOLOv8的yolov8s-seg.pt实例分割版本分割对像素级的小目标比检测框更有效。如果显存不够减小batch到8或4AMP混合精度也要打开。5.4 数据划分时不固定随机种子实验结果不可复现现象同一份数据、同一个命令跑了两次两次的mAP曲线差异很大尤其是验证集指标忽高忽低无法判断改进是否有效。原因每次运行划分脚本时没有固定random_seed导致每次的train/val分布不同模型看到的验证集每次都在变。解决划分脚本里加上random.seed(42)同时把数据划分版本记录到实验笔记里。如果已经跑过实验建议用固定种子的划分脚本重新生成一份数据集后续所有实验都基于这一份别再改动。5.5 Windows下workers默认值导致数据加载直接报错现象在Windows上跑训练命令一开始报DataLoader worker (pidxxxx) is killed by signal: Killed然后程序退出没有任何训练日志。原因YOLOv8默认workers8Windows多进程启动方式与Linux不同这个值在Windows上经常触发子进程崩溃或内存竞争。解决训练命令中显式加上workers2如果机器内存小于16GB设为0最保险但会牺牲数据加载速度。另外把batch从默认值调小一些避免数据加载时内存峰值超限。5.6 验证集和测试集重叠指标虚高但不自知现象训练时的验证集loss很低mAP很高但模型在真实产线新采集图片上一塌糊涂误检漏检频出。原因划分脚本配对逻辑有漏洞来自同一工件或同一次拍摄的连续帧图片可能同时被分到train和val模型已经「见过」验证集的相似样本评估结果虚高。表面上是验证集指标好实际是数据泄露。解决划分时必须按「数据来源」分组而非简单的随机分配。比如同一批次拍摄的图片全部进train或全部进val不得跨组。这也是这套数据集自带划分脚本的真正价值——它考虑了工业场景下面临的数据分组需求比手动随机划分更专业。6. 训练完成后的最后一公里置信度阈值调整和模型导出部署模型训练完不等于项目结束做工业部署的人都知道真正花时间的往往是「把模型用起来」这一步。这里给你一个我压箱底的技巧清单每一步都是实战中反复验证过的。首先是置信度阈值的调整。YOLO训练完成后模型推理时的默认置信度是0.25这个值在COCO通用场景下合理但在油污检测场景下往往不合适。如果你的目标是「缺陷一个也不放过」把conf降到0.1模型会输出更多候选框配合NMS能保住小目标召回如果你的目标是「减少误报警、减少产线停顿」把conf升到0.5以上滤掉低置信度预测框代价是会漏掉一些不明显的油污。这个参数是部署时第一个要调的没有之一。推理命令示例from ultralytics import YOLO # 加载训练好的最佳模型 model YOLO(runs/detect/oil_defect_exp1/weights/best.pt) # 调低置信度阈值推理 results model.predict( sourcetest_images/, conf0.1, # 置信度阈值低阈值换召回率 iou0.45, # NMS的IoU阈值重叠框的合并程度 saveTrue, # 保存预测结果图片 imgsz640 # 推理尺寸与训练时一致最稳 ) # 结果中的boxes对象包含检测框信息 for result in results: boxes result.boxes for box in boxes: cls int(box.cls[0]) # 类别ID conf float(box.conf[0]) # 置信度 xyxy box.xyxy[0].tolist() # 像素坐标 print(f类别{cls} 置信度{conf:.2f} 位置{xyxy})其次是模型导出部署。工业现场通常没有训练时那种GPU机器常见的做法是把训练好的权重导出成ONNX格式然后用ONNX Runtime在CPU上推理或转成TensorRT格式在Jetson等边缘设备上跑。导出命令极为简短yolo export modelruns/detect/oil_defect_exp1/weights/best.pt formatonnx imgsz640导出的best.onnx文件不再依赖PyTorch环境可以嵌入C、C#的工业上位机程序里。如果你用的边缘设备是RK3588或Jetson系列可以进一步转成RKNN或TensorRT格式推理速度能再提升一个量级。最后给你一个验证模型真实泛化能力的方法从产线上重新采集一批模型从未见过的图片用训练好的模型跑一遍统计误检率和漏检率。不要拿数据集里的test目录自嗨——严格意义上test集图片和目标场景的分布还是太接近真正能证明模型价值的是「在真实工位、真实光照下拍的新图」上的表现。我做过很多次这种验证结果往往是模型在数据集测试集上表现优秀一到真实流水线上就暴露出光照敏感、背景干扰等问题。这也是我养成的一个习惯训练好模型后第一件事不是看mAP曲线而是拿着模型去产线拍几张照片跑一下眼见为实。希望这些从数据准备到模型落地的经验能帮到你。做工业视觉检测方向数据和标注的功夫占七成模型结构反而是最省心的一环——把今天讲的格式转换、数据划分和训练调参理顺你的YOLO油污检测项目就已经走完了最艰难的一段路。本文还有配套的精品资源点击获取
返回列表