简介面向计算机视觉与工业质检场景这份数据集收录了轴承、螺栓、法兰、齿轮、螺母、弹簧六类常见机械零件的目标检测标注图像共约五千九百张。数据采用Pascal VOC与YOLO双格式存储每张图像均配有对应的XML和TXT标注文件使用labelImg进行矩形框标注总标注框数达两万四千零四十九个可直接用于YOLO系列模型训练也方便转换至其他检测框架。压缩包共两千个文件以XML标注文件与TXT说明文件为主整体大小约二百二十四点七MB目录结构清晰便于按类别组织与筛选样本。目前已有九百一十九人学习下载适合算法工程师、研究生及工业视觉竞赛团队用于快速验证模型、积累机械零件检测经验并可在此基础上扩展缺陷识别等细分任务有效降低数据采集与标注成本。1. 目标检测常见机械零件数据集5900张5类VOCYOLO双格式底料值得先看“目标检测常见机械零件数据集5900张5类VOCYOLO”这个 zip是我近期下载后完整跑了一遍的资源。之前自己标注机械零件图的精力消耗让我对这类数据集特别挑剔拿到手第一件事就是确认三件事五类是否覆盖车间常见品型、VOC 和 YOLO 两种标注是否真实齐全、标签与图片文件名能否对齐。这三个判断点基本决定了一个资源是直接能用还是得先花一个晚上返工。这份数据的价值在于把收集图像和标注这两件最耗时的差事先做完了解压后就能进入训练环节特别适合做算法验证、毕业设计和产线质检预研的从业者。如果你正需要一套 yolov8 目标检测数据集处理的练习样本又不想从零收图这份资源是一个合格的起点。下面按我实际跑过的顺序讲格式拆解、转换、训练和踩坑。2. 拆开看数据VOC 与 YOLO 双格式目录结构与标签对应关系2.1 先跑一个统计脚本确认五类分布而不是凭感觉解压 zip 的时候留心文件名我习惯把压缩包放到一个没有中文和空格的路径下再解压。打开后你会发现典型的双格式布局VOC 风格的 Annotations 目录保存原始 XML 标注YOLO 风格的 labels 目录保存训练直接读取的 txt 标注。这时不要急着开训先统计一下每类目标的数量。很多机械零件数据集类别分布并不平均像垫圈、小螺栓这类小件数量会明显高于大齿轮等大件这个比例直接影响后面要不要做类别重平衡。import os from collections import Counter labels_dir dataset/labels counter Counter() empty_files 0 for root, _, files in os.walk(labels_dir): for f in files: if not f.endswith(.txt): continue lines open(os.path.join(root, f), encodingutf-8).read().strip().splitlines() if not lines: empty_files 1 continue for line in lines: cls int(line.split()[0]) counter[cls] 1 print(每类目标数:, dict(counter)) print(空标签文件数:, empty_files)这段脚本的逻辑很简单遍历 labels 目录下所有 txt按行读取每行第一个字段是类别索引用 Counter 累加。空标签文件单独计数因为空文件在 yolov8 训练时不会报错但会拖慢数据加载并让正样本匹配产生空洞。参数上需要注意 labels 目录路径必须指向 YOLO 格式的标签目录而不是 VOC 的 Annotations如果压缩包里没有单独的 labels 目录说明还需要执行第 3 章的转换脚本。另外Counter 默认把类别索引作为 key先跑出分布才能判断后续增强策略。2.2 目录结构对照表哪些目录训练时必须保留压缩包里的目录结构大致可以拆成三块VOC 原始标注、YOLO 训练目录、以及辅助说明文件。下面这张表是我整理后的目录用途清单你拿到手后可以对照着看。目录或文件所属格式训练时是否必需说明Annotations/*.xmlVOC否原始框坐标标注用于复核或二次转换JPEGImages/*.jpgVOC否与 Annotations 同名的原始图像ImageSets/Main/*.txtVOC否VOC 官方训练/验证划分文件images/train/*.jpgYOLO是训练图像images/val/*.jpgYOLO是验证图像labels/train/*.txtYOLO是训练图像对应的 YOLO 标签labels/val/*.txtYOLO是验证图像对应的 YOLO 标签关键点在于 yolov8 训练时只认 images 和 labels 两个目录Annotations 里的 XML 它根本不看。所以我建议直接把images/train、images/val、labels/train、labels/val这四个目录复制到项目里其他文件保留在原始位置做备份。这种做法的好处是后面如果你要换 mmdetection 或者 RT-DETR还能回到 VOC 原始标注重新转换不至于把原始数据改坏。2.3 XML 和 txt 里的坐标怎么对应一个例子讲清归一化VOC 记录的是绝对像素坐标YOLO 记录的是归一化中心点坐标和宽高。我用一个简化示例说明假设一张 640x640 图像里有一个螺母XML 的 bndbox 区域是 xmin120、ymin80、xmax220、ymax180。对应到 YOLO 的 txt 里应该是这样一行1 0.2656 0.2031 0.1562 0.1562计算逻辑框宽 100 像素、高 100 像素中心点 x(120220)/2170归一化 170/6400.2656中心点 y 同理(80180)/2130130/6400.2031宽高各 100/6400.1562。注意类别索引从 0 开始所以第一列是类别索引第二列是中心点 x。手工换算一次就能记住公式第 3 章的转换脚本也用的这个公式。同时也解释了为什么直接修改 txt 里的坐标容易出错——YOLO 格式下中心点坐标和宽高都被限制在 0 到 1 之间你从图像编辑器里读出来的像素值不能直接填进去必须先归一化。这份数据集之所以方便就是因为它默认已经帮你做好了这层换算。3. 把 VOC 转成 YOLO 格式转换脚本写法和四个边界坑3.1 什么时候要转、什么时候直接用如果你只想用 yolov5/yolov8 训练压缩包里的 YOLO 格式目录可以直接用没必要转换。但实际项目中我经常遇到三种情况必须回头处理 VOC一是要查某个目标框是否标错需要打开 XML 对照原始图像二是要把数据集送进 mmdetection 或自定义训练框架它们只认 VOC 或 COCO三是想复核 YOLO 标签是否和 XML 一致防止压缩包作者在生成 txt 时出了偏差。所以我建议把转换脚本保留在项目里它不是每步都用但每次排查数据问题都会用到。3.2 一个可复用的 XML 转 txt 脚本下面这段脚本是我按这份数据集的常见目录结构写的直接放在数据集目录下执行即可。import os import xml.etree.ElementTree as ET # 示例类别映射按你手里这份数据集的 labels 顺序替换 class_mapping {bolt: 0, nut: 1, washer: 2, gear: 3, bearing: 4} voc_annotations VOCdevkit/Annotations yolo_labels yolo_labels os.makedirs(yolo_labels, exist_okTrue) def convert_one(xml_path): 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) lines [] for obj in root.iter(object): name obj.find(name).text if name not in class_mapping: continue box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) cx ((xmin xmax) / 2) / img_w cy ((ymin ymax) / 2) / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{class_mapping[name]} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) return lines for xml_file in os.listdir(voc_annotations): if not xml_file.endswith(.xml): continue xml_path os.path.join(voc_annotations, xml_file) out_lines convert_one(xml_path) out_name os.path.splitext(xml_file)[0] .txt with open(os.path.join(yolo_labels, out_name), w, encodingutf-8) as f: f.write(\n.join(out_lines))脚本核心是先读 XML 里的 size 节点拿到图片宽高再遍历 object 计算中心点和宽高的归一化值最后写同名 txt。参数上有几个地方要特别注意class_mapping 必须与后续 data.yaml 里的 names 顺序完全一致否则类别索引会错位读取宽高直接用 XML 里的 size避免额外打开图像文件速度快很多os.listdir 只遍历一层目录如果 Annotations 里有子目录需要换成 os.walk。3.3 四个边界坑从坐标越界到类名错乱转换脚本写起来不难但跑起来会遇到几个挺隐蔽的问题我按踩过的顺序列一下。坑一是坐标越界。部分机械零件图存在标注框超出图像边缘的情况比如 xmax 比图片宽度还大归一化后 w 超过 1YOLO 训练时会被当成异常样本或直接 filter 掉。解决办法是在写出 lines 之前加一句w min(w, 1.0)或者用clip把 cx、cy、w、h 全部限制在 0 到 1 之间。坑二是 XML 里有 difficult 字段。有些标注软件会把模糊、极端的样本标成 difficult1这类样本不应该作为正样本参与训练。我一般会先过滤掉。判断逻辑是找到 object 下的 difficult 节点如果值为 1 就跳过这样能避免训练时模型被低质量标注干扰。坑三是类名五花八门。机械零件数据集的 class 名经常混着英文、中文和拼音比如螺栓可能写成 bolt、Bolt、螺丝、luoshuan转换脚本里 class_mapping 只有其中一个其余类被静默跳过结果某类目标训练时全没了。排查方法很简单转换后统计 labels 里出现的类别索引如果发现某个索引缺失大概率是类名没映射上。坑四是空标签与文件名错位。XML 里没有 object、或者图片和 XML 同名但扩展名拼写不一致都会生成空 txt。yolov8 训练时如果出现 No labels found多半就是这个问题。我在脚本最后一行后面会加一个检查统计生成的 txt 里有多少是空文件数量超过图片数 5% 就必须回头查文件名匹配。4. 用这份数据集跑通 YOLOv8data.yaml、训练命令与评估指标4.1 先写对 data.yaml路径和 names 才是训练的生命线训练前我习惯先用一个干净的数据集目录结构而不是在解压目录里直接跑。把images和labels放进dataset/下然后写 data.yaml。下面是我在这份数据集上用的配置写法# dataset/data.yaml path: ./dataset train: images/train val: images/val names: 0: bolt 1: nut 2: washer 3: gear 4: bearingpath 字段指定数据集根目录train 和 val 是相对于 path 的路径不要写绝对路径方便换机器后直接训练。names 的索引顺序必须和 labels 里 txt 的第一列数字一一对应第 3 章转换脚本里的 class_mapping 也是同一套顺序三处不一致就会导致类别标签错乱。我见过有人把 names 改成字母序结果训练出来的模型推理时全部分类错误损失还降得挺正常这个坑尤其隐蔽。如果你习惯用 anaconda 管理环境建议给 yolo 单独建一个虚拟环境避免污染基础环境。创建环境后安装 ultralytics 包然后用下面的命令训练。4.2 训练命令与关键超参数imgsz、batch、patience 怎么取舍这份数据集规模 5900 张属于中小型数据我建议用 yolov8s 起步而不是 ns 模型能在机械零件这种纹理细节多的场景下保留更多特征表达。训练命令我一般这样写yolo detect train \ modelyolov8s.pt \ datadataset/data.yaml \ epochs80 \ imgsz640 \ batch16 \ device0 \ patience20model 指定预训练权重yolov8s.pt 会自动下载data 指向刚才写好的 yamlepochs 和 batch 按显存调整。imgsz 这里需要展开说一下机械零件里像垫圈、小螺栓这类目标在原图中占的面积很小imgsz640 是下限如果显卡是 24G 显存建议直接上 960小目标召回率会有肉眼可见的提升。batch16 在 8G 显存下比较安全显存小就降到 8并且学习率也相应调低一点。patience20 是早停参数意思是 20 轮内验证集 mAP 没有提升就中断训练。这类数据集的验证集波动比较大patience 设太大会浪费时间设在 15 到 25 之间比较合适。4.3 训练过程的评估盯着 metrics 看别只盯着 loss训练过程中控制台和 runs/detect 目录下会生成 results.csv每一行是一个 epoch 的各项指标包括 train/box_loss、val/box_loss、metrics/mAP50、metrics/mAP50-95 等。我习惯开一个终端持续观察梯度有没有爆炸tail -f runs/detect/train/results.csv训练时最容易误判的是只看训练集 loss它一直在下降但验证集 mAP 停住不动说明模型开始过拟合或者学习率已经不适合继续训练。train/box_loss 和 val/box_loss 之间距离拉大就是过拟合的早期信号。这时候要么提前结束要么把数据增强强度提上去比如加大 hsv_h、hsv_s 的扰动范围。训练完成后用 best.pt 做一次正式验证拿到的才是最终可汇报的指标yolo val modelruns/detect/train/weights/best.pt datadataset/data.yaml这个命令会输出每类 AP 和综合 mAP同时生成混淆矩阵图 confusion_matrix.png。第 6 章我会重点讲怎么从单类 AP 和混淆矩阵里定位问题这一步先跑通即可。5. 机械零件检测避坑清单训练中常见的五个翻车现场5.1 现象验证集 mAP 很高灰度配件图却一个都检不出训练完在验证集上 mAP 到了 0.85看似不错但换到现场摄像头拍的灰度零件图一个大螺丝都框不出来。原因在于这份数据集以彩色图像为主模型把颜色信息当成了重要判别特征灰度图输入后特征分布发生偏移。解决方法是训练阶段就把灰度抖动加进去在 YOLOv8 的命令行里调整增强参数yolo detect train \ modelyolov8s.pt \ datadataset/data.yaml \ epochs80 \ imgsz640 \ batch16 \ hsv_h0.015 \ hsv_s0.7 \ hsv_v0.4hsv_s 和 hsv_v 调大后模型不能再依赖固定颜色纹理和形状特征的权重自然提升。推理端我还会做一步预处理把灰度图先转成三通道再喂给模型保证输入分布一致import cv2 gray cv2.imread(test.png, cv2.IMREAD_GRAYSCALE) rgb cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)5.2 现象训练到 60 轮左右 loss 开始锯齿震荡训练到后半段val/box_loss 不再是平滑下降而是出现明显的锯齿上升下降。原因是 mosaic 增强一直在全流程开启机械零件图像经过随机裁剪拼接后目标被切碎的情况很常见后半程模型已经拟合得差不多这种强扰动反而干扰收敛。解决办法是让训练最后阶段关闭 mosaicYOLOv8 提供了内置参数yolo detect train \ modelyolov8s.pt \ datadataset/data.yaml \ epochs80 \ imgsz640 \ batch16 \ close_mosaic10 \ cos_lrTrueclose_mosaic10 表示最后 10 轮关闭 mosaic 增强配合 cos_lr 让学习率平滑下降。我用这个组合后loss 曲线从锯齿变成平稳收敛验证集 mAP 也小幅上涨。5.3 现象小零件全漏、大齿轮全中尺度差异压不住垫圈、小螺钉这类目标几乎全部漏检而大齿轮的精确率接近 1。这类尺度差异在机械零件数据集上特别常见。原因是同一张图里目标大小跨度太大模型下采样后小目标在特征图上只剩几个像素特征信息不足。我试过两种有效方案第一种是提高输入分辨率imgsz 从 640 提到 960小目标对应像素成倍增加召回率提升明显。第二种是切图训练把大图从左到右切成带重叠的 patch每个 patch 单独训练推理时也按同样方式切图再合并结果。代价是训练和推理时间变长但效果真实。别只看综合 mAP要把 per-class AP 列出来看小目标类别的 AP 才是这条线的瓶颈。5.4 现象训练日志提示 No labels found标签文件大量为空训练刚开始就报 WARNINGNo labels found in .../labels/train或者训练集图片数远大于标签数。这种一般是路径或文件名匹配问题。我遇到过一次是 labels 目录下的 txt 与 images 目录下的 jpg 文件名大小写不一致Linux 下直接匹配失败。排查命令ls dataset/images/train | wc -l ls dataset/labels/train | wc -l两个数量对不上就写个循环把同名文件找出来对比扩展名和大小写。解决后重新生成一次 txt或者把文件名统一改成小写。另外要注意压缩包里如果带子目录yolov8 的 train 路径要精确到具体子目录不能写成images/完事。5.5 现象加载预训练权重后第一轮 loss 爆炸用 yolov8s.pt 做预训练权重第一轮 loss 从 5 起步之后慢慢回落看起来像正常但有些情况下一直不回落。原因是预训练模型的输出类别数是 COCO 的 80 类而这份数据是 5 类模型的检测头最后一层是重新初始化的第一轮 loss 高是正常的。但如果 data.yaml 里的 names 数量与模型配置不一致比如写了 6 个类名但数据里只有 5 类loss 会持续异常。解决方法是确认 names 长度严格等于 5索引从 0 到 4 连续中间不能跳号。不要手动改模型结构里的 nc 参数除非你明确知道自己在做什么。yolov8 会自动根据 data.yaml 的类别数重建检测头乱改反而容易出错。6. 类别不均衡时的调参与单类验证把训练结果拆开看6.1 用 per-class AP 找拖后腿的类别训练跑完之后不要只汇报一个总 mAP。机械零件类别之间有很强的相似性比如螺母和垫圈从某些角度几乎分不清单类 AP 才能告诉你是漏检还是错分。用下面的命令把验证结果导出yolo val modelruns/detect/train/weights/best.pt datadataset/data.yaml save_jsonTrue生成的 predictions.json 里能看到每个类别的 AP 数值再配合 outputs 目录下的 confusion_matrix.png能一眼看出哪些类别互相混淆。如果某类 AP 明显低于其他类先看它的样本数量再去 labels 目录抽查几张标注框排除标注本身的问题。6.2 少样本类别的增强组合与部署落地的最后一个技巧少数类样本不足时我一般是两条路并行一是加大数据增强中的 copy_paste 和 mixup 权重让每个 batch 里少样本类别以合成形式反复出现二是适度提高 imgsz让少样本类的小目标不被下采样吞掉。命令上可以这样叠加yolo detect train \ modelyolov8s.pt \ datadataset/data.yaml \ epochs100 \ imgsz960 \ batch16 \ copy_paste0.3 \ mixup0.2验证没问题后为了部署到没有训练环境的机器我会顺手导成 ONNXyolo export modelruns/detect/train/weights/best.pt formatonnx imgsz960推理端用 onnxruntime 加载即可注意输入尺寸和归一化方式必须与训练一致否则现场推理精度和验证集结果对不上。这类细节最容易被忽略但往往就是模型落地时“看着玄学”的根源。从那以后我拿到任何一份机械零件数据集都会先跑一遍第 2 章的统计脚本再做一次第 3 章的坐标越界检查最后才敢开训。这套流程多花十分钟省下的都是训练失败返工的时间。希望帮到你。本文还有配套的精品资源点击获取