
简介基于YOLO的轴承生产缺陷检测数据集与配套代码以568张现场图片为基础面向工业视觉质检、自动化产线缺陷识别场景的开发者与学习者专门解决缺少带标注工业样本、难以快速上手YOLO目标检测流程的问题。资源共1772个文件压缩包约755MB其中包含jpg现场图片及配套的txt、xml两类标注文件覆盖三类典型轴承生产缺陷另附2个Python脚本和1个YAML配置用于数据集检查、格式转换或训练环境适配方便直接接入YOLO系列模型。已有337人学习下载。数据已预先完成类别ID划分与边界框标注省去手动标注与格式整理环节可立即用于YOLO模型的训练、验证和检测效果可视化借助脚本与配置也能快速复现从数据预处理到模型评估的完整链路。对正在构建轴承表面缺陷检测方案或希望系统掌握YOLO数据集制作与训练流程的读者这是一份结构清晰、可直接上手的实战素材。1. 用YOLO做轴承缺陷检测568张图三类缺陷这份资源能帮你少走多少弯路聊轴承缺陷检测绕不开YOLO上手YOLO绕不开数据集。这套资源给的是一个YOLO格式的轴承生产缺陷检测数据集568张图片三类缺陷图片和同名txt标注已经按标准目录配对好。它最适合两类人一类是刚接触工业视觉、想用一个真实小数据集把YOLO训练全流程跑通的开发者另一类是在轴承检测项目里做算法选型、需要一份带标注数据来验证训练管线的工程师。先说一个反直觉的结论568张图在深度学习里不算多但对工业缺陷检测来说已经足够暴露大部分问题。数据标注是否一致、类别是否均衡、小缺陷是否漏标、训练参数是否激进都能在这个规模下看出端倪。把这份资源的每一张标注当成调试工具来用比单纯追求“更大的数据集”更实际。2. 拆这份数据集的底细文件命名、标签格式与类别分布跑训练前最怕的不是模型选错而是数据集拿到手就直接塞给训练脚本。下面按“盘点文件→读懂单行标注→统计类别分布→划分训练集”四个步骤拆开每一步都能找到对应的检查手段。2.1 先盘点文件图片、标签、类别清单三者要一一对应从项目给出的图片列表看图片命名是356.jpg、355.jpg、357.jpg这类纯数字编号。对应的YOLO标签通常同名、后缀为.txt放在labels目录。解压后第一步我建议做三件事数图片数量、数标签数量、检查重复文件名。# 在数据集根目录执行先看总量 find images -name *.jpg | wc -l find labels -name *.txt | wc -l这里有个容易被忽略的细节原始文件列表里359.jpg出现了两次。重复文件名在Windows解压、网盘同步、git管理时都可能产生。如果images目录里同一张图有两份标签文件却只有一份训练时这张图会被重复采样导致模型对该张图过拟合如果图片去重了但标签留了两份则标签统计数量虚高。我一般会先把重复名字拎出来单独查一下# 找出所有重复图片名输出重复清单 find images -name *.jpg | xargs -n1 basename | sort | uniq -dsort和uniq -d组合起来能直接列出出现超过一次的文件名比用Python脚本更快速。看到重复项不要直接删先比较文件大小和md5值再决定保留哪一份。另外还要确认是否存在classes.txt或data.yaml这个文件定义了三个类别ID的对应顺序没有它后面训练时的类别名会乱掉。2.2 读懂txt单行标注类别ID、归一化坐标和边界框宽高YOLO的标注文件不是直接存像素坐标而是存归一化坐标。每一行格式固定为类别ID x_center y_center width height前四列都是相对于图片宽高的比例值取值范围通常是0~1只有类别ID是整数。假设有一张1280x1024的轴承端面图其中一个缺陷的边界框中心是(320, 512)框宽128像素、高64像素那么对应txt里的一行是1 0.250000 0.500000 0.100000 0.062500这个例子中五列分别表示类别ID为1、框中心x比例0.25、框中心y比例0.5、框宽比例0.1、框高比例0.0625。读标签时最需要警惕两类错误一类是坐标没有归一化直接写成像素值训练时边界框会超出图片范围另一类是五个数字的顺序写错把x_center和width对调训练不报错但丢失效果极差。在开始训练前我通常会把每张图对应的txt打开至少看三行确认里边的类别ID确实是0、1、2而不是1、2、3。如果编码是从1开始把所有类别ID统一减1否则data.yaml里的nc和names会全部错位。还有一个值得注意的细节检查一下标签里有没有0.000000或1.000000这类边缘值。如果坐标落在图片边界上有可能是标注时手滑拖出了画面这类框在增强时容易被裁剪掉导致训练数据白白丢失一部分。2.3 用Python统计类别分布和框大小先判断数据是否可训工业缺陷检测里三类缺陷数量往往不对称。某个缺陷占一半以上另外两类加起来都不到30%。568张图本身不多这种不平衡会被进一步放大。所以我在拿到数据集后的第一件事是写一个统计脚本把每个类别的样本数、每张图的平均框数、平均框尺寸算出来。import glob from collections import Counter labels glob.glob(labels/*.txt) cls_counter Counter() box_counter 0 total_w 0.0 total_h 0.0 for lb in labels: with open(lb, r, encodingutf-8) as f: for line in f: parts line.strip().split() if len(parts) 5: continue cls_counter[int(parts[0])] 1 box_counter 1 total_w float(parts[3]) total_h float(parts[4]) print(类别分布:, dict(cls_counter)) print(总标注框数:, box_counter) if box_counter: print(平均框尺寸占比: {:.3f} x {:.3f}.format(total_w / box_counter, total_h / box_counter))脚本逻辑并不复杂读取labels目录下所有txt文件逐行解析五列内容把第一列作为类别ID计入Counter把宽高比例累加后求平均。输出结果里如果某一类样本数只有几十个、平均框宽低于0.05就是一个预警信号。前者说明样本太少需要复制增强后者说明缺陷目标偏小需要提高输入分辨率或使用SAHI切片推理。类别ID对应的业务含义需要和数据集自带的class定义对应。一个典型的三类缺陷映射可能长这样类别ID常见缺陷类型训练检查项0表面裂纹确认裂纹框是否贴紧缺陷1划痕划痕常为长条检查锚框长宽比2边缘毛刺边缘缺陷容易漏检单独看AP实际类别名以压缩包内classes.txt或README中写明的为准。这里给出的是最常见的映射方案不是从该数据集硬性推出的。确认好类别后把统计脚本的输出和这张表对照就能知道训练前需不需要做类别重平衡。2.4 划分train/val不要直接随机切按类别做分层抽样很多教程会让你直接执行一个随机划分脚本把图片按比例分成两份。在小数据集上这种随机划分很容易导致val集中缺少某类缺陷。比如某个类别总共只有30张随机分15%出来可能只有3张到val另外还有可能一张都分不到。验证集里缺类mAP计算时该类的AP算作0产生误导性的结果。我建议按类别分层抽样先把所有包含类别A、B、C的图片分别列出来再按各自类别数量的一定比例抽取val。用Python实现时最简洁的方式是使用scikit-learn里的train_test_split或者直接写一个简单的分层脚本import glob import random from collections import defaultdict random.seed(42) img_files glob.glob(images/*.jpg) by_cls defaultdict(list) for img in img_files: lb img.replace(images, labels).replace(.jpg, .txt) if not os.path.exists(lb): continue with open(lb, r, encodingutf-8) as f: cls_set set(line.split()[0] for line in f if line.strip()) by_cls[tuple(sorted(cls_set))].append(img) val_imgs set() for cls_key, imgs in by_cls.items(): val_count max(1, int(len(imgs) * 0.15)) val_imgs.update(random.sample(imgs, val_count)) print(val图片数:, len(val_imgs))这段脚本的核心逻辑是先把图片按“包含哪些类别”分组再从每个分组中按15%抽到val。这样即使一张图同时含三类缺陷也不会被重复分进val。最终train和val的目录可以用一个shutil.move循环完成。这里提醒一句不要在脚本里把jpg的替换写成大写.JPG不同平台导出的图片后缀大小写不统一会导致标签匹配失败。3. 用这份数据把YOLO训练跑通目录编排、训练命令和首轮评估数据盘点结束接下来就是落地训练。这里推荐的流程以YOLOv8为准因为它的自定义数据集接口比Darknet更干净适合快速验证如果你执意要用Darknet数据结构是一样的但配置文件和anchor计算要额外处理。YOLOv8的训练流程分四步编排目录、写data.yaml、跑训练命令、解读首轮输出。3.1 目录编排images和labels同级train和val分开YOLOv8要求数据集根目录下必须有images和labels两个同级目录每个目录下再按train和val分开。很多人习惯把图片放在data/img、标签放在data/label训练脚本找不到标签浪费一整个下午查路径。标准结构如下bearing_defect/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ ├── data.yaml └── classes.txt这里的目录名不能改写成image、label或者annotations除非你愿意修改训练脚本里的路径拼接逻辑。特别需要注意的是train和val的图片目录与标签目录必须一一对应images/train里的每一张图必须在labels/train里有同名txt。不能把A目录下的图配到B目录下的标签即使路径能对上数量训练脚本也会因为找不到同名文件而把图丢弃。划分时我一般把val控制在总样本量的15%~20%。568张图的情况下train可以放460张左右val放100张左右。如果某个类别在val里的样本数少于5张说明划分比例可能有问题需要回到2.4里的分层抽样调整。3.2 写data.yamlnc和names决定模型知道自己在检测什么data.yaml是YOLO训练的数据入口。它至少需要四个字段path或数据根目录、train相对路径、val相对路径、nc和names。一个可用的配置如下# data.yaml path: /home/user/bearing_defect train: images/train val: images/val nc: 3 names: 0: crack 1: scratch 2: burr这里nc是类别总数names是类别名。这看起来简单但却是训练配置里最容易出错的字段。如果标签里实际出现了类别ID3而nc仍然填3训练脚本会把ID3的行当作无效标注扔掉表现为loss下降正常但mAP上不去。如果names的下标写成了1、2、3和标签ID差一位推理时类别名会全部错位部署到界面时显示的缺陷类型完全不对。类别名建议用英文小写。工业软件里经常用中文显示缺陷名称但训练配置里使用中文会在Windows环境出现编码问题转TensorRT时还要额外处理字符映射。正确做法是训练时用crack、scratch、burr这样的英文名在业务界面里再做一次中文翻译。3.3 YOLOv8训练命令参数不是越大越好准备就绪后在终端或PyCharm里运行训练命令。以yolov8s为预训练权重命令如下yolo train datadata.yaml modelyolov8s.pt epochs300 imgsz640 batch16 patience30 projectruns/bearing_defect nameexp1参数选择有明确的业务逻辑。modelyolov8s.pt选s而不是n是因为工业缺陷目标普遍偏小s模型的颈部网络能保留更多细节epochs300看起来多但配合patience30实际可能在120轮左右就停止属于“给足预算但允许早停”的写法。imgsz640是第一轮验证用的分辨率如果后续发现小缺陷漏检再提高到768或1024。batch16在12G显存上比较稳妥8G卡建议降到8。这里最容易被误解的是patience。它代表多少个epoch没有改善就停止训练而不是最多训练多少轮。小数据集的loss曲线震荡严重如果patience设成10模型可能在上升期被截断设到30到50更合理。训练过程中不要随手改参数重启先让它跑完一个完整轮次再看曲线。如果不想用命令行在PyCharm里直接运行Python脚本也是一样的核心调用是from ultralytics import YOLO model YOLO(yolov8s.pt) model.train(datadata.yaml, epochs300, imgsz640, batch16, patience30)不管是命令行还是脚本逻辑完全一致只是写法不同。第一次跑的时候建议开启verboseTrue让控制台打印出每个epoch的完整信息方便后面排查问题。3.4 首轮输出怎么读先别盯总mAP看单类AP和预测图训练启动后控制台先打印模型结构、参数量、FLOPs然后进入epoch迭代。第一个epoch结束时终端会出现val指标包括mAP50和mAP50-95。在568张图的小数据集上第一次迭代的mAP可能只有0.2甚至更低这是正常的模型还没有充分学习。真正要盯的是后面几十个epoch里mAP是否持续上升。训练结束后进入runs/bearing_defect/exp1/目录重点看两个文件。第一是results.png里面有box_loss、cls_loss、mAP曲线。如果box_loss一直在降但mAP50在某个位置不再变化优先怀疑某个类别的标注噪音。第二是val_batch0_pred.jpg这类可视化图看预测框是紧贴缺陷边缘还是把金属纹理反光也框了进来。后者在轴承表面高反光场景非常常见仅靠mAP看不出来。相比DarknetYOLOv8训练自定义数据集时少了一个麻烦anchor自动学习。Darknet需要预先计算anchor尺寸输入图片为640分辨率时用错anchor就会导致很多候选框根本不覆盖小缺陷。YOLOv8的anchor是自动调整的但代价是更依赖数据本身的标注质量。如果val图上一个框都没画出来先回标签格式和目录里去查不要先怀疑模型结构。3.5 小数据集的过拟合信号loss下降、单类AP异常工业场景里过拟合不是单纯“mAP低”而是训练集mAP很高、val mAP波动大甚至反向下降。在results.png中这种信号的典型表现是box_loss在train侧降到0.02以下但val侧box_loss重新抬头两个曲线分叉。原因是网络开始记住568张图里某些独特的金属纹理而不是学习缺陷本身的共性。对这种过拟合最有效的手段不是缩小模型而是加强数据增强和正则化。可以在训练命令中增加增强参数比如hsv_h0.015, hsv_s0.7, hsv_v0.4, degrees10.0, translate0.1, scale0.5让模型每次看到的是同一缺陷的不同光照和角度版本。轴承检测还有一个特殊的有效手段随机裁剪。把图像增强里的mosaic1.0和mixup0.2打开模型对非缺陷背景的过拟合会明显缓解。这个内容不需要修改代码YOLOv8把这些开放成了训练参数。4. 轴承缺陷数据集的常见问题排查五个坑现象原因与解决下面五条是从实际项目中反复踩出来、验证过的通用问题直接对号入座就行。4.1 图片与标签数量不一致训练报“found no labels”现象数据目录配置好后运行训练脚本终端提示找不到标签或者labels里的txt数量明显少于images里的图片数量每个epoch几秒钟就结束val阶段没有任何预测输出。原因大部分情况是解压工具丢文件或者文件名没有严格同名。YOLO惯例是0001.jpg对应0001.txt如果图片是.jpg标签写了.jpeg.xml或者图片是png而标签是txt数量就会对不上。还有一个隐藏原因某些网盘在Windows下解压会把长文件名截断后缀变成奇怪的缩写标签文件无法被识别。解决先不要改训练脚本用清单比对脚本把问题文件找出来。import os from pathlib import Path img_dir Path(images) label_dir Path(labels) imgs {p.stem: p for p in img_dir.rglob(*) if p.suffix.lower() in (.jpg, .jpeg, .png)} labels {p.stem: p for p in label_dir.rglob(*.txt)} missing_label [str(p) for name, p in imgs.items() if name not in labels] missing_image [str(p) for name, p in labels.items() if name not in imgs] print(缺标签图片数:, len(missing_label)) print(缺图片标签数:, len(missing_image))这段脚本用stem作为关联键把图片和标签分别装进两个字典然后对比缺失项。它比直接数文件数量更可靠因为它能发现同名但放在错误子目录的情况。输出的清单里如果缺的是标签回到标注工具重新导出如果缺的是图片检查是不是被误移动到backup目录。4.2 标签里出现第四类nc参数错位导致误检现象训练时loss能正常下降推理时在无缺陷区域频繁输出高置信度框而且框的位置与轴承边缘纹理高度相关。查看类别统计时发现出现了标签ID大于等于3的标注。原因项目在标注时把“背景”或“正常”也标成了一个类别导出YOLO格式时背景成了类别0三类缺陷顺延成1、2、3。data.yaml里nc仍然填3类别3的标注被训练脚本忽略模型实际看到的有效类别只剩两个背景纹理被迫承担了第三个类别的预测任务。解决先统计一下标签里的最大类别ID。如果确实出现了3而且第4类是背景正确的做法是删除该类别对应的所有标签行而不是把nc改成4。因为轴承缺陷检测场景下无法穷举所有正常纹理把背景当成一个类别训练在线推理时必然会出现大量假阳性。# 找出含类别ID大于2的标签文件 grep -rlE ^[3-9] labels/ | head -n 20用grep快速定位含异常ID的文件然后单独处理。如果异常ID是标注失误直接修改对应行如果是一个独立类别要回到标注工具确认这个类别是否有足够样本支撑训练。实话说在568张图这个规模下不建议用四类数据硬训去掉背景类、聚焦三类缺陷更容易拿到可交付的模型。4.3 划痕类缺陷漏检严重mAP50不低产线实测打不到现象验证集mAP50达到了0.85以上但拿现场拍的新图测试细小的划痕和浅裂纹基本漏检偶尔框出来的也是断断续续的片段。放大预测图后发现预测框比缺陷本身大很多。原因划痕是典型的长条形小目标宽高比常有1:10甚至更极端。YOLO默认输出层会对特征图做下采样640分辨率输入时一个宽度占比不到3%的小划痕在下采样后的特征图上可能只剩1到2个像素特征强度不够。另外如果标注框贴着划痕的包围盒但长宽比极端模型回归难度也高。解决优先把imgsz提高到768或1024这一步对长条形缺陷的提升通常比换模型更明显。接着在训练参数中开启更强的增强尤其是degrees15和scale0.5让模型见到不同旋转角度和不同尺度的划痕。还有一招是把该类别单独复制一份做拼接增强比如把多个小划痕图拼成一张训练图变相增加该类别在每张图里的出现频率。如果实测阶段仍然漏检把检测置信度阈值从默认的0.25适当降低到0.1再看漏检情况。阈值降低会增加误检但可以用来区分“模型学到了但没有自信”和“模型根本没学到”。这一步在生产环境里要谨慎阈值的最终值要结合误检成本来确定。4.4 正常轴承图片混进训练集模型开始学会漏检现象训练loss表现正常推理时对没有缺陷的轴承也输出高置信度框误检率居高不下换个场景真实缺陷反而被漏检。原因无标注图片放在了images目录里训练脚本会把它们当作负样本背景。这类图片数量一旦偏多模型学到的倾向是“尽量输出空框”。更有问题的是如果一张图里有缺陷但漏标了训练脚本会认为该区域的纹理属于背景直接压制模型对同类缺陷的响应。解决把正常件、无标注图、漏标注图全部从训练目录里请出去。正常件如果确实要参与训练要么单独加一个normal类别要么不在训练集里出现、只作为推理阶段的负样本测试集。在轴承产线上无缺陷样本往往比缺陷样本容易获取得多正确用法是留一批正常图专门做阈值调参和误检率统计而不是混在训练数据里让模型“自己悟”。4.5 显存不足、PyCharm里训练中断batch、workers、cache顺序排查现象训练跑到第几十个epoch时突然报CUDA out of memory或者整个IDE卡死重启后训练进度丢失。部分时候现象表现为CPU吃掉绝大部分核GPU利用率却只有零头。原因8G或12G显存的机器上imgsz640、batch16、yolov8s理论上能跑但叠加了Mosaic增强、缓存、过多的数据加载线程后显存和内存会同时飙升。尤其是PyCharm这类IDE里跑训练解释器自带的内存分配和调试器会额外吃掉一部分资源问题更容易复现。解决依次调整三个参数。第一是batch8显存占用大约减半第二是显式设置cacheFalse关闭数据缓存第三是workers2降低数据加载线程数。如果这三个都改了还崩把imgsz降到480试试。已经中断的时候weights目录下通常有last.pt直接在训练命令末尾加resumeTrue就能从最近一次保存的权重继续不用从头开始。需要说明的是resume依赖YOLOv8内部断点机制如果中断前没正常保存就不要强求继续直接检查日志定位原因更实际。5. 从mAP到产线可用三类缺陷的验证顺序和部署参数边界训练收尾后离产线还差两步验证顺序和部署参数。先说验证顺序。我拿到一个训练好的模型不会直接看总mAP而是按三个步骤执行。第一步打开results.png看三类缺陷各自的AP曲线找到明显短板的那一类第二步用该类的真实图像做预测可视化区分是漏检、误检还是定位偏移第三步截取一段生产现场视频按10秒一段统计误检次数。这套顺序能在不写复杂代码的情况下把模型的主要失效模式定位出来。部署时最常被问到的问题是T4上用TensorRT跑640分辨率YOLO能支持多少路1080p 25fps的视频流。这类问题的答案不能靠嘴说必须实测。我的做法是先用batch1测单路纯推理时间然后把总帧率除以单路帧率再乘一个0.7的安全系数。真正容易翻车的地方有三个一是只测了模型推理时间没有算视频解码和前后处理二是没有考虑多个推理进程共享显存时的峰值三是int8量化之后小缺陷的AP可能比fp16掉得更明显。对轴承这类小目标缺陷场景建议量化后逐个类别重新跑一次AP再决定用int8还是fp16。如果某一类缺陷的AP掉了超过3个百分点就退回fp16。自从我做过一次“只测推理时间就定方案”的蠢事以后每次拿到新的轴承缺陷模型都会强制走一遍“逐类AP→误检视频测试→三档量化对比”的流程确认所有参数后才去谈路数。这个习惯救过我很多次希望帮到你。本文还有配套的精品资源点击获取