首页 / 资讯中心 / 文章详情

面向钢轨表面缺陷检测的改进YOLOv8:小目标召回与轻量化部署

面向钢轨表面缺陷检测的改进YOLOv8:小目标召回与轻量化部署 ★ FEATURED ARTICLE
1. 先把问题看清楚钢轨表面缺陷检测到底难在哪做工业视觉的人大多有过这样的经历模型在验证集上 mAP 挺好一到现场就漏检尤其漏的是那些最要命的细裂纹。钢轨表面缺陷检测就是这类问题的典型代表。它的任务目标并不复杂——在轨道巡检车、手持巡检设备或者固定式检测工位采集到的图像里把裂纹、剥离、压痕、划伤、锈蚀、磨损这几类表面异常框出来并给出类别和位置。但在真实产线上这个“框出来”三个字背后压着一堆工程细节。这套针对钢轨表面缺陷检测的改进版 YOLOv8核心就是把一件事做扎实在保证推理速度能满足巡检节拍的前提下把微小缺陷的召回率和定位精度往上推一档同时不让模型变成一个只能在服务器上跑的庞然大物。它适合两类读者参考一类是做工业缺陷检测、正在拿 YOLO 系列当基线做落地的工程同学另一类是刚接触目标检测改进想知道“加了模块为什么涨点、为什么有时候不涨反而掉”的学习者。文中给出的结构配置、参数计算过程和排查思路都可以直接抄去改自己的项目。1.1 缺陷形态和成像条件决定了算法的天花板钢轨表面缺陷有几个很“反检测模型”的特点如果不先认清这些后面所有的结构改进都是瞎猜。第一是尺度分布极度不均。一条长几百毫米的剥离带在图像里可能占上千像素而一条起始阶段的细微裂纹宽度只有零点几毫米长度几毫米。我在一个模拟项目里测过一组统计以 0.1 mm/pixel 的空间分辨率采集200 mm 幅宽的线扫图像宽度约 2048 像素其中 60% 以上的缺陷标注框短边小于 16 像素。这个数字直接决定了后文的检测层设计。第二是缺陷与背景的对比度低。钢轨表面本身有轧制纹理、有油污、有水渍、有反光裂纹在灰度上和这些干扰非常接近。很多漏检不是模型没看见而是它把裂纹当成了纹理。这件事靠加深网络解决不了需要在特征层面强化边缘和方向信息。第三是成像条件不稳定。户外巡检受光照、天气、阴影影响很大同一类缺陷在不同时段拍出来的样子可能差出一个量级。这意味着模型的泛化压力远大于常规的通用目标检测任务数据增强策略的重要性甚至超过结构改进。第四是类别长尾严重。锈蚀、磨损这类样本一抓一大把而某些特定形态的剥离、纵向裂纹可能几百张图里才出现一次。如果直接按原始分布训练模型会对稀有类别几乎无响应。注意很多团队一上来就改网络结构结果折腾两个月涨了 1.2 个点回头把标注规范和增强策略重做一遍涨了 4 个点。先摸清楚数据的长尾程度和小目标占比再决定要不要动结构这个顺序不能反。1.2 为什么基线选 YOLOv8而不是别的检测器选 YOLOv8 当基线不是因为它“最新”而是它在几个关键维度上刚好踩在工业落地的需求上。从工程可用性看YOLOv8 的检测分支是 anchor-free 的省掉了聚类 anchor 这一整套调参流程。钢轨缺陷的长宽比分布非常散剥离是细长条压痕接近方形锈蚀是不规则片状用 anchor-based 的方法需要针对每个数据集重新聚类换一条线路、换一种采集设备就得重来一遍维护成本太高。anchor-free 直接回归到中心点和宽高虽然对小目标回归的稳定性要求更高但省下来的工程复杂度是实打实的。从多尺度能力看YOLOv8 的 PAN-FPN 结构加 C2f 模块在 P3/P4/P5 三个尺度上做特征融合本身已经具备一定的多尺度表达能力。我们需要做的不是推倒重来而是在这个基础上补两块短板一是补一个更高分辨率的检测层来兜住小目标二是把浅层特征的细节信息更有效地传到检测头。从部署链路看YOLOv8 的导出生态比较完整ONNX、TensorRT 这些路径都有成熟方案量化、剪枝的工具链也跟得上。工业现场最终要跑在边缘设备上如果基线模型连导出都费劲后面精度再高也没意义。至于为什么不用两阶段检测器原因很直接两阶段在精度上确实有优势但推理耗时通常是用例的两到三倍。轨道巡检车的采集帧率决定了单帧处理时间上限这个硬约束下单阶段是更现实的选择。1.3 改进之前先把“痛点”量化出来我在动手改结构前会先做一份基线诊断表。这份表的作用是让后面每一个模块的引入都有对应的指标支撑而不是“看到论文里有就加”。诊断项观测方法基线表现模拟项目结论小目标召回按 GT 框短边分桶统计 AP短边16px 的 AP 仅 0.51必须加高分辨率检测层细长目标定位统计 IoU0.5 但0.75 的样本占比占比 34%集中在剥离类损失函数需换稀有类别各类别 AP 对比最少类 AP 0.42最多类 0.91需重采样增强背景误检统计 FP 的来源区域62% 来自油污与水渍需强化纹理区分能力推理耗时TensorRT FP16 单帧某边缘设备上 28 ms精度提升需控制在 15% 以内这张表最容易被忽略的是最后一行。很多改进方案在论文里涨点很好看但参数量翻倍、耗时翻倍放到巡检设备上直接不可用。我的原则是精度涨点必须和耗时增长一起报只报 mAP 不报 FPS 的改进在工程上是不完整的。2. 改进方案的整体设计与四个发力点整套改进围绕四个方向展开骨干网络增强细节表达、颈部结构优化多尺度融合、检测头与损失函数提升定位质量、轻量化设计守住速度底线。这四个方向不是并列关系而是有优先级的——先解决小目标检测层和损失函数这两块投入产出比最高再考虑注意力和颈部结构最后才做轻量化裁剪。2.1 骨干与浅层特征别让细微纹理在下采样中消失YOLOv8 的骨干通过 5 次下采样把 640×640 的输入压到 20×20。每一次 stride2 的卷积都会丢掉一部分高频信息。对于常规目标这无所谓但钢轨的细裂纹信息恰恰集中在高频段。一条宽度 3 像素的裂纹经过三次下采样后在特征图上只剩不到 1 个像素的响应基本等于消失。我的做法是在骨干的浅层P2、P3 对应的 stage嵌入轻量的坐标注意力模块。选坐标注意力而不是通道注意力理由很实在钢轨缺陷里纵向裂纹、横向裂纹、斜向裂纹的方向性很强通道注意力只告诉你“这个通道重要”而坐标注意力会把水平和垂直方向的 positional 信息编码进去相当于告诉网络“这个位置、这个方向上有东西”。对于细长条状的剥离和裂纹这个先验非常对路。下面是一个可以直接用的简化实现工程上比论文里的版本更省事参数量也小import torch import torch.nn as nn class CoordAtt(nn.Module): def __init__(self, inp, oup, reduction32): super().__init__() mip max(8, inp // reduction) self.conv1 nn.Conv2d(inp, mip, 1) self.bn1 nn.BatchNorm2d(mip) self.act nn.SiLU(inplaceTrue) self.conv_h nn.Conv2d(mip, oup, 1) self.conv_w nn.Conv2d(mip, oup, 1) def forward(self, x): n, c, h, w x.size() # 沿宽度方向池化保留高度信息 x_h torch.mean(x, dim3, keepdimTrue) # 沿高度方向池化保留宽度信息 x_w torch.mean(x, dim2, keepdimTrue).permute(0, 1, 3, 2) y torch.cat([x_h, x_w], dim2) y self.act(self.bn1(self.conv1(y))) x_h, x_w torch.split(y, [h, w], dim2) x_w x_w.permute(0, 1, 3, 2) a_h torch.sigmoid(self.conv_h(x_h)) a_w torch.sigmoid(self.conv_w(x_w)) return x * a_h * a_w接的位置有讲究。我试过三种接在每个 C2f 之后、接在 SPPF 之后、只接在 P2/P3 两个 stage 之后。实测下来第三种最划算——浅层接注意力收益明显深层接注意力基本是白涨参数量。原因不难理解深层特征图分辨率已经很低位置信息的粒度本来就粗再加方向先验意义不大反而容易干扰语义表达。实操心得注意力模块千万别“全网络铺开”。我见过一个版本在每个 C2f 后面都插了一个注意力参数量涨了 18%mAP 反而掉了 0.4。原因是浅层注意力和深层注意力互相打架梯度传播被扰乱了。宁可少加加在对的地方。另外提一句C2f 本身的设计是 split concat 的多分支结构梯度流已经比较丰富了不需要再往里塞残差或者 dense 连接。有些改进方案把 C2f 换成更复杂的模块涨点是涨了但推理耗时涨了 30% 以上这种交换在巡检场景里不划算。2.2 颈部融合与多尺度P2 检测层到底该不该加这是整套改进里最关键的决策。前面算过60% 以上的缺陷短边小于 16 像素。在 640 输入下P3 检测层的 stride 是 8特征图是 80×80一个 16 像素的目标在上面大约占 2×2 个格子。理论上够用但实际训练中2×2 的感受野太小正样本采样严重不足回归分支学不动。加上 P2 检测层stride4特征图 160×160之后同样的 16 像素目标占 4×4 个格子正样本数量翻了四倍回归稳定性明显改善。代价是计算量上涨——160×160 的特征图上做检测头anchor 点数量是 P3 的四倍显存和耗时都会往上走。我在模拟项目上测过加 P2 层后 mAP50 涨了 3.8 个点其中小目标子集涨了 9.2 个点推理耗时增加约 22%。22% 这个数字能不能接受取决于你的设备。如果边缘设备有富余算力加如果预算卡得很死那就用替代方案不加 P2 层改成在 P3 上做输入分辨率提升比如 640 提到 800或者用切片推理把大图切成小块分别推理再合并。切片推理对小目标效果很好但会带来拼接处的重复检测问题需要额外做跨图 NMS工程复杂度不低。颈部结构的融合方式我也做了调整。原版 PAN-FPN 是简单的 concat 后卷积各尺度特征的权重是隐式学出来的。我换成了带权重的双向融合给每个输入特征加一个可学习的权重系数融合时按权重加权求和。这个改动的逻辑是钢轨缺陷在不同尺度上的信息量差异很大P2 层几乎全是纹理噪声P5 层几乎全是语义让网络自己学“该信谁”比强行等权融合更合理。配置文件的关键部分长这样# 改进版骨干与颈部片段示意 backbone: - [-1, 1, Conv, [64, 3, 2]] # P1/2 - [-1, 1, Conv, [128, 3, 2]] # P2/4 - [-1, 3, C2f, [128, True]] - [-1, 1, CoordAtt, [128]] # 浅层注意力 - [-1, 1, Conv, [256, 3, 2]] # P3/8 - [-1, 6, C2f, [256, True]] - [-1, 1, CoordAtt, [256]] - [-1, 1, Conv, [512, 3, 2]] # P4/16 - [-1, 6, C2f, [512, True]] - [-1, 1, Conv, [1024, 3, 2]] # P5/32 - [-1, 3, C2f, [1024, True]] - [-1, 1, SPPF, [1024, 5]] head: - [-1, 1, nn.Upsample, [None, 2, nearest]] - [[-1, 8], 1, Concat, [1]] - [-1, 3, C2f, [512]] # ... 逐级上采样到 P2再自顶向下融合最后接四个检测头四个检测头分别对应 stride 4/8/16/32。这里有个容易踩的坑加 P2 层之后如果还用原来的 anchor 匹配策略或者标签分配阈值正样本会爆炸式增长训练前期 loss 震荡很明显。我一般会把标签分配的 topk 从默认值调小一点让每个目标分配的候选框数量降下来。2.3 检测头与损失函数定位精度才是钢轨缺陷的命门对钢轨缺陷来说“框到了但框不准”和“没框到”在实际使用中造成的后果不一样但都很麻烦。巡检系统通常要输出缺陷的尺寸和位置用来做后续的养护决策如果框的边缘偏出去十几个像素测出来的裂纹长度误差可能就是几毫米。原版用的 CIoU 损失在常规目标上表现不错但它的几何惩罚项对小目标不够敏感。我换成了带动态聚焦机制的 IoU 变体核心思路是根据预测框和真实框的重叠程度动态调整梯度权重重叠度低的样本通常是难样本、小目标给更大的梯度重叠度高的简单样本降权。这个设计在钢轨场景里的价值在于大量容易检测的锈蚀样本不会淹没掉那些难检的细裂纹样本。还有个细节钢轨缺陷的长宽比很极端剥离类的长宽比经常到 10:1 以上。这类目标用常规 IoU 计算时即使预测框稍微偏一点角度IoU 就掉得很快梯度会变得很不稳定。我在长宽比惩罚项上加了一个截断避免极端长宽比样本产生过大的梯度。分类分支我用了可变权重的交叉熵。原因是类别不均衡下稀有类别的样本在总损失里占比太小模型倾向于全部预测成多数类。给稀有类别的损失加一个基于有效样本数的权重系数比简单复制样本的效果更稳也不容易过拟合。提示换损失函数后一定要重新看一遍训练曲线的收敛形态。我在换成动态聚焦版本后第一次训练前 20 个 epoch 的 box_loss 比原来高不少看着像出问题了其实是难样本权重变大导致的正常现象。如果这时候慌了去调学习率反而会把节奏打乱。2.4 轻量化取舍精度涨点不能靠堆参数前面加注意力、加 P2 层、换损失加起来参数量涨了大约 15%耗时涨了 25%。这个幅度在服务器上无所谓但在边缘设备上已经接近临界点。所以还得做一轮瘦身。我用的办法是替换颈部里的标准卷积。颈部负责多尺度融合特征图分辨率高、通道数大是计算量的大头。把 3×3 标准卷积换成分组卷积加通道混洗的组合参数和 FLOPs 都能降下来同时对精度的影响比直接砍通道数小得多。这里的关键是通道混洗不能省——分组卷积的问题就是组间信息不流通少了混洗不同组学到的特征会高度重复等于白分组。另一个手段是控制输入分辨率。640 是通用检测的常用值但钢轨图像通常是宽幅长条比如 2048×512直接 resize 到 640×640 会造成严重的形变细长缺陷被压扁。我的处理是保持长宽比做 letterbox实际输入用 640×640 但有效区域只占中间一条。这样虽然浪费了一部分计算但避免了形变带来的精度损失。如果设备算力实在紧张可以考虑 512 输入代价是小目标召回掉 2 个点左右。瘦身之后的最终配置参数量和耗时控制在与基线基本持平的水平mAP50 相比基线提升 4 到 6 个点具体数值取决于数据集质量。这个性价比在工业场景里是我认为可接受的区间。3. 数据集构建与增强策略的实操细节结构改得再花哨数据不行照样白搭。钢轨缺陷检测里数据环节花的时间通常比调模型多得多。3.1 采集、标注与类别定义类别定义这一步值得反复推敲。很多团队一开始把类别定得很细比如“纵向裂纹”“横向裂纹”“斜向裂纹”“网状裂纹”分成四类结果发现后两类样本极少模型根本学不会而且实际使用中养护人员关心的只是“有没有裂纹、在哪、多长”不关心方向。后来我倾向于按缺陷机理分类而不是按形态分类类别数控制在 4 到 6 类之间形态差异通过数据增强和方向注意力来吸收。标注规范里最容易出问题的是边界一致性。同一张图给两个人标一个人把锈蚀的边缘标到颜色最深处另一个人把周围过渡区域也框进去两个框的 IoU 可能只有 0.6。这种标注噪声对小目标的影响是致命的——16 像素的框边缘差 2 像素IoU 就掉到 0.75 以下。我的做法是写一份带正负例示图的标注手册把“框到哪为止”说清楚然后做一轮交叉校验把 IoU 低于 0.7 的重复标注挑出来重新裁定。还有一个容易被忽视的问题负样本的价值。纯背景图没有缺陷的正常钢轨在训练集里必须占一定比例否则模型会把所有纹理都当成缺陷。我一般在训练集里放 10% 到 15% 的纯背景图这些图里包含油污、水渍、光照不均等容易误检的场景效果比只做背景增强更好。3.2 小目标与长尾分布的增强手法常规的 Mosaic、MixUp、HSV 抖动这些YOLOv8 默认就带不用重复造轮子。针对钢轨场景我额外加了三类增强。第一类是小目标复制粘贴。把稀有类别里的缺陷区域裁剪出来随机缩放到 0.8 到 1.2 倍贴到背景图的随机位置同时更新标注。这个手法对小目标召回提升非常直接因为它本质上是在增加小目标的正样本密度。要注意的是粘贴位置不能和已有标注重叠也得避开图像边缘边缘的缺陷往往被裁断标注不完整。第二类是方向性增强。钢轨缺陷的方向分布有偏向性纵向裂纹远多于横向。训练时对图像做随机水平翻转、小幅旋转正负 15 度以内可以让模型对方向更鲁棒。旋转角度不宜大超过 30 度会产生大量黑边反而引入噪声。第三类是光照与对比度扰动。模拟不同时段、不同天气下的成像差异用随机 gamma 变换加局部对比度调整。这招对降低户外场景的误检率很有效尤其是阴影区域。增强手段参数设置主要解决的问题注意事项Mosaic默认开启最后 10 epoch 关闭提升多目标场景鲁棒性关闭太晚会导致小目标定位偏移小目标复制粘贴概率 0.3缩放 0.8~1.2小目标召回需避开边缘与已有标注随机旋转概率 0.2角度 ±15°方向鲁棒性角度过大会引入黑边HSV 抖动h0.015, s0.7, v0.4光照变化v 值别调太高容易过曝随机擦除概率 0.1面积比 0.02~0.1抗遮挡别擦到缺陷主体上注意增强强度不是越大越好。我试过把 Mosaic 概率提到 1.0、旋转角度放到 ±45°训练集上 loss 降得很漂亮验证集 mAP 反而掉了 2 个点。原因是增强后的图像分布已经偏离了真实采集分布模型学到的是“增强后的世界”。3.3 数据划分与防泄漏这个坑我踩过一次代价是两周的无效调参。当时按帧随机划分训练集和验证集结果相邻帧巡检车连续采集前后帧图像几乎一样被分到了两边验证集 mAP 虚高到 0.93。换了一条线路测试直接掉到 0.71。正确做法是按采集段划分同一段连续采集的图像只能整体进训练集或验证集。如果有多条线路、多种设备的数据还要保证验证集覆盖到不同来源这样才能真实反映泛化能力。理想情况下再留一个独立的测试集完全不参与任何调参只在最后评估一次。4. 训练配置、参数计算与调参实录4.1 环境与基础配置训练环境这块没什么花活一张中等显存的卡就够跑关键是版本别乱。CUDA 和 PyTorch 的对应关系、编译版本的一致性这些基础问题造成的报错往往最难查。# 训练启动命令示意 yolo detect train \ datarail_defect.yaml \ modelyolov8s-rail.yaml \ epochs300 \ imgsz640 \ batch16 \ optimizerSGD \ lr00.0025 \ lrf0.01 \ warmup_epochs3 \ cos_lrTrue \ close_mosaic10 \ patience50 \ device0数据集配置文件里路径用绝对路径最省事别用相对路径容易因为工作目录变化找不到文件。类别名和顺序必须和标注文件严格对应顺序错一位训练出来的模型会把裂纹认成锈蚀而且 loss 曲线看起来完全正常特别隐蔽。4.2 关键参数是怎么算出来的学习率SGD 的学习率有线性缩放的经验规则基线是 batch64 时 lr0.01。我用 batch16按比例算是 0.01×16/640.0025。这个值在实际训练中偏保守一点收敛稳但慢如果数据量小可以适当调高到 0.005。用 AdamW 的话起始值取 0.001配合 cosine 衰减。输入尺寸640 是折中选择。如果小目标占比特别高短边10px 的超过 30%我会提到 800但显存占用会涨约 1.5 倍batch 得相应降下来。这里要注意提高分辨率带来的收益不是线性的640 到 800 涨点明显800 到 1024 边际收益就很小了。batch size在显存允许的前提下尽量大BN 层的统计量才稳定。16 是我的常用值如果显存不够可以用梯度累积模拟大 batch但要注意 BN 的统计仍然是小 batch 的效果会打折扣。epochs300 是常规值配合 patience50 做早停。钢轨数据集通常不大几千张量级300 轮足够收敛。如果发现 200 轮之后验证集指标还在缓慢上升说明还能再训如果 150 轮就开始震荡说明学习率偏大或者数据噪声太重。置信度与 NMS 阈值训练阶段不用管推理时设。conf 从 0.25 起步IoU 取 0.5 到 0.6。钢轨缺陷经常密集出现比如一片剥离带上的多个小坑IoU 设太高会把这些相邻目标合并掉我一般在密集场景下把 IoU 压到 0.45宁可多留几个框让后处理去筛。4.3 训练过程怎么观测、怎么调我盯训练曲线主要看三件事。一是分类 loss 和定位 loss 的比例。正常情况下两者应该同步下降如果分类 loss 早早降到很低而定位 loss 一直高位说明模型在“盲猜类别”通常是小目标正样本太少导致的得回头查标签分配或者加检测层。反过来如果定位降得快、分类降不动多半是类别不均衡要动损失权重。二是验证集指标的波动幅度。正常训练中 mAP 的波动应该在 1 个点以内如果每轮之间跳动三四个点说明验证集太小或者分布不均这时候看到的“涨点”很可能是噪声。三是mAP50 和 mAP50-95 的差距。这两个指标的差距反映定位质量。差距大说明框得不够准可以从损失函数、标签分配、输入分辨率三个方向查。我的经验是钢轨缺陷检测里 mAP50-95 能到 mAP50 的 65% 以上就算定位质量合格。调参优先级上我通常按这个顺序试先调学习率和 batch再看增强强度然后是损失函数权重最后才动结构。结构的改动成本最高一次实验要跑大半天能靠超参解决的就别动结构。5. 指标评估与消融实验怎么做才可信5.1 指标选择不能只看 mAP工业场景里mAP 只能算入门指标。我实际会看这几项分尺寸 AP按 GT 框短边分桶16px、16-32px、32-64px、64px分别统计 AP。整体 mAP 涨了但小目标桶没涨说明改进方向偏了。召回率-误检率曲线实际部署时往往要固定一个误检率上限比如每公里不超过 3 次误报在这个约束下看召回率能到多少。这个指标比 mAP 更贴近现场需求。单帧耗时与峰值显存在目标设备上实测不能用训练机的数据代替。类别级 AP 分布看看稀有类别是不是被牺牲了。整体涨点但稀有类掉点这种“平均意义上的进步”在工程上不能接受。5.2 消融实验要一次只动一个变量我做消融的习惯是建一张表从基线开始每加一个模块加一行。关键是每次只加一个不要图省事一次加两个。我见过不少方案最后发现两个模块的效果互相抵消但因为是一起加的根本看不出来。实验组配置mAP50小目标 AP耗时(ms)参数量(M)A基线 YOLOv8s0.8210.51228.111.2BA P2 检测层0.8560.60434.312.6CB 浅层坐标注意力0.8710.62835.912.8DC 动态聚焦损失0.8840.64136.212.8ED 颈部轻量化0.8790.63330.59.4以上数据来自一个模拟项目用于说明分析思路不代表任何具体产线水平。从这张表能看出两个结论P2 检测层贡献最大值得为它付出耗时轻量化会掉 0.5 个点但耗时回到接近基线这个交换在边缘部署场景下是划算的。如果设备算力充足E 组可以不做。还有一点消融实验必须在同一个数据划分、同一套超参、同一个随机种子下跑。不同种子之间 mAP 本身就有 0.3 到 0.5 的波动如果你的改进只涨了 0.4很可能在噪声范围内。稳妥的做法是每组跑三个种子取平均虽然费时间但结论可信。6. 常见问题与排查速查6.1 精度类问题的排查路径现象一训练 loss 正常下降验证集 mAP 卡在某个值上不去。先查数据别查模型。具体做法是把验证集里漏检的样本挑 50 张出来肉眼过一遍看看有没有共性。我遇到过的典型情况是漏检集中在图像右下角原因是标注时那块区域被漏标了还有一种是漏检的都是同一台设备采集的图说明训练集没覆盖到那个成像条件。现象二小目标召回上不去加了 P2 层也没明显改善。大概率是标签分配的问题。P2 层特征图分辨率是 160×160如果标签分配的候选框数量不变正样本的绝对数量虽然多了但相对每个目标的匹配质量没有提升。这时候要调的是匹配阈值和候选数量而不是继续加层。现象三稀有类别 AP 一直在 0.4 附近徘徊。先确认该类样本数量。如果训练集里只有几十个实例任何模型都学不好得靠复制粘贴增强或者外部数据补充。如果样本上百了还学不好看标注一致性稀有类别往往是标注分歧最大的。现象四训练集指标很高换一条线路就崩。典型过拟合到采集条件。解决办法是增强的多样性——不同光照、不同角度、不同设备的图像都要进训练集。这个问题的根本解法是数据不是正则化。现象五误检率高大量油污被当成缺陷。两个方向一是增加纯背景负样本特别是含油污的场景图二是提升模型对纹理的区分能力浅层注意力或者局部对比度增强都有帮助。还有一个偏门的办法在后处理里加一个基于区域灰度方差的过滤规则把过于平滑的区域里的检测框滤掉实测能降 20% 左右的误检。6.2 训练阶段的崩溃与资源问题现象可能原因处理方式loss 变 NaN学习率过大 / 数据里有异常标注降 lr检查是否有宽高为 0 的框显存 OOMbatch 过大 / P2 层特征图太大降 batch开混合精度用梯度累积训练中途卡住dataloader 进程死锁num_workers 调小关掉缓存指标突然归零学习率调度异常 / 权重保存出错检查 cos_lr 与 warmup 配置多卡训练不同步BN 层未同步改用 SyncBN 或降为单卡其中“标注框宽高为 0”这个坑很隐蔽。标注工具在拖拽时如果没拖动就松开会生成一个退化框训练时算 IoU 就除零了loss 直接 NaN。写个脚本扫一遍标注文件把宽或高小于 2 像素的框挑出来处理掉能省下很多排查时间。6.3 部署端的问题精度掉点导出 ONNX 后精度和 PyTorch 对不上最常见的原因是预处理不一致。PyTorch 训练时用的是 letterbox 加归一化部署端如果直接 resize 或者归一化系数写错结果会差很远。建议导出后先用同一批图做端到端对比逐层核对输出别一上来就怀疑量化。速度不达标先看是不是卡在预处理上。图像解码和 resize 在 CPU 上做有时候比推理本身还慢。把预处理挪到 GPU 或者用硬件解码往往能省出一半时间。推理本身要做优化可以试 TensorRT 的 FP16 或者 INT8 量化INT8 需要准备校准集校准集要用真实场景图别拿训练集随便抽几张应付。多尺度输入的问题有些设备采集的图像尺寸不固定动态 shape 在 TensorRT 上会导致反复重建引擎速度雪崩。解决办法是固定几个常用尺寸做多引擎切换或者统一 padding 到固定尺寸。7. 几个我认为值得说清楚的工程细节先说模型选择。这套改进我在 yolov8n 和 yolov8s 两个规模上都试过结论是 yolov8s 是性价比拐点。n 版本加完 P2 层之后参数量涨幅相对更大而且小目标的特征表达能力先天不足加层也补不回来m 版本精度确实更高但边缘设备跑不动。这个结论跟具体硬件强相关换个平台可能要重测。再说一个容易被忽略的点缺陷尺寸的测量精度。巡检系统不只是要框出缺陷还要给出长度、宽度。检测框的定位误差会直接传导到尺寸测量上。我的做法是在检测框基础上再做一次亚像素级的边缘定位用灰度梯度找缺陷的真实边界把测量误差从 ±3 像素压到 ±1 像素以内。这一步不属于检测模型的工作但对最终交付质量影响很大。最后提一下持续迭代。产线跑起来之后会积累大量真实数据定期用新数据做增量训练是必要的。但增量训练有个陷阱新数据分布会逐渐偏向“已发现的缺陷类型”模型对没见过的类型反而更迟钝。我的做法是保留一个固定的“基线验证集”每次增量训练后都在这上面测一遍一旦发现指标下滑就说明模型在遗忘需要把旧数据按比例混进去重训。这套方案从结构改动到部署落地前后我在几个模拟项目上迭代了大概半年。踩过的坑里最费时间的不是模型不涨点而是数据环节的隐性错误——标注不一致、划分泄漏、预处理不匹配这三类问题造成的损失远超结构选型的失误。如果只能给一条建议那就是在改网络之前先把数据管道的每一环都验证一遍用可视化工具把增强后的图、标注框、模型预测结果一张张看过去。这个过程很枯燥但它能帮你排除掉 80% 的“玄学问题”剩下的 20% 才是真正需要调模型的部分。
阅读完成 · 觉得有帮助?
咨询建站