
简介基于YOLOV5的齿轮图像缺陷检测实战项目面向毕业设计、工业质检与目标检测学习者提供从数据准备到模型部署的完整闭环。资源共2000个文件压缩包376MB核心数据为1400个txt格式标注文件和442张jpeg齿轮图像覆盖多种表面缺陷类别以及对应图像样本代码部分含51个Python脚本和50个YAML配置可完成数据划分、模型训练、验证及推理另有部署环境所需的Dockerfile、shell脚本及设计文档目录结构清晰便于按用途快速定位。已有238人学习下载可用于快速理解YOLOV5在工业检测中的落地方式。项目自带完整数据集与标注无需额外采集即可直接训练适合在此基础上调整网络结构或超参数进行消融实验与性能对比也可作为课程设计、毕业设计的参考基线扩展至其他工件表面缺陷检测场景。1. 齿轮图像缺陷检测为什么盯着 YOLOV5 不放产线质检工位上一块齿圈从上一工位传过来机械手只有不到 7 秒的时间完成判断。拍到的图像里齿面可能附着氧化皮也可能带着油污反光同一张图上既可能出现转角崩边又可能出现齿根裂纹还藏着针尖大小的砂眼。传统模板匹配在光照变化面前几乎一换产线就失效而普通分类网络只能给出“有问题”的结论说不出缺陷落在哪一颗齿上后道返工根本没法精准执行。以 YOLOV5 为代表的单阶段检测器把问题收敛成一张图像中的多个目标框一次前向同时给出位置、类别和置信度配合足够的缺陷样本就能稳定落地。这篇内容围绕yolov5 训练自己的数据集的完整流程展开适合刚完成目标检测入门、想拿真实工业视觉任务练手的工程师也适合给产线做视觉质检预研的小团队项目自带数据集与代码省掉了最耗时的数据准备工作。2. YOLOV5 在齿轮缺陷检测中的任务定义与数据准备2.1 为什么检测任务比分类任务更适合齿轮缺陷齿轮缺陷检测本质上是一个多目标、多类别、小目标并存的问题。分类网络把整张图压成一个特征向量输出的是“这个齿轮有没有缺陷”但对产线来说这个答案远远不够。返修工人需要知道缺陷在哪颗齿的哪个位置是崩角还是裂纹这才有手段去处理。检测任务把输出设计成边界框加类别加置信度的组合网络在特征图上逐网格预测每个框负责一个局部区域天然具备定位能力。YOLOV5 属于单阶段检测器核心思路是在特征图上用锚框作为基准回归出目标框的偏移量。与两阶段检测器相比它省去了区域提议网络推理速度快CPU 机器上也能勉强跑放到 GPU 上做产线实时视频流完全够用。齿轮图像缺陷检测这类任务还有一个特点缺陷区域占整张图的比例通常很小缺齿和崩角算中尺寸目标砂眼、细小裂纹算小目标。YOLOV5 的 PANet 结构会把深层语义信息和浅层细节特征做融合浅层分支恰好保留了小目标需要的边缘与纹理这也是它在工业缺陷场景里比不少分类网络更稳的原因。# 以数据集自带的 data.yaml 为例确认类别数与 nc 字段 # nc 必须与标注文件里出现的类别 id 最大值 1 一致 names: 0: chipped_tooth # 崩齿 1: crack # 裂纹 2: missing_tooth # 缺齿 3: sand_hole # 砂眼 nc: 4齿轮缺陷标注中经常出现类别定义含糊的问题。同一个图像痕迹一个标注员标成裂纹另一个标成划伤模型学到的是不一致的边界验证集 mAP 再高也没意义。我一般建议在开始标注前先定死判级标准裂纹必须呈现线性延伸且跨越齿面方向划伤是平行纹路且深度均匀拿不准的标成背景不参与训练。这个动作看着不起眼对最终漏检率的影响比调任何超参数都大。2.2 齿轮缺陷数据集的采集、标注与自动初见工业场景的缺陷检测项目里标注成本常常比训练成本高一个数量级。齿轮缺陷公开数据集相对少很多团队走的路子是“公开开源数据集轴承齿轮打底加上自己产线拍的真实缺陷图”。开源部分负责提供背景多样性和常见缺陷形态自采部分负责覆盖当前产线的光照、油污和位姿分布。我见过的做法是先把两者混在一起跑一轮初版模型再用初版模型对未标注产线图做预标注人工只负责确认和修正。这里说的自动预标注就是热词里反复出现的“如何通过界面操作 yolov5 完成数据集的自动标注”。常见做法是用 X-AnyLabeling 这类工具加载一个已经训练好的 YOLO 模型在图形界面上批量推理未标注图片推理框直接出现在画布上标注员只需调整边缘和删除误检。这样一套流程下来一张图的标注时间能从 40 秒压到 10 秒以内。要注意的是自动标注会引入模型本身的偏差新类别、新角度的缺陷很可能被漏掉所以不要完全放手至少保留人工巡检环节。# 目录组织方式YOLOV5 训练脚本默认按日期区分实验建议把数据放外部目录 gears_dataset/ ├── images/ │ ├── train/ # 训练集图片 │ └── val/ # 验证集图片 ├── labels/ │ ├── train/ # 对应的 txt 标注文件 │ └── val/ └── gear_defect.yaml标注文件的格式是每行一个目标类别id x_center y_center width height其中 x_center、y_center、width、height 全部是相对图像宽高的归一化数值。例如一张 1280x960 的图里某个裂纹框左上角在 (320, 240)宽高为 (128, 64)换算后应为1 0.5 0.375 0.1 0.0667。很多新手直接用标注工具的默认格式导出成 VOC 的 XML忘了转成 YOLO 的 txt训练脚本会报找不到标签这个坑几乎每周都能在技术社区看到一次。2.3 数据划分与样本均衡的实操方法数据划分最忌讳的是随意把同一颗齿轮的多张相邻角度图片分别扔进训练集和验证集。齿轮缺陷图经常是转台连续拍摄的相邻帧之间背景和缺陷形态高度相似这种划分会造成数据泄露验证集指标虚高换到真实产线立刻掉点。我一般按零件 ID 分组同一个零件的所有图片整体划分保证验证集见不到训练集零件的近亲样本。缺陷类别训练集张数验证集张数时出现频率划分策略崩齿 chipped_tooth1200300高按零件 ID 整体划分裂纹 crack800200中裂纹细长易漏检浮保留缺齿 missing_tooth500150低大目标易学数量可少砂眼 sand_hole900220中小目标切片增强# 按零件 ID 划分数据的简单脚本避免数据泄露 import random import shutil from pathlib import Path random.seed(42) img_root Path(gears_dataset/images/all) label_root Path(gears_dataset/labels/all) parts {} for img_path in img_root.glob(*.jpg): part_id img_path.stem.split(_)[0] # 文件名形如 part001_view02.jpg parts.setdefault(part_id, []).append(img_path) all_parts list(parts.keys()) random.shuffle(all_parts) split_at int(len(all_parts) * 0.85) train_parts set(all_parts[:split_at]) for part_id, paths in parts.items(): split train if part_id in train_parts else val for img_path in paths: label_path label_root / (img_path.stem .txt) if not label_path.exists(): print(fwarn: missing label {label_path}) continue shutil.copy2(img_path, img_root.parent / split / img_path.name) shutil.copy2(label_path, label_root.parent / split / label_path.name)这段脚本的分割点用了 85% 训练、15% 验证。代码里随机种子固定为 42保证每次执行划分结果一致这对复现实验非常关键。当文件命名规则不同的数据集时手动观察几张图片确认前缀代表零件 ID 再套用不要盲目跑完不检查。3. 齿轮图像缺陷检测训练环境配置、超参数与完整命令3.1 yolov5 环境配置的完整过程齿轮缺陷检测对显存的要求不算苛刻一张 8GB 显存的显卡就能用 s 模型跑 640 分辨率输入用小批次训练。环境配置是大部分数据集到位之后第一个卡壳点常见问题集中在 PyTorch 版本与 CUDA 版本不匹配上。我推荐用 conda 单独建环境Python 版本选 3.9 或 3.10这两代对 torch 生态的兼容性最稳。conda create -n gear-yolo python3.9 -y conda activate gear-yolo pip install torch2.1.0 torchvision0.16.0 --index-url https://download.pytorch.org/whl/cu118 git clone https://github.com/ultralytics/yolov5.git # 对应 7.0 版本主线 cd yolov5 pip install -r requirements.txt python -c import torch; print(torch.cuda.is_available(), torch.__version__)安装完成后必须做一次 GPU 可用性验证上面最后一条命令输出True 2.1.0才说明环境就绪。如果输出False多半是 CUDA 驱动版本太旧或者 torch 装成了 CPU 版本卸载重装带 cu118 后缀的包即可。requirements.txt 里的 opencv-python 版本有时会和系统预装版本冲突遇到导入 cv2 失败时先卸载再用 pip 重装一个固定版本。3.2 数据集 YAML 配置与目录挂载YOLOV5 的训练脚本要求数据集描述文件以 yaml 格式给出路径和类别信息。路径既可以是相对 data 目录的路径也可以是绝对路径。工程上更推荐相对路径加软链接的组合这样换机器时不需要改动任何代码。# gear_defect.yaml train: ../gears_dataset/images/train val: ../gears_dataset/images/val nc: 4 names: [chipped_tooth, crack, missing_tooth, sand_hole]注意 yaml 文件里的train和val指向的是图片目录脚本会自动在同级labels目录下查找同名 txt。如果把数据集的 images 和 labels 分别放在不同盘符可以用软链接把它们归拢到同一个目录树下mkdir -p /data/gears_dataset ln -s /mnt/ssd1/gear_images /data/gears_dataset/images ln -s /mnt/ssd2/gear_labels /data/gears_dataset/labels软链接方式的好处是数据文件不需要拷贝复制训练脚本读取时完全无感知。在 Windows 下创建软链接需要管理员权限或开启开发者模式如果嫌麻烦直接把 images 和 labels 复制到同一目录下也能跑。3.3 启动 YOLOV5 训练与超参数设置齿轮缺陷检测的训练命令基本收敛为一个模板先给出一份可直接运行的cd yolov5 python train.py \ --data gear_defect.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --imgsz 640 \ --name gear_defect_v1需要重点关注的超参数集中在下方表格中。--img控制输入分辨率齿轮的砂眼缺陷偏小如果显存允许我会把分辨率提到 960 或 1280比盲目堆训练时间更有效。--batch受显存限制8GB 显卡跑 640 分辨率时设 16 是安全值batch 太小会导致 BN 层统计不稳定表现为训练 loss 曲线剧烈震荡。超参数推荐值调参方向img/图片来源640砂眼漏检多时提高到 960batch16显存小降到 8配合大 lr 起步epochs100早停未见效时先查数据不是延长轮数lr00.01验证集过拟合明显时降到 0.005mosaic1.0缺陷样本少时保留mosaic 提供上下文调训练 workers8卡在数据读取时降到 4--weights yolov5s.pt是从 COCO 预训练模型开始迁移学习。对工业缺陷检测来说预训练权重能加速收敛冻层参数也值得调整。常见做法是前 10 个 epoch 用--freeze 10冻结主干网络让随机初始化的检测头先适应齿轮数据集的目标尺寸和类别分布等 loss 降不动再解冻全部层进行精调。# 断点续训训练中断后从上次权重继续不丢失已学到的特征 python train.py \ --data gear_defect.yaml \ --weights runs/train/gear_defect_v1/weights/last.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --name gear_defect_v1_resume \ --resume--resume参数会让脚本自动读取 last.pt 中保存的 epoch、optimizer 状态和超参数不需要手动改 epoch 数量。如果中断发生在 epoch 接近 80 的位置直接续跑剩余轮数即可。注意 resume 模式下不需要再传--weights脚本会从上次实验记录里找权重路径。3.4 训练过程监控与过拟合识别训练期间的实时监控命令是tensorboard --logdir runs/detect/gear_defect_v1浏览器打开 6006 端口后重点看训练集和验证集的 box_loss、cls_loss 曲线。如果训练 loss 持续下降但验证 loss 在 60 轮后开始反弹就是过拟合信号。齿轮缺陷数据集偏小的情况下过拟合非常常见处理顺序是先加数据增强再考虑降低模型复杂度最后才考虑加数据因为扩充工业缺陷数据的成本最高。YOLOV5 内置的自动学习率调度会随轮次衰减但初始学习率过高会出现 loss 直接发散成 nan 的情况。遇到这类问题我一般会看训练前 5 轮的 loss 输出如果第一轮就超过 0.15 且后续不下降把--lr0调小一个数量级再跑。4. 模型推理、验证集评估与齿轮漏检的排查4.1 用 detect.py 对齿轮图像批量推理训练完成后检测环节的入口是 detect.py。我建议养成每次推理都写明确输出目录的习惯不要把多个实验的结果混在同一个 detect 输出文件夹里。python detect.py \ --weights runs/train/gear_defect_v1/weights/best.pt \ --source /data/gears_dataset/images/val \ --conf 0.25 \ --iou 0.45 \ --img 640 \ --save-txt \ --save-conf \ --project runs/detect \ --name gear_val_v1--conf 0.25是置信度阈值低于该值的框会被过滤。对齿轮缺陷检测来说裂纹和砂眼的置信度普遍偏低如果验证结果里漏检多先把阈值调到 0.1 看推理结果图的框数量有没有增加很明显的地面真值目标千万不要一上来就降低阈值那样会引入大量误检框。--iou 0.45是 NMS 的 IoU 阈值阈值越高保留的重复框越多同一区域多个缺陷粘连时我会降低到 0.3 让重复框清除得更干净。--save-txt会输出每张图的文本检测结果--save-conf把每个框的置信度一并写入 txt 文件这两项在后续统计产线漏检率时是必要的数据源。4.2 用 val.py 读取验证集指标与混淆矩阵训练结束后不要只盯着 detect.py 输出可视化图片还应该运行一遍验证脚本拿到量化指标。YOLOV5 的 val.py 输出 mAP50、mAP50-95 以及每类别的精确率和召回率。python val.py \ --data gear_defect.yaml \ --weights runs/train/gear_defect_v1/weights/best.pt \ --img 640 \ --conf 0.001 \ --iou 0.6 \ --save-json \ --project runs/val \ --name gear_val_metrics验证时把置信度阈值设为 0.001目的是在完整置信度曲线上计算 mAP而不是只衡量单点置信度下的表现。--save-json会输出 COCO 格式的 JSON 预测结果配合一些外部工具能绘制 PR 曲线和混淆矩阵。混淆矩阵对齿轮检测的意义在于看清类别混淆裂纹被判成划伤、崩齿被判成缺齿对应的误判往往是实际产线上返修指令错误的直接根源。若裂纹类别的召回率明显低于其他类别后续增强可以和裂纹样本的方向性、长度多样性对齐。4.3 小目标漏检与近色背景的三类坑齿轮缺陷项目里最容易翻车的不是网络结构而是数据分布偏差。第一类坑是砂眼这类小目标在 640 分辨率下只有十来个像素经过 5 次下采样后在特征图上仅剩一个有效像素点训练时前景特征极度微弱。应对办法有两个把输入分辨率提高到 960 以上或者在标注阶段用切片工具把小目标区域单独裁剪出来放大后并入训练集同时保留原图和裁剪图的标注。第二类坑是齿面金属反光导致的近色背景误检。油污在图像里呈现暗色团块和真实缺陷的灰度分布重叠严重。训练集里如果缺少干净齿面与油污齿面的对照样本模型很容易把油污边缘学成缺陷特征。我会在采集时记录同一颗齿轮清洗前后的图像对把这组对照加入训练集相当于显式告诉模型“长这样的暗区是背景不是缺陷。”第三类坑是标注框不贴合缺陷实际边界。YOLO 训练对框的精确度没有想象中敏感但大量框只有目标的一半时回归目标本身的噪声会把 loss 抬高。批量自动标注后的结果经常出现这类偏移人工修正时着重检查长条裂纹的两个端点是否都落在图像内容内。# 对验证集预测结果做漏检统计快速定位是数据问题还是模型问题 import json from collections import Counter with open(runs/val/gear_val_metrics/predictions.json) as f: preds json.load(f) label_to_images {} # 记录真实缺陷类别在哪些图里出现 with open(gears_dataset/labels/val/*.txt) as f: # 实际开发中用 glob 读取全部文件这里展示统计逻辑 pass detected_classes Counter(p[category_id] for p in preds if p[score] 0.25) print(detected_classes)这段代码的作用是把验证集中所有置信度大于 0.25 的预测类别汇总。当你手握类别维度的命中数与真实标注数做笛卡尔积对比时就能一目了然地看出哪类缺陷贡献了大多数漏检下一步的增强和调参全部围绕这个类别展开。5. 把齿轮缺陷检测模型部署成产线可用的推理服务5.1 导出 ONNX 格式实现跨平台推理PyTorch 权重不能直接部署到产线工控机上常见做法是先导出为 ONNX再用 ONNX Runtime 或 TensorRT 运行。导出命令如下python export.py \ --weights runs/train/gear_defect_v1/weights/best.pt \ --include onnx \ --imgsz 640 \ --batch 1 \ --simplify--simplify会调用 onnx-simplifier 对计算图做常量折叠与算子融合通常能让模型体积缩小 10% 以上推理速度提升 5% 到 15%。导出完成后用onnxruntime做一次数值对齐验证确保 ONNX 版本的推理结果与 PyTorch 版本在大框位置上的偏移不超过 1 个像素。# ONNX Runtime 推理齿轮图像的极简代码 import cv2 import numpy as np import onnxruntime as ort session ort.InferenceSession(best.onnx, providers[CUDAExecutionProvider]) img cv2.imread(gear_part001.jpg) img cv2.resize(img, (640, 640)) blob img[:, :, ::-1].transpose(2, 0, 1)[None] / 255.0 # BGR to RGB, NCHW outputs session.run(None, {session.get_inputs()[0].name: blob.astype(np.float32)}) # outputs[0] 形状为 (1, 25200, 85)其中 85 5 类别数 boxes outputs[0][0] print(fcandidate_boxes: {len(boxes)})这里的输出形状依赖输入分辨率和数据集类别数。640 分辨率下特征图三个尺度的预测框总数是 25200类别数为 4 时每个候选框维度是 5 4 9但导出模型默认拼接了 COCO 类别数所以实际维度要看 export 时的类别配置。常见错误是收到 85 维输出却按 9 维去解析导致取置信度时下标错位。推理前先打印一次输出的维度与模型训练时的 nc 对照。5.2 部署时保留的验证与回退机制产线部署不能只准备一套模型就跑。我在每个版本上线前会固定留出 300 张最近一周的产线实拍图这些图不参与训练在上线前用脚本批量推理并统计置信度分布。如果新版本在这批留样上的低置信度框数量明显多于旧版本说明模型在数据漂移方向上出现退化应该回退旧版而非强行上线。缺陷检测产线的最后一道保障是置信度阈值之外的“低置信度抽检”。把阈值以下、0.05 以上的检测框默认标记为“需人工复核”每周定时抽查 200 张持续跟踪模型的误检趋势。这套机制用很小的人力成本换来模型持续演进的方向感比反复调阈值更有效果。本文还有配套的精品资源点击获取