YOLOv5钢轨表面缺陷检测实战:从数据准备到部署优化

发布时间:2026/10/23 6:59:47
YOLOv5钢轨表面缺陷检测实战:从数据准备到部署优化 1. 项目全貌与系统框架拆解先交代一下背景。我前阵子接了一个跟轨道检测相关的视觉项目需求很直接从轨道巡检车拍回来的高清图像里自动标出钢轨表面存在的裂纹、擦伤、剥落之类缺陷。数据量不算大也就几千张标注图但场景很典型——户外光照变化大、钢轨表面反光强、缺陷形态又碎又小。方案从传统图像处理一路对比到多个检测模型最后还是定在YOLOv5上。这篇就把整套代码逻辑从头到尾拆一遍为什么选它、数据怎么组织、训练怎么调、推理怎么做以及那些文档里不会写的坑。先说结论YOLOv5这套框架在工业缺陷检测里确实够稳。社区生态成熟、代码结构清楚、部署链路完整从训练到导出再到落地推理几乎每一步都有现成方案可以抄。拿它做钢轨表面缺陷检测本身就是一条被反复验证过的路径我这边做的主要工作是把它适配到轨道场景的具体细节上——数据组织、参数配置、后处理策略以及针对小缺陷的几个关键调整。这个内容适合谁看如果你正在做工业质检、缺陷识别相关的视觉项目或者刚接触YOLOv5想找一个真实场景的完整案例这篇文章都能给你省不少时间。我会把代码仓库的核心模块、训练流程、推理脚本都过一遍重点讲清楚那些不跑一遍根本发现不了的问题。整个系统从功能上可以分为五块数据准备环节负责把巡检图像转成训练所需的格式模型训练环节负责拟合缺陷特征验证评估环节负责衡量模型效果推理检测环节负责把模型用起来最后的部署优化环节负责让模型跑得更快。下面按照这个链路逐一展开。因为YOLOv5的代码生态已经很成熟仓库结构和基础逻辑大多数人都眼熟我不会逐行复述源码而是挑出跟钢轨缺陷检测强相关的部分做深度解析——数据怎么配、anchor怎么调、小目标怎么处理、后处理参数怎么设这些才是真正决定模型能不能用的地方。1.1 钢轨缺陷检测的痛点决定了技术路线钢轨表面缺陷检测这个场景跟通用目标检测有一个显著区别缺陷目标极小。典型的钢轨表面裂纹宽度可能只有两三个像素长度几十个像素在整张1920×1080的巡检图像里占比非常低。如果直接用默认参数训练YOLOv5小目标漏检问题会非常突出。另一个痛点是背景干扰。钢轨表面本身就有纹理、锈迹、水渍、油污再加上户外拍摄的光照变化和相机反光很多背景区域长得比缺陷更像缺陷。用传统视觉方案去处理比如边缘检测加形态学过滤面对固定场景还能凑合一换光照、一换钢轨型号就全线崩溃。反观深度检测模型YOLOv5这类单阶段检测器天然就比传统方案抗干扰因为它学的是高维语义特征而非手工设计的低层特征。在实测对比中同一个钢轨表面缺陷数据集传统方案的最好成绩也只有不到六成的召回率而YOLOv5s在相同数据上能达到九成以上的召回率。这个差距是决定性的。1.2 为什么最终没有选YOLOv8或其他框架每次提到选型总有人问现在YOLOv8都出来了为什么还用v5答案不复杂。YOLOv5的生态积累足够深文档、教程、预训练权重、部署方案都是最齐全的。对于我们这个场景模型的绝对精度差异并不大但调试便利性和可参考案例的丰富程度差别很大。遇到问题想搜解决方案v5版本基本都能搜到v8相对少很多。还有一个实际考量是部署兼容性。钢轨巡检系统的落地环境以工业PC为主有些还是老旧工控机对CUDA版本和驱动版本有严格限制。YOLOv5对PyTorch版本的要求更宽泛ONNX导出也更稳定在受限的工业环境里不容易翻车。至于最新版本带来的速度提升在钢轨巡检这个每秒处理一帧就够用的场景里并不构成核心优势。2. 数据准备与标注规范——决定模型上限的第一步在这个项目里数据准备占掉了大约六成的工作量。模型结构可以抄现成的训练参数可以照搬但数据不行——每个场景的数据都得自己采集、自己清洗、自己标注。而且数据质量直接决定模型上限后面所有的调参优化都只能在这个上限内做文章。2.1 缺陷类别定义与标注规范我这边将钢轨表面缺陷划成了四类裂纹、擦伤、剥落、压溃。这个分类跟轨道维护人员的习惯保持一致。如果分类粒度太粗不同形态的缺陷混在一起模型训练时特征冲突精度上不去如果粒度太细比如把裂纹按长度再细分几个等级类间差异又太小标注一致性很难保证模型也学不出区分度。标注规范这件事特别重要也是很多项目翻车的地方。钢轨裂纹形态不规则标注时最常用的原则是“最小外接矩形”——框住缺陷的主体区域即可不需要把每一条细小分叉都包进去。但如果多人协作标注每个人的框选习惯不一样最终数据里同类缺陷的框大小差异会非常大直接影响回归头的收敛效果。我处理这个问题的方法是先做标注规范文档再对标注结果做一致性抽检。具体做法是计算每个类别的平均宽高比分布如果某个标注者的结果明显偏离群体平均值就要回头重新校对。实测下来这一步能有效避免训练时box_loss震荡的问题。2.2 钢轨缺陷数据集的目录结构与格式YOLOv5的数据组织遵循固定的目录规则钢轨缺陷数据集按照这个规则组织后训练时不需要额外写数据加载逻辑。核心是images和labels两个主目录各自再拆成train和val子集。标注文件跟图片一一对应是同名的txt文件每行代表一个目标框。标注文件每行的格式是五个数值类别索引、归一化中心x坐标、归一化中心y坐标、归一化宽度、归一化高度。注意YOLOv5的坐标全部是归一化后的值归一化基准是图片宽高而不是边长。如果转换标注时用错基准模型训练后会出现预测框整体偏移一个方向的问题而且loss降不下去。对于钢轨缺陷这种小目标数据有一个额外建议原始高清图不要直接缩放到训练尺寸。一张1920×1080的图直接缩到640分辨率很多细小裂纹会直接消失。更好的做法是先用切片脚本把大图切成若干小块保留缺陷的原始像素信息再做缩放。钢轨巡检图像切成四个512×512的小块后小缺陷的保留效果明显改善。2.3 数据增强策略在钢轨场景的取舍YOLOv5内置的Mosaic增强在大多数场景都好用但钢轨缺陷检测这里要留个心眼。Mosaic会把四张图拼在一起训练如果四张图的亮度差异太大模型会学到一些奇怪的亮度特征。我的做法是开启Mosaic但把mixup概率降到很低同时强化HSV增强里的饱和度变化因为钢轨表面缺陷的颜色特征本来就以暗色为主饱和度扰动有助于模型忽略颜色干扰、专注形状特征。钢轨场景还需要增加一种平移和旋转的增强强度。巡检图像中缺陷出现的位置随机性强角度也随机适度加大仿射变换的幅度可以提升泛化能力。但不要开太大否则缺陷形变失真模型反而学到不真实的形态。3. 核心训练逻辑与代码模块拆解数据和配置准备好之后真正进入训练环节。YOLOv5的训练代码虽然看起来庞大但核心逻辑并不复杂。我按从数据读取到损失计算这条主线来拆把关键模块和代码逻辑讲清楚。3.1 数据加载与标签匹配机制YOLOv5的数据加载响主要实现在datasets.py中核心类继承自PyTorch的Dataset。读取流程是按索引取图片路径和对应标注文件读取后做Mosaic等在线增强然后做Letterbox缩放统一尺寸最后归一化并转为Tensor。这里重点是构建了合理的预处理链路。标签匹配机制是YOLOv5的核心设计之一。模型每个输出位置有多个anchor输入标注框首先计算与这些anchor的宽高比匹配度高的分配为正样本参与预测和损失回传匹配度低的归为背景。这组anchor对钢轨缺陷这种长宽比差异大的场景需要调整策略——钢轨裂纹的长宽比可以到10比1但默认的anchor分布并没有覆盖这个极端范围。我这边处理方式是先用自己的数据集跑一次自动聚类用k-means生成更适合钢轨缺陷的anchor尺寸然后在模型配置文件中覆盖默认值。这是一个容易被忽视的步骤但对小缺陷检测效果的提升非常明显。实测中仅调整anchor这一步就让mAP提升了约3个百分点。3.2 损失函数设计与关键参数调节YOLOv5的损失由三部分组成分类损失BCE、目标置信度损失BCE和定位损失CIoU。在钢轨缺陷场景中这三部分的表现各有各的问题。分类损失容易出现过拟合倾向因为某些缺陷类别样本数量偏多。解决思路是开启类别权重给样本少的类别提高损失权重。置信度损失在缺陷检测中经常出现“什么都检测成目标”的现象原因是钢轨表面纹理复杂大量背景区域被误判为含目标。定位损失对缺陷这类小目标本身就比较严格因为CIoU会对中心点距离和宽高比差异敏感小目标的微小像素偏差就会导致损失值大幅波动。为了解决小目标定位难的问题我做了两个调整。第一个是增加输入分辨率把默认的640改成960让小目标占据更多像素。第二个是开启YOLOv5的P2检测层专门为小目标增加一层高分辨率特征图输出。这两个调整配合后细裂纹的召回率提升非常显著。3.3 训练过程解析——loss曲线的真实含义YOLOv5训练时终端会实时打印三类损失box_loss、obj_loss、cls_loss。很多人盯着这三个数看半天也不知道到底正常不正常这里说下我的判断经验。健康的loss曲线应该是三线同步下降在前50个epoch下降明显之后逐渐平缓。如果box_loss一直高位震荡不下降多半是标注问题——框选不准确或尺寸不一致模型怎么拟合都拟合不了。如果obj_loss降得很慢说明前景和背景的区分度不够需要回到数据增强上做调整。如果cls_loss降得快但验证集mAP不高大概率是过拟合了需要加大增强强度或增加样本量。我第一版训练时遇到过一个很典型的问题cls_loss在后期突然反弹。排查下来是因为验证集和训练集有图片泄露——数据增强过程中生成了大量视觉上非常接近的变体被错误地划到了验证集。修正划分逻辑后cls_loss曲线立刻恢复健康。4. 训练调参与性能评估的完整实操这一节把训练环节的可落地细节完整过一遍。包括硬件基准、超参数设置、训练命令、性能评估指标以及调参的优先级策略。4.1 硬件环境与训练超参数配置训练环境方面我用的是一张24G显存的显卡。钢轨缺陷数据集不算大单卡完全够用。如果你只有一张8G显存的卡也不是不能跑就是把batch size调小、输入尺寸降到640即可代价是训练时间变长。下面是我为钢轨缺陷场景最终采用的训练参数组合超参数推荐值说明输入尺寸960×960比默认640更能保留小缺陷细节Batch Size32根据显存调节不宜过小否则BN层不稳定初始学习率0.01配合余弦退火衰减曲线使用动量0.937延续默认值权重衰减0.0005防止过拟合Epoch300早停机制为patience50预训练权重YOLOv5m比s精度高比l训练快均衡选择学习率这块值得多说一句。YOLOv5默认使用SGD加上余弦退火调度。我试过用AdamW收敛确实更快更稳但最终精度略低于SGD。工业项目中模型的最终精度比训练速度重要所以最终用了SGD加余弦退火组合。4.2 模型规模选型与训练命令示例YOLOv5的模型规模从n、s、m、l到x共五档。对于钢轨缺陷检测直接用x级模型是没必要的——缺陷类别少、语义复杂度有限大模型带来的精度收益有限但推理成本大幅增加。折中方案是YOLOv5m精度比s有明显提升速度又比l快很多。训练时的命令行示例cd yolov5 python train.py \ --data rail_surface.yaml \ --weights yolov5m.pt \ --img 960 \ --batch 32 \ --epochs 300 \ --device 0 \ --cache \ --patience 50其中rail_surface.yaml是数据集配置文件必须保证类别名称顺序跟标注文件中的索引完全一致这是一个很容易出错的地方。如果yaml里第一个类别是crack但标注文件中索引0代表scratch训练不会报错但评估结果全乱。4.3 评估指标怎么读——不只是看mAP模型训练完成后可以用以下命令跑一轮验证python val.py --data rail_surface.yaml --weights runs/train/exp/weights/best.pt --img 960输出指标中mAP0.5是最常用的衡量指标但在钢轨缺陷场景里我个人更关注每个类别单独算的召回率。四类缺陷样本量差异较大平均数据可能把某些类别的劣势掩盖掉。比如整体mAP可能有0.85但单独看裂纹召回率只有0.7这个差距必须单独观察。另一个需要关注的指标是F1分数在0.25到0.5置信度区间的表现。工业场景中置信度阈值设置直接影响误报率和漏报率。如果模型在0.25置信度下的F1明显高于0.5置信度说明模型对低置信度的检测结果还有信息量可以在推理时适当降低阈值并配合更严格的NMS来抑制重复框。5. 推理代码实现与部署优化训练完成之后真正的挑战才开始。模型要在巡检车上跑起来还要跟现有的轨道巡检软件集成。这一节讲推理侧的代码实现和部署优化也是项目从技术验证走向产品化的关键环节。5.1 自定义推理脚本实现YOLOv5自带的detect.py可以直接用来做单张图片推理或者视频推理但实际集成场景中通常需要把检测逻辑嵌入到现有的巡检软件框架里。这时最好写一个自己的推理封装核心代码逻辑如下import cv2 import torch from models.experimental import attempt_load from utils.general import non_max_suppression, scale_coords from utils.plots import Annotator def load_model(weights_path, device): model attempt_load(weights_path, devicedevice) return model def letterbox(img, new_shape960): # 保持宽高比缩放并填充边缘 shape img.shape[:2] r min(new_shape / shape[0], new_shape / shape[1]) new_unpad int(round(shape[1] * r)), int(round(shape[0] * r)) dw (new_shape - new_unpad[1]) / 2 dh (new_shape - new_unpad[0]) / 2 img_resized cv2.resize(img, new_unpad, interpolationcv2.INTER_LINEAR) top, bottom int(round(dh - 0.1)), int(round(dh 0.1)) left, right int(round(dw - 0.1)), int(round(dw 0.1)) img_padded cv2.copyMakeBorder(img_resized, top, bottom, left, right, cv2.BORDER_CONSTANT, value(114, 114, 114)) return img_padded def detect(img, model, device, conf_thres0.25, iou_thres0.45): img_letterboxed letterbox(img) img_tensor torch.from_numpy(img_letterboxed).to(device) img_tensor img_tensor.permute(2, 0, 1).float().div(255).unsqueeze(0) pred model(img_tensor)[0] pred non_max_suppression(pred, conf_thres, iou_thres) return pred这段代码有两个细节值得注意。一是letterbox的填充逻辑不能省训练时输入图片是经过letterbox处理的推理时不处理的话输入分布不一致检测效果会明显退化。二是NMS的iou阈值在钢轨缺陷场景中不宜设得太低因为密集裂纹区域会有大量互相重叠的预测框如果iou_thres设成0.7以上重叠框会大量输出后处理时还要再过滤。5.2 推理坐标换算——最容易出错的环节推理完成后得到的目标框坐标是基于缩放后图像尺寸的需要按letterbox的反向逻辑映射回原图坐标。这一步出错的表现是框的位置偏离真实际目标通常偏向图像中心方向。def scale_boxes(orig_shape, pred, letterbox_shape): # pred为NMS后的检测结果格式为[x1, y1, x2, y2, conf, cls] pred[:, :4] scale_coords(letterbox_shape, pred[:, :4], orig_shape).round() return predYOLOv5的utils里已经封装好了scale_coords函数直接用就行。但注意传入的letterbox_shape必须是缩放填充后的完整尺寸而不是原始尺寸。我见过不少人在这一步传错参数导致所有检测框都偏移。5.3 模型导出与单帧性能优化训练好的PyTorch模型可以直接部署但工业场景中通常建议先导出为ONNX或TensorRT格式。ONNX的跨平台兼容性最好TensorRT在NVIDIA显卡上有最高推理速度。python export.py --weights runs/train/exp/weights/best.pt --img 960 --include onnx导出后可以用ONNX Runtime加载运行比原生PyTorch推理快不少。实测中同一个模型PyTorch单帧推理耗时约45ms转成ONNX后降到28ms转成TensorRT后进一步降到约15ms。对于钢轨巡检这种对实时性没有极端要求的场景ONNX格式已经够用。除了模型格式推理侧的优化还有两个方向。第一个是预处理优化把图像缩放方式从逐帧动态计算改成提前分配固定缓存。第二个是批量推理如果巡检系统同时处理多路相机图像把多帧打包成一个batch推理能显著提升整体吞吐量。6. 常见问题排查与调优实录这部分是实际踩坑的记录。我在钢轨缺陷检测项目里遇到的问题多数都是YOLOv5在工业数据上很典型的问题。整理成速查表形式方便遇到问题时快速定位。6.1 钢轨缺陷检测高频问题速查表问题现象可能原因解决方案box_loss高位震荡标注框尺寸不一致、错误标注重新审核标注统一标注规范裂纹类目漏检严重小目标在640下像素太少提升输入尺寸至960开启P2层调整anchor误报率高、背景被识别成缺陷光照不均、训练数据背景多样性不足增加HSV饱和度和曝光扰动采集更多背景负样本验证集mAP高于训练集数据划分时序错误导致泄露按原始图片切分而不是按增强后图片切分导出ONNX后输出shape不一致PyTorch版本与ONNX版本不兼容锁定torch1.x稳定版本导出时指定opset12推理时检测框整体偏移letterbox参数配置错误、scale_coords传参错误检查预处理与坐标映射环节参数6.2 小目标检测优化的三次迭代实例这个项目最有代表性的一段优化经历就是解决细裂纹漏检问题。第一版模型在960输入尺寸下整体mAP到了0.87但单独看裂纹类目召回率只有0.72。这个表现在工业场景里基本不可用因为漏掉裂纹比多报几个误检严重得多。我的第一次调整是改anchor。让YOLOv5在数据上聚类生成新anchor然后重新训练。跑完看结果裂纹召回率只提高到了0.76提升有限。主要原因是光调anchor不够模型提取小目标特征的能力还得靠网络结构配合。第二次调整是开启P2检测层。在模型配置里增加一层更高分辨率的输出特征层让小目标对应的特征图从80×80细分成160×160获得的特征信息更密集。这次效果明显裂纹召回率提高到0.83。第三次调整是把推理时的置信度阈值从默认的0.25降到0.15配合一个专门的NMS后处理逻辑先保留低置信度但跟高置信度框高度重叠的裂纹候选框。这一步把召回率提上了0.88。代价是误报率增加了但再通过验证集的置信度校准最终在误报可控的前提下把裂纹召回率稳定在了0.86左右。6.3 部署环境适配的几个坑工业落地场景中部署机器的软件环境比训练机器复杂得多。我遇到过的典型问题是巡检电脑的显卡驱动版本太老只支持CUDA 10.2以下的版本而训练环境里的PyTorch和CUDA版本都更高。导出的ONNX模型在推理机上直接加载失败。解决方案是模型侧不做修改纯粹靠导出时的兼容性参数来适配。把ONNX的opset版本设为12是兼容性最好的一个版本同时把动态输入改为固定尺寸输入。这样导出后的模型几乎可以在任何ONNX Runtime版本上运行不再依赖训练时的CUDA环境。如果部署机器没有NVIDIA显卡只能用CPU推理那YOLOv5m模型跑960输入的单帧时间可能接近300ms明显偏慢。建议是训练一个YOLOv5s模型专用于CPU环境的轻量部署。小模型在钢轨缺陷上精度差不了太多但CPU推理速度能快近一倍。有条件的话也可以用OpenVINO工具做推理优化实测CPU推理性能能有3倍左右的提升。7. 项目维护与模型迭代的经验总结项目上线不是终点模型还需要随着采集数据量的增加做持续迭代。重新训练模型前要把新采集的图像经过同样的标注流程加入数据集然后重跑一遍训练、评估、导出流程。这个过程有几个细节要注意新增数据必须按同样的规范标注新增数据在随机划分时要保证同一个缺陷不漏泄到验证集里模型迭代后要做回归测试确认新模型没有在旧数据上出现性能回退。我在实际维护过程中还发现了一个提高迭代质量的技巧每次收集到的新图像先人工快速筛选一遍把模糊、过曝、纯背景的丢出去避免无效数据稀释模型的学习效果。钢轨巡检车跑一天下来的数据量很大真正含有新缺陷形态的图像占比不高做好筛选能大幅提升每次迭代的效果。这个项目后续还可以往两个方向扩展。一是把单帧检测扩展到视频序列检测利用时序信息过滤误检这在连续性巡检场景中效果会很好。二是加入缺陷等级分类让系统不仅能检测缺陷位置还能输出缺陷严重程度给维护人员的维修决策提供参考。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询