ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于YOLO的齿条螺栓缺陷检测:从数据组织到推理验证全链路实战

基于YOLO的齿条螺栓缺陷检测:从数据组织到推理验证全链路实战 简介本资源面向计算机视觉初学者与工业检测方向的开发者提供一套基于YOLO的实时物体检测完整代码与数据资料重点覆盖齿条、螺栓、螺母及裂缝等工业场景目标的识别与定位适合用于课程设计、项目复现与算法入门实践。压缩包共2000个文件约199.17MB以1903个txt标注或说明文件为主辅以49个h头文件、46个c源文件及少量cpp与md文档构成从数据标注到网络层实现的完整工程结构。内容预览可见data.c、parser.c、image.c、network.c、region_layer.c、yolo_layer.c等核心模块涉及数据加载、图像处理、网络构建与检测层实现便于读者理解YOLO将检测转化为回归问题的整体流程。目前已有67人学习下载适合希望掌握实时检测原理、动手调试工业缺陷检测模型的读者参考。1. 从一堆齿条螺栓里把缺陷挑出来这套 YOLO 检测资源到底能干什么产线上最磨人的活不是拧螺栓是盯着一堆长得几乎一样的齿条、螺栓、螺母靠人眼判断哪个有裂纹、哪个缺角、哪个螺纹不对。人盯两小时就花眼漏检率蹭蹭往上涨。这套资源就是冲着这个场景来的用 YOLO 做实时物体检测把齿条、螺栓、螺母这些标准件从画面里框出来顺带识别裂纹这类表面缺陷。它适合两类人——一类是手上已经有工业质检需求、想快速跑通一个能落地的检测 demo 的工程师另一类是正在学 YOLO、想拿一个真实零件数据集练手的学生或转行者。资源本身给的是可复现的训练与推理链路不是一份 PPT 讲解你拿到手就能配环境、跑训练、看结果。下面我按自己拆包复现的顺序把选型理由、环境配置、数据组织、训练参数和踩过的坑一条条讲清楚。2. 为什么这个场景选 YOLO实时性与小目标检测的取舍2.1 齿条螺栓检测对模型的三条硬约束工业零件检测和通用目标检测不一样它有三个绕不开的约束。第一是实时性产线节拍通常按秒算模型单帧推理必须压到几十毫秒以内否则堆帧就是堆成本。第二是小目标密集螺栓螺母在整幅图里占比很小齿条的裂纹更是细长条特征弱、背景杂。第三是类别不均衡正常件远多于缺陷件模型很容易学会“全判正常”这种偷懒策略。YOLO 系列之所以在这个场景里被反复选中核心原因是它把检测当成单阶段回归问题一次前向就出框和类别没有两阶段方法那种候选区域生成的额外开销。YOLOv8 这一代在 neck 部分用了 PAN-FPN 结构浅层高分辨率特征和深层语义特征融合得比较充分对小目标比早期版本友好不少。我一般会优先选 v8 的 n 或 s 规模做基线参数量小、推理快精度不够再往上换。提示不要一上来就上 x 或 l 规模。工业零件类别数少、纹理相对固定小模型往往就够大模型带来的精度提升经常抵不过推理延迟的代价。2.2 单阶段检测的损失函数在零件场景里意味着什么YOLO 的损失由三块组成分类损失、边界框回归损失、目标置信度损失。v8 用的是 TaskAlignedAssigner 做正负样本分配配合 CIoU 类的回归损失。放到齿条螺栓场景里这个设计的影响很直接——正样本分配策略决定了小目标能不能被“看见”。如果锚点或分配阈值设得不合适密集排列的螺母很容易被漏分配训练时 loss 看着在降实际召回上不去。我踩过一次坑螺母挨得太近默认分配策略下相邻两个框互相干扰mAP 卡在 0.6 上不去。后来把输入分辨率从 640 提到 960同时检查了标注框有没有重叠粘连召回才正常。所以选 YOLO 不是选完就完事损失函数和分配策略背后的参数才是决定这套资源能不能在你数据上跑通的关键。2.3 和两阶段、Transformer 方案的边界对比有人会问现在 Transformer 检测那么火为什么还用 YOLO。我的判断是看场景。DETR 类方法在密集小目标上收敛慢、训练数据需求大工业缺陷样本本来就少硬上容易翻车。两阶段方法精度可能略高但推理速度在产线节拍面前基本没得谈。YOLO 的边界在于类别数不多、目标尺度跨度不算极端、对实时性有要求——这正好是齿条螺栓检测的画像。如果你的场景是超大图里找几个极小目标或者需要像素级分割那这套资源的方向就不对得换思路。3. 环境配置与数据组织把训练链路先跑通3.1 环境搭建的版本对齐问题YOLO 环境最烦的不是装不上是版本对不上导致训练中途崩。我一般用 conda 建独立环境把 Python、PyTorch、CUDA 三者版本锁死。下面是我在 v8 上跑通的一套组合你可以照抄再按自己显卡调整。# 创建独立环境Python 版本不要追新3.9/3.10 最稳 conda create -n yolo_parts python3.10 -y conda activate yolo_parts # 安装 PyTorchCUDA 版本按 nvidia-smi 显示的驱动能力选 # 这里以 CUDA 11.8 为例驱动版本要 对应要求 pip install torch2.1.0 torchvision0.16.0 --index-url https://download.pytorch.org/whl/cu118 # 安装 ultralytics不要手动装一堆依赖让它自己解析 pip install ultralytics # 验证环境和 GPU 是否可见 python -c import torch; print(torch.__version__, torch.cuda.is_available())逻辑说明先隔离环境避免和系统里的其他项目打架PyTorch 的 CUDA 版本必须和驱动匹配否则cuda.is_available()返回 False训练会静默掉到 CPU 上慢到你以为卡死了。参数上torch2.1.0配cu118是我验证过和 ultralytics 兼容性较好的一组如果你显卡驱动较新可以换 cu121 的对应版本。注意训练中 BN 层崩溃报错里带 batch norm 或 NaN loss十有八九是 batch size 太小或学习率太大。单卡显存不够时宁可降分辨率也别把 batch 压到 2 以下。3.2 数据集目录结构与标注格式YOLO 要求的数据组织很固定别自己发明结构。图像和标签分开放标签是每行一个目标的 txt格式为类别索引 中心x 中心y 宽 高全部归一化到 0~1。齿条、螺栓、螺母、裂纹这几类类别索引从 0 开始连续编号。parts_dataset/ ├── images/ │ ├── train/ # 训练图 │ └── val/ # 验证图 ├── labels/ │ ├── train/ # 与训练图同名的 txt │ └── val/ └── data.yaml # 数据集描述文件data.yaml是训练入口写错路径是最常见的低级错误# data.yaml path: /home/user/parts_dataset # 数据集根目录绝对路径最稳 train: images/train # 相对 path 的路径 val: images/val nc: 4 # 类别数齿条/螺栓/螺母/裂纹 names: [rack, bolt, nut, crack]逻辑说明path用绝对路径能避免训练脚本工作目录变化导致的找不到文件nc必须和 names 长度一致多一个少一个都会在训练启动时报维度错误。标注这块我建议用 labelImg 或 roboflow 导出 YOLO 格式别手写坐标归一化算错一位整个框就飞了。3.3 从原始标注到可训练集的一次性检查数据进训练前我会跑一段脚本做体检统计每类框数量、检查有没有越界坐标、看图像和标签是否一一对应。这一步能省掉后面几小时的无效训练。import os from collections import Counter label_dir parts_dataset/labels/train img_dir parts_dataset/images/train counter Counter() bad [] for name in os.listdir(label_dir): if not name.endswith(.txt): continue # 图像和标签必须同名缺图就是脏数据 img_name name.replace(.txt, .jpg) if not os.path.exists(os.path.join(img_dir, img_name)): bad.append(name) with open(os.path.join(label_dir, name)) as f: for line in f: parts line.split() if len(parts) ! 5: bad.append(name) continue cls, x, y, w, h parts # 归一化坐标必须在 0~1越界说明标注工具导出有问题 if not all(0 float(v) 1 for v in (x, y, w, h)): bad.append(name) counter[int(cls)] 1 print(每类框数量:, dict(counter)) print(可疑文件:, bad[:20])逻辑说明Counter统计各类别框数能立刻看出类别不均衡有多严重越界检查拦住标注导出错误同名检查拦住图像标签错位。参数上如果某类框数只有个位数训练前就得考虑过采样或加数据增强否则模型学不会这一类。4. 训练参数怎么设从基线到能用的调参路径4.1 启动训练与关键参数含义环境数据都齐了训练命令本身很短但每个参数都影响结果。下面这条是我在齿条螺栓数据集上的基线配置。yolo detect train \ dataparts_dataset/data.yaml \ modelyolov8s.pt \ epochs100 \ imgsz960 \ batch16 \ lr00.01 \ patience20 \ projectruns/parts \ namebaseline逻辑说明modelyolov8s.pt用官方预训练权重做迁移学习比从零训收敛快得多这是小数据集能跑出效果的前提。imgsz960是我针对小目标特意提上去的默认 640 对螺栓螺母这种小框召回不够。lr00.01是初始学习率配合默认的余弦退火策略。patience20表示 20 轮验证指标不涨就早停省时间也防过拟合。参数怎么改显存不够先降batch再降imgsz召回低优先提imgsz过拟合明显就加dropout或减epochs。别一次改一堆参数那样出了问题你根本不知道是哪个引起的。4.2 数据增强在零件检测里的取舍YOLO 默认开了一堆增强但工业零件场景不能照单全收。翻转、缩放、色彩抖动一般没问题但上下翻转对齿条这种有方向性的零件可能引入错误先验马赛克增强在小目标密集时会把框拼得乱七八糟。# 在 data.yaml 同级或训练参数里覆盖增强配置 hsv_h: 0.015 # 色调抖动零件颜色固定可调小 hsv_s: 0.7 hsv_v: 0.4 degrees: 0.0 # 旋转角度零件有方向就别乱转 translate: 0.1 scale: 0.5 flipud: 0.0 # 上下翻转关掉齿条方向敏感 fliplr: 0.5 mosaic: 0.5 # 马赛克降一半小目标密集时别开满逻辑说明flipud0.0是因为齿条上下翻转后语义变了模型会学到错误特征mosaic降到 0.5 是血泪经验开满时密集小框拼接后标注容易错位验证指标虚高但实际推理拉胯。参数调整的原则是先关掉可能破坏语义的增强再逐步加回来看验证集表现。4.3 训练过程监控与指标解读训练跑起来后别只盯着 loss 看。真正决定模型能不能用的是验证集上的 mAP50 和 mAP50-95以及混淆矩阵。混淆矩阵总和不唯一是很多人遇到的玄学问题本质是预测框和真实框的匹配阈值导致的不同 IoU 阈值下统计口径不同别慌。# 训练结束后用验证集评估输出各类别指标 yolo detect val \ modelruns/parts/baseline/weights/best.pt \ dataparts_dataset/data.yaml \ imgsz960逻辑说明best.pt是验证指标最好的权重不是最后一轮的。评估时imgsz要和训练一致否则小目标指标会掉。看结果重点看裂纹那一类的召回缺陷类召回低意味着漏检产线上这是最不能接受的。5. 避坑与排查那些让训练白跑的常见问题5.1 训练 loss 正常但 mAP 极低现象loss 一路下降验证 mAP 却卡在 0.1 以下。原因通常是标注格式错了——坐标没归一化、类别索引和 names 对不上或者图像标签文件名不匹配。解决回到 3.3 的体检脚本逐项核对重点看坐标是否在 0~1 之间、类别索引是否从 0 连续。5.2 训练中途 BN 崩溃或 loss 变 NaN现象跑几十轮后突然报 batch norm 相关错误loss 变成 NaN。原因一般是学习率过大或 batch size 太小BN 层统计量不稳定。解决把lr0降到 0.001batch提到 8 以上显存不够就降imgsz而不是继续压 batch。5.3 边缘部署时误检率飙升现象本地验证 mAP 挺好部署到边缘设备后误检一堆。原因多是推理分辨率被压缩、量化精度损失或者现场光照和训练集差异大。解决部署时保持和训练一致的预处理别为了速度把imgsz砍太狠现场补采一批图做微调比调阈值管用。5.4 混淆矩阵总和不唯一现象两次评估混淆矩阵数字对不上。原因是匹配阈值和置信度阈值不同统计口径变了。解决固定评估参数记录每次用的conf和iou阈值对比时保证一致别拿不同口径的结果互相印证。5.5 裂纹这类细长缺陷召回上不去现象齿条裂纹漏检严重。原因是细长目标特征弱默认锚点尺度不匹配。解决提高输入分辨率检查标注框是否把裂纹框得太紧导致特征丢失必要时单独对裂纹类做过采样。6. 进阶技巧把训练好的模型真正用起来训练出best.pt只是开始能不能落地看推理和验证。我一般会先用一段脚本在视频或图片上跑推理肉眼确认框的位置和类别对不对再谈部署。from ultralytics import YOLO # 加载训练好的权重 model YOLO(runs/parts/baseline/weights/best.pt) # 对单张图推理conf 控制置信度阈值 results model.predict( sourcetest_rack.jpg, imgsz960, # 必须和训练一致 conf0.4, # 阈值太低误检多太高漏检多按场景调 iou0.5, # NMS 的 IoU 阈值密集目标可适当调低 saveTrue ) # 打印每个框的类别和置信度方便核对 for box in results[0].boxes: print(model.names[int(box.cls)], float(box.conf))逻辑说明conf和iou是推理阶段最该调的两个参数。缺陷检测里我通常把conf设低一点保召回宁可多报也别漏报后处理再人工复核。imgsz必须和训练一致这是很多人忽略的细节改了分辨率小目标直接消失。验证方法上我会做两件事一是拿一批没参与训练的现场图跑一遍统计漏检和误检二是把推理结果和标注叠在一起看确认框的贴合度。这两步做完心里才有底。从那以后我每次训完模型都强制走一遍“现场图推理 人工核对”的流程绝不只看验证集数字就上线。这套齿条螺栓检测资源的价值不在于它给了多完美的模型而在于它把从数据组织到推理验证的链路完整摆出来了你照着跑一遍坑踩一遍就真正会用了。希望帮到你。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进