钢轨表面缺陷检测这件事,工业界喊了很多年要从人工目视巡检转向自动化,但真正落地的人都知道,这里面最难的不是模型本身,而是数据。我在做这个基于Yolov5的钢轨表面缺陷检测项目时,最大的体会就是:训练模型只是在链条末端把活儿干完,前面从缺陷类别定义、采集设备布设、标注规则制定到数据增强策略,每一步都直接决定最终检测率能不能拿得出手。
这篇博文围绕Yolov5算法展开,完整记录了我从数据集构建、标注规范、模型训练到导出部署整个流程里踩过的坑和验证过的做法。目标读者有两类:一类是把目标检测当主要研究方向的同学,另一类是正在做轨面视觉检测、需要把算法从实验台搬到现场的工程人员。这套方案不挑特定硬件,通用性比较强,你完全可以照着流程在自己的数据上重跑一遍。
1. 项目核心思路与方案选型
1.1 为什么是Yolov5而不是其他目标检测框架
钢轨表面缺陷检测本质上是一个目标检测问题,输入是轨面图像,输出是缺陷的类别和位置框。这类问题能用的算法其实不少:传统图像处理的路子、两阶段检测器、单阶段检测器、还有基于Transformer的新架构。我选Yolov5,不是因为它是最新的,而是因为它在工业落地上最省心。
先对比一下各个方向的取舍。传统图像处理,比如阈值分割、边缘检测、形态学处理,对场景极其敏感,光照一变、油污一多,分割结果马上崩掉,只能作为辅助手段。两阶段检测器以Faster R-CNN为代表,精度是很高,但速度掉得厉害,轨面图像常年在千万像素级别,推理时间完全扛不住。Transformer类检测器,如DETR系列,理论先进,但在小目标和细长目标上优势不明显,而且部署依赖更高,现场设备普遍吃不消。
Yolov5这套从CSPDarknet骨干网络加PANet特征融合的结构,在速度和精度之间取得了很实用的均衡。CSPDarknet负责分层提取特征,PANet像物流分拣一样把不同层级的语义信息和纹理信息重新组合,YOLO Head再把融合后的特征转成边界框预测。这套结构的好处是:骨干足够轻量,特征融合足够充分,三个尺度输出能够同时照顾到大的剥离掉块和细小的表面裂纹。更重要的是它的工程生态成熟,官方开源实现有一整套训练、验证、导出、部署的工具链,遇到问题社区里一搜就有答案。对生产项目来说,可维护性比模型刷分重要得多。
1.2 钢轨缺陷视觉检测的三个特殊难点
选好了框架,还得知道这个场景和通用目标检测有什么不同。我做了几轮实验之后,把钢轨缺陷检测的难点归结成三个:目标形态特殊、背景环境脏、缺陷样本稀缺。
第一,钢轨缺陷形态极不规整。拿表面裂纹来说,它往往是细长的一条线,宽度只有几个像素。目标检测的框是矩形,一个细长裂纹在一个大框里占比很小,模型很容易把框内的轨面纹理当成背景学进去。第二,轨面现场太脏了。车轮碾过之后有光带、有水渍、有油污,还有焊点、锈迹,这些东西的外观和真实缺陷混在一起,模型非常容易误检。第三,缺陷样本实在太少。钢轨本身质量是可靠的,正常服役期里出现缺陷是小概率事件,采集十公里轨面可能才碰到几个有价值的阳性样本,和通用场景里动辄几十万的物体类别数据完全不是一个量级。
这三个难点直接决定了后面的数据集构建和训练策略。所以我在动手训练之前,先花了一半的项目周期在设计数据流上。后面聊到数据集的时候,你会发现很多细节都是在针对这三个问题做对抗。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 数据集构建是决定上限的关键
2.1 缺陷类别定义与样本筛选
很多目标检测项目翻车都翻在类别定义上。钢轨缺陷种类多,但如果把相近形态的缺陷硬拆成独立类别,标注会混乱,模型也学不好。我最终参考了几个公开的轨面检测研究方向和现场工务经验,把项目收敛为五类:表面裂纹、剥离掉块、擦伤、波纹磨耗、鱼鳞伤。
这五个类别划分的逻辑是:形态区分度足够大,标注人员能一眼判断;每一类对应的行车安全影响等级不同,后续业务处理可以区别对待。下表是我实际用的标注规范,可以直接拿来当SOP参考。
| 缺陷类别 | 典型形态 | 标注框建议 |
|---|---|---|
| 表面裂纹 | 细长线状,可能有分支,宽度窄 | 用最小矩形紧贴裂纹本体,不要包含周边纹理 |
| 剥离掉块 | 片状缺肉,边缘不规则,面积较大 | 贴合缺损外边缘,适当包含一圈过渡区 |
| 擦伤 | 轨面局部发亮或发暗的磨损斑块 | 框住磨损区,不要把光带整条划进去 |
| 波纹磨耗 | 周期性波浪状亮暗交替区域 | 框住一个完整波纹周期,至少包含两三个波峰 |
| 鱼鳞伤 | 密集的小裂纹或微剥离,呈鳞片状 | 用单个框包住整个鳞片集群,不逐条标 |
样本筛选上有个经验:宁缺毋滥。模糊的、离焦的、遮挡严重的图,宁可不要也别留。一张坏标注混进训练集,模型学到的是脏特征,后面再调参都很难救回来。我前期筛选图片用了整整一周,把采集设备拍到的几千张候选图逐张过了一遍,删掉了大约百分之二十的无效样本,后面训练过程收敛得明显顺畅。
2.2 标注规范设计:从像素到框的一致性问题
标注一致性是目标检测项目的隐形杀手。如果十个人标注标准不一样,模型会无所适从。我在项目里制定了一套刚性规则,并且要求所有标注完的数据都要过一遍复审。
规则一:裂纹类缺陷标注框必须紧贴缺陷像素的最外沿,不能为了省事用一个框把附近裂纹全装进去。规则二:当缺陷与车灯光带重叠时,框只标缺陷本体,光带不算。规则三:如果一张图里有多个同类别缺陷,全部标,不要觉得挨得近就合并。规则四:拿不准的样本单独建一个待定文件夹,由项目负责人统一裁决,绝不能让标注员凭感觉乱标。
标注出来的框质量会直接影响Yolov5的anchor学习和回归头收敛。曾经有一批样本的框普遍偏大,训练完之后发现模型预测的框普遍比真实缺陷大一圈,而且召回率上不去。后来我把这批样本复核修正,在同样参数下重新训练,mAP直接提升了四个多点。这件事给我的教训很深:标注框的质量不是锦上添花,而是模型性能的前提。
2.3 数据增强策略:别让Mosaic帮倒忙
Yolov5自带一套挺强的数据增强管线,包括Mosaic、MixUp、随机仿射、色彩扰动等。Mosaic把四张图拼成一张,极大丰富了背景和小目标数量,是Yolov5在通用场景里表现好的关键因素。但在钢轨缺陷检测里,Mosaic用不好反而会帮倒忙。
原因很简单:钢轨缺陷是细长条目标,Mosaic拼接时会把原图按比例缩放,一张轨面图缩到四分之一后,本来就细的裂纹可能只有两三个像素宽,模型根本学不到有效特征。我的做法是降低Mosaic启用概率,从默认值改到0.5左右,同时把尺度扰动范围调小。对于细长缺陷,我额外加了旋转增强——但角度限制在正负十五度以内,转太多会让裂纹形态失真,反而误导模型。
另外,我强烈推荐做在线裁剪训练。钢轨原图太大,直接resize到640会导致缺陷在图上占比极小。我是先把轨面区域裁剪成1280宽度的条带,再按比例缩放到640送入模型训练。这样既保留了缺陷的尺度信息,又不至于让小目标缩到消失。实测下来,这条策略对召回率的提升非常明显。
3. 训练全流程:从配置到完成
3.1 环境搭建与目录准备
训练环境不用太豪华,一块常规的GPU就能跑通。我用的是单卡训练,显存大约十几G,batch size放在24左右,模型选的是Yolov5s和Yolov5m两个规格分别试跑。软件环境按官方仓库的要求来:Python版本、PyTorch框架、依赖包列表,这些照搬就行。我一般建议把训练环境用虚拟环境隔离起来,避免多个项目互相污染依赖版本。
目录结构我习惯是项目根目录下分images和labels两个总目录,各自再分train和val子目录。图像文件用时间戳命名,标签文件是同名txt,每行格式为:类别编号 中心点x 中心点y 宽度 高度。注意这里的坐标是相对原图宽高的浮点数,标定工具导出的时候会自动换算,但如果你是自己写脚本生成的标签,千万别算错。
钢轨图像普遍偏大,一张原图可能有几万像素宽。Yolov5默认输入是640,直接把整张大图resize进去会损失太多细节。我的处理方式是在标注之前就把原图切块:按1280宽度切成若干条带,重叠区域留100像素防止缺陷正好卡在切缝上。切完的条带再交给标注工具,这样训练和推理的输入口径一致,后面部署时就不用再走一道预处理了。
3.2 关键超参数设置与依据
超参数设置不能把Yolov5的默认值直接拉满,要根据任务特征调整。我在这轮项目里最终跑出的参数组合如下,可以作为你第一次实验的起点。
- 输入分辨率:640x640,不允许再低。如果你的缺陷普遍小于20像素,建议直接用1280训练,代价是显存占用大涨。
- batch size:24,在GPU显存允许的前提下尽量大,能让BN层的统计更稳。
- epochs:300轮。钢轨缺陷样本少,300轮足够收敛,再多意义不大。
- 学习率:初始lr设为0.01,配合warmup前3个epoch预热。钢轨数据背景复杂,学习率过大会导致前期震荡明显。
- 类别数nc:之前定义的五类,改配置文件即可。
- anchor:让Yolov5的autoanchor自动重新计算。钢轨缺陷的长宽比和通用物体差异很大,手动指定的默认anchor并不适配。
- 标签平滑:设为0.05,可以在训练后期让模型对难样本更稳。
还有一个重要选择是预训练权重。我用了官方开源的Yolov5s预训练权重做迁移学习,而不是从零训练。钢轨缺陷样本量少,从零训练很容易过拟合到轨面背景上。预训练权重在COCO上已经学会了很多底层特征——边缘、纹理、形状组合,这些对轨面裂纹的识别依然有效。事实证明,迁移学习让模型在第50轮左右就达到了从零训练要200多轮才有的效果。
3.3 训练过程监控与止损判断
训练不是启动命令就完事了,要盯着曲线判断什么时候该停、什么时候该调。我主要看三个指标:训练损失是否持续下降、验证集mAP是否上升、训练损失和验证损失的差距是否拉大。
在钢轨缺陷这种小样本场景里,过拟合来得特别快。如果训练损失一路降到接近零,但验证mAP在某个轮次后开始掉头向下,那基本就是过拟合了。这个节点一定要盯住,我通常在mAP的平台期开启早停机制,连续几十轮不提升就停。另外,验证集要固定不动,不要一边训练一边把表现不好的验证样本挪到训练集里去,这会让指标失真。
训练过程里还有一个常见的困惑:mAP曲线震荡剧烈。钢轨缺陷样本少,验证集里一个误检导致的波动都会被放大。我的做法是看EMA平滑之后的曲线趋势,而不是被单轮峰值牵着走。Yolov5官方的训练日志会记录每一轮的完整指标,我习惯训练到一半时直接把结果目录里的results.png翻出来看一眼,如果train/obj_loss出现台阶式下降后又快速反弹,往往说明学习率不合适,需要回去把lr调小,然后重跑。
4. 评估、导出与部署实测
4.1 评估指标解读:mAP到底说明什么
很多项目报告里喜欢写一个整体mAP,但钢轨缺陷检测里这个数有误导性。不同缺陷类别对漏检和误检的容忍度完全不一样,表面裂纹漏检一次可能导致钢轨断裂风险,而擦伤类误检最多就是多派一次人工复核。所以我在评估时不是只看mAP,而是把每个类别的精度、召回率单独列出来,按业务权重加权。
具体做法是:验证阶段导出每个类别的PR曲线,重点看裂纹类在高召回率区间下还能不能维持精度。如果为了把裂纹召回率拉高到百分之九十五以上,误检率飙升得没法看,那这个模型在业务上就是不可用的。钢轨检测的实际要求往往不是追求极致召回,而是控制一定误报率的前提下,把缺陷尽可能筛出来交给人工复核。所以在模型调优阶段,我会把“每天一千张图里误报不超过几个”作为比mAP更优先的约束条件。
4.2 导出与推理优化
训练好的PyTorch模型不能直接跑在现场工控机上,一步步导出和优化很关键。我的常规路线是:先把pt模型导出为ONNX,再用加速推理引擎做一次精度优化。ONNX的好处是格式中立,不管现场用的什么推理框架,都能接进来。
导出这一步有几个细节。第一,输入尺寸要固定,和训练一致。第二,导出时开启半精度FP16,在线推理速度能提升不少,精度损失在钢轨缺陷这类任务里几乎感知不到。第三,启用NMS后处理优化,合并重复框。
还有个要点是batch size。现场推理通常在边缘设备上跑,一般用batch=1,导出时也按这个设置,免得框架内部做多余优化。如果你要用GPU加速服务,可以导出固定batch=4或8,吞吐量会好一些。但注意NMS的逻辑和耗时也会跟着变,建议实测后再定。
模型规格选择上,我对比了Yolov5s和Yolov5m。m规格精度更高,推理时间大概是s规格的两倍;s规格速度快,对小目标召回率略低。在钢轨检测现场,如果工控机算力允许,我会优先用m。如果现场设备老旧或者要求实时性极高,s加上切图策略也是能用的,前提是把漏检控制住。
4.3 现场部署中的稳定性处理
从实验环境搬到现场,最先遇到的问题不是算法本身,而是图像质量问题。现场的光照不均匀、车轮反光、相机抖动,都会让模型的输入分布和训练集不一致。我的处理方式是在部署前加一道图像预处理:先把轨面区域裁剪出来,再做标准化的亮度校正,最后才送入模型。
部署时推荐加一个ROI区域过滤。在真实场景里,整张图最可能出缺陷的只有钢轨表面的狭窄区域,两侧的道床、扣件、轨枕全是干扰。我用一个简单的轨面定位逻辑把有效区域裁剪出来,只在这个区域内做缺陷检测。这个方法能够极大降低误检率——很多模型的误检都来自背景里的铁锈、树叶、螺栓托板,把背景直接排除掉,精度立刻就上去了。
推理速度方面,我在一套常规工控机上实测Yolov5s处理1280宽条带图,单张耗时在十几毫秒量级,完全满足天窗期巡检的实时性要求。如果你用的是m规格模型,单个条带耗时大约增加一倍,但仍然够用。
5. 高频问题速查与我的避坑建议
5.1 高频问题排查表
做个速查表,总结我在训练和部署阶段遇到的高频问题,按症状、原因、解决方案三列给你排好,方便你直接对号入座。
| 症状 | 可能原因 | 解决方案 |
|---|---|---|
| 小裂纹几乎完全漏检 | 输入分辨率低或者切块太大导致缺陷缩得太小 | 提高训练分辨率到1280,或者缩小切块宽度 |
| 水渍、油污被反复误检 | 负样本太少,模型没见过这些干扰 | 采集大量无缺陷轨面图作为背景样本,加入训练集 |
| 训练损失前期抖动剧烈 | 初始学习率偏大 | 降低初始lr到2e-3,并确认warmup轮数足够 |
| 验证mAP震荡严重 | 验证集样本太少,单张误检影响大 | 扩大验证集,按类别分层抽样 |
| 模型预测框整体偏大 | 标注框普遍偏大,回归头学到了偏差 | 复核并收紧标注框,重新训练 |
| 部署后比训练时误检明显增多 | 现场光照分布和训练集差异大 | 增加光照扰动增强,增加现场图进训练集 |
| 推理速度不达标 | 模型规格选太大或切块无重叠浪费 | 换成s规格,或降低切块重叠比例,或导出FP16 |
5.2 三条最实用的经验建议
第一,钢轨缺陷检测这类任务,精度和召回率的业务权衡比模型结构本身更重要。在项目开始之前,先和需求方确认清楚:漏一个缺陷的代价是什么,误报一个缺陷的代价又是什么。钢轨场景里漏检高风险缺陷是绝对不可接受的,所以我会优先保召回率,通过阈值调整和人工复核机制控制误报成本。
第二,现场数据回流比调参有效得多。模型部署之后,我建议把每天推理出的误检样本、难样本、新增的缺陷样本全部存下来,定期补充进训练集重新训练。这套主动学习的流程,跑两三个月之后的效果比你在实验室里调一两个月参数提升都大。缺陷样本贵,但误检样本便宜,别浪费。
第三,钢轨表面的光照统一化处理要前置做好。我见过不少项目在模型上反复折腾,最后发现是现场相机曝光和白平衡没有统一,导致同一段钢轨在不同时间段拍出来的图风格差异巨大。先把采集端的成像质量稳定下来,后面的模型训练才能稳定下来。这是投入产出比最高的一步。
做了几次现场实测之后,我最大的体会是:模型训练只是整条链路里最不神秘的一环,真正的核心功夫全在数据集和部署细节上。钢轨缺陷检测这类工业视觉项目,首先要做的是把检测能力边界讲清楚,哪些缺陷能稳定检出、哪些在现阶段不适合做,然后再去谈自动化替代程度。最后再分享一个小技巧:每次迭代训练都固定同一套验证集,并且保留所有历史测试图片;不换测试集,只看新旧模型在同一批数据上的表现差异。这个方法比任何花哨的评估指标都更能说明模型到底进步了没有。它的后续扩展方向也很有意思,从目标检测升级到缺陷像素级分割,或者加入轨面三维重建来识别更多隐蔽伤损,都是完全可以走的路,但第一步永远是先让现在的检测结果稳定可用。
