钢轨表面缺陷检测这些年一直是工业视觉里"看着简单、落地要命"的典型场景。我在某轨道交通检测项目中折腾过一整套基于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,结果细小裂纹大量漏检,反而得不偿失。第二个是--hyp,Yolov5默认的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 指标解读:不能只看mAP@0.5项目验收的时候经常被问到指标,很多文章会直接说"mAP达到0.9以上"。但钢轨缺陷检测只报一个mAP远远不够。mAP@0.5衡量的是在IOU阈值为0.5时各类缺陷的平均精度,这个值对位置精度要求不高,主要看"框有没有大概框住目标"。实际缺陷定位对后续检修有实际意义,必须再看mAP@0.5:0.95,这个指标才是框准确度的真标准。我训练完的模型mAP@0.5能到0.92左右,但mAP@0.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推理,mAP@0.5:0.95大约下降了2到4个百分点,而裂纹这类小目标的召回率下降更明显。解决办法有两个方向:如果工控机性能足够,优先用FP32的TensorRT模型;如果必须FP16,建议在训练时把输入分辨率再加大一档,或者对低置信度结果的多级筛选条件放宽一点,给FP16模型留出容错空间。还有一次踩坑是TensorRT转换后预测框有整体偏移,排查下来是图像预处理时多了一次不必要的格式转换,导致输入张量的像素值范围不对。TensorRT的输入必须和训练时预处理管线的处理逻辑完全一致,不能随意改变归一化方式。4.4 实际场景的综合效果评估在我的模拟测试中,把装配好的检测小车推到一段锈蚀比较严重、且存在一条人工设置的横向裂纹的钢轨上,以正常的巡检速度通过,模型对裂纹准确报警,剥落区域也有多帧连续检出。整体效果如下:评测项实测结果推理帧率(TensorRT FP16)约24 FPS,满足低速巡检需求横向裂纹召回率多帧连续检出,轨迹稳定锈蚀区域精确率约0.87,存在少量与油渍混淆误报率干燥环境较低,雨天约10%偏高雨天误报偏高这个问题花了很长时间才控制住。最后做了两件事:一是加了"多帧确认"逻辑,同一区域连续多帧都报警才输出最终结果,单帧偶发误报会被直接滤掉;二是把雨滴、水渍这类干扰样本单独加了大约500张图参与二次训练,模型对水渍和裂纹的区分能力明显提升。这个思路是通用的:上线后收集误报样本,持续迭代训练,比任何代码层面的修补都更治本。5. 训练好的模型和数据集之外:我给同样做这个方向的朋友们的建议这个项目做完之后,我最大的体会是:Yolov5相关的代码、权重、数据集可能网上都能找到,但真正决定一个钢轨缺陷检测系统能不能用的,是对业务场景的理解深度。三个最值得注意的方向。第一,数据采集时不要只为了"攒够数量"而采集,每一张图的场景多样性、光照条件、缺陷形态都要有记录,后期扩展类别或优化模型时,这些元信息比标注本身还值钱。第二,不要迷信最新的网络结构,在工业界,成熟稳定、可复现、可维护比单点指标更重要,我见过不止一个项目因为追求新结构导致部署周期拉长,最后又退回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,结果细小裂纹大量漏检,反而得不偿失。第二个是--hyp,Yolov5默认的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 指标解读:不能只看mAP@0.5项目验收的时候经常被问到指标,很多文章会直接说"mAP达到0.9以上"。但钢轨缺陷检测只报一个mAP远远不够。mAP@0.5衡量的是在IOU阈值为0.5时各类缺陷的平均精度,这个值对位置精度要求不高,主要看"框有没有大概框住目标"。实际缺陷定位对后续检修有实际意义,必须再看mAP@0.5:0.95,这个指标才是框准确度的真标准。我训练完的模型mAP@0.5能到0.92左右,但mAP@0.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推理,mAP@0.5:0.95大约下降了2到4个百分点,而裂纹这类小目标的召回率下降更明显。解决办法有两个方向:如果工控机性能足够,优先用FP32的TensorRT模型;如果必须FP16,建议在训练时把输入分辨率再加大一档,或者对低置信度结果的多级筛选条件放宽一点,给FP16模型留出容错空间。还有一次踩坑是TensorRT转换后预测框有整体偏移,排查下来是图像预处理时多了一次不必要的格式转换,导致输入张量的像素值范围不对。TensorRT的输入必须和训练时预处理管线的处理逻辑完全一致,不能随意改变归一化方式。4.4 实际场景的综合效果评估在我的模拟测试中,把装配好的检测小车推到一段锈蚀比较严重、且存在一条人工设置的横向裂纹的钢轨上,以正常的巡检速度通过,模型对裂纹准确报警,剥落区域也有多帧连续检出。整体效果如下:评测项实测结果推理帧率(TensorRT FP16)约24 FPS,满足低速巡检需求横向裂纹召回率多帧连续检出,轨迹稳定锈蚀区域精确率约0.87,存在少量与油渍混淆误报率干燥环境较低,雨天约10%偏高雨天误报偏高这个问题花了很长时间才控制住。最后做了两件事:一是加了"多帧确认"逻辑,同一区域连续多帧都报警才输出最终结果,单帧偶发误报会被直接滤掉;二是把雨滴、水渍这类干扰样本单独加了大约500张图参与二次训练,模型对水渍和裂纹的区分能力明显提升。这个思路是通用的:上线后收集误报样本,持续迭代训练,比任何代码层面的修补都更治本。5. 训练好的模型和数据集之外:我给同样做这个方向的朋友们的建议这个项目做完之后,我最大的体会是:Yolov5相关的代码、权重、数据集可能网上都能找到,但真正决定一个钢轨缺陷检测系统能不能用的,是对业务场景的理解深度。三个最值得注意的方向。第一,数据采集时不要只为了"攒够数量"而采集,每一张图的场景多样性、光照条件、缺陷形态都要有记录,后期扩展类别或优化模型时,这些元信息比标注本身还值钱。第二,不要迷信最新的网络结构,在工业界,成熟稳定、可复现、可维护比单点指标更重要,我见过不止一个项目因为追求新结构导致部署周期拉长,最后又退回Yolov5。第三,训练好的模型只是起点,必须有持续的数据回流和模型迭代机制,否则上线三个月后场景变化,精度会肉眼可见地掉。关于"数据集+训练好的模型"这个交付模式,我给个实际建议:直接用现有的开源缺陷数据集训练,可以快速验证流程,但距离真正上线还差着好几个量级的自采数据。如果条件允许,尽量自己搭建一个采集装置,哪怕一开始是简陋的,攒出来的第一手数据才是这个项目真正值钱的部分。模型可以重新训练,但好数据是唯一不可替代的资产。最后分享一个小的实操习惯:每次训练前,把同一份验证集固定下来,和上一次训练出来的模型做对比评测,不只看最终指标,还要单独看每一类的召回率变化。这样每次改动是变好还是变坏,心里清清楚楚。这个习惯让我少走了很多弯路,也希望你们用上。