
简介在工业视觉与深度学习工程实践中目标检测模型的性能上限往往由数据质量决定。YOLOv5作为当前应用广泛的目标检测框架其标准化的数据集目录结构images/labels划分、data.yaml配置、txt归一化标注为模型训练提供了统一规范。合理组织的数据集不仅能确保训练流程稳定更能直接提升缺陷识别的精度与泛化能力。面向齿轮缺陷检测这一典型工业质检场景规范标注的划伤、碰伤、锈蚀三类样本结合正确的训练配置与验证策略可有效规避数据泄漏、小目标漏检、标签错乱等常见问题。本文围绕YOLOv5格式齿轮数据集从目录结构、标注换算到训练自检系统梳理从数据到模型落地的完整链路助力工程师快速跑通工业视觉检测流程。 做工业视觉检测这几年我见惯了模型调参的焦虑也见过太多人把AP上不去的锅甩给网络结构。可一旦把数据和标签摊开来看问题往往就明明白白摆在那里——标注框画得宽一圈、类别顺序对不上、训练验证集混了同一批齿轮随便一条都够你白跑一整天。最近我在做齿轮缺陷检测实验用的就是一套标准的YOLOv5目录格式数据集3个类别训练集和验证集都配好了。这篇文章不聊玄乎的算法就把这套数据集从头拆到尾目录结构怎么组织的、标注txt里的五个数字是怎么算的、三个缺陷类别分别该按什么标准标、以及你拿它训练时最容易在哪几个地方翻车。无论你是刚接触目标检测的新手还是已经在工业质检里摸爬滚打了一阵子的工程师照着这篇文章操作基本能把数据到模型的链路跑通。1. 齿轮缺陷检测为什么绕不开YOLOv5目录格式1.1 工业场景里数据质量决定了模型上限齿轮是机械传动系统的核心零件从汽车变速箱、减速机、机器人关节到风力发电设备几乎所有旋转动力传递都离不开它。齿轮一旦出现缺陷轻则产生噪音和振动重则导致断齿、卡死甚至整个设备报废。所以在产线上齿轮表面质量检测一直是质检环节的重点。过去大多数工厂靠人工目检老师傅拿着手电筒一颗齿一颗齿地看效率低不说漏检率很大程度上取决于当天的精神状态。后来大家开始上机器视觉最初用的是传统图像处理就是设定固定阈值、找边缘、做形态学滤波那套。规则写死了换一种光照、换一个机位算法就失灵。深度学习目标检测方案能自动学习缺陷的视觉特征对光照变化、缺陷形态变化的容忍度高很多。但要训练一个可靠的目标检测模型首先得有数据。这里的数据不是随便找几张图、画几个框就完事而是要有规范的目录组织、统一的标注格式、合理的类别定义以及严格划分的训练集和验证集。随便拿一批没有规范化的图片去训练你会发现自己永远在解决数据读不进来标签对不上loss降不下去这类和算法完全无关的问题。1.2 YOLOv5目录格式为什么能成为事实标准我最早做目标检测的时候用过VOC格式后来也转过COCO格式再后来切到YOLOv5就再也不想回去了。原因很简单YOLOv5目录格式太省心了。它本质上是一套文件和文件夹组织约定图片放在images目录下标签放在labels目录下训练集和验证集用train、val子文件夹区分另加一个data.yaml描述类别数量、类别名称和数据集路径。没有复杂的XML解析没有JSON嵌套结构一个txt文件一行一个目标五个数字完事。YOLOv5目录格式能成为事实标准我认为有三个原因。第一它足够简单人眼能看懂脚本也好处理新手半天就能上手第二它的生态足够成熟官方仓库、社区教程、标注工具全都围绕这套格式来适配遇到问题搜一下就有答案第三它的迁移成本极低训练好的模型可以轻松部署到不同的推理框架数据集本身也可以平滑迁移到YOLOv8、YOLOv11这些新版本上只需要改改配置文件里的路径和格式模型结构升级不影响你已有的标注资产。1.3 这套齿轮数据集解决了什么问题齿轮缺陷检测数据集的核心价值在于把实际产线上的缺陷样本变成了开箱即用的训练资源。它包含3个类别覆盖了齿轮表面最容易出现的几类典型缺陷目录结构完全按照YOLOv5规范组织下载解压后改一下data.yaml路径就能开始训练同时提供了训练集和验证集省去了自己划分数据的步骤也避免了划分不合理带来的评估失真。对初学者来说这套数据集可以直接用来跑通YOLOv5训练流程理解标注格式观察不同缺陷类别在训练过程中的表现对有经验的工程师来说它可以作为预训练数据或者新场景的底料在自采数据的基础上做迁移学习缩短标注周期。2. 目录结构、data.yaml与标注文件逐个拆解2.1 目录树长什么样为什么这么长拿到数据集解压之后你会看到这样的目录结构gearbox_data/ ├── images/ │ ├── train/ │ │ ├── gear_001.jpg │ │ ├── gear_002.jpg │ │ └── ... │ └── val/ │ ├── gear_101.jpg │ ├── gear_102.jpg │ └── ... ├── labels/ │ ├── train/ │ │ ├── gear_001.txt │ │ ├── gear_002.txt │ │ └── ... │ └── val/ │ ├── gear_101.txt │ ├── gear_102.txt │ └── ... ├── data.yaml ├── train.txt └── val.txt这个结构里最关键的一点是images下的图片和labels下的txt文件必须一一对应。images/train/gear_001.jpg对应labels/train/gear_001.txt文件名相同只有扩展名不同。YOLOv5训练时就是靠这个匹配关系去读标签的如果两边文件对不上训练过程要么找不到标签直接跳过要么报错退出。很多人第一次接触会不理解为什么YOLOv5不能像之前的一些框架那样把标注塞进一个文件里把标注文件和图片分开存放有什么好处一个好处是处理起来灵活标注文件和图片可以分别放不同的存储层比如图片放在机械硬盘标注放在SSD读取速度更快另一个好处是便于管理和检查你想看某一批图片有哪些目标直接打开同名txt就可以了不需要额外解析XML结构。另外注意train.txt和val.txt这两个文件。在YOLOv5的官方代码里data.yaml的train和val字段可以直接指向目录也可以指向包含图片路径列表的txt文件。这种设计是考虑到有些场景下原始图片分散在多个目录直接写目录不方便就用txt列出所有训练图片的绝对路径或相对路径。这套数据集把两种方式都准备好了你用哪种都行。2.2 data.yaml决定训练流程的起点data.yaml是整个训练流程的入口配置内容和下面差不多# data.yaml train: gearbox_data/images/train val: gearbox_data/images/val nc: 3 names: 0: scratch 1: chipping 2: rustnc是类别数量names是类别名称列表。这里有个细节我踩过坑names的索引顺序必须和标注txt文件里的第一个数字严格一致。标注文件里类别id是0那对应的一定是scratch是1就是chipping。如果顺序写反了模型不会报错但它会把划伤当成碰伤去学最后验证集上的mAP再高实际推理结果也完全没法用。路径写法也值得注意。我最开始训练时直接在data.yaml里写死了类似/home/user/gearbox_data/images/train的绝对路径后来把数据集和代码一起拷到另一台服务器上配置文件忘了改训练直接报路径不存在。现在我的习惯是数据集和代码放在同一个工程根目录下data.yaml里统一用相对路径在哪台机器上跑都省心。YOLOv8之后data.yaml的格式大体兼容但有些字段的写法更严格了。如果你以后把数据集迁到YOLOv8或YOLOv11上只需要把train和val字段确认为实际存在的路径names改成列表或字典形式就能直接训练。2.3 标注txt五个数字背后的换算打开任意一个labels下的txt文件你会看到一行行这样的内容0 0.513280 0.419643 0.043240 0.127083 1 0.224130 0.510714 0.071240 0.093361 2 0.830238 0.354833 0.136354 0.181162每行五个数字分别是类别id、目标中心点x坐标、目标中心点y坐标、目标宽度、目标高度。这里的所有坐标都是归一化后的值范围在0到1之间而不是像素坐标。具体换算公式是x_center (xmin xmax) / 2 / image_width y_center (ymin ymax) / 2 / image_height box_width (xmax - xmin) / image_width box_height (ymax - ymin) / image_height其中xmin、ymin、xmax、ymax是目标边界框的像素坐标。为什么要归一化因为一张图片可能被缩放到不同尺寸如果标注框用像素坐标写死图片一缩放标注框就失配了。归一化之后无论原始图片是1920x1080还是640x640标注框里存的比例关系都不会变。我在检查数据时有个习惯随便拿一张图和它的txt放在一起人工对照一下边界框位置是否合理。你不需要一个个算直接用OpenCV画个框看一眼就够了。具体脚本后面在第4节里给你。3. 三个缺陷类别的工业定义与标注边界3.1 划伤scratch划伤是齿轮表面最常见的缺陷之一形态上呈线性或条状宽度不一长度从几毫米到跨越多颗齿都有可能。产生原因通常是加工过程中的刀具划碰、切屑残留或者上下料环节异物刮擦。从检测算法角度来看划伤属于典型的细长小目标这是检测难度最高的一类。一张1920x1080的图片里一条划伤可能只有几百个像素缩放到YOLOv5默认的640分辨率之后就只剩几十个像素了很容易被下采样丢掉。所以标注划伤时边界框一定要紧贴缺陷边缘宁可稍微小一点也不能把正常齿面框进去。如果划伤横跨一整颗齿轮导致边界框拉伸成长宽比极度夸张的矩形我会建议在标注前先做切图处理把图片切成几块再标否则训练时难以收敛。还有一个容易混淆的地方齿轮加工产生的规则纹理和划伤在视觉上非常像。标注时要严格区分纹理是等间距、方向一致的正常特征而划伤是突变的、不规则的痕迹。如果标注时把纹理也框成scratch模型会被带偏之后在实际场景里疯狂误检。下表是三个类别的直观特征对比我在标注时基本按这个口径来判断类别id名称形态特征常见的误判对象0scratch 表面划伤细长、条状、线性突变齿轮表面加工纹理、反光细线1chipping 齿面碰伤/崩角局部缺损、块状、边缘不齐阴影、油污、高光晕2rust 锈蚀/氧化区域型、片状、颜色异常油污、氧化后变深的正常齿面3.2 齿面碰伤/崩角chipping碰伤或崩角是齿轮在运输、装配、啮合过程中受到冲击后产生的缺损特征是一颗齿的齿面或齿角被硬生生磕掉一块。它跟划伤最大的区别是形态上的缺失感——划伤是表面多了一条线碰伤是表面少了一块。标注碰伤时我建议框住缺损区域本身而不是把整颗齿框进去。有些标注员图省事看到齿面有缺角直接框了一整颗齿导致边界框里大量像素其实是正常的齿面。这样训练出来的模型会对一整颗齿产生响应而不是对缺损产生响应在实际检测中会把完好的齿也当成缺陷。如果同一颗齿上有两处独立崩角也要分开标不能合并成一个框。合并框通常会把中间正常的齿面也包进来引入额外噪声。另外齿面反光和阴影经常和碰伤长得很像。一个实用的标注原则是在光照条件不变的情况下旋转或微调齿轮角度如果那块阴影还在、形状不变那大概率是缺陷如果阴影随角度变化消失那只是光照现象。数据集整理阶段如果有条件最好多角度采集对照能大幅降低标注和后续训练的困扰。3.3 锈蚀rust锈蚀是齿轮存储或清洗环节常见的问题表现为齿面局部或大面积出现黄褐色、红褐色的氧化斑块。和碰伤不同锈蚀通常不改变齿轮的几何形状它只是改变了表面颜色和反射特性这恰恰给检测算法带来挑战——因为很多工业场景里正常齿轮表面也会因为油污、热处理膜层而呈现深浅不一的颜色。标注锈蚀时以颜色异常区域的外轮廓为准。一片锈斑内部如果有明显的深浅分层只要连成片就按一个整体标注如果锈点分散成多个独立小点则分开标注。我个人的经验是锈蚀的标注边界宁紧勿松。锈斑边缘和正常齿面往往是渐变过渡的如果边界框画得过大模型会学到整个齿面偏暗就是锈蚀导致所有暗色区域都被误检。框紧一点模型反而能学到锈蚀的核心特征泛化能力更好。3.4 三类缺陷组合为什么适合入门这套数据集选用划伤、碰伤和锈蚀三个类别是有讲究的。从机器学习角度看这三类缺陷的形态特征差异足够大划伤是线性特征碰伤是局部几何缺损锈蚀是区域颜色异常。检测网络要同时对这三类目标都做出正确判断就必须同时利用边缘特征、局部形状特征和颜色纹理特征而不是只靠某一个维度去蒙。从工程落地角度看这三类缺陷也是齿轮质检中最常见的排除项。把这三类跑通了再扩展其他缺陷类别比如磨损、点蚀、热处理裂纹时只需要新增标注数据和类别id训练思路可以完全复用。所以它特别适合作为目标检测入门和工业质检方案验证的起步数据集。4. 从数据集到训练结果自检、跑通与指标解读4.1 训练前先做三件事拿到数据集不要急着跑训练先花十分钟做自检。第一件事确认图片和标签文件是否一一对应不要有缺失。可以用下面这个脚本快速扫描from pathlib import Path for split in [train, val]: img_dir Path(fgearbox_data/images/{split}) lbl_dir Path(fgearbox_data/labels/{split}) imgs {p.stem for p in img_dir.glob(*.jpg)} lbls {p.stem for p in lbl_dir.glob(*.txt)} missing_label imgs - lbls missing_image lbls - imgs print(f[{split}] images{len(imgs)} labels{len(lbls)}) if missing_label: print( 缺标签文件:, list(missing_label)[:5]) if missing_image: print( 缺图片文件:, list(missing_image)[:5])第二件事检查标签里的坐标有没有越界或格式错误。YOLOv5要求五个数字都在0到1之间如果某一行出现了大于1的数或者一行只有四个数字、六个数字训练时轻则跳过该目标重则直接报错。检查方法和上面差不多逐行读取txt再判断就行。第三件事也是最重要的用可视化确认标注内容。我每次拿到新数据集都会画一批图出来看脚本也不复杂import cv2 from pathlib import Path label_file gearbox_data/labels/train/gear_001.txt image_file gearbox_data/images/train/gear_001.jpg img cv2.imread(image_file) h, w img.shape[:2] colors [(0, 0, 255), (0, 255, 0), (255, 0, 0)] class_names [scratch, chipping, rust] with open(label_file) as f: for line in f: parts line.strip().split() if len(parts) ! 5: continue cls, cx, cy, bw, bh map(float, parts) x1 int((cx - bw / 2) * w) y1 int((cy - bh / 2) * h) x2 int((cx bw / 2) * w) y2 int((cy 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.5, colors[int(cls)], 2) cv2.imwrite(check_gear_001.jpg, img)把可视化的图片快速过一遍比看任何统计数字都直观。如果标注框明显偏离目标实体或者类别标得张冠李戴这组数据就算有高精度也白搭。4.2 训练命令与参数选择的实际理由数据集自检通过后就可以开始训练了。以YOLOv5官方仓库为例先确保环境里已经安装了依赖项官方requirements.txt里列的那些装好就行。然后执行训练命令cd yolov5 python train.py \ --data gearbox_data/data.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100几个参数我解释一下选择依据。--weights yolov5s.pt用的是小尺寸预训练权重。齿轮缺陷检测任务不算特别复杂3个类别目标形态结构清晰yolov5s的容量已经足够。直接上yolov5x不是不行但训练时间和显存占用都会显著增加收益却有限。我的习惯是先用小的跑通流程确认数据和配置没问题再根据验证集结果决定要不要换大模型。--img 640是分辨率YOLOv5默认值。对于多数缺陷检测任务这个分辨率在速度和精度之间比较平衡。但是划伤这种细长小目标在640分辨率下可能只剩几个像素宽检测不到是正常现象不是数据集有问题。如果发现小目标漏检严重可以试试把--img调到960甚至1280代价是训练和推理速度都变慢。--batch 16取决于显存大小。如果不确定自己的显卡能跑多大batch可以先从8开始观察显存占用再往上加。batch太小训练不稳定太大又容易爆显存8到32是工业缺陷检测里比较常见的区间。--epochs 100是一个经验值。训练过程中我会盯着loss曲线和验证集mAP如果epoch 60就已经收敛mAP不再上升就提前结束如果到100还没收敛说明数据复杂度超出预期需要检查学习率或数据质量而不是盲目加轮次。4.3 验证阶段看什么指标训练结束后用best权重在验证集上评估python val.py \ --data gearbox_data/data.yaml \ --weights runs/train/exp/weights/best.pt \ --img 640输出里会有一张混淆矩阵、一张F1曲线图以及一组数值precision精确率、recall召回率、mAP0.5、mAP0.5:0.95。这几个指标的含义要弄清楚。precision是模型说是缺陷的目标里到底多少真的是缺陷recall是所有真实缺陷里模型找回了多少。mAP是综合两者在不同置信度阈值下的表现得到的均值。mAP0.5表示IoU阈值取0.5时的平均精度mAP0.5:0.95表示从0.5到0.95每隔0.05取一个阈值再取平均要求更高。对工业质检来说recall通常比precision更重要。漏检一个缺陷可能导致产品流入市场而多报一个缺陷最多是让工人多看一眼。所以我在看验证结果时第一眼看recall第二眼看mAP0.5第三才看precision。5. 训练中踩过的坑泄漏、小目标与标签错乱5.1 训练集和验证集划分的数据泄漏问题这套数据集已经提供了划分好的train和val正常情况下直接用就行。但如果你打算自己重新划分数据有个坑必须避开同源数据泄漏。什么意思如果同一批齿轮零件在传送带上是连续拍摄的相邻两帧画面高度相似你把一帧分进训练集另一帧分进验证集训练时模型等于提前见过验证集的一半内容。最后验证集指标会非常漂亮但一上现场就露馅实际检出率远低于离线验证结果。我见过不止一个项目在这个问题上吃过亏。所以划分数据前先按零件编号或拍摄批次把样本分组确保同一个零件或同一次连续拍摄的帧不会同时出现在训练集和验证集里。宁可每组样本少一点也不能让两边重叠。5.2 细长与微小缺陷的检测上限划伤这类缺陷在目标检测里有个别名叫极端长宽比目标。它的宽可能只有几个像素长却有几百个像素。YOLO系列的检测头是锚框机制默认的锚框长宽比一般在1:1到1:4左右极端长宽比目标很容易落到锚框的覆盖盲区。如果你在验证结果里发现划伤的召回率显著低于其他两类可以先做两件事。第一把输入分辨率提高让划伤在特征图上的像素数增加第二对包含划伤的图片做切图推理把大片区域切成多个小块分别检测再合并结果。这两种方案实测都能有效提升细长缺陷的召回率。另一个思路是如果项目允许把划伤检测单独拆出来用专门训练的模型做不要和碰伤、锈蚀混在一个模型里。不同缺陷的形态差异太大一个模型里强行共存可能会互相干扰。这个取舍要看具体场景和算力条件。5.3 类别不平衡与错误标注的连锁反应数据集中三个类别的样本数量如果不是平均分配模型会倾向于把置信度偏向样本更多的类别。极端情况下样本少的类别几乎学不出来验证集里该类别的precision和recall全部接近0。遇到这种情况我的处理顺序是先看是不是标注质量问题。错误标注对训练的影响比样本少还严重——模型把正常齿面学成缺陷区域时loss会一直降不下来每轮指标都在震荡。有人问错误标注会导致训练集loss降不下来吗我的答案是会而且表现形式很有迷惑性loss曲线看起来在降但验证集mAP上不去、预测结果乱七八糟这时候就应该回头查标注。排查标注质量最有效的方式是随机抽样本可视化不是一次性看几十张而是一张张看看到边界框位置可疑就停下来对比原图。标注框与目标本身偏差超过一个边框宽度的我会直接标记出来重新标。如果确认标注没问题再考虑类别不平衡的常规手段对少样本类别做离线增强复制粘贴带标注的样本注意只在train集内做、调整类别权重、或者用mosaic增强让少样本类别在训练过程中多出现几次。YOLOv5默认开启mosaic对小数据集来说本身就是一个天然的增强器这也是我建议你训练时保留默认增强参数的原因。数据驱动模型模型反哺数据这是我做缺陷检测项目最深的一点体会。很多人盯着backbone、neck、损失函数改来改去效果却始终原地踏步就是因为没有把数据当做一个需要持续维护的核心资产。这套齿轮缺陷数据集如果用在正确的流程里——先检查、再训练、后分析——你会发现模型训练会比你预想的顺利得多真正的问题往往不在算法而在那些被忽略的目录细节、标注口径和数据边界。本文还有配套的精品资源点击获取