简介这份资源面向从事工业视觉检测、机械零件识别与目标检测算法练习的开发者与学习者提供了一套覆盖常见机械零件类别的标注数据集可用于模型训练、迁移学习与算法对比实验。压缩包共约2000个文件以1999个VOC格式xml标注文件和1个说明txt为主整体约224.71MB图片与标注一一对应方便直接接入Pascal VOC或YOLO训练流程。数据集共5913张jpg图片标注类别包含bearing、bolt、flange、gear、nut、spring六类总框数达24049个其中nut、bolt、gear、bearing等类别样本较为充足flange相对较少适合用来观察类别不均衡对检测效果的影响。所有标注均使用labelImg以矩形框方式完成标注规则统一便于快速构建训练集与验证集。目前已有924人学习下载适合需要真实机械零件数据做课程设计、毕业项目或算法验证的读者参考使用。1. 机械零件检测数据集5900 张 5 类 VOCYOLO 到底能跑出什么结果拿到一个标注好的机械零件数据集第一反应往往不是兴奋而是怀疑——5900 张、5 个类、VOC 和 YOLO 双格式听起来像是能直接开训但真正决定成败的是类别边界清不清楚、框贴不贴边、训练集和验证集有没有同图泄漏。机械零件检测和通用目标检测最大的区别在于零件之间高度相似螺栓和螺母在低分辨率下几乎只差一个内孔垫片和法兰盘在俯拍视角下轮廓接近模型很容易把「像」当成「是」。这个数据集的价值就在于它把场景收敛到工业零件这一垂直领域5 类目标、5900 张图规模不算大但足够跑通一条从 VOC 到 YOLO 的完整链路适合做产线分拣、零件计数、装配前缺件检查这类落地验证。如果你手上正好有类似需求或者想找一个比 COCO 更贴近工业现场的练手数据这篇笔记会从格式转换、类别映射、训练参数到排错把能踩的坑一次讲清。2. 先看清数据VOC 与 YOLO 双格式的目录结构和类别分布2.1 VOC 格式的目录约定与文件职责VOC 格式的核心是三个目录Annotations放 XML 标注JPEGImages放原图ImageSets/Main放划分文件。XML 里每张图对应一个object节点包含name类别名、bndboxxmin/ymin/xmax/ymax左上右下绝对像素坐标。很多人拿到数据集直接开训结果发现类别名对不上就是因为没先读 XML 里的name实际值。常见做法是先跑一遍统计脚本把类别名和数量打出来确认没有拼写不一致比如bolt和Bolt混用。import os import xml.etree.ElementTree as ET from collections import Counter ann_dir Annotations counter Counter() for f in os.listdir(ann_dir): if not f.endswith(.xml): continue tree ET.parse(os.path.join(ann_dir, f)) for obj in tree.findall(object): name obj.find(name).text.strip() counter[name] 1 for k, v in counter.most_common(): print(k, v)这段脚本遍历所有 XML统计每个类别名出现的次数。重点看两件事类别名是否只有 5 个、有没有大小写或空格差异。如果出现 6 个以上说明标注时用了别名需要在转换前统一映射否则 YOLO 训练时类别数会对不上。2.2 YOLO 格式的归一化坐标与类别索引YOLO 格式每张图对应一个.txt每行是class_id x_center y_center width height全部归一化到 0~1。class_id 从 0 开始顺序由classes.txt或data.yaml里的names决定。VOC 转 YOLO 时最容易翻车的地方是坐标归一化用了错误的宽高——必须用图片实际尺寸不是 XML 里可能存在的size节点有些标注工具写的 size 和真实图片不一致。我一般会直接用 PIL 或 OpenCV 读图拿尺寸避免被 XML 里的脏数据带偏。from PIL import Image def voc_to_yolo(xml_path, img_path, class_map): tree ET.parse(xml_path) root tree.getroot() w, h Image.open(img_path).size lines [] for obj in root.findall(object): name obj.find(name).text.strip() if name not in class_map: continue cls_id class_map[name] bnd obj.find(bndbox) xmin float(bnd.find(xmin).text) ymin float(bnd.find(ymin).text) xmax float(bnd.find(xmax).text) ymax float(bnd.find(ymax).text) xc (xmin xmax) / 2 / w yc (ymin ymax) / 2 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{cls_id} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}) return linesclass_map是类别名到 id 的字典必须和data.yaml里的names顺序一致。归一化保留 6 位小数足够再多没必要。如果某张图没有目标YOLO 允许空 txt但训练时要注意有些版本会报错建议直接跳过或补一个空文件。2.3 5 类零件的样本均衡与长尾问题5900 张 5 类平均下来每类 1180 张但实际分布往往不均匀。机械零件数据集里螺栓、螺母这类小件容易标注多法兰盘、轴承这类大件可能偏少。先统计每类框数如果最多和最少差 3 倍以上训练时就要考虑过采样或 focal loss。常见做法是在data.yaml里不改而是在训练脚本里对稀有类做重复采样或者用 YOLO 的cls_pw参数给类别加权。别一上来就上复杂方案先跑一版 baseline 看每类 AP再决定要不要动。类别名建议 id典型框数占比备注bolt025%~35%小目标多注意 anchornut120%~30%与 bolt 易混washer210%~20%薄片框易偏flange310%~15%大目标尺度差异大bearing45%~15%样本少时优先增广3. 从 VOC 到 YOLO转换脚本、划分策略与 data.yaml 写法3.1 转换脚本的四个关键参数转换不是把 XML 读一遍就完事下面四个参数决定后面训练顺不顺。第一class_map必须和data.yaml的names严格一致顺序错了模型学到的 id 就全乱。第二图片尺寸用真实读图结果不用 XML 里的 size。第三坐标要裁剪到 [0,1]有些标注框会超出图片边界不裁剪会导致 YOLO 报错。第四空标注图要么跳过要么写空 txt看训练框架要求。import os from PIL import Image def convert_all(ann_dir, img_dir, out_dir, class_map): os.makedirs(out_dir, exist_okTrue) for f in os.listdir(ann_dir): if not f.endswith(.xml): continue stem f[:-4] img_path os.path.join(img_dir, stem .jpg) if not os.path.exists(img_path): continue lines voc_to_yolo(os.path.join(ann_dir, f), img_path, class_map) with open(os.path.join(out_dir, stem .txt), w) as fp: fp.write(\n.join(lines))out_dir建议单独放不要和原 VOC 混在一起。转换完随机抽 10 张用可视化脚本画框确认坐标没偏。这一步花 5 分钟能省后面几小时的排查。3.2 训练集/验证集划分别让同图泄漏毁掉指标划分策略比转换更容易被忽视。常见错误是随机按 8:2 分但同一批零件可能在同一场景下拍了多张随机分会导致训练集和验证集出现几乎相同的图验证 mAP 虚高。机械零件数据集尤其要注意如果同一工位、同一光照下连拍建议按「拍摄批次」或「零件实例」划分而不是按图随机。没有批次信息时至少用固定随机种子并检查验证集里有没有和训练集文件名相邻的图。# 按 8:2 划分固定种子生成 train.txt 和 val.txt python - EOF import os, random random.seed(42) imgs [f[:-4] for f in os.listdir(labels) if f.endswith(.txt)] random.shuffle(imgs) n int(len(imgs) * 0.8) with open(train.txt, w) as f: f.write(\n.join(imgs[:n])) with open(val.txt, w) as f: f.write(\n.join(imgs[n:])) EOFtrain.txt和val.txt里写图片路径不带扩展名或带扩展名看框架要求。YOLO 系列一般用data.yaml里的train和val指向目录或 txt具体看版本。划分完统计一下两边的类别分布如果某类在验证集里只有个位数指标波动会很大考虑分层抽样。3.3 data.yaml 的最小可用配置与路径陷阱data.yaml是 YOLO 训练的入口写错路径是最常见的翻车点。下面是一个最小配置path: /data/mech_parts train: images/train val: images/val nc: 5 names: [bolt, nut, washer, flange, bearing]path是根目录train和val是相对路径。注意 YOLO 默认会去找images/train对应的labels/train所以目录结构要对称。如果图片和标签不在同一级要么改配置要么建软链接。另一个坑是names的顺序必须和转换时的class_map完全一致差一个位置所有指标都不可信。4. 训练参数怎么设5 类机械零件的 epoch、imgsz 与增广取舍4.1 小目标偏多时 imgsz 和 anchor 的调整机械零件里螺栓、螺母、垫片都偏小默认imgsz640可能不够。如果原图分辨率高比如 1920×1080直接缩到 640 会让小目标只剩十几个像素模型很难学。常见做法是imgsz960或1280但显存会涨。另一个办法是切图训练把大图裁成小块每块里目标占比更大。anchor 方面YOLOv5/v8 会自动聚类但如果小目标 AP 明显低可以手动调小 anchor 尺寸或者用--img-size配合--rect保持长宽比。# YOLOv8 训练示例imgsz 提到 960batch 按显存调 yolo detect train \ datadata.yaml \ modelyolov8s.pt \ epochs100 \ imgsz960 \ batch8 \ workers4 \ patience20 \ projectruns/mech \ nameexp01patience20表示 20 个 epoch 没提升就早停省时间。batch8是 960 下的保守值显存够可以加到 16。先跑 20 个 epoch 看 loss 曲线如果 cls loss 不降检查标签有没有问题如果 box loss 震荡降学习率或加 warmup。4.2 增广策略哪些能用哪些会帮倒忙机械零件检测的增广要克制。翻转、轻微旋转、亮度对比度调整一般安全但大幅旋转、裁剪、mixup 可能破坏零件的几何特征导致模型学到错误的形状先验。特别是螺栓和螺母旋转后螺纹方向变了如果产线有方向要求增广反而有害。常见做法是先用默认增广跑 baseline再逐项加看验证集 AP 变化。Mosaic 对小目标有帮助但机械零件场景里如果零件密集mosaic 拼接后可能让目标更小适得其反。增广项建议原因hsv_h/s/v0.015/0.7/0.4光照变化常见安全degrees0~5大幅旋转破坏方向特征translate0.1轻微平移安全scale0.5尺度变化有助于泛化mosaic0.5~1.0小目标多时慎用mixup0~0.1机械零件混叠不自然4.3 学习率、优化器与早停的实操取值YOLO 默认 SGD 余弦退火lr00.01对大多数场景够用。如果 loss 一开始就爆炸降到 0.001 再试。优化器方面AdamW 收敛快但容易过拟合小数据集SGD 更稳。5900 张 5 类不算大建议lr00.01、lrf0.01、momentum0.937、weight_decay0.0005。早停patience20~30别设太小机械零件指标波动大太早停会错过后面的提升。训练完看results.csv重点看metrics/mAP50-95和每类 AP如果某一类 AP 特别低回去查那类的标注质量。5. 避坑与排查机械零件检测里最容易翻车的 5 个点5.1 类别名不一致导致 nc 对不上现象训练启动报AssertionError: nc5 but names has 6或类似。原因XML 里出现了class_map没覆盖的类别名或者大小写不一致。解决先跑 2.1 的统计脚本把所有类别名打出来统一映射后再转换。转换脚本里对未知类别直接跳过并打印警告别静默丢弃。5.2 坐标归一化用了错误尺寸现象可视化时框整体偏移或大小不对。原因用了 XML 里的size而不是真实图片尺寸或者宽高写反。解决统一用 PIL 读图拿(w, h)转换后随机抽 10 张画框检查。如果框整体偏小多半是宽高反了。5.3 验证集泄漏导致 mAP 虚高现象验证 mAP 0.9但实际推理一塌糊涂。原因同一场景连拍图被随机分到训练和验证。解决按拍摄批次或零件实例划分没有批次信息时用固定种子并人工检查验证集文件名是否和训练集相邻。发现泄漏就重新划分别心疼已经跑完的 epoch。5.4 小目标 AP 低但不知道从哪查现象整体 mAP 还行但 bolt/nut 的 AP 只有 0.3。原因imgsz 太小、anchor 不匹配、或者标注框太松。解决先提 imgsz 到 960 跑一版再可视化验证集的预测框看是漏检还是定位不准。漏检多就加 anchor 或切图定位不准就检查标注框是否贴边。5.5 训练 loss 正常但推理结果乱现象loss 曲线漂亮推理时框乱飞或类别错。原因data.yaml的names顺序和转换时的class_map不一致或者推理时预处理和训练不一致。解决核对names和class_map的键值对确保 id 对应关系一致。推理脚本里的 resize、归一化参数要和训练时相同。6. 进阶技巧用混淆矩阵和每类 AP 反推标注质量训练完别只看一个 mAP 就收工。YOLO 训练会输出混淆矩阵和每类 AP这两个东西能反推标注质量。混淆矩阵里如果 bolt 和 nut 互相错分严重说明这两类在视觉上确实难分要么加数据要么在标注规范里明确区分标准比如按内孔有无。每类 AP 如果 washer 特别低去看那类的框是不是太薄薄片目标的框容易偏可以尝试放宽标注标准或单独调 anchor。# 读取 results.csv打印每类 AP 和混淆矩阵关键项 import pandas as pd df pd.read_csv(runs/mech/exp01/results.csv) cols [c for c in df.columns if AP in c or mAP in c] print(df[cols].tail(10))这段代码打印最后 10 个 epoch 的 AP 指标看是否还在提升。如果已经平了但某类 AP 低就是数据问题不是训练问题。另一个技巧是用验证集跑一遍推理把置信度 0.25~0.5 之间的框单独拿出来看这些是模型的「犹豫区」往往对应标注模糊或类别边界不清的样本。把这些图挑出来重新标一遍比盲目加数据更有效。我自己的习惯是每次训完先看混淆矩阵再看低 AP 类的预测可视化最后才决定要不要调参。十次里有七次问题出在标注不在模型。希望帮到你。本文还有配套的精品资源点击获取