铁路轨道故障图像识别:380张标注数据如何训练YOLO小模型

发布时间:2026/10/6 18:55:58
铁路轨道故障图像识别:380张标注数据如何训练YOLO小模型 简介铁路轨道故障图像识别数据集适用于深度学习图像分类任务主要面向轨道交通运维、缺陷检测方向的开发者和学习者用来训练区分轨道损坏与未损坏状态的二分类模型。包内包含约380张已标注图像并按照训练集、验证集、测试集预先划分json文件提供了具体类别标签减少自行标注和整理的工作量。整个压缩包共387个文件以jpg、jpeg图片为主体附带1个py脚本用于数据可视化、1个json标注文件资源大小为159.73MB结构清晰便于直接读取和使用。目前已有192人浏览学习。借助配套的show脚本读者可直观查看样本与标签分布快速评估数据质量数据集既适合入门者实践图像分类流程也可用于CNN分类网络或YOLOv5分类方案的训练对比降低轨道缺陷识别项目的启动成本。1. 铁路轨道故障图像识别数据集380张已标注图像究竟能撑起什么任务一个已标注的铁路轨道故障图像识别数据集规模固定在约380张这个量级常给人“太少”的第一印象。但做过实际项目的人会清楚380张已标注图像如果处理得当完全能支撑一个分类器甚至一个轻量检测器从零到一完成。关键不在数量本身而在标签粒度、类别分布和标注质量。常见做法是拿到数据后的第一件事不是急着训练而是先把标签文件、图像尺寸、类别映射逐项盘一遍。这个数据集解决的是“能不能用视觉模型在轨道巡检图片里自动抓缺陷”这个问题适合三类人一是做轨检小车或无人机巡检算法的工程师需要种子数据二是试水图像识别但在数据标注上预算有限的团队三是想了解已标注数据集价值、准备立项做轨面异常识别的人。这篇文章会顺着数据梳理、任务定义、模型训练、边界避坑到阈值调优这条线把每一步落地方案和参数讲清楚。2. 先看清任务边界轨道故障图像识别的缺陷类型、标注粒度与任务选型2.1 轨道“故障”在视觉上到底长什么样轨道故障图像识别不是识别一个“轨道”对象而是找出轨道上的异常。按工务常见分类大致有这几种能靠光学图像分辨的缺陷钢轨裂纹轨头、轨腰或轨底的细微裂缝图像识别里最难的一类因为背景纹理和裂纹在灰度上高度接近尤其当裂纹宽度只有几个像素时很容易被模型当成噪声过滤掉。剥离掉块与鱼鳞伤轨头表层金属呈片状脱落表面形成不规则的暗色凹坑在侧光照射下有一定立体感但光线不足时看起来只是脏污。轨头磨耗主要出现在曲线段外侧轨头轮廓发生明显变形在图像中表现为带状高光或轮廓异常。扣件缺陷扣件缺失、松动、断裂、锈蚀严重。这是沿线数量最多的零部件很多轨道故障数据集里扣件类样本占比很大也是图像识别最容易见效的一类。轨枕与道床异常轨枕裂纹、道砟污染或异物侵入这类目标尺寸较大识别难度最低但容易出现“背景正常但是光照异常导致误报”的问题。图像识别在轨道场景的落地形态通常有两种一种是安装在轨检车上的线阵面阵相机连续采集轨面图像后台自动抓取缺陷另一种是无人机或手持设备拍摄定点照片识别是否有缺陷、缺陷在画面中的像素位置。后者就是这份380张已标注数据集最常见的用武之地静态图像标好框或类别能直接作为无人机巡检图像识别系统的种子数据。2.2 380张已标注图像能撑起什么任务这里先给一个直接结论图像级分类任务直接做目标检测属于“能跑通但精度受限”像素级分割不建议一上来就上。图像级分类也就是判断这张图里有没有故障380张已标注图像如果正负样本大致均衡基于ImageNet预训练的ResNet18或ResNet34做微调配合数据增强验证集准确率可以到90%以上。即使样本里带一点噪声也不会导致训练崩掉。目标检测也就是输出缺陷框位置如果标注是bounding boxYOLOv8n或YOLO11n这类轻量模型能跑通但必须开较强的增强、做k折交叉验证否则验证mAP会一直抖动。380张框标注用于检测大约相当于一个完整数据集的15%到20%数据量可以达到可演示但不够稳定的效果。像素级分割不建议。分割本质上是像素级密集分类极其依赖数据量380张只能作为预标注或半自动标注的底料离可用效果差距比较大。多数宣称“铁路轨道故障图像识别数据集”的打包文件按常见做法是框标注和类别标注兼有。拿到手先打开标签文件看一眼确认到底是分类还是检测是第一件事不是直接训练。2.3 检查标注文件值不值得用的三个判据拿到数据集后我先按三个判据决定是否值得投入时间。第一标签文件是否与图像一一对应这是最常见的坑标签文件比图像少几十份多出来的图像可能是空标签负样本也可能只是漏标必须去CSV或JSON里确认而不是靠文件名猜。第二框坐标是归一化YOLO格式还是像素COCO格式如果混了训练时损失根本降不下去框会全部偏到图像外。第三类别列表是单类还是多类如果是多类要统计每类实例数避免出现某类只有5个框的情况。标框质量方面还要看长宽比。有些标注会把一个横跨半幅画面的裂纹画成巨大的矩形框这在检测任务里基本没有意义因为框内大部分是正常纹理模型学到的不是“裂纹”而是“大面积偏暗区域”。遇到这种情况常见处理是把大框手工拆成多个小框或者放弃定位任务、只做图像级分类。2.4 与公开数据集对比为什么轨道场景要单独考虑领域差异很多公开图像识别数据集在视觉上看起来很“规整”例如CCPD车牌数据集目标占画面比例大HRSC2016遥感舰船数据集背景相对单一这些数据集训练的模型直接搬到轨道场景都会失效。轨道缺陷数据集的特殊性有三个目标是细长或小块的异常区域不能套用“物体在画面中央”的先验背景是轨枕、道砟、扣件和钢轨纹理重复度极高模型会不自觉去学背景纹理同一缺陷在不同光照、锈蚀程度和拍摄角度下视觉差异很大。所以选模型时不宜一上来就用大网络。以YOLO为例从YOLOv8n或YOLO11n起步比直接从YOLOv8x开始要稳得多大模型在小数据集上非常容易复刻训练集噪声而且推理成本对巡检边缘设备不友好。对大目标识别有经验的人在做轨道场景前最好先把“小目标 纹理背景 光照变化”这三个点刻在脑子里。3. 把380张已标注数据梳成训练集格式统一、切分与均衡3.1 数据包的结构第一件事是盘文件拿到数据集先不要急着跑训练。用下面命令看结构和文件数量find . -type f -name *.jpg | wc -l find . -type f -name *.png | wc -l find . -type f -name *.txt | wc -l find . -type f -name *.json | wc -l这里最关键的检查是图像数量与标签数量是否一一对应。例如宣称约380张数据如果标签只有350份说明存在“空标签”图或漏标图。空标签图中若全部是正常轨道应当保留作为负样本若是有缺陷但没标签混进训练集则会把模型带偏。接下来用Python脚本检查标签内容与类别分布import os from glob import glob from collections import Counter img_dir images label_dir labels label_files glob(os.path.join(label_dir, *.txt)) print(f标签文件数: {len(label_files)}) cls_counter Counter() img_with_no_label 0 for img_path in glob(os.path.join(img_dir, *.jpg)): # 假设图像文件名与标签名一致仅后缀不同 base os.path.splitext(os.path.basename(img_path))[0] lbl_path os.path.join(label_dir, base .txt) if not os.path.exists(lbl_path): img_with_no_label 1 continue with open(lbl_path) as f: for line in f: parts line.strip().split() if len(parts) 1 and parts[0].isdigit(): cls_counter[int(parts[0])] 1 print(f无标签图像数: {img_with_no_label}) print(f各类别框数量: {cls_counter})逻辑说明这个脚本只做两件事——核对文件名对应关系并统计每个类别的实例总数。标注目录和图像目录可以按YOLO的约定组织images存放原图labels存放同名txttxt每行格式为“class_id cx cy w h”且坐标已归一化。如果检查出txt内容是五列浮点数但第一列不是整数大概率是归一化坐标文件如果出现大于1或小于0的坐标说明标签没有归一化或越界需要在后面统一处理。参数说明脚本里的img_dir和label_dir需要按实际路径改glob用的扩展名这里写成jpg实际数据也可能是png或bmp。我一般会把所有图像统一转成jpg再训练统一后缀能避免DataLoader阶段隐式格式不一致的问题转换用Pillow一行命令即可不要在数据集目录里保留两种扩展名。3.2 固定切分70/15/15还不够要用分层抽样380张数据做训练最忌讳的是“从头随机分配”。缺陷是长尾的如果某一类样本只集中在训练集或验证集里验证指标会严重失真。常见做法是用Scikit-learn的StratifiedShuffleSplit按图像级类别做分层切分而不是按文件顺序乱切。import numpy as np from sklearn.model_selection import StratifiedShuffleSplit # 以单标签分类为例image_names 是图像文件名列表image_labels 是其类别 X np.array(image_names) y np.array(image_labels) split StratifiedShuffleSplit(n_splits1, test_size0.3, random_state42) for train_idx, val_idx in split.split(X, y): train_names, val_names X[train_idx], X[val_idx] # 把训练集再切一次得到 train/val/test 三个子集逻辑说明第一次切出70%训练、30%临时验证第二次在30%里再切一半作为验证和测试。两层嵌套的写法比一次性三分干净因为可以控制每一层的类别比例一致。对小数据集验证集和测试集至少要各留50张以上太少的话一次随机波动就把指标拉掉五个点。参数说明random_state必须固定否则复现实验时指标对不上。如果数据集中某些类只有1到2张图分层抽样会报错这时需要先把长尾类别合并成“其他缺陷”类再做切分。380张规模下建议优先保证每个类别在训练集中至少出现五张以上。3.3 类别分布严重不均重采样、合并与权重检查完类别数量后遇到某类只有几个框的情况常见处理路径有三条。第一对数量少的类做重采样整图复制或局部裁剪复制让其在每个epoch出现次数增加第二把细粒度类别合并成单类例如把“裂纹”和“剥离掉块”合并成“轨面伤损”先保证模型学会“找出异常区域”第三训练时引入类别权重让少数类的loss贡献放大。以ultralytics YOLO为例data.yaml可以这样组织# dataset.yaml train: ./train val: ./val # 0 正常1 轨面伤损2 扣件缺陷 nc: 3 names: [normal, surface_damage, fastener_defect]逻辑说明yaml里的类顺序必须与标签txt中的数字完全对应这是模型能训练起来的第一前提。很多人在这一步翻车标签文件里是0和1两类但yaml里写了3个类结果训练时模型把0当背景、把1当第二类mAP显示异常还不明所以。参数说明如果打开训练日志发现cls_loss降不下来而box_loss很低几乎可以断定是类别映射错乱优先检查data.yaml和标签txt的对应关系。另一个值得注意的点是在detect任务里背景是隐式类不需要在yaml里写normal类如果一张正常轨道图没有框它自动成为背景样本。3.4 做一次标签可视化把标注框画回图上这个步骤很多人跳过但在小数据集上极其值得做。把标签画回原图人眼扫一遍通常只需要半小时能发现的错误比任何脚本都多。import cv2 def draw_yolo_labels(img_path, label_path, class_names): img cv2.imread(img_path) h, w img.shape[:2] with open(label_path) as f: for line in f: cid, cx, cy, bw, bh map(float, line.split()) x1 int((cx - bw / 2) * w) y1 int((cy - bh / 2) * h) x2 int((cx bw / 2) * w) y2 int((cy bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.putText(img, class_names[int(cid)], (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1) return img逻辑说明这段代码把归一化框坐标换算成像素坐标并画框。巡检图片里经常出现框只框住裂纹的一半、或者把扣件和钢轨一起框进去的情况人眼扫一遍就能发现。参数说明class_names列表要和data.yaml里的names顺序保持一致否则名字张冠李戴。建议每隔五张图抽一张做可视化380张全画出来也可以关键是扫图时对框的精度心里有数。4. 基于YOLO跑通铁路缺陷识别基线模型选型、关键参数与增强策略4.1 模型选型为什么是YOLOv8n而不是更重的网络轨道故障识别属于小目标检测数据量又只有380张模型越重越容易过拟合。YOLOv8n以640输入尺寸在单张显卡上能跑到百帧级参数量只有3.2M左右适合巡检小车或边缘设备部署。YOLO11n是后续轻量版本特征复用效率更高但如果没有对应预训练权重稳妥起见先选YOLOv8n。用ultralytics工具链跑训练一般是这样pip install ultralytics yolo detect train \ datatrack_fault.yaml \ modelyolov8n.pt \ epochs150 \ imgsz640 \ batch16 \ patience30 \ lr00.01 \ cos_lrTrue \ augmentTrue \ project./runs \ nametrack_fault_v1逻辑说明这些参数针对“380张小样本”场景做过取舍。patience30意味着30个epoch验证指标不改善就早停避免小数据集上跑满150个epoch后彻底过拟合cos_lr让学习率沿余弦曲线下降比阶梯下降更适合小数据集的精细收敛batch16受限于显存同时配合增强策略能让每个epoch看到更多样本组合。参数说明lr00.01对yolov8n.pt做微调可以如果用随机初始化的yolov8n.yaml从头训练建议降到0.005否则前几个epoch会出现loss震荡。imgsz640对细长裂纹其实不够但380张数据里如果原图分辨率高先640跑通再进阶到1024是合理路径。如果标签只有图像级类别没有框就不能用detect任务要改用分类yolo classify train \ data./cls_dataset \ modelresnet18.pt \ epochs100 \ imgsz224 \ batch32逻辑说明cls_dataset目录结构一般是train/和val/两个目录每个类别一个子文件夹。分类任务的收敛速度比检测快得多380张图足够支撑ResNet18微调。4.2 关键参数再解释早停、mosaic与rect在ultralytics中训练默认会开启mosaic和fliplr增强。对于轨道缺陷我的经验是mosaic必须开它把四张图拼接成一张新图等效于把样本组合数量放大数倍让模型在不同光照和背景组合下学习缺陷。但细长裂纹经过mosaic拼接后会被压缩到很小建议确认mosaic_scale范围不要太小避免目标缩到十个像素以下。水平翻转方面钢轨缺陷大多没有左右语义裂纹从左上到右下翻转后从右上到左下仍然成立fliplr可以开。但如果标注涉及“左轨扣件”“右轨扣件”这种方向性类别必须关掉。亮度对比度增强对轨道场景极其重要。隧道内、树荫下、逆光拍摄的轨道图光照差异很大hsv_v扰动建议给到0.03到0.05hsv_s扰动0.5到0.7。这样做能让模型不那么依赖整体亮度而更多依赖局部对比度。4.3 用K折交叉验证代替单一数据划分第3章里70/15/15是建立基准的方法。380张图做离线评估时单一划分的方差很大某次划分到验证集的都是清晰裂纹指标就虚高下一次划分到验证集的都是锈蚀背景指标又塌下去。常见做法是把数据集做5折交叉验证轮流用4/5数据训练、1/5数据验证最后综合五个模型的平均mAP。from sklearn.model_selection import KFold kf KFold(n_splits5, shuffleTrue, random_state42) fold_index 0 for train_idx, val_idx in kf.split(image_names): with open(ffold{fold_index}_train.txt, w) as f: for i in train_idx: f.write(image_names[i] \n) with open(ffold{fold_index}_val.txt, w) as f: for i in val_idx: f.write(image_names[i] \n) fold_index 1逻辑说明YOLO训练时data.yaml可以指向包含图像路径列表的txt文件而不是目录。这段脚本生成五组划分文件每组对应一折的train和val。每一折独立训练后用同一组指标对比最终取平均值作为数据集真实水平。参数说明KFold只保证随机划分不保证类别均衡。类别极不均衡时应改用StratifiedKFold。五折训练会产出五个模型部署时不要五个模型做投票常见做法是选验证mAP最高的一折作为最终部署模型其余折作为测试参考。4.4 第一次训练结果怎么看训练结束后看两样东西。第一是训练曲线train_loss持续下降、val_loss先降后升说明过拟合已经发生需要提前停或增加增强val_loss和train_loss同步下降且差值不大说明模型还在正常学习。第二是PR曲线在val集上输出的precision和recall曲线如果曲线下面积集中在高置信度区间说明模型对自己的判断比较自信如果曲线在中低置信度区域才抬升说明缺陷和背景的区分度不足。ultralytics训练完会在runs目录下生成results.png和confusion_matrix.png。重点关注混淆矩阵中缺陷类被错分成背景的比例这比mAP数值更直观。如果背景类误报率高先检查负样本是否充足如果缺陷类漏检多先看是不是该类别实例数太少。5. 380张已标注数据训练后的避坑排查过拟合、脏标签与类不均衡5.1 现象训练loss降到很低、验证mAP抖动或居高不下这是小数据集上最常见的翻车现场。训练loss一路降到0.03验证mAP却在不同epoch之间大幅震荡甚至还在0.2附近徘徊。原因不是“网络不行”而是模型在训练集上直接记住了特定图像的光照、纹理和拍摄角度并没有学到“缺陷模式”。验证集里出现相似背景时指标短暂走高下一张分布略差就掉下来。解决路径有三个层次。第一先把patience降到20用早停拦住过拟合第二检查是否所有正常轨道图都混入了训练如果只有缺陷图没有正常图模型会把一切轨道纹理当作故障必须补充负样本到缺陷样本的1.5到2倍第三降低imgsz到512让模型更关注局部纹理而非整图布局。5.2 现象空标签图片和重复框让检测器行为异常一个380张的数据包里往往混着几张“看起来有缺陷但没有任何框”的图像或者同一个缺陷被两个标框重复覆盖。空标签图会被当作背景负样本训练如果里面其实有缺陷模型就被反复教导“这种裂纹不算正样本”推理时遇到同类缺陷置信度极低。重复框则会让模型产生尺寸上的混乱同一个目标要输出两个框。原因是标注阶段采用了不同标注员或半自动标注工具审核不严。解决方法是清洗标签写脚本检测同一图像中IoU大于0.7的框对保留面积大的那个同时把所有无标签图像拿出来人工判断是负样本还是漏标。380张规模的清洗工作量不大但影响远大于换模型结构。5.3 现象某一类缺陷完全学不出来检测结果几乎为0原因多半是类别实例数太少。例如扣件缺失可能只有12个实例集中在3到5张图像里即使class_weight默认设1模型也很难从这种数量里学到泛化特征。解决方式不是换网络而是先做重采样把含扣件缺失缺陷的整张图复制五份放回训练集配合mosaic和随机光照增强让它在每个epoch里多次出现。等验证集该类recall开始上升再逐步还原复制比例。另一个解决方向是合并类别。如果业务只需要判断“有没有故障”把多类合并成单类380张图里的全部缺陷实例一起参与训练检测器的召回率会明显提升。等后续数据扩充后再分裂成细粒度类别这是一条很实用的缓坡路线。5.4 现象图像分辨率不一致导致检测框集中在某个尺度如果数据里既有1920乘1080大图又有640乘480小图直接统一缩放到640会洗掉小图的细节大图里的裂纹也被缩小到不可见。解决方式是先记录每张原图长边分桶训练让分辨率相近的图像进入同一个训练配置或者使用ultralytics的rect模式按原始宽高比做batch填充。但rect模式会影响batch组成380张数据规模下建议直接手动分桶更稳妥。如果标签文件是像素坐标而数据中存在不同分辨率图片需要统一转成归一化坐标def convert_xyxy_to_yolo(x1, y1, x2, y2, img_w, img_h): # VOC格式像素框 - YOLO归一化框 cx (x1 x2) / 2 / img_w cy (y1 y2) / 2 / img_h bw (x2 - x1) / img_w bh (y2 - y1) / img_h return cx, cy, bw, bh逻辑说明这里一次性把所有像素坐标转换为YOLO格式归一化框。转换后建议抽样可视化而不是直接相信坐标数字。参数说明x1、y1、x2、y2是像素整型坐标img_w和img_h是从原图读取的实际宽高不是统一缩放后的宽高。很多人在这里忽略一旦用了LetterBox填充坐标会整体偏移必须在转换前先把padding扣除。6. 把380张数据的识别系统推向可落地阈值校准、可视化验证与主动扩标对于这种规模的已标注数据模型跑通只是第一步真正能上线边缘设备还需要三步调优用验证集校准置信度阈值用可视化确认模型看的是缺陷而非背景纹理用主动学习扩标下一批数据。6.1 用验证集校准置信度阈值YOLO默认的conf阈值是0.25但在小样本数据集上这一阈值常常不是最优的。常见做法是从验证集统计不同conf下的精确率和召回率找到F1最高的一点作为部署阈值。实际项目里我一般保留两个阈值硬阈值用于自动告警取值0.4到0.45之间比默认值高宁可漏掉少数并清晰报告也不刷屏软阈值用于生成候选列表供人工复核取值0.15左右。380张数据规模下背景多样性不足模型对相似背景易给出过高置信度这是把阈值调高的原因。6.2 用可视化验证模型关注的区域检测模型没有分类模型那样直观的Grad-CAM但有替代方式对验证集里的含缺陷图做推理把预测框和标签框重叠输出成一张对比图人工确认预测框是否贴合缺陷位置。如果预测框总是偏向图像边缘说明模型在利用图像边界的光照差异需要增加随机裁剪或光度增强。如果预测框总是框住整块扣件区域而不是缺失部位说明标注本身框选范围过大需要回到第3章的标签可视化步骤修正。6.3 主动扩标380张不是终点把现有模型对未标注图像做推理按置信度从低到高排序。置信度最低的那批往往是特征模糊、最难判别的样本优先把这批交给人工标注比随机抽样更高效。实际操作时我把新标注数据与旧数据合并后重新做五折交叉验证对比新增前后的val mAP。只有数值涨了才说明这批标注值得加入如果没涨回第5章继续清理标签噪声。轨道小目标识别的数据边际收益在几百到几千张区间非常明显这也是很多已标注数据集即便只有380张仍然值得作为种子项目启动的原因。我的习惯是训练后把最低置信度的30张预测图单独存一个目录随手截图写两行注释。这个习惯帮我快速发现模型在“装懂”的阶段有些缺陷拍得清晰模型早早就给出高置信度而真正模糊的缺陷需要人工复核。希望帮到你。本文还有配套的精品资源点击获取