☰
基于YOLOv5的钢轨表面缺陷检测:从数据处理到模型部署全流程
2026/10/19 2:58:25 网站建设 项目流程

1. 项目背景与整体思路拆解

先说结论:这个项目不是那种“拿着公开数据集跑个demo、晒个mAP就完事”的练手作品,而是一套从数据到部署都走通的钢轨表面缺陷检测方案。基于YOLOv5框架,配套了标注好的钢轨缺陷数据集,还提供了训练完的模型权重。拿来就能做推理,或者直接在自己的数据集上微调。做钢轨巡检、工业质检、机器视觉方向的朋友,应该能从这里找到不少可以直接抄作业的东西。

1.1 为什么钢轨缺陷检测要上深度学习

钢轨表面缺陷检测,听上去是个很传统的工业视觉问题,但真正做过的人才知道它有多难缠。传统方案一般是两类:一类是基于数字图像处理的,用灰度阈值、边缘检测、纹理分析来定位缺陷;另一类是基于传统机器学习的,手工提取特征再扔给分类器。这两种方案我都试过,刚开始在实验室的“干净”样本上效果还行,一旦上了现场就原形毕露。

主要痛点有三个:

  • 光照环境不可控。户外钢轨检测是白天黑夜、阴晴雨雪都要跑的,同一个缺陷在不同光照下,灰度分布完全是两个模样。固定阈值方案在这种场景下直接失效。
  • 缺陷形态千奇百怪。钢轨表面缺陷有裂纹、擦伤、剥离、掉块、锈斑等等,同一类缺陷的大小、走向、深浅差异也很大。手工设计特征根本枚举不完各种形态。
  • 实时性要求高。巡检车跑起来速度不低,图像采集帧率一高,传统图像处理算法那点算力根本跟不上。

这种情况下,深度学习目标检测算法天然就是更合理的选项。它不需要人工设计特征,端到端地从数据里学;泛化能力比固定规则强太多;GPU推理速度也能满足实时要求。而在当前的目标检测模型选择里,YOLOv5是综合性价比最高的一个,后面细说。

1.2 YOLOv5选型:为什么不选Faster R-CNN,也不选YOLOv8

模型选型是项目正式动手之前的第一个关键决策。我先对比了主流的目标检测方案,筛选逻辑如下:

模型速度精度部署难度生态成熟度
Faster R-CNN慢高中高
YOLOv3/v4中中中高
YOLOv5快高低极高
YOLOv8快高低中(较新)
各类Transformer检测器中高高中

Faster R-CNN的精度确实不错,尤其是小目标召回上有优势,但两阶段的架构决定了它速度上不去。钢轨检测这类场景,后续要部署到巡检设备上做实时推理,速度这条必须优先满足。所以直接放弃了。

YOLOv8当时也考虑过,但有几个现实问题:一是项目启动时v8发布还不久,社区踩坑积累不够;二是v5的生态极其完善,从训练到导出再到部署,各种优化教程一大把,遇到问题容易找到解决方案;三是我手上已有的很多工具脚本都是基于v5写的,迁移成本也不低。综合评估下来,YOLOv5是当时最稳的选择。实际做下来,这个决策没让我后悔。

1.3 项目最终交付了什么

这个项目的成果物围绕“一条完整可用链路”来组织:

  • 钢轨表面缺陷数据集:包含数千张标注图像,覆盖裂纹、擦伤、剥离、掉块、锈斑等典型缺陷类别,附带YOLO格式的标注文件,可直接用于训练,也可以做划分后的训练集/验证集/测试集。
  • 训练好的模型权重:在自有数据集上完成训练和验证,mAP指标达到了可用水平,模型可直接加载推理。
  • 推理脚本与交互逻辑:提供了基于PyTorch的推理脚本,支持图片、视频流输入,输出检测结果可视化。
  • 数据标注规范与流程图:标注工作流转不起来,后面全白搭,所以数据和流程分开交付。

一句话概括:别的地方给你一个孤零零的权重文件,我这里把“原料+配方+成品+使用说明”一次性备齐了。

2. 数据集的构建与预处理

2.1 数据从哪来:采集策略决定效果上限

很多人不重视数据采集,觉得网上找个公开数据集下载下来就能训练。但工业场景和通用场景的差异非常大。公开数据集里的“钢轨”大多是旅行博主拍的风景照,几乎没有近景的、大光比的、带油污遮挡的钢轨表面图像。用公共数据集训练出来的模型,一上现场就漏检,一点不奇怪。

我的数据来源主要有两个渠道:

第一是自己搭建模拟采集环境。用线阵相机配合特定光源搭建了一条模拟钢轨表面采集平台,把实际钢轨样本放到平台上,以固定速度通过,模拟巡检车的工作方式。这样做的好处是采集条件可控,可以人为制造不同光照、角度、速度下的图像,覆盖测试工况中的大部分变量。

第二是从现场巡检视频中抽帧。用巡检车在试验线路上跑了几趟,采集了一部分现场视频数据,然后按帧提取。这里面有个坑:视频帧之间的信息高度冗余,直接全部抽出来会导致训练集和验证集之间出现“数据泄露”——同一块缺陷的相邻几帧既进了训练集又进了验证集,指标虚高得离谱。

处理方法是:连续帧按间隔抽样,具体来说每10帧取1帧,然后再用图像哈希算法做去重筛选,把高度相似的帧过滤掉。这个步骤很多人忽略,但它对指标真实性的影响非常大。

2.2 标注规范的制定:比动手标注更重要的事

数据标注是整个项目里耗时最长、也最容易返工的环节,没有之一。我踩过最大的坑就是:一开始没定标注规范,几个人各标各的,结果训练完发现模型对同一个缺陷的检测框一会儿大一会儿小,边界模糊得厉害。后来花了两周时间返工重标,代价惨痛。

现在把标注规范的核心要点整理出来,你们做类似项目时可以直接抄:

  • 检测框必须紧贴缺陷的真实边界。缺陷检测不像行人检测,框的边缘贴着缺陷边界走,不要为了“框住整个区域”多留背景像素。背景像素混得越多,模型越难学清楚缺陷的真实特征。
  • 对长条形缺陷,拆分成多个框进行标注,而非用一个细长的大框覆盖全部。因为YOLO系列的anchor机制对细长目标的回归天然存在劣势,拆开标注反而更好收敛。
  • 标记类别优先按照“形态+成因”来分,而非按严重程度分。比如“裂纹”和“擦伤”要分开,不要统称“表面缺陷”。“严重裂纹”和“轻微裂纹”也建议合成一类,因为严重程度是连续变量,不适合做成离散类别。
  • 标注争议区域统一用“疑似缺陷”规则处理,无法判断的先标记为待定,定期开标注评审会一起定。宁可丢一个样本,也不要标错一个样本。

标注工具用的是开源的LabelImg,操作简单、上手快。唯一要注意的是输出格式默认为Pascal VOC的XML格式,需要再转一步成YOLO格式的TXT标注文件。我在项目里写了一个转换脚本,批量做了格式转换,同时顺便检查了有没有越界坐标、空标注文件等低级错误。

2.3 数据扩增的艺术:不是每种扩增都有效

数据扩增是提升模型泛化能力的重要手段,但很多人陷入了一个误区:扩增方法越多越好,参数越狠越好。实际并不完全是这样。

以钢轨表面缺陷为例,我试过的扩增组合及效果如下:

扩增方法是否采用原因
随机水平翻转采用钢轨缺陷没有方向性语义,翻转不影响标注含义
随机亮度/对比度调整采用模拟不同光照条件,提升鲁棒性
高斯噪声/运动模糊采用模拟传感器噪声和运动模糊,缺陷是微小纹理,这部分特别关键
随机旋转小角度采用巡检图像中缺陷姿态略有变化,小角度旋转有效
马赛克增强采用YOLOv5内置支持,丰富上下文信息
上下翻转不采用钢轨在图像中的方向一般是固定的,上下翻转会生成现实中不会出现的样本
随机裁剪大比例不采用大比例裁剪会破坏缺陷的上下文语义,反而增加误检

这里多说一句:扩增不是为了“变多”,而是为了让模型见过的图像分布更接近真实部署时的分布。比如巡检车在高速运动时图像会产生运动模糊,那就在训练时人为加模糊;光照变暗了,就调低亮度。这才是扩增的本质。

2.4 数据集划分与平衡处理

划分数据集时,我坚持了一个原则:同一块钢轨的缺陷图像只能出现在一个集合里,禁止跨集合混用。按照这个原则,把源头采集到的图像划分成训练集、验证集、测试集,比例约7:2:1。

关于类别不平衡问题,钢轨表面缺陷中“擦伤”占比很大,“掉块”占比很低。如果直接训练,模型会对多数类过拟合,少数类经常漏检。解决方案是先统计各类别实例数量,然后做了两类操作:

  • 对样本量少的类别,提高其参与训练时被重复采样的概率;
  • 对样本量大的类别,适当降采样,避免模型在训练中过度偏向。

在YOLOv5中,可以通过调整每个epoch的数据加载权重来实现,也可以用更简单的“过采样少数类”的办法。我把两种方式都试了,最终是在数据加载阶段使用了类别权重的方式,效果更平滑一些。

3. 模型训练全流程拆解

3.1 模型配置与预训练权重选择

YOLOv5提供了从小到大几个型号:n、s、m、l、x。模型越大,精度越高,但推理延迟也更大。在钢轨缺陷这个场景下,缺陷虽然不算极小的目标,但很多“裂纹”在整张图像里的像素占比很小,所以模型容量不能太小。我最后选的是YOLOv5m作为折中方案,单张图像推理时间在GPU上大概十几个毫秒,既能跑在边缘设备上,又有足够的容量去拟合细节特征。

训练时没有从随机初始化开始,而是加载了在大型通用数据集上的预训练权重。这背后的原理是:预训练模型已经学到了大量底层视觉特征(边缘、纹理、朝向等),这些特征在钢轨缺陷检测任务中依然成立。在预训练基础上做微调,比从头训练收敛快得多,而且不容易被小数据量带偏。

有个参数容易忽略:freeze冻结层数。开始训练前10个epoch冻结了主干网络,只更新检测头部分,让损失先降下来,之后再解冻主干做全量微调。这个操作能让训练过程更稳定,也能减少显存占用。实测下来,冻结合并微调的最终精度比直接全量训练略微高一点,虽然差异不算显著,但训练过程确实平稳很多。

3.2 关键训练参数的经验取值与调优心得

YOLOv5训练时的参数很多,我挑几个影响最大的说一下,附带我的经验取值:

图像尺寸imgsz。我做的是640。钢轨缺陷的物理尺寸一般在毫米到厘米级别,如果图像分辨率太低,细小裂纹会直接消失。640是一个精度和速度都比较平衡的点。之前试过1280,精度确实有提升,但训练显存占用翻了一倍不止,推理速度也明显下降。考虑到后续要部署做实时,最终锁定了640。

批大小batch-size。选了32,这是由显存决定的。批大小影响的是梯度的稳定性,太小了loss震荡严重,太大了容易跑满显存。在有限的硬件条件下,batch-size在16到64之间对最终效果影响不是特别大,但会影响训练速度和显存占用。建议优先满足显存约束,再尽量取大。

学习率策略。初始学习率设0.01,配合余弦退火策略。实际训练中,我观察过学习率曲线对loss的影响:固定学习率训练,后期容易在局部最优附近反复横跳;余弦退火则能逐渐降步长,让模型在后期更细腻地收敛。这里没有用自动寻找最优学习率的工具,直接凭过往项目的经验值起步,然后观察第一个epoch的loss变化,如果出现发散就调小初始学习率,如果收敛太慢就调大。

训练轮数epochs。设了200,但这不是硬性的。我建议每训练几十个epoch就保存一次权重,然后综合观察训练loss、验证loss和mAP曲线的走势,如果验证集指标连续20个epoch没有提升,就可以提前停止了。我在实际训练中大约是第140个epoch左右达到最佳验证指标,后续继续训练基本是浪费算力。

YOLOv5自带的早停机制(patience参数)就是这个用处。设patience=20,它会自动判断验证集指标是否长时间没有提升,如果是就停止训练。这个功能相当实用。

3.3 训练中必看的指标与曲线

训练过程不是跑起来完事儿,每个关键节点都要盯指标。我最常用的是这几个:

  • Box Loss:定位损失的收敛情况。如果box loss降不下去,说明检测框回归不准确,常见原因包括anchor设置不合适、标注框质量差等。
  • Class Loss:分类损失。如果分类损失居高不下,说明模型对缺陷类别区分度不足,大概率是类别标注质量或样本量分配出了问题。
  • mAP@0.5和mAP@0.5:0.95:最终模型性能的判断标准。前者是宽松指标,后者更严格。钢轨缺陷检测场景中,我主要看mAP@0.5,因为缺陷检测允许的定位误差一般没有自动驾驶那么苛刻。
  • Precision和Recall曲线:这两个指标对工业缺陷检测尤其重要。钢轨检测有个特点:漏检的代价远超误检。裂纹漏检可能导致重大安全事故,而多标一个锈斑最多让运维人员多看一眼。所以我在调模型时,会刻意把置信度阈值调低来提升召回率,宁可误检多一些。

训练日志的记录同样重要。我会把每一轮的验证指标写入CSV文件,方便训练结束后做趋势分析。YOLOv5本身就输出results.csv,拉出来用Excel或者一个小脚本绘图就够了。

3.4 模型评估与失效案例分析

训练完成后,除了看总体的mAP,我会做细致的“按类分解”评估。统计每一类的精确率和召回率,找出“拖后腿”的类别。在我的案例里,表现最差的是“剥离”这一类,召回率比其他类低了不少。

分析原因发现:一方面“剥离”样本数量偏少,不足“擦伤”的三分之一;另一方面“剥离”与“掉块”在视觉形态上非常接近,边界本来就模糊。优化思路是在训练时给“剥离”类适当增加样本权重,同时把标注规范中“剥离”和“掉块”的边界描述得更明确,重新标注了一批样本。第二版模型训练后,“剥离”的召回率明显改善。

评估阶段还有一个重要动作是可视化错误案例。把漏检和误检的图像抽取出来,逐张查看模型到底错在哪里:

  • 如果漏检的多为暗光环境下的小裂纹,说明模型对低对比度目标的表达不足,可以增加对应的数据增强或者提升图像采集的前端照明质量;
  • 如果误检的多为表面锈斑被当成掉块,说明类别间的语义距离太近,需要从标注定义或模型结构上想办法。

做完这一步,才敢说模型是真的“懂了”缺陷检测,而不只是指标好看。

4. 推理部署与工程化落地

4.1 权重导出与推理脚本实现

YOLOv5训练完成得到的是PyTorch格式的权重文件,后续使用有两种路径:一种是用torch.hub直接加载PyTorch模型进行推理;另一种是导出成其他格式做部署。我先把PyTorch这条路径跑通,因为它改起来最方便,适合在开发阶段验证效果。

推理脚本的核心逻辑很直接:

import torch model = torch.hub.load('./yolov5', 'custom', path='best.pt', source='local') model.conf = 0.25 model.iou = 0.45 results = model(img_path) results.show()

这里有两个参数要特别注意:conf是置信度阈值,iou是NMS的IoU阈值。要在线检测场景中,不要把conf设得太高。巡检车拍下的钢轨表面,很多缺陷本身对比度就不高,模型对这些目标的置信度天然偏低。把conf从0.25调到0.1,召回率能提很多,代价是误检框变多。这个不可一概而论,需要根据实际项目对漏检和误检的容忍度来定。

4.2 部署形态考量:边缘设备与中心服务器

钢轨巡检的部署形态,一般分成两种思路:

边缘实时检测:在巡检设备上直接挂GPU模块或边缘计算盒子,模型跑到摄像头的视频流上,实时输出检测结果并叠加到画面中,同时保存关键帧。优点是响应快、不依赖网络;缺点是设备成本高、算法升级要上现场刷机。

中心离线分析:巡检车只负责采集原始图像,回传后由中心服务器统一跑模型分析。优点是部署维护方便、算力不受边缘限制;缺点是回传数据量很大,而且分析有时间延迟。

实际项目中通常两者结合:边缘端做粗筛,发现可疑帧就保存;中心端做细判,对可疑帧做二次高精度分析。这在工业场景中是很常见的“两级检测”架构,用较低的算力成本换取全链路精度。

4.3 实测性能与落地效果

我在最终模型上跑了一批现场的验证数据,这里列出几个有代表性的指标值(约值):

指标数值
精度(Precision)87% 左右
召回率(Recall)82% 左右
mAP@0.585% 左右
单帧推理耗时(GPU)12ms 左右
单帧推理耗时(CPU)120ms 左右

这个结果说明模型在GPU设备上跑实时检测完全没问题,在CPU设备上则更接近准实时。如果CPU设备要跑满帧率,还需要做模型剪枝或量化,这块后面可以单独展开讲。

高召回率对钢轨检测场景极其重要:宁可让运维人员看到几个错误的预警,也不能漏掉一处真实裂纹。

5. 常见问题与排查技巧实录

5.1 训练侧典型问题速查表

问题现象可能原因解决方案
训练loss不降学习率过高或过低调整初始学习率,或使用学习率预热策略
mAP指标虚高训练集和验证集之间存在数据泄露按源头划分数据,严禁同一缺陷的不同帧跨集合
某类缺陷召回率特别低样本数量不足或类别语义冲突增加样本量、调整类别权重、细化标注规范
检测框偏移严重anchor机制与目标形状不匹配使用聚类算法重新计算anchor,或用--noautoanchor关闭自动锚框
训练后期过拟合模型容量过大而数据量不足增加正则化、增强数据扩增、降低模型规模

5.2 推理侧典型问题速查表

问题现象可能原因解决方案
漏检多置信度阈值太高降低conf参数,优先保证召回率
一个缺陷被框两次NMS的IoU阈值太高适当降低iou参数
光照变暗时检测失效训练数据中暗光样本不足增加亮度扰动扩增或补充暗光数据
模糊帧检测效果差训练时缺乏运动模糊模拟加入高斯模糊、运动模糊扩增
大量误检为锈斑锈斑与其他缺陷特征相似细化标注标准、考虑增加锈斑负样本或单独成类

5.3 两个最值得分享的实践经验

第一个经验是关于数据泄露的隐蔽形式。使用视频抽帧构建数据集时,即使做了抽帧,相邻帧之间依然可能存在相似内容。我处理这类问题时,不只依赖人工判断,还会计算图像间的感知哈希距离,设置一个阈值自动过滤掉相似度超标的图像。这样做的收益在验证集mAP的可信度上体现得很明显——对比过滤前后的验证集指标,夸张的时候能差8个点以上。

第二个经验是注重训练复现性。训练神经网络有随机性,同一个代码、同一个数据,两次训练结果也会有一些波动。如果只是跑一次训练得到一份权重就完事,无法判断这个结果到底是模型能力还是随机运气。我在项目中固定了随机种子,每次训练记录下核心超参数,同样的配置至少跑三次取统计结果。这样才能获得有信心的性能结论。

结语

坦白讲,钢轨表面缺陷检测不是一个“跑通YOLOv5就完事”的项目,它真正考验的是对数据质量的理解、对业务场景的判断和对工程细节的把控。现阶段我已经把基于YOLOv5的检测链路完整跑通,测试集指标可以支撑现场试用。后续要做的其实是两件事:一是持续扩充现场返回的真实缺陷数据,尤其是那些“长尾”的、罕见的缺陷形态;二是往更轻量、更快的方向走,尝试模型量化和剪枝,让它在更廉价的边缘设备上也能达到实时。这两个方向都有不少坑,等我把它们填平了,再来分享新一轮的心得。

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

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

立即咨询