钢轨表面缺陷检测实战:基于Yolov5的数据集、训练与部署
钢轨表面缺陷检测这些年一直是工业视觉里看着简单、落地要命的典型场景。我在某轨道交通检测项目中折腾过一整套基于Yolov5的识别流程从数据采集、标注、训练到上小车实测踩坑不少。这篇就按我实际做法把数据集怎么攒、模型怎么训、训练好的模型怎么用这三个核心问题拆开讲清楚。内容围绕钢轨表面缺陷检测全流程涉及数据准备、Yolov5工程细节、训练参数策略以及部署时的真实坑点适合准备入坑轨交视觉检测或者正在做类似工业表面缺陷项目的朋友参考。1. 先搞清楚钢轨表面缺陷到底长什么样数据集的采集与标注是决定成败的起点很多入门者拿到这个标题第一反应是赶紧找个开源数据集丢进去训练。但真正的钢轨检测项目最值钱的恰恰是数据本身。钢轨缺陷类别多、形态差异大而且背景纹理本身就带着锈蚀、油污、水渍这些干扰项如果数据质量不达标后面再调网络结构都是白费。1.1 真实巡检环境下的数据采集方案我在项目里用的方案是搭建了一个模拟巡检小车平台相机以一定倾角朝下拍摄钢轨表面。实际巡检中钢轨是连续的所以采集时要让小车保持匀速前进相机用连续拍摄模式或者按固定帧率抓取。关键参数大致如下相机分辨率至少1920×1080更低会导致细小裂纹在图像里只有几个像素标注和识别都没法做拍摄高度相机到钢轨表面距离大约30到60厘米具体以视野覆盖整个轨面宽度为准钢轨顶面宽度约70毫米左右光照方式建议用条形光源侧向打光让裂纹和剥落区域产生明显的影子对比比正面打光更能突出缺陷的立体特征存储格式原始图像存为无损PNG不要直接存JPG反复压缩会把微小缺陷的细节吃掉。采集不要只挑晴天、干净的轨道段。我特意在雨天、雨后、傍晚逆光、轨面有积水或落叶等条件下都采集了一部分。模型只有见过足够多的干扰场景上线后遇到类似条件才不会胡乱报警。另外同一个位置可以用不同角度多拍几次丰富同一缺陷在图像中的表现形态。1.2 缺陷类别命名与标注规范钢轨表面缺陷没有完全统一的标准分类各家检测系统命名的口径也不一样。我的做法是把缺陷归为以下几类尽量保证每个类别有独立形态避免类别间的视觉边界太模糊类别名称典型特征标注难点裂纹Crack细长线状方向与钢轨长度平行或呈小角度目标细长框太大容易把背景带进去剥落Spalling表层金属成片剥落形成凹陷或亮斑边缘不规整容易标成多边形而不是矩形擦伤Scratch连续划痕宽度不大但长度可能较长亮度对比低远距离看不清压痕Indentation轨面局部凹陷常伴随变形与正常轨面纹理容易混淆锈蚀Rust表面氧化变色往往面积较大光照不均时颜色变化大斑状缺陷Spot散点、片状不连续异常区数量多容易漏标标注工具我用的是LabelImg和X-AnyLabeling个人更推荐后者支持矩形框和多种格式导出。标注规范上有几条是我吃了亏之后才定下来的裂纹这类细长目标矩形框必须紧贴缺陷外接矩形宁可框稍微多含一点背景也不要截断目标一个缺陷跨图时在每张图中只标注缺陷完整存在的那部分同一图像中多个同类缺陷时全部标注不要漏标漏标会在训练时把该区域当负样本严重干扰收敛标注完成后至少换一个人复标一轮只标一遍的数据往往会有大量框偏大或偏小的问题。1.3 数据增强工业场景必须克制Yolov5自带马赛克、仿射变换、HSV扰动、翻转、MixUp等增强。很多教程都把增强参数开到满但钢轨检测里这是个大坑。钢轨缺陷检测的核心难点不是类别多而是背景单一、目标相对小增强过猛会导致模型学到大量伪缺陷特征比如把增强产生的假阴影、假纹理当成缺陷。我实际使用的增强组合相对保守马赛克增强开启但只对目标尺寸较小的类别起作用且每个批次中马赛克样本比例控制在0.5以内HSV亮度扰动幅度适中用于模拟阴天、晴天光线差异水平翻转开启因为钢轨左右方向的缺陷形态在物理上是对称的垂直翻转关闭钢轨纵向特征翻转后不符合真实采集方向随机缩放范围限制在0.5到1.5之间过大缩放会让小目标直接消失。数据总量方面如果只包含单方向、单光照条件的数据1万张图也可能过拟合。但如果数据形态覆盖足够多样2000到3000张标注图就能训出可用的模型。我的经验是数据质量大于数量多样性大于总量。2. 为什么用Yolov5而不是其他版本版本选择背后的逻辑和环境配置细节很多项目卡在第一步就是被网络结构选择搞晕。到了我做这个项目的时间点Yolo家族已经有很多版本了但我仍然选定了Yolov5。这不是因为它最新最好而是因为它在工业落地场景里综合成本最低。2.1 Yolov5相对其他方案的取舍相对两阶段检测器Faster R-CNN钢轨巡检对实时性有硬指标检测速度必须满足车辆运行速度下的帧率要求YOLO的单阶段结构天然占优相对YOLOX、YOLOv8等更新版本它们的精度确实可能略高但训练好的模型、成熟部署工具链、社区问题解决方案、各种边缘设备上的兼容性都不如Yolov5稳。工业项目里稳比新重要得多相对Yolov5自身不同版本我当时用的是6.0版本结构清晰、文档全、导出ONNX和TensorRT的坑基本都被前人踩平了。如果你的算力有限或者需要部署到老旧的工控机Yolov5s是个很合适的起点如果缺陷检测精度要求苛刻可以升到Yolov5m或Yolov5l代价是推理速度下降但对小目标召回率有明显提升。2.2 环境搭建中最容易出问题的点环境配置看起来简单我还是建议严格按固定版本走Python 3.8或3.10皆可但不要用3.11以上依赖兼容性问题太多PyTorch版本建议1.12到2.0之间匹配你的CUDA版本。如果你的GPU是老卡那套例如算力低要装对应老版本CUDA编译的PyTorch克隆Yolov5仓库后第一件事不是装requirement而是先看requirements.txt里锁定的库版本。很多报错都是opencv-python或numpy版本冲突引起的如果使用TensorRT部署CUDA、cuDNN、TensorRT三者的版本必须严格匹配我因为版本不匹配反复折腾过两天后来干脆把整个环境记录成固定的Docker镜像。训练时的显存管理上有个细节Yolov5默认开启--cache参数也就是把图像预加载到内存中加速训练但工业场景数据集经常是几万张高清大图内存会爆掉。我的做法是单机训练时不开--cache用磁盘流式读取多花一点训练时间换来不掉线。3. 训练流程的完整复盘超参数、训练指令、指标解读一次说透数据准备好、环境装好之后正式训练阶段也有很多讲究。这个阶段特别容易被忽视因为很多人以为只要把配置文件里的类别数改一下、点一下训练就能出结果实际上训练过程的每一个参数都会对最终模型产生相当大的影响。3.1 数据集的目录组织与配置文件写法Yolov5对数据目录结构有默认要求我使用的是以下结构datasets/ └── rail_defect/ ├── images/ │ ├── train/ │ └── val/ └── labels/ ├── train/ └── val/对应的data.yaml文件内容是这样的train: datasets/rail_defect/images/train val: datasets/rail_defect/images/val nc: 6 names: 0: Crack 1: Spalling 2: Scratch 3: Indentation 4: Rust 5: Spot需要特别注意路径尽量用相对路径或者绝对路径统一不要因为不同机器路径不同导致训练启动时报错。另外数据划分时必须保证同一缺陷在不同图像中不出现重复如果一个缺陷被多次采集到只能放进同一个集合否则验证结果虚高上线后立刻打回原形。3.2 关键超参数的设置依据我训练钢轨缺陷的基准配置如下表解释一下每个参数为什么这么设参数我的取值设置理由--img1280钢轨缺陷中小目标多输入分辨率不能低1280是精度与显存开销的平衡点--batch16取决于显存A100或3090可跑32但要配合小模型--epochs200数据量不大200轮足够收敛如果加载预训练模型会更早收敛--hyp修改后的hyp.scratch-low.yaml降低马赛克和HSV增强强度避免工业场景过增强--weightsyolov5s.pt加载COCO预训练权重做迁移学习不是从零训练--optimizerSGD在数据量较小、类别单一的任务中SGD的泛化能力比Adam稳定重点关注两个参数。第一个是--img我测试过480、640、1280三档小缺陷的召回率从480到1280提升非常显著1280相对640大约能把裂纹的召回率提升五个点左右。代价是训练时间翻倍、推理时间上升。有不少同行为了追求速度把推理分辨率降到640结果细小裂纹大量漏检反而得不偿失。第二个是--hypYolov5默认的hyp.scratch-high.yaml针对的是大规模通用目标数据集增强幅度很大直接套到钢轨上会明显劣化。3.3 训练指令与训练过程中的异常处理训练指令我用了官方标准写法加上关闭缓存python train.py \ --data rail_defect.yaml \ --weights yolov5s.pt \ --img 1280 \ --batch 16 \ --epochs 200 \ --no-cache训练过程中常见的几种异常这里提前说一下loss震荡不下降先检查数据标注是否正确尤其是类别文件的索引是否对得上标注的类别ID越界时loss会呈现诡异状态再检查是否加载了预训练权重从零训练在数据量小时极难收敛训练到一半显存溢出把--batch调小或者开启--noval跳过验证阶段节省显存验证集mAP很高但预测几乎全错大概率是标签和类别名错位也就是数据增强后标签没跟着变检查增强参数配置。3.4 指标解读不能只看mAP0.5项目验收的时候经常被问到指标很多文章会直接说mAP达到0.9以上。但钢轨缺陷检测只报一个mAP远远不够。mAP0.5衡量的是在IOU阈值为0.5时各类缺陷的平均精度这个值对位置精度要求不高主要看框有没有大概框住目标。实际缺陷定位对后续检修有实际意义必须再看mAP0.5:0.95这个指标才是框准确度的真标准。我训练完的模型mAP0.5能到0.92左右但mAP0.5:0.95只有0.62左右。差距主要来自裂纹、剐蹭这类细长目标——框哪怕偏几个像素IOU就会掉很多因为它们占的面积太小。另外必须逐类看P精确率和R召回率的单独数值。钢轨缺陷检测现场漏检比误检严重得多一条横向裂纹漏过去了可能造成安全事故所以我会尽量把召回率提升到0.9以上然后接受精确率略低大约0.85用后端的人工复核低置信度结果机制兜底。4. 训练好的模型部署到实际检测场景小车集成与推理调优训好的模型只有跑在实际巡检设备上才算真落地。这一步涉及的坑完全不比训练少尤其是工控机性能有限推理速度、稳定性和可维护性都要一起考虑。4.1 推理流程编排与结果输出格式我的部署方案是把训练好的best.pt转成ONNX再转成TensorRT的engine以获得最大的推理速度提升相机采集的图像帧直接在预处理层做缩放统一送到推理引擎推理结果输出为JSON格式每一条包含类别、置信度、框坐标同时把原始图像和画框后的可视结果都存到本地对置信度大于0.7的直接上报小于0.3的直接丢弃0.3到0.7之间的低置信度结果单独保存到一个待人工确认目录。低置信度结果单独处理的这个设计非常有必要。钢轨现场在雨天、逆光、脏污的情况下模型会把油渍、水渍当作缺陷这些误报在0.5到0.7置信度区间很常见。直接丢掉怕漏检全部上报又会让检修人员崩溃。单独归档让人工扫一眼操作路径最简单可靠。4.2 Tiny缺陷与NMS参数对检测结果的影响训练好的模型在部署时NMS参数是需要调整的。Yolov5默认NMS的IOU阈值是0.45我测试中发现钢轨缺陷场景里相邻的多个小缺陷非常容易被NMS合并掉。比如轨面上连续排列的斑点每个斑点都是独立缺陷但它们之间的IOU较高默认参数下几个框会被当成同一个目标保留一个。我做了参数寻优最终把IOU阈值提到0.5同时把置信度阈值降到0.25这样小目标漏检率明显下降代价是几个重叠较大的误报框会同时出现但后续反正要人工复核这个代价可以接受。对于Tiny目标Yolov5自身对小目标的召回不够。我在项目里还做了一步切成瓦片的策略也就是把1280分辨率的输入图再均匀切分成两张或者四张分别推理再合并结果。这个操作的收益非常明显小裂纹单独放在子图里能得到更多有效像素参与检测比单纯提升输入分辨率性价比更高。4.3 TensorRT转换的精度损失与修复经验TensorRT的FP16推理会把模型体积缩小一半、速度提升一倍但精度会有轻微下降在小缺陷检测场景里这个下降可能不小。我实测的FP16推理相比FP32推理mAP0.5:0.95大约下降了2到4个百分点而裂纹这类小目标的召回率下降更明显。解决办法有两个方向如果工控机性能足够优先用FP32的TensorRT模型如果必须FP16建议在训练时把输入分辨率再加大一档或者对低置信度结果的多级筛选条件放宽一点给FP16模型留出容错空间。还有一次踩坑是TensorRT转换后预测框有整体偏移排查下来是图像预处理时多了一次不必要的格式转换导致输入张量的像素值范围不对。TensorRT的输入必须和训练时预处理管线的处理逻辑完全一致不能随意改变归一化方式。4.4 实际场景的综合效果评估在我的模拟测试中把装配好的检测小车推到一段锈蚀比较严重、且存在一条人工设置的横向裂纹的钢轨上以正常的巡检速度通过模型对裂纹准确报警剥落区域也有多帧连续检出。整体效果如下评测项实测结果推理帧率TensorRT FP16约24 FPS满足低速巡检需求横向裂纹召回率多帧连续检出轨迹稳定锈蚀区域精确率约0.87存在少量与油渍混淆误报率干燥环境较低雨天约10%偏高雨天误报偏高这个问题花了很长时间才控制住。最后做了两件事一是加了多帧确认逻辑同一区域连续多帧都报警才输出最终结果单帧偶发误报会被直接滤掉二是把雨滴、水渍这类干扰样本单独加了大约500张图参与二次训练模型对水渍和裂纹的区分能力明显提升。这个思路是通用的上线后收集误报样本持续迭代训练比任何代码层面的修补都更治本。5. 训练好的模型和数据集之外我给同样做这个方向的朋友们的建议这个项目做完之后我最大的体会是Yolov5相关的代码、权重、数据集可能网上都能找到但真正决定一个钢轨缺陷检测系统能不能用的是对业务场景的理解深度。三个最值得注意的方向。第一数据采集时不要只为了攒够数量而采集每一张图的场景多样性、光照条件、缺陷形态都要有记录后期扩展类别或优化模型时这些元信息比标注本身还值钱。第二不要迷信最新的网络结构在工业界成熟稳定、可复现、可维护比单点指标更重要我见过不止一个项目因为追求新结构导致部署周期拉长最后又退回Yolov5。第三训练好的模型只是起点必须有持续的数据回流和模型迭代机制否则上线三个月后场景变化精度会肉眼可见地掉。关于数据集训练好的模型这个交付模式我给个实际建议直接用现有的开源缺陷数据集训练可以快速验证流程但距离真正上线还差着好几个量级的自采数据。如果条件允许尽量自己搭建一个采集装置哪怕一开始是简陋的攒出来的第一手数据才是这个项目真正值钱的部分。模型可以重新训练但好数据是唯一不可替代的资产。最后分享一个小的实操习惯每次训练前把同一份验证集固定下来和上一次训练出来的模型做对比评测不只看最终指标还要单独看每一类的召回率变化。这样每次改动是变好还是变坏心里清清楚楚。这个习惯让我少走了很多弯路也希望你们用上。