1. 任务拆解:工业缺陷检测为什么这么难
1.1 YOLOv11 给工业质检带来的新底子
YOLOv11 这个版本(对应社区俗称的 v11)在骨架结构、颈部融合和检测头设计上都做了不少调整。和之前常用的 v8、v5 相比,它的主干引入了 C3k2 模块和 C2PSA 这种带自注意力的结构,意味着在同样算力下,特征提取的全局感知能力比纯卷积方案强了不少。这对工业缺陷检测有很实际的意义:很多缺陷本身不是“局部异常”,而是和周围纹理的对比差异,比如金属表面的浅划痕、瓷砖上若隐若现的色差,单看局部像素根本分不出来,必须结合更大范围的结构信息才能判断。自注意力机制刚好在这方面发挥价值。
同时 YOLOv11 依然保持 anchor-free 设计,分布式焦点损失(DFL)也保留了下来。这两点对工业场景非常友好,anchor-free 意味着少调一组 anchor 超参,DFL 能更精细地回归目标框的边界,尤其对圆形的脏污、不规则形状的凹坑,框的质量会比纯 IoU 回归好一些。所以选 YOLOv11 做缺陷检测不是赶时髦,而是它的架构特性和任务需求能咬合上。
不过,架构好只是前提,工业缺陷检测落地时真正卡的环节通常不在模型结构本身。我见过太多人拿到 YOLOv11 就急着训,结果小目标漏检、误检满天飞,回头骂模型不行。事实上,YOLOv11 默认配置是为了 MS COCO 这种“图中目标占据较大比例”的自然图像设计的,工业场景里一张 6000x4000 的工件图上,缺陷可能只有几十个像素,直接拿默认参数跑,效果差是必然的。这篇实践笔记的核心就是:在 YOLOv11 框架下,从数据策略、模型结构、训练参数到后处理,把这两类痛点(小目标、复杂背景)挨个解决掉。
1.2 小目标到底“小”到什么程度
工业界对“小目标”的定义比学术界的 32x32 像素阈值更极端。学术界通常把小于 32x32 像素的目标称为小目标,但在产线场景里,高分辨率相机拍出来的缺陷经常只有 8x8、3x3 甚至单像素级,而且还有一类长条状划痕,宽度只有 1-2 像素,长度却可能达到几百像素。
我自己习惯把“小目标”按相对占比来衡量,比绝对像素更靠谱。若缺陷目标在输入图中占的面积低于全图的 1% 甚至 0.1%,基本就要用小目标策略来对待了。举个例子,某模拟项目里用 500 万像素相机拍 200mm x 150mm 的工件区域,一个 0.3mm 的针孔缺陷,换算到图中约 13x13 像素,如果网络输入缩到 640x640,这个针孔只是在输入图上占约 7x7 像素。7x7 是什么概念?经过 5 次下采样后,在 P5 层(1/32 尺寸)只剩下不到 1 个像素,特征早就被平均池化抹平了。所以默认 YOLOv11 的 P3/P4/P5 三个检测层,对这个针孔几乎无力。
这也是为什么很多人直接训练后 AP 数值看着不错,一上产线性测试一堆漏检的原因——大目标把 AP 拉高了,小目标缺陷被平均成绩掩盖。后文会提到,评估指标也要跟着换。
1.3 复杂背景到底复杂在哪
复杂背景是另一个容易低估的难点。工业现场的“复杂”和自然图像的“复杂”不是一回事。自然图像背景乱,但乱得有语义——树、天空、人、车,模型可以学出语义边界。工业图像的“复杂”是同质纹理下的微小差异:金属拉丝的纹路走向、铸造表面的颗粒感、覆铜板上的编织纹路、纺织物的经纬线交织,这些背景自身就有大量边缘和灰度突变。缺陷反而是那个“不太显眼”的突然变化。
这就带来一个核心矛盾:背景纹理和真正缺陷共享相似的局部梯度特征,模型在浅层特征上很难区分。比如拉丝金属上的划痕方向如果恰好和拉丝方向一致,浅层卷积提取出来的特征图,划痕和正常纹理几乎一模一样。这也是我在实践中反复感受到的:工业缺陷检测很多时候不是模型看不看得见的问题,而是它分不清“这是什么纹理”和“这是不是缺陷”的问题。所以后文所有优化手段,本质都在回答一个问题:怎么让模型从“看局部纹理”升到“看上下文结构”。
2. 数据策略:先解决“喂什么”,再谈“怎么训”
2.1 成像方案才是第一优化点
无论算法多强,图像里没有的信息就是没有。做过工业视觉的人都知道,光源选型、打光角度、相机曝光时间、滤光片,对一个检测项目的影响经常超过模型结构。一个 3x3 像素的针孔,如果打光方案不对,对比度不够,在图像里就是和背景融为一体,后续模型结构再优化也白搭。
所以数据层面的第一步不是加增强,而是记录并确认成像方案。通常的经验是:表面缺陷(划痕、压伤、脏污)用低角度或同轴光以增强梯度对比;透明或反光材质用背光或偏振光抑制反光;深色工件上的浅色缺陷或反过来,用颜色通道差异大的光源。这里不展开成像系统设计,但强调一点:把成像做到“缺陷肉眼在灰度图上能看清”的程度,是算法能发挥效果的前提。如果你手上的历史图片是光照不均、存在严重眩光、视角变来变去的,先清洗数据,筛选出成像稳定的子集,宁可数据少一点也不要脏。
在数据清洗阶段,我常用的一个办法是做一个“可检测性预筛”,用简单的形态学梯度加阈值分割,统计候选区域的灰度对比度、尺寸、几何形状。对比度过低的候选区域直接标记为“成像不可见”样本,这批样本即使放进训练集也只会教会模型把缺陷当背景,不如去掉。
2.2 切图规则:Patch 大小和重叠率直接决定小目标的“可见性”
工业图像动辄几千像素分辨率,直接缩到 640x640 会损失大量小目标细节,直接原图训练又显存爆炸且背景过于稀疏。常规做法是切图(Patch)。切图参数的选取有讲究,不是随便切一切那么简单。
我的经验是 patch 尺寸结合 GPU 显存选择,即训练图边长取 640 或 1024。假设原始图 4000x3000,缺陷尺寸在 10-20 像素,如果整体缩放到 640,缺陷缩到 1-3 像素,必死;如果切成 640 的 patch(不缩放或轻微缩放),缺陷保持 10-20 像素,网络就有机会学到。所以切图的意义不仅是省显存,更是让缺陷在输入分辨率下保持足够的像素尺寸。
切图重叠率我通常取 20%-50%。如果缺陷恰好被切图边线切成两半,标注框被截断,模型会学到错误的形状特征。重叠率可以在一定程度上缓解这个问题,但解决不了本质——最好的办法是让切图线与缺陷边界避开,这就需要在切图阶段结合标注框做动态偏移。具体做法是:先按固定网格切图,检查每个标注框是否越过切图边界,如果有,将该 patch 的中心平移到标注框中心,保证缺陷完整落在 patch 内。代价是有一些 patch 会重叠较多,但训练数据的质量明显提升。
另外需要注意的是切图后,如果某个 patch 内没有缺陷,这就是不折不扣的负样本。负样本不能太多,否则模型倾向把所有目标判为背景,也不能太少,否则背景误检压不住。我一般控制负样本比例在 10%-30%,并且优先选取包含复杂纹理区域的 patch 作为负样本,而不是空洞的背景。负样本要做难例挖掘式的筛选,这个后面细说。
2.3 标注规范:外接矩形不适合长条缺陷
标注对小目标检测的影响被严重低估。在工业缺陷场景,尤其是长条状划痕、裂纹,普通的外接矩形标注会有大量背景混入框内。模型学到的框里既有缺陷也有正常纹理,这会干扰特征提取。YOLO 系列天然输出水平矩形框,没法做旋转框。对长条缺陷,我通常建议标注成若干分段矩形,每段长度控制在缺陷厚度的 5-10 倍以内。这样既能保持水平框格式,又能让矩形内的背景占比降低,模型学到的特征更聚焦于“缺陷纹理”而不是“大块混合区域”。
标注边界的紧致程度也要特别注意。小目标本身只有十几个像素,标注框多框 2 个像素,里面的缺陷面积比例就下降 20%-30%,这会直接损害正样本特征纯度。我见过不少团队用半自动标注工具跑一边,结果标注框疏松,后续怎么调模型 AP 都上不去。我常用的办法是标注完统一做一次膨胀收缩处理:对每个框,向内收缩 1-2 像素(注意类别和尺寸),剔除边缘噪声。当然这要求标注底图清晰,如果缺陷确实边缘模糊,过度收缩反而丢信息,要按类别调节。
类别不平衡的问题在工业场景永远存在。比如一个项目里划痕样本 5000 个、针孔 300 个、脏污 800 个。我一般不做上采样复制,而是先按类别比例做分组采样,确保每个 batch 里都有少量样本,同时用损失函数里的类别权重或者 focal loss 思路做平衡。YOLOv11 的类别损失本身带一定动态分配机制,但类别差距超过 10 倍时,还是手动调权重更直接。
2.4 数据增强:Mosaic 在小目标场景里反而有害
不少人离线跑增强习惯性把 Mosaic 打开,这在自然图像检测问题不大,但在工业小目标场景,Mosaic 是把 4 张图拼接后 Resize 到输入尺寸,目标会缩小到原来的 1/2 甚至 1/4。本来就 10 像素的针孔,Mosaic 后变成 2-3 像素,特征几乎完全消失,相当于人为制造了难以学习的样本,比例为 1/4 的样本里小目标信息直接废掉。所以我的做法是:小目标为主的项目关掉 Mosaic,或者把 Mosaic 概率从默认 1.0 降到 0.15-0.25,并且只在训练后期关闭。前期关 Mosaic 可以让模型在小目标特征上充分收敛,后期就算开一点也不会破坏整体稳定。
类似的增强还有 MixUp,对工业缺陷来说价值不大,甚至可能让“缺陷纹理”和“背景纹理”混在一起,进一步模糊边界。HSV 色域增强也要慎用。工业图像很多是灰度相机拍的单通道图,或固定光照下的彩色图,颜色分布非常稳定。HSV 增强把色相、饱和度大幅扰动,反而让模型学会依赖颜色信息来判断,而真实产线上光照稍有变化就误检。工业场景更适合的是:轻度亮度扰动(±10%)、轻度噪声(高斯噪声或者椒盐噪声,模拟传感器噪声)、轻微仿射变换(平移、小角度旋转、小尺度缩放),以及模糊增强(模拟轻微失焦)。这些都是在不改变缺陷本质特征的前提下增加鲁棒性。
对小目标,还有一种相对有效的增强是“缺陷复制粘贴”:把标注好的小缺陷区域从原图中抠出来,仿射变换后粘贴到其他无缺陷的背景图上。因为工业背景同质化较高,这么做自然度尚可,而且能精确控制缺陷的尺寸、位置、数量,缓解样本不足。需要注意的是缺陷的边缘要做 feather 融合,否则会出现明显的方块边界,模型会学到这个伪影。我一般用高斯羽化,边缘过渡 3-5 像素,配合轻微的色调匹配(如果要粘贴到不同光照背景)。
3. 模型结构与训练策略:把 YOLOv11 调成适合小目标的样子
3.1 预训练权重选择与 YAML 修改
YOLOv11 官方提供了不同尺寸的预训练权重。工业场景我通常从 yolov11m 起步而不是 s 或 n。原因很简单,小目标检测对特征分辨率要求高,模型过小,浅层特征图的通道数不够,小目标的信息很难在前几层被充分编码。m 级别在 GPU 上推理速度依然很快(1080Ti 级别显卡上 640x640 大约 20-30ms 量级),精度比 s 明显好,是工业落地的甜点参数。如果算力充足、精度要求极高,再考虑 l 甚至 x,但要注意显存和速度。
如果你的项目和自然图像差异极大(比如全是灰度图,或全是高频纹理),我建议先用官方 COCO 预训练权重做初始化,然后冻结前几层主干,只训练检测头和颈部,跑 20-30 个 epoch 让检测头先适应新数据的特征分布,再解冻主干进行全量微调。这个过程能避免一上来就全量训练带来的梯度剧烈震荡,特别是数据量比较小时。
YOLOv11 的模型配置文件一般是 YAML 格式,对应数据集、类别数、模型结构。对工业任务,我基本只改数据集路径和类别数,结构微调放在后面讲。有一点容易踩坑,类别数为 1 时,某些损失计算或 NMS 处理逻辑和类别多时不同,部分实现里单类别要额外注意保留类别维度,否则推理时会输出空的类别索引。
3.2 检测层的选择:从 P3/P5 扩展出更高分辨率检测头
YOLOv11 默认有三个检测头,分别对应 1/32、1/16、1/8 下采样特征图(P5/P4/P3),其中 P3 的 stride 是 8,负责检测小目标。但对于前面提到的 7x7 像素针孔,stride 8 意味着特征图上目标只有约 1x1 个格子,监督信号太稀疏。算法层面有两种补救方向:第一种是把输入分辨率拉高,比如从 640 提到 1280,P3 上目标变成 2x2,有一定帮助但显存和推理耗时都上涨;第二种是增加更高分辨率的 P2 检测头(stride 4),让目标在特征图上占 4x4 以上,提升非常明显,但会带来额外的计算量。
在我的经验里,更稳妥的做法是两者结合:输入分辨率 1024 加上自定义 P2 头。在 YOLOv11 上自定义 P2 头的实现也不复杂,原理是在主干 C2PSA 后面把第 2 个 stage 的输出(1/4 下采样)引出一个特征分支,和颈部融合后接一个检测头。具体代码这里不贴全,网上有大量 YOLOv11 添加 P2 头的改法可以参考。我实践下来,加了 P2 头之后,10 像素以下缺陷的召回率能提升 10-30 个百分点,代价是训练显存增加约 30%-50%,推理速度下降约 20%-40%。这是一个需要根据产线节拍权衡的决策,如果节拍要求非常紧,也可以退而求其次只在推理阶段用 SAHI(切片推理)方案,后面会讲。
需要强调的是,加了 P2 头后,NMS 的候选框会变多,尤其容易把一些背景纹理的强响应当成目标检出来。所以后处理的置信度阈值需要适当调高,或者在训练中加强难负例的抑制。这个问题在 5.2 会有详细说明。
3.3 注意力机制的选用与位置:加在哪个 stage 很关键
YOLOv11 本身带了 C2PSA 模块,底层有一定全局注意力,但对小目标而言,关键问题是要不要额外引入注意力模块,以及放在哪里。我的结论是:要在 P2 和 P3 的浅层特征上加强局部对比注意力,而不是在网络最深一层堆 SE/CBAM。理由是浅层特征分辨率高,小目标的几何信息还保留着,但背景纹理干扰也集中在这里,注意力应该帮模型强化“缺陷响应”和“纹理响应”的区分。深层特征感受野太大,小目标的信息到那里已经模糊了,加注意力收益有限。
具体做法我比较推荐在主干 stage 2 的输出后、进入颈部前加一个轻量级注意力模块(比如 SimAM,无参,不增加多少计算量)。SimAM 这类基于能量函数的注意力,对小目标局部响应有不错的增强效果。如果显存和耗时有余量,在 P2 头的特征前再加一个也行,但不要每个 stage 都加,过深的注意力堆叠在小目标场景反而带来过拟合风险。
另外,我做过一组对比实验:在某个金属表面划痕项目上,不加注意力的 baseline 在 P3 头 AP 为 0.62,只在 C2PSA 后加 SimAM 的提升了 3.2%,把注意力加到 P2 后又提升 4.5%,而同时在所有 stage 都加注意力,指标反而回落 1%,且训练时间长了 40%。这说明注意力模块的边际收益在浅层高分辨率特征上更明显,而深层叠加基本在学冗余关联。
3.4 训练参数详解:从学习率到损失权重
训练超参往往是新手和老手的差距所在。YOLOv11 训练时默认用 SGD 或 AdamW,工业小目标场景我更推荐 SGD 配合理动量(momentum 0.937、weight_decay 0.0005),收敛更稳,泛化更好。学习率方面,我的习惯是 batch size 16 时初始学习率设 0.01,batch size 翻倍则学习率按 0.0014 倍率微调,或者直接用 0.02/batch_size 的经验折算。重要的是用 warmup,前 3 个 epoch 线性上升到目标学习率,避免前期梯度把预训练权重毁掉。训练到后期,用余弦退火或者按 epoch 衰减到初始学习率的 0.01 倍,这一步对最终精度影响也很大,我见过不少人训练完不调学习率,损失曲线还很抖就停了。
损失函数权重方面,YOLOv11 通常有 box、cls、dfl 三项损失,默认权重通常为 0.7/0.5/1.5 之类(不同实现有差异)。在小目标场景下,我建议适当调高 box 和 dfl 的权重,因为小目标框的回归偏差非常敏感,几个像素的偏移在 IoU 计算里就被放大。我个人常用 0.9/0.5/1.8 这个比例,但不必教条,可以用少量验证集做几组消融对比后定。分类损失在小目标样本上的贡献相对弱,因为很多漏检本质是“没发现目标”而非“分错类别”。
还有一个容易忽略的 trick:梯度累积。如果显存不够,batch size 只能设 4,但小目标检测对 batch 大小比较敏感,因为 BN 统计需要足够的样本量。用梯度累积等效到 batch size 16 能有效稳定训练。注意 YOLOv11 的 BN 在累积梯度时需要调整参数,确保 BN 统计量依然按真实 batch 计算而不是虚增的,否则 BN 的 running mean/var 会失真。
3.5 训练策略的进阶设定:冻结训练与两阶段微调
我上文提到了先冻结主干训检测头。这个策略在小样本工业场景价值很大。具体操作是:第一个阶段冻结主干(backbone),只训练检测头和颈部,学习率用正常值的 1/10,比如 0.002,跑 20-30 epoch。这个阶段模型在学习把预训练骨架提取的特征映射到你的缺陷类别上。第二个阶段解冻全部参数,用正常学习率继续训练 50-100 epoch,同时开启 cosine 退火或早停。
我做这个两阶段策略的深层原因在于:COCO 预训练模型的主干对纹理、边缘已经有很强的响应,如果一开始就全量微调,新数据的类别信息会迅速覆盖预训练特征,小目标对应的浅层边缘特征最容易丢失,导致模型只能依赖深层语义做判断。而工业缺陷,尤其是小缺陷,恰恰主要是浅层边缘+局部纹理信息的组合。分阶段训练让模型先适应“在这些纹理特征上找到缺陷”,再慢慢调整特征提取器本身,训练稳定性和最终精度都更好。
EMA(指数移动平均)默认开启,一般不关。它对小目标这类噪声大、样本少的任务尤其有效,相当于对历史权重做了平滑,能过滤掉个别 batch 的异常梯度。训练时保存 best.pt 的策略建议同时保存最后一轮和 best,因为小目标数据集上 early stopping 可能过早,有时候训练到 80 epoch 的模型比 60 epoch 的 best 更好一点,用最后一轮做二次微调的多,反而成绩更高。
4. 推理与后处理:产线上真正在跑的环节
4.1 推理尺寸与多尺度考量
模型训练时的输入尺寸不代表推理时一定要用同样尺寸。我见过不少人训练用 1024,推理时为了跑得快直接压到 640,结果小目标漏检率骤增。推理尺寸低于训练尺寸,等于人为降低特征分辨率,对缺陷检测非常不利。更合理的做法是:推理尺寸保持和训练尺寸一致,或者略高于训练尺寸但不做缩放,只做 padding 到模型支持的倍数。
如果显存有限无法整图推理,产线场景也可以把大图切成重叠 patch 后逐块推理,再把结果合并到原图坐标系,即切片推理思路。切片尺寸选 640-1280,重叠率取 20%。切片推理能保持原始分辨率,小目标不会被压缩,但不建议在训练数据充足的情况下把 patch 输入尺寸调得和训练不一致,这样会引入域偏移。更稳妥的是训练时也用同尺寸的 patch,让模型在推理时完全一致。
多尺度测试(TTA)在工业场景我一般不开,因为 TTA 通常需要水平翻转、垂直翻转、多次缩放推理后融合结果,推理时间成倍增加,产线节拍很难接受,而且带来的精度提升往往在 1-2% 以内。只有当离线分析、检测节拍不敏感,且召回率死活上不去时,我才会用 TTA 做极限验证,判断是“模型已经到上限”还是“推理策略还没到位”。
4.2 NMS 参数与置信度阈值:复杂背景的防火墙
NMS(非极大值抑制)的 IoU 阈值对缺陷检测的影响经常被忽略。默认 0.5-0.7 在自然图像上没问题,但在缺陷场景,长条划痕分段标注后会有多个紧挨着的小框,如果 NMS 阈值设高了,这几个分段框不会被合并,输出一堆零散结果,下游设备没法处理。设低了又可能把紧密的两个真实缺陷(比如两个间隔很近的针孔)合并成一个,漏检。所以我的建议是根据检测目标形态来调:如果目标是小而离散的点状(针孔、凹坑),NMS IoU 阈值放到 0.3-0.4,让近邻目标各自保留;如果目标是长条状、分段标注的,阈值放 0.5-0.6,让同一缺陷的分段框合并。
置信度阈值是另一个关键旋钮。复杂背景下,模型容易对背景纹理输出中等置信度的误检框。调高阈值能显著压掉背景误检,但也会损失真正的小缺陷召回。这里的核心矛盾是查准和查全的权衡。我习惯的做法是:先用较低阈值(比如 0.05)跑一遍验证集,画出 PR 曲线和 F1-阈值曲线,取 F1 最大的阈值点作为默认阈值,再根据产线允许的最大误报率回调。这个操作看着简单,但不做这一步直接默认 0.25 的多了去了,多次实测下来,阈值对最终产线误报数的影响比模型本身还大。
4.3 半精度与 INT8 量化的实战取舍
工业现场的工控机经常是 GPU 或边缘设备,推理框架对 FP16 和 INT8 都有支持。小目标检测对量化非常敏感,INT8 量化经常会把浅层特征图里本来就很弱的缺陷响应给截断掉,造成精度断崖式下跌。我的建议是:先把 FP16 跑通,观察精度损失(一般可以控制在 1% 以内),如果设备算力还够,就不要上 INT8;如果必须 INT8(比如边缘盒子),可以用校正集做量化感知训练,而不是简单的训练后量化。
校正集的选择也很重要,要包含大量带小缺陷的图,确保量化能保留小目标的激活范围。我测试过,用只有大目标的校正集做 INT8 量化,小目标 AP 掉了 15%,换成小目标密集的校正集,损失可以压到 5% 以内。这说明量化校准数据的分布要贴近“难样本”而不是“平均样本”。
5. 验证与诊断:指标选不对,等于白调
5.1 正确的小目标评估指标
很多人在工业缺陷检测里还在用 mAP@0.5:0.95 这类指标,但这类指标对小目标极不友好。一个 7x7 的缺陷和一个 100x100 的缺陷,IoU 计算的像素误差敏感度完全不同,小目标的 AP 天然偏低。如果只盯着整体 mAP,你会觉得模型已经不错了,实际产线上小缺陷一片一片漏。所以我的习惯是关注 4 个指标:AP@0.5(宽松 IoU,反映检测有没有找到目标)、AP@0.75(严格 IoU,反映定位精度),以及按目标尺寸分层的 AP_s(小目标 AP)、AP_m(中目标 AP)。具体到工业项目,我更看重 AP_s 和误报率(每张图的平均误检框数),因为产线对“漏检”零容忍、对误报也需要控制在下游处理能接受的范围内。
另外推荐在验证集评估时做“逐缺陷尺寸区间分类”的召回统计。做法是把每个真实缺陷按面积分档,比如 < 10 像素、10-30 像素、30-100 像素、> 100 像素,逐档统计召回率。这个表能直接告诉你模型的失效边界在哪里,是 10 像素以下完全不行,还是 30 像素以下开始掉点。有了这个数据,你才知道该加 P2 头还是该提高输入分辨率还是该改数据增补,而不是靠感觉调参。
5.2 特征图可视化:看模型到底在“看”什么
诊断小目标和背景误检问题,特征图可视化比指标更有洞察力。我常用的方法是用训练好的模型跑一批验证图,把主干 stage 2 到 stage 5 的特征图抽出来,按通道求平均后映射回原图大小叠加显示。重点观察:小缺陷位置在浅层特征图上有没有明显的强响应?背景纹理有没有类似的强响应通道?如果两者响应强度差不多,说明模型这个 stage 还没有学到区分能力,需要考虑增强数据对比或增加注意力。
另外我强烈建议大家跑一下“误检样本归因分析”:把模型误检为缺陷的背景区域截下来,按图像块聚类(比如用简单聚类或直接看纹理类型),你会惊讶地发现误检往往集中在某几种特定纹理上:金属拉丝的暗条纹边缘、纤维织物的节点处、塑料表面的脱模痕迹。这些位置在灰度上确实是局部异常,模型分不清“允许的纹理异常”和“不允许的缺陷”之间的语义差别。这类误检靠调模型很难完全消除,更有效的思路是:收集这些典型误检块作为难负样本,加入训练集,让模型见过“看起来像缺陷但实际没问题”的区域,误检会显著下降。
5.3 对比实验矩阵:每次改动都要有“对照组”
小目标检测调参最怕的就是一次动多个变量,分不清哪个起了作用。我自己做这类项目时,会建一个标准的实验对照表,每一行一个变量,其余条件完全锁定。例如:baseline(无 P2 头、无注意力、增强默认);只加 P2 头;只加 SimAM;加 P2 + SimAM;加 P2 + SimAM + 数据增强调整。每组跑相同的 epoch、相同的数据划分、相同的训练尺寸,最后对比 AP_s 和误报率两个核心指标。
这样做还有一个额外好处:你能积累自己业务领域的经验阈值。比如这个项目加 P2 头提升大,那个项目提升小,慢慢就能总结出“缺陷平均尺寸/输入尺寸、背景纹理复杂度”和 P2 头收益之间的规律。以后再遇到类似的品类,直接能判断该从哪下手。
6. 常见问题速查表与避坑清单
6.1 训练期问题快查
| 现象 | 可能原因 | 处理办法 |
|---|---|---|
| 损失不降或震荡 | 学习率过大;预训练权重被破坏 | 调低 lr 至 0.001 左右,增加 warmup epoch |
| mAP 整体低但召回高 | 置信度阈值过低或分类置信度未校准 | 绘制置信度-F1 曲线重新定阈值 |
| AP_s 特别低 | P2 头缺失或训练尺寸太缩 | 加 P2 层;把训练尺寸提到 1024+ |
| 训练后期过拟合明显 | 数据量太少或增强不足 | 引入轻松增强如亮度/噪声扰动,或做缺陷复制粘贴扩样本 |
| 验证集波动大 | 负样本比例过高或数据划分不均 | 按类别分层抽样划分训练/验证集 |
| 背景误检集中在特定纹理 | 难负样本不足 | 挖掘典型误检块加入训练集做难例挖掘 |
这里我想单独强调一下“难例挖掘”的完整流程:训练第一轮结束后,把验证集和整批训练图都跑一遍,找出所有误检框。按“置信度从高到低”排序取 Top 误检区域,裁剪成小块,和真实缺陷的正样本块混合组成一个难例补充集,加入下一轮训练。这个过程可以迭代 2-3 轮,每轮误报率都会肉眼可见地下降。这是我在工业项目里最常用也最有效的“独家小技巧”,常规文档不讲,但实际价值比调结构参数还大。
6.2 推理部署期容易忽略的细节
推理阶段还有几个常被忽略但能坑死人的细节。第一是输入图像的 padding 方式。YOLOv11 推理时自动 letterbox,默认 padding 颜色是灰色(114),如果训练时图片全部来自切图(没有 padding),推理时整张大图用 letterbox 就会产生大量灰色填充区域。模型没学过灰色区域的特征,往往会对它产生怪异的高响应。解决方法是训练时也模拟 letterbox,或者推理时用反射 padding 替代纯色填充。
第二是 batch 推理 vs 单图推理的不一致。有些推理框架在 batch 模式下会隐式改变归一化参数,导致单张测试没问题,批量跑时误检突然变多。我踩过几次之后,习惯把“单图结果”和“batch=8 推理结果”做一次严格对比,确认输出框完全一致再部署。
第三是检测框的坐标映射。切图推理时,patch 的检测框需要 + offset 映射回原图,这个看似简单的操作在多层嵌套坐标变换(比如先裁剪 ROI,再切 patch)时很容易出 bug。建议写一个工具函数集中处理坐标变换,并用可视化叠加图验证至少 100 张图,确保框的位置和原图缺陷对齐。
6.3 关于复杂背景,再补两招
结合这两类难点还有两个比较偏门的技巧。第一个是利用“背景差分”的朴素先验辅助训练。如果产品朝向固定、背景模板稳定,可以先用一张正常无缺陷的模板图做差分,得到差分图作为额外输入通道(4 通道输入),或者在数据层直接用差分图替代原图训练。对背景极其复杂但前景纹理高度一致的场景(比如固定工位的表面检测),差分往往比任何注意力模块都粗暴有效。不过它要求模板严格对齐,如果工件有轻微偏移或旋转,差分图就噪声很大,需要配合配准处理。
第二个是把“缺陷存在性”作为辅助监督信号。模型的主任务是检测框回归和分类,但你可以增加一个图像级分类分支(Image-Level Classification),告诉模型这张图里有没有缺陷。这在弱监督和半监督工业场景很有用,模型在共享特征提取时会同时学到“视觉显著性”(哪里异常)和“语义判别”(是不是缺陷),对小目标和复杂背景都有帮助。这个分支实现不算复杂,就是在 head 前加一个全局池化 + 全连接的二分类输出,损失和检测损失加权相加。我用过几次,对小目标召回有 2-5 个百分点的稳定提升。
7. 我的实际体会
这一套流程做下来,最核心的认知还是那个:工业缺陷检测是一个系统工程,模型结构最多只占三成作用,数据和策略才是决定上限的部分。YOLOv11 给了我们一个很强的特征提取底座,但产线上的难题往往藏在成像、切图、标注、阈值和后处理里。我见过不少团队反复折腾网络结构,最后发现是数据标注不一致导致模型学混乱;也见过一个项目老老实实做难例挖掘后,误检率直接降了一半。把这些“脏活”做好,比追求新模型带来的收益大得多。
如果你手上的项目和这里描述的场景类似,我建议先花一周时间把数据整理、切图标注、评估指标梳理清楚,再动手训练调参。后面的优化会顺畅很多。如果你的小目标问题在加 P2、调增强、做难例挖掘后依然顽固,不妨重新审视成像方案和标注质量,往往问题不在模型这边。