☰
基于YOLOv8的轴承表面缺陷检测系统:从数据集到Web部署全流程实践
2026/10/20 4:08:05 网站建设 项目流程

做工业视觉质检这几年,我越来越确信一件事:模型本身往往不是瓶颈,真正考验人的是——数据到底干不干净、训练流程能不能复制、部署之后现场能不能用。去年我们接手了一个轴承表面缺陷检测项目,从一个只跑得通Demo的算法,到最后落地成带Web前端界面、能一键训练、能实时推理的小系统,中间踩的坑比想象中多得多。

这套系统的主线其实很简单:用YOLOv8做目标检测,输入轴承表面图像,输出缺陷类别和位置框,再通过Web前端把检测结果可视化。核心工作集中在三块:标注好的轴承缺陷数据集、围绕YOLOv8做的一批量改进点、以及后端推理和前端展示的整体部署方案。代码和数据集都整理成了“拿到就能用”的状态,对做工业质检算法、做毕设、或者刚接触YOLO想要一份完整工程参考的朋友来说,属于非常难得的全链路参考。

这篇文章我就把这个项目从数据到部署完整拆开讲,包括为什么选YOLOv8、数据集怎么标才不容易翻车、训练改进点怎么选、部署时哪些地方最拖后腿,以及我在整个过程中踩过的坑和对应的排查方案。

1. 项目整体拆解:从一条“检测链路”到一套“闭环系统”

1.1 为什么说轴承表面缺陷检测是个典型场景

轴承是旋转机械里最基础的零件,出厂前如果表面有划伤、压痕、剥落这类缺陷,装机之后轻则异响、磨损加速,重则直接卡死甚至引发设备损坏。传统做法是人工目检,但轴承表面往往有金属反光,细小的划痕在流水线上快速经过时,肉眼很容易漏看,而且不同检验员的标准还不一样。

这个场景非常适合用目标检测来做:缺陷种类明确、位置信息重要、图像背景相对固定。它不是那种需要高深语义理解的难题,而是一个“看得准、跑得快、标得对”就能变现的典型任务。我们项目里的目标就定在6类常见缺陷:划伤、压痕、剥落、麻点、锈迹和污渍,没去做缺陷分割,主要原因是产线上的需求是“先发现、再定性”,矩形框足够支撑后续的工位拦截。

1.2 YOLOv8凭什么作为基座模型

选型的时候其实对比过几个方向。两阶段的Faster R-CNN精度上限高,但推理速度在边缘设备上不够理想,尤其是一拖多路视频流的时候会吃力。单阶段的YOLO系列一直是工业质检的性价比之选,而到了YOLOv8这一代,几个关键改进让它比前代更舒服:

  • 主干网络换成C2f结构,特征提取更充分,梯度流更丰富。
  • 检测头变成Anchor-Free解耦头,分类和回归分开,收敛更稳定。
  • 自带的数据增强和训练策略非常成熟,模型配置文件与训练命令统一,改起来省事。

对我来说最重点的是YOLOv8的生态。官方代码可以直接跑训练、验证和导出,还能转成ONNX、TensorRT,部署链路不用自己造轮子。对一个要快速验证、又要上线的项目来说,这一点比单纯看精度提升还重要。

对比项Faster R-CNNYOLOv5YOLOv8
推理速度较慢快快
小目标表现较好一般中上,可加P2头提升
部署生态一般好好
训练易用性配置繁琐好最好
改进扩展性中等好好

最后定了YOLOv8s作为基线,既保留了比较好的特征提取能力,推理速度也够快。如果现场对算力有顾虑,可以直接降级到YOLOv8n,如果对精度要求更高,换YOLOv8m或YOLOv8l也不难——数据、脚本、部署逻辑都不用大改。

2. 数据集的构建逻辑:比模型更值得花时间的地方

2.1 数据采集与类别定义

轴承表面缺陷数据集是整个项目的基石,这块如果糊弄,后面再好的改进点都白搭。采集时我们用的是工业面阵相机加环形光源,分辨率在1200万像素左右,拍摄时尽量让缺陷和背景有稳定的对比度。数据采集阶段最重要的事是覆盖“各种形态的同一种缺陷”,划伤有可能是细长一条,也有可能是短促的几道,如果只采一种形态,模型学到的就只是特定形态的模板,换一种光源角度就可能漏检。

数据量上,我们总共标了8000多张图,每张图上的缺陷数量从1个到十几个不等。总共标注实例数接近3万个,平均每类4000个左右。这里特别提醒一点:不要过分追求总数,要关注类别的均衡性。如果划伤占了60%,而锈迹只有5%,训练的模型大概率对锈迹非常不敏感。我们的做法是先统计类别分布,对数量少的类别单独补采、补标,尽量让最少的类别不低于总数的10%。

2.2 标注规范与YOLO格式

标注用的是图形化标注工具,输出直接存为YOLO格式的txt文件。每一行代表一个目标,格式是:

class_id x_center y_center width height

注意坐标全部是归一化后的值,除以图片宽高。比如一张960x540的图,某个目标中心在(480, 270),宽200,高100,那么对应的内容是:

0 0.5 0.5 0.2083 0.1852

初始标注看起来很容易,但真正细究起来有几个细节决定生死。划伤这类细长缺陷,标准矩形框如果框得比缺陷本身宽很多,训练时模型看到的目标背景噪声比例就大,很容易把背景特征学进去。我们的原则是:边界框紧贴缺陷边缘,同时保留2到3个像素的余量,避免标注和真实区域完全贴死导致回归损失震荡。

另外要保证标注一致性。一个人标的时候,框大框小可能全凭手感;多人协作时,必须定一个标注规范,例如“框到明显特征边界,不包含模糊过渡区”。我见过不止一个项目因为标注风格不一致,训练出来的模型在验证集上总觉得莫名其妙的掉点。

提示:YOLO格式的txt文件名必须和对应图片名保持一致,例如 image_001.jpg 对应 image_001.txt。否则训练时很多样本会被自动忽略,而且排查起来非常费劲。

2.3 数据增强与样本平衡策略

YOLOv8默认自带莫赛克增强、随机翻转、HSV色域扰动等策略。对于轴承这种表面纹理和光照条件比较固定的对象,增强不能太狠。光照抖动做得太夸张,反而会让模型学着去适应不存在的极端光照,拖慢收敛。我把随机旋转限制在正负10度以内,水平垂直翻转打开,略微加了模糊和噪声增强,用来模拟相机轻微失焦或传感器噪声的场景。

另外对标注框特别小的缺陷,单纯依赖随机增强不一定够。我们做了离线过采样:把含小目标的图像复制增强后重新混进训练集,让模型在每个epoch里看到的小目标样本更多。结果mAP50比不做任何处理提高了将近3个百分点,代价是训练时间稍微变长。

训练集、验证集、测试集的划分也要讲究。不能简单按图片随机分,因为同一个轴承零件的两张照片高度相似,可能会被拆到不同集合里,造成数据泄漏,验证集分数虚高。正确做法是按工件ID划分:同一工件所有图像进同一个集合,这样验证集能真实反映模型面对新工件时的表现。

3. 模型训练与改进点实践:把通用模型改造成缺陷检测专用模型

3.1 一键训练的基础工程配置

这个项目里我写了一个train.py脚本,把环境检查、数据集校验、yaml配置生成和YOLOv8训练命令串起来,做到命令行一条指令直接开工:

python train.py --data dataset.yaml --model yolov8s.pt --epochs 300 --batch 16 --imgsz 640

dataset.yaml是最重要的配置文件,它指定了训练集、验证集路径、类别数和类别名:

path: /home/user/bearing_datasets train: images/train val: images/val test: images/test names: 0: scratch 1: dent 2: spalling 3: pit 4: rust 5: stain

YOLOv8会自动根据这个yaml读取图片和对应的txt标注。脚本里我在训练前强制做了一次标注校验:统计txt文件数量与图片数量是否一致、每张图的标注框有没有超出边界、类别id是否越界。这一个步骤帮我们拦截了多次数据问题,强烈建议你也加上。

3.2 改进创新点:注意力和特征融合怎么做才有用

标题里提到的“70多套改进创新点”,其实就是把近年来常见的目标检测改进方向整理成一张可选清单,覆盖主干网络、颈部结构、检测头、损失函数、注意力机制这几大方向。实际改的时候不必贪多,我的经验是:小数据集上堆改进点很容易过拟合,挑两三个针对场景痛点的组合就够了。

我们最终采用了三组改进的组合。

第一组是注意力机制。在主干网络的不同stage后面插入轻量注意力模块,例如通道注意力加空间注意力的组合模块,让网络更关注缺陷区域、抑制金属纹理背景。轴承表面的纹理反光很干扰,纯卷积网络很容易被背景拉走注意力,加了注意力模块之后,验证集上的精确率明显提升。

第二组是颈部特征融合改进。YOLOv8默认的特征融合是PANet结构,对多尺度目标已经不错,但对极小尺寸缺陷还可以再进一步。我在颈部增加了一条更高分辨率的特征通路,把浅层信息更早地融合进来,这对宽度只有十几个像素的划伤尤其有效。代价是计算量略增,但换来的小目标召回率提升是值得的。

第三组是损失函数层面的优化。默认的CIoU在细长缺陷上经常出现预测框和真实框的宽高比差异大,导致回归不够稳定。我在原损失函数上引入了额外的辅助回归分支,对宽高比差异大的样本做加权,实验下来对细长划伤的定位精度改善很明显。

下面是我整理的一张改进方向与适用场景对照表,方便你做选择时不走弯路:

改进方向解决的问题建议使用场景
注意力机制背景干扰强、小目标响应弱金属反光、纹理复杂的表面
高分辨率检测头极小缺陷漏检划伤、麻点、针孔
特征融合增强多尺度差异大缺陷尺寸跨度大的数据集
损失函数优化长宽比极端目标回归不稳细长划伤、条状剥落
轻量化主干推理速度不够边缘设备、高帧率需求

每一条改进点我都保留了一套独立配置和实验记录,这样在给新数据集调优时能快速试错,而不是对着一个“黑盒模型”瞎猜。

3.3 训练过程的调参心得

训练参数上,imgsz选640是因为工业图像分辨率本身比较高,缩得太小会把小目标细节抹掉,放大到1280又会明显拖慢训练和推理。epochs设成300,配合早停机制,如果连续30个epoch验证损失没有下降就自动停。我个人不建议无脑训练固定epoch数,早停能省下大量时间。

batch size要看显存。我在单张24G显存的卡上跑YOLOv8s,batch可以开到64,但16到32之间的变化对结果影响不算大,反而是学习率这种超参数更敏感。YOLOv8默认会按照batch大小自动调整学习率,所以基本不用像老版本那样手工设置。

还有一个非常实用的技巧:先冻结主干训练前50个epoch,让检测头先把基础能力学起来,再解冻主干联合训练。因为预训练权重中的主干已经具备较好的通用特征提取能力,一开始就全模型更新,容易在数据集比较小的情况下把主干学歪了。

训练完成后一定要同时看P、R和PR曲线,不要只盯着mAP。我们遇到过一种情况:mAP50达到0.92,看起来不错,但一看召回率只有0.78,这意味着现场会有两成左右的缺陷漏掉,这是绝对不能接受的。后来通过补充难例数据、调整分类阈值,才把召回率拉到0.88以上。

注意:模型改进不是越多越好。我见过有人把五个改进方向同时叠加上去,结果训练时间翻倍,精度反而掉了2个点。改进要基于实验,不要基于想象力。

4. 部署与Web前端展示:让算法真正变成能用、可看的产品

4.1 推理服务的后端架构

训练好的PyTorch模型不能直接扔给前端,我们用ONNX Runtime做推理后端,语言用的是Python,框架选了FastAPI。导出命令很简单:

yolo export model=best.pt format=onnx imgsz=640

但导出之后有一步很多人忽略:输入预处理。YOLOv8默认训练时会做letterbox,即把图片等比例缩放并填充灰边到640x640。推理时也必须执行一模一样的预处理,否则检测框坐标会整体偏移。很多部署异常都是因为这个没对齐。

后端的核心接口就两个:

  • /detect/file:接收上传的图片文件,返回检测结果JSON。
  • /detect/base64:接收前端Canvas传过来的base64图像,用于摄像头帧的实时检测。

接口内部流程很简单:接收图像、解码、letterbox预处理、ONNX推理、NMS后处理、把归一化坐标还原成原图坐标、整理JSON返回。响应结构类似:

{ "success": true, "detections": [ {"label": "scratch", "confidence": 0.87, "bbox": [128, 96, 180, 120]}, {"label": "rust", "confidence": 0.76, "bbox": [300, 220, 340, 250]} ], "cost_ms": 35 }

部署时我特意把预处理和后处理逻辑从训练代码里复制出来独立维护,而不是直接调模型库的predict方法,这样可控性更强,而且后面换TensorRT加速时不用动接口。

4.2 前端展示:上传检测与摄像头实时流

前端没有用重的框架,就是纯HTML加JavaScript。主界面左侧是图片预览区,右侧是检测结果列表和置信度信息。上传图片后通过fetch POST到后端接口,拿到检测框数据后在Canvas上画矩形框和标签。

画框时有个细节要注意:Canvas的坐标系和后端返回的坐标必须统一。我们在后端返回的就是原图坐标,前端直接用就行。如果是摄像头实时流,做法是视频帧绘制到Canvas,定时抽取当前帧转为base64发送到后端,再将检测框叠加到画面。

实时检测我做了两种交互方案。第一种是按钮触发单帧检测,适合现场工人拍一张看一张;第二种是连续检测模式,设置了每秒最多3帧的频率上限,既保证流畅性,又不至于把后端打满。连续模式实测延迟在40到60毫秒之间,肉眼基本感觉不到卡顿。

4.3 性能优化与并发处理

部署阶段最拖后腿的不是模型本身,而是推理服务的吞吐量。单张图片串行推理,单路视频没问题,但要多路摄像头同时接入就扛不住了。我做了三个优化:

第一个优化是批量推理。收到多张请求后,按CPU核数或GPU余量做动态批处理,把等待时间相近的请求合并成一个batch推理。GPU利用率从30%提到75%,吞吐量翻了一倍。

第二个优化是ONNX算子融合。导出ONNX后顺手用onnxsimplifier做一轮图优化,模型体积减少15%,推理速度提升10%。这一步几乎零成本。

第三个优化是把NMS放到一个独立线程池处理,避免后处理阻塞推理主流程。对高并发场景效果非常明显。

我还给推理服务加了一个内存缓存:同一张图片短时间内重复请求直接返回缓存结果,这样前端切图或者网络重试时不会反复消耗算力。

提示:ONNX Runtime的CPU和GPU版本不要装混。项目里有人直接在同一个环境装了两套,结果推理时莫名其妙报算子错误,排查了很久才发现是动态链接库冲突。

5. 常见问题与排查技巧实录:这些坑我替你踩过了

5.1 数据和标注阶段的高频问题

数据阶段最大的坑是“标注框越界”。有些图本身尺寸特殊,标注时没注意,归一化后的坐标算出来超过1.0。YOLOv8训练时会直接忽略这些越界框,但如果越界又没忽略,可能报错。我的校验脚本能直接统计所有异常框,分类汇总出来,方便一次性修正。

第二个坑是类别命名不一致。比如有人把划伤标成scratch,另一个人标成scratch_mark,在yaml里如果写了scratch,另一批标签就会被当作未知类别跳过。建议所有标注人员共用同一个类别清单文件,不要自己顺手发明名字。

第三个坑是“废图”太多。有些图像上实际没有任何缺陷,却在总数据量里占了不少比例。如果不加筛选,模型会把大量背景学成负样本的默认输出,导致真正有缺陷时反而不敏感。我们后期做了一轮清洗,把无缺陷图控制在整体的10%左右,只做背景干扰用。

5.2 训练阶段的高频问题

训练阶段最典型的问题是loss降不下去或者剧烈震荡。排查顺序是:先看数据有没有问题,再看推理单张图的正向输出是否正常,最后看学习率。学习率太高时loss会在前几个epoch疯狂震荡,调低0.1倍后通常立刻稳定。

另一个高频问题是验证集mAP很高但现场表现差。原因多半是划分数据时泄漏了,或者训练集里的拍摄条件和现场完全不同。我建议训完之后特意去现场拍一批新图回来做盲测,这个分数比验证集分数可信得多。

最后是过拟合。轴承缺陷数据集通常几千到一万张,对YOLOv8来说并不算大。当训练集loss持续下降、验证集loss却开始上升时,优先做三件事:增加数据增强强度、增加dropout或权重衰减、切到更小的模型。

5.3 部署阶段的高频问题

部署阶段的坑主要集中在版本和路径上。我遇到过一次模型导出一切正常,但加载到ONNX Runtime时提示某个算子不支持,原因是用新版PyTorch导出的模型遇到旧版ONNX Runtime。解决方案是固定依赖版本,把PyTorch和ONNX Runtime的版本组合写进一份环境说明。

另一个问题是路径写死。代码里如果写死了训练时的数据集路径,部署到其他机器后只要路径不同,模型加载虽然不受影响,但日志里各种输入输出目录会乱。我改用相对路径加环境变量,彻底解决了迁移问题。

下面是一张问题速查表,是我压箱底的排查顺序:

问题现象最可能原因排查建议
训练时loss为NaN学习率过高或标注坐标异常先降至0.01倍原学习率,再查标签有无inf
推理坐标整体偏移预处理letterbox不一致对比训练与推理的resize方式
检测框抖动剧烈置信度阈值过低、NMS阈值不当调高conf阈值到0.25以上
GPU利用率低单张小图推理、无批处理开动态批处理或异步推理
前端偶尔白屏后端返回超时检查请求超时时间,增加失败重试
摄像头画面卡顿推理频率过高或网络带宽不足限制每秒推理帧数,压缩传输图像

说到个人体会,我会说这个项目给我最大的收获不是模型精度从多少提到多少,而是搞清楚了一条工程链路上每一个环节的真实工作量。数据标注是最枯燥的,却决定了上限;训练改进是最有成就感的,却最容易过热;部署是最考验耐心的,却直接决定用户觉不觉得“好用”。

如果你也想做出一个从数据集到Web界面的完整检测系统,我给的建议是:先跑通最小闭环,再用实验数据说话,最后回头把数据质量打磨到位。模型永远可以换,数据集和工程链路才是真正的护城河。

对了,最后分享一个小技巧:做这种项目强烈建议从第一天就用git管理每一个实验配置,改进点、数据集版本、训练参数都打上标签。我这个项目中间至少回滚过五次,没有版本记录的话,光是找回某个“曾经效果不错”的配置都能让人崩溃。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询