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

YOLOv6工业缺陷检测落地:从数据标注到TensorRT量化部署

YOLOv6工业缺陷检测落地:从数据标注到TensorRT量化部署 ★ FEATURED ARTICLE
1. 先把产线指标翻译成模型语言漏检、过杀与节拍工业视觉检测项目里最常见的一种翻车方式是拿着一个在公开数据集上 mAP 很漂亮的 YOLOv6 权重兴冲冲跑到产线旁边结果被质检班长一句这个划痕它没看见打回原形。问题不在模型在于我们从一开始就没把检测这件事说清楚。工业视觉检测要的不是平均精度而是在固定节拍内把该抓的抓出来不该抓的别乱抓。YOLOv6 只是在中间承担看见并定位的那一环前后还有光源、相机、触发信号、判定逻辑、复检工位。这篇文章我想把自己在几类表面缺陷检测项目里踩过的坑摊开讲从模型结构为什么这么选到数据怎么采、训练怎么调、ONNX 怎么导、TensorRT 怎么量化、产线怎么联调尽量给到能直接抄的参数和排查顺序。我接手过的项目里有一类典型场景金属冲压件表面缺陷检测六类缺陷裂纹、划伤、凹坑、污渍、毛刺、缺件单件检测窗口 300 毫秒相机 500 万像素产线速度每小时两千件左右。这个场景对 YOLOv6 提出的要求和论文里的 COCO 评测完全是两套语言。先说清楚这套语言怎么翻译后面的所有取舍才有依据。1.1 工业缺陷和自然图像根本不是一个分布自然图像里猫就是猫轮廓完整、纹理丰富、光照大体均匀。工业缺陷恰恰相反目标极小、对比度极低、边界模糊、样本极少。一道细划痕在 500 万像素的原图里可能只占 20×3 个像素灰度差只有十几个等级和背景的纹理噪声混在一起一个凹坑在侧向光下有点阴影换个批次的反光件就完全看不见。更麻烦的是缺陷这个概念本身没有稳定形态——同一类划伤长一点短一点、深一点浅一点都可能被判为同一类。这就决定了两件事。第一输入分辨率不能省。YOLOv6 默认 640 输入一张 2592×1944 的原图缩到 640那道 20 像素的划痕只剩 5 个像素网络根本学不到有效特征。第二光源和成像方案的价值远大于换模型。我曾经在一个项目上花了三天调 loss 权重最后发现把环形光换成低角度条形光同一批样本的可用对比度直接翻倍模型一周内就达标了。记住这条成像阶段能解决的问题不要留给网络。还有一个容易被忽略的点工业数据集的背景极其单一。几千张图可能都是同一个工位、同一个角度、同一种工件摆放。这种数据训出来的模型在验证集上表现极好一上线遇到批次更换、镜面反光、工件微偏就崩。所以从采集第一天起就要有意识地做多样性注入不同批次、不同光照强度、不同工件姿态、甚至人为制造的轻微离焦和脏污。这不是数据增强能替代的增强只能模拟几何和色彩变化模拟不出真实的材质差异。1.2 别拿 mAP 当交付指标甲方验收不会问 mAP他们会问三个数字漏检率、过杀率、单帧耗时。这三个指标和 mAP 的关系非常间接甚至是相互冲突的。指标定义工业含义常见目标漏检率真实缺陷中未被检出的比例流出不良品风险最高低于 0.5%过杀率误报数量占检测总数的比例造成人工复检浪费低于 3%单帧耗时从图像就绪到输出判定直接决定能否跟上节拍小于节拍的 60%重复精度同一样本多次检测结果一致性影响判定稳定性框位置抖动小于 2 像素漏检和过杀是一对相互拉扯的指标。你把置信度阈值从 0.5 降到 0.2漏检降了过杀飙升反过来也一样。所以工业项目的第一步不是训模型而是和业务方一起画出这条权衡曲线明确我们愿意用多少过杀换多少漏检。我一般的做法是推理时输出置信度 0.1 以上的所有候选框判定环节再用分级策略处理而不是在模型里就把阈值卡死。这样后续调整策略不用重新训练和导出改配置文件就行这个设计在后面第 6 章还会展开。节拍这块也得提前算。假设产线每小时 2000 件单件可用时间 1.8 秒扣掉上下料、通信、执行机构动作留给视觉的窗口可能只有 300 毫秒。这时候如果模型在目标卡上跑一帧要 200 毫秒加上图像传输、预处理、后处理基本没有余量任何一次抖动都会造成漏拍。稳妥的做法是把视觉耗时压到节拍的 50% 到 60%留出缓冲。这个预算会反过来约束你选 YOLOv6 的哪个尺寸、用多大分辨率、要不要量化。2. YOLOv6的结构选择哪些设计在工业场景真能用上选 YOLOv6 不是因为它精度榜单排第几而是它的几个结构决策恰好对工业部署友好。但友好归友好每个设计在缺陷检测场景下都有它的适用边界用错了反而添麻烦。这一章我按结构—场景的对应关系拆开讲。2.1 EfficientRep重参数化与产线推理的匹配关系YOLOv6 的骨干大量使用 RepVGG 风格的多分支结构训练时是 3×3 卷积加 1×1 分支加恒等映射并联推理时通过重参数化把多分支合并成单个 3×3 卷积。这个设计的价值在工业场景里体现得非常直接——训练时享受多分支的表达能力推理时享受单路卷积的速度。为什么单路卷积对产线重要因为工业部署大多数跑在边缘推理卡上算子融合和显存访问模式对速度影响巨大。多分支结构在推理时会引入额外的张量读写和 kernel launch单路卷积则能被推理框架做更彻底的融合。实测下来同参数量下重参数化后的模型在目标卡上的延迟通常能低 15% 到 30%具体数字取决于输入分辨率和框架版本。但这里有个坑必须提前知道重参数化一旦完成模型就冻结了。你不能再对合并后的模型做结构剪枝也不能指望它保持原来的训练动态。所以流程应该是训练完整模型验证精度导出前执行重参数化融合再导出 ONNX。如果后面发现要改结构只能回到训练权重重新走一遍。还有一个细节BN 层融合的时机。YOLOv6 官方仓库在导出脚本里会调用fuse相关的函数把 Conv 和 BN 合并。如果自己改过网络结构比如加了自定义模块一定要确认新模块也参与了融合否则会出现训练时正常、导出后精度掉一截的怪现象。我遇到过一次原因是往 neck 里插了一个带 BN 的自定义残差块导出脚本没覆盖到融合后那一层的数值分布完全变了最终表现为大量小目标框偏移。排查方式很简单导出前后用同一批图跑一遍逐层对比特征图的最大绝对误差超过 1e-3 的那一层就是问题所在。2.2 Anchor-free加TAL标签分配对小缺陷的利与弊YOLOv6 采用 anchor-free 的 point-based 预测方式配合 TALTask Alignment Learning做标签分配。TAL 的核心思想是把分类得分和回归质量联合起来衡量一个锚点是否对齐用这个联合指标来动态选择正样本。相比固定 IoU 阈值的分配方式TAL 对形状差异大的目标更友好。对工业缺陷来说这是把双刃剑。好处是不需要为每类缺陷手工设计 anchor。缺陷的长宽比分布极其发散一道划痕可能是 20:1一个凹坑可能是 1:1靠聚类 anchor 很难覆盖anchor-free 直接绕过了这个问题。坏处是TAL 的打分依赖分类置信度和 IoU 的联合而极小目标的 IoU 本身就不稳定——20×3 的框偏移两个像素IoU 就掉到 0.5 以下。这会导致小缺陷在分配阶段就被判为不对齐正样本数量严重不足训不出来。我的处理办法有三条。第一放大输入分辨率让缺陷在特征图上至少占 8 到 16 个像素这是最根本的解法。第二适当放宽正样本选择的 topk 数量让更多候选点参与缓解小目标正样本稀疏的问题。第三在数据层面做切片训练把大图裁成重叠的小块分别训练和推理等效于进一步放大目标。关于切片第 3 章会给出具体参数。提示切片推理时一定要注意重叠区域的目标被切断问题。重叠率建议不低于切片边长的 20%并且在合并结果时用 NMS 处理跨切片的重复框否则同一个缺陷会被检出两次直接推高过杀率。2.3 解耦头与VFL在类别极不均衡下的表现YOLOv6 使用解耦检测头分类和回归分支分开。工业场景里这个设计的好处很实在分类分支学是不是缺陷、是哪类缺陷回归分支学框在哪两者互不干扰。在缺陷样本只占全图极小面积的情况下耦合头容易出现分类拖累回归的现象解耦之后回归精度更稳。分类损失用的是 VFLVarifocal Loss它对正负样本做了非对称加权正样本按回归质量加权负样本按置信度衰减。这个设计对工业场景的海量负样本是有帮助的——一张 500 万像素的图里可能只有一个缺陷其余全是背景普通交叉熵会被背景淹没。但我实测下来发现一个问题VFL 对高质量正样本的偏好很强如果标注框本身不够精细比如标注员习惯性地把框画大一圈模型会学到一个偏大的框导致定位精度上不去。所以标注规范里必须明确框要贴边不留白边也不切掉目标。这一条我在第 3 章会展开。另外一个实操经验是当某一类缺陷样本极少比如只有几十个时不要指望调 loss 权重能救回来。我试过把类别权重调到 10 倍结果只是让模型对该类过拟合验证集上该类精度上去了产线上遇到新形态照样漏。正确做法是回到数据采集或者把这类缺陷降级为疑似输出交给复检工位人工确认。工程上承认模型的边界比强行拔高一个不可靠的指标要负责任得多。3. 数据与标注模型上限在进训练脚本之前就定了我常跟团队里的人说训练脚本敲下回车那一刻模型的精度上限就已经定死了后面所有的调参只是在逼近这个上限。工业视觉项目里八成的问题出在数据和标注而不是网络结构。这一章讲我实际怎么把控这两块。3.1 采样与光源先解决看得见的问题采样阶段最重要的工作不是多拍而是拍全。我的做法是先做一轮失效模式梳理拉上工艺和质检的人把这类工件历史上出现过的缺陷形态列出来按出现频次和危害程度排序形成一个采集清单。然后针对每一类刻意去构造能拍到它的成像条件。光源这块几种常见方案的适用场景差别很大我整理了一张对照表光源方案适用缺陷特点注意事项低角度条形光划痕、裂纹、凹凸掠射增强表面纹理对工件平整度敏感翘曲件效果差同轴光镜面件表面缺陷消除反光成像均匀成本高对灰尘极敏感环形漫射光一般外观、污渍通用性好对比度偏低小缺陷易淹没背光缺件、孔洞、轮廓对比度极高只能看透射特征选定光源后还要固定相机参数曝光、增益、白平衡全部手动锁定禁止自动曝光。自动曝光在产线上是灾难工件颜色稍有变化整体亮度就漂移模型直接失效。这一点我在早期项目上吃过亏现场调试时一切正常换了个批次的料图像整体偏暗原本能检出的污渍全部漏掉查了两天才发现是相机自动曝光在工作。采集数量上我的经验值是每类缺陷至少 300 个独立实例正常样本不少于 2000 张。注意是独立实例同一件工件旋转角度拍十张不算十个。数量不够的时候宁可先把类别合并比如把轻微划伤和重度划伤合成一类也不要硬凑样本数。3.2 标注规范与一致性校验标注是工业项目里最容易失控的环节。十个标注员能标出十种风格最后模型学到的是标注员的习惯不是缺陷本身。我的做法是先写一份标注规范文档把每一类缺陷的定义、边界、最小可标尺寸、排除条件写清楚配正反例图然后做一致性校验。规范里必须包含这几条硬约束最小可标尺寸小于该尺寸的缺陷不标同时也不作为漏检考核项。这一条要和业务方签字确认否则后期扯皮。框的贴合度框边距离目标边缘不超过 3 个像素不允许为了保险画大框。遮挡处理被工件结构遮挡超过 50% 的目标标为困难样本训练时保留评估时单独统计。同类合并规则相邻距离小于 5 像素的同类缺陷合并为一个框避免模型学到碎片化目标。一致性校验我一般这样跑随机抽 200 张图让两个标注员独立标注计算同一类别的框 IoU 匹配率。匹配率低于 85% 的类别说明定义有歧义必须回去改规范重新培训。这个步骤花两天能省掉后面两周的返工。顺带说一个容易被忽略的问题负样本的标注质量。工业数据集里绝大多数图是没有缺陷的这些图不需要画框但需要确认确实没有缺陷。如果采集时把有缺陷的图误归到正常类模型就会学到这种形态是正常的造成系统性漏检。我的做法是对正常样本做 100% 人工复核成本高但值得。3.3 增强策略的取舍与切片训练YOLOv6 默认的增强配置比较激进Mosaic、MixUp、随机缩放、色彩抖动一应俱全。这套配置在 COCO 上有效搬到工业场景要打折。Mosaic 的问题在于它会破坏缺陷的空间上下文。工业缺陷往往和工件的结构位置相关比如某个转角处容易产生裂纹。Mosaic 把四张图拼在一起模型学到的是任意位置都可能有缺陷反而削弱了位置先验。我的做法是训练前期开启 Mosaic后期关闭做微调让模型在最后阶段适应真实分布。MixUp 在工业场景我基本不用。缺陷的判别依赖局部纹理两张图按比例混合后纹理被破坏产生大量语义模糊的样本对收敛没有帮助。色彩抖动要谨慎。工业成像的光照是固定的过度的色彩抖动会让模型对颜色不敏感而有些缺陷恰恰是靠色差判别的比如氧化变色。我的经验是把亮度、对比度的抖动幅度控制在 ±10% 以内色调抖动基本关掉。真正有效的是几何增强加噪声增强随机旋转 ±5 度模拟工件摆放偏差、随机平移 ±3%、高斯噪声、轻微运动模糊。这几项能显著提升上线后的稳定性。当缺陷尺寸小于输入分辨率的 1/50 时切片训练几乎是必选项。具体参数原图 2592×1944切成 1024×1024步长 768即重叠 256 像素重叠率 25%。这样每张原图产生 6 个切片训练样本量放大 6 倍缺陷在切片里的相对尺寸放大了 2.5 倍。推理时同样切片合并结果后统一做 NMSIoU 阈值设 0.5。# data/metal_defect.yaml train: /data/metal/images/train val: /data/metal/images/val nc: 6 names: [crack, scratch, dent, stain, burr, missing]4. 训练阶段的参数落地从官方配置到产线可用模型拿到一份干净的、标注一致的数据集之后训练本身反而没那么玄乎。YOLOv6 的默认配置已经相当能打我要做的是针对工业数据的几个特点做定向调整。这一章给的是可直接抄的配置思路和背后的理由。4.1 分辨率、batch与学习率的联动分辨率是第一优先级。前面说过小目标的问题这里给个量化判断标准统计训练集中所有标注框的宽高取 5% 分位数如果该值小于输入分辨率的 1/40就必须提高分辨率或切片。比如 5% 分位数的框宽是 18 像素输入 640 时占比 2.8%低于 2.5% 的阈值附近属于危险区建议提到 1024 或切片。分辨率提高会带来显存和耗时的平方级增长。1024 相比 640像素数翻 2.5 倍训练显存大约翻 2.5 到 3 倍推理耗时也接近这个比例。所以要在训练前就把推理预算算清楚如果目标卡上 1024 输入的 FP16 推理要 80 毫秒节拍 300 毫秒那没问题如果要 200 毫秒就得考虑换更小的模型尺寸比如从 s 换到 n或者上量化。学习率要跟着 batch 走。YOLOv6 官方配置里学习率是按特定 batch 调的如果你把 batch 从 32 改成 16学习率要相应下调经验公式是线性缩放lr_new lr_base * batch_new / batch_base但同时要把 warmup 轮数适当拉长否则前期容易发散。python tools/train.py \ --batch 16 \ --conf configs/yolov6s_finetune.py \ --data data/metal_defect.yaml \ --device 0 \ --epochs 300 \ --img 1024 \ --workers 8预训练权重一定要用。工业数据集通常只有几千张从零训很难收敛到理想状态。用 COCO 预训练权重初始化然后把学习率调低一个量级做微调。我一般设初始学习率 0.005 左右余弦退火warmup 3 个 epoch。冻结骨干训练几个 epoch 再解冻对小数据集也有帮助能避免前期把预训练特征破坏掉。4.2 类别不平衡和难样本的处理六类缺陷样本量可能是 800、500、300、200、80、40 这样的分布。40 的那一类基本训不出来。前面说过不要靠调权重硬救但也不是完全没办法。我的处理顺序是这样的。先看这一类能不能合并或降级能合并就合并能降级为疑似就降级。如果业务上必须检出就走过采样加针对性增强把该类样本复制 3 到 5 倍同时只对该类做更强的几何变换旋转、缩放、弹性变形增加形态多样性。注意过采样要在数据集层面做不要用 sampler 加权后者容易导致同一个 batch 里全是同一类BN 统计量偏移。难样本挖掘是另一个有效手段。训练到中期比如 150 epoch后用当前模型跑一遍训练集把漏检和低置信度正确检出的样本挑出来人工复核后加进训练集再训。这一轮通常能带来 1 到 2 个点的漏检率改善代价是多花一天时间。还有一个实操细节背景图的比例。工业数据集里正常样本很多如果全部参与训练正负样本比例会极端失衡。我一般按 1:3 的比例采样正常样本和缺陷样本进训练集剩下的正常样本作为独立的验证集专门用来测过杀率。这样既能控制训练时的失衡又能真实评估误报水平。4.3 蒸馏与自蒸馏值不值得上YOLOv6 论文里提到了自蒸馏方案用一个大模型当 teacher 指导小模型。工业场景要不要上我的判断标准是当你需要把模型压到更小尺寸以满足节拍而直接训小模型精度不够时蒸馏值得试。如果大模型本来就能跑得动那就没必要折腾。实际做过一次目标卡上 yolov6s 在 1024 输入下要 95 毫秒超预算必须换 yolov6n。直接训 n漏检率是 1.8%达不到 0.5% 的要求。上自蒸馏后降到 1.1%配合后面的量化才勉强达标。蒸馏的配置要点是teacher 用已经训好的 s 模型蒸馏温度设 1 到 2蒸馏损失的权重从 0.5 开始训练中期逐步衰减。标签分配蒸馏这块官方实现里是有的直接用就行。但蒸馏有个隐性成本训练时间翻倍调参空间变大。如果项目周期紧我会优先考虑其他手段比如提高分辨率加切片、或者接受稍高的过杀率用复检兜底。4.4 验证集构造与早停策略验证集必须独立于训练分布这句话听着像废话但在工业项目里经常被违反。如果你从同一批采集数据里随机划分训练验证验证集和训练集的背景、光照、工件批次完全一样验证精度会虚高上线必崩。我的做法是按批次划分用 A、B 两个批次的数据训练用 C 批次的数据验证。如果采集时没做好批次标记至少按采集时间划分用前 70% 时间的数据训练后 30% 验证。这样验证集才能反映真实的上线表现。早停不要只看 mAP。工业场景我盯的是固定过杀率下的漏检率在验证集上把置信度阈值调到过杀率刚好 3% 的位置看此时的漏检率是多少这个指标连续 15 个 epoch 不降就停。这个指标比 mAP 更贴近交付要求。训练日志里我还会额外记录两个东西一是每类的漏检数二是小目标面积小于 32×32的召回率。后者是工业项目的晴雨表它掉下去通常意味着分辨率不够或者正样本分配出了问题。5. 导出与推理加速ONNX到TensorRT的完整链路模型训完只是半成品真正决定项目成败的是部署链路。我见过太多训练精度很好上线精度稀烂的案例九成出在导出和量化这两个环节。这一章按实际操作顺序讲包括每一步的坑。5.1 导出参数与解码一致性导出 ONNX 的第一原则导出的图和训练时的前处理必须严格一致。前处理包括 resize 方式letterbox 还是直接缩放、归一化参数、通道顺序、是否 BGR 转 RGB。这四项任何一项不一致精度都会掉而且掉得莫名其妙。YOLOv6 官方导出脚本的典型用法python deploy/ONNX/export_onnx.py \ --weights runs/train/exp/weights/best_ckpt.pt \ --img 1024 \ --batch 1 \ --simplify \ --iou-thres 0.65 \ --conf-thres 0.25 \ --topk 100几个参数值得说明。--simplify会用 onnx-simplifier 做图优化能去掉冗余节点、合并常量通常能带来 5% 到 10% 的推理加速但偶尔会引入一些奇怪的算子如果后面 TensorRT 解析报错可以先去掉这个选项试试。--iou-thres、--conf-thres、--topk是决定 NMS 是否被写进计算图里的参数。是否把 NMS 导进图里是个需要权衡的决策导进去省事端到端输出直接可用但会限制灵活性阈值改不了不导进去NMS 在 C 里手写灵活但增加代码量。我的建议是 NMS 不进图图里只输出原始预测后处理用代码实现方便线上调阈值。还有一点动态 batch。如果产线是单帧触发batch 固定为 1导出时就不要开动态轴静态 shape 能让 TensorRT 做更激进的优化。如果要做多路相机合并推理才需要--batch 4之类。我见过有人无脑开动态维度结果推理速度掉了三成纯属自找。5.2 FP16与INT8量化的实测差异FP16 基本是白送的。绝大多数推理卡的 FP16 算力是 FP32 的两倍以上精度损失在检测任务里通常可以忽略。我的经验是 FP16 相比 FP32mAP 掉幅在 0.1 个点以内速度提升 1.6 到 2 倍。除非你的模型里有对数值范围特别敏感的算子否则直接用 FP16。INT8 就是另一回事了。它能把速度再提一倍左右但精度损失取决于校准质量搞不好会掉好几个点而且掉得最多的地方往往是小目标和低对比度目标这恰恰是工业场景最在意的。构建 engine 的命令大致是这样# FP16 trtexec --onnxyolov6s_1024.onnx \ --saveEngineyolov6s_1024_fp16.engine \ --fp16 \ --minShapesimages:1x3x1024x1024 \ --optShapesimages:1x3x1024x1024 \ --maxShapesimages:1x3x1024x1024 \ --workspace4096 # INT8 需要校准缓存 trtexec --onnxyolov6s_1024.onnx \ --saveEngineyolov6s_1024_int8.engine \ --int8 \ --calibcalib.cache \ --shapesimages:1x3x1024x1024 \ --workspace4096校准集是关键。校准集必须来自真实产线分布且要覆盖各类缺陷和正常样本。我一般用 500 到 1000 张其中缺陷样本占 30% 左右。如果校准集全是正常样本模型对缺陷区域的特征分布估计不准量化后小缺陷的响应会被压平表现为漏检。实测数据给个参考同一批 800 张验证图1024 输入同一张推理卡精度模式单帧耗时漏检率过杀率备注FP32148 ms0.62%2.8%基线FP1679 ms0.64%2.9%基本无损INT8校准良好41 ms0.81%3.4%可接受需复检兜底INT8校准集偏斜40 ms2.7%6.1%不可用这张表是我印象比较深的一次对比INT8 在校准集偏斜的情况下漏检率直接翻了四倍问题就出在校准集里几乎没有小缺陷样本。后来补充了 300 张带小缺陷的图进校准集漏检率回到 0.8% 左右。所以 INT8 上线前一定要做量化前后的逐类对比测试看哪一类掉得最狠针对性补校准数据。5.3 后处理与Python到C的迁移后处理看起来简单实际是精度事故高发区。YOLOv6 的输出是 anchor-free 的密集预测每个位置输出分类得分和框的四个距离值左、上、右、下需要做解码、阈值过滤、NMS。Python 版本的原型大概长这样import numpy as np def decode(pred, strides(8, 16, 32), conf_thres0.25): boxes, scores, classes [], [], [] for level, stride in enumerate(strides): # pred[level]: [1, H, W, 4nc] fmap pred[level][0] h, w fmap.shape[:2] cls_score fmap[..., 4:] cls_id cls_score.argmax(-1) conf cls_score.max(-1) ys, xs np.mgrid[0:h, 0:w] cx (xs 0.5) * stride cy (ys 0.5) * stride l, t, r, b (fmap[..., i] * stride for i in range(4)) x1 cx - l y1 cy - t x2 cx r y2 cy b mask conf conf_thres boxes.append(np.stack([x1[mask], y1[mask], x2[mask], y2[mask]], -1)) scores.append(conf[mask]) classes.append(cls_id[mask]) return np.concatenate(boxes), np.concatenate(scores), np.concatenate(classes)迁到 C 时最容易出问题的三个地方一是坐标对齐方式Python 里(xs 0.5) * stride这个 0.5 的偏移很多 C 实现会漏掉导致整体框偏移半个 stride小目标直接崩。二是浮点与整数混用C 里如果用了整型做中间计算会引入截断误差。三是NMS 的排序稳定性Python 的argsort和 C 的std::sort在分数相同时顺序不同理论上不影响结果但会让两次运行的结果有微小差异调试时容易误判为模型不稳定。我的建议是Python 原型跑通后用同一批图分别跑 Python 和 C 版本逐框对比坐标和分数误差应该在 1e-3 以内。超出就说明有一边写错了不要带着这个问题往下走。5.4 常见掉精度问题的排查顺序上线后精度不达标按这个顺序排查能覆盖九成以上的问题前处理一致性拿一张图分别用训练时的 dataloader 和部署代码做前处理对比输出的张量逐元素差值应该在 1e-4 以内。输出张量一致性同一张图过 PyTorch 模型和 ONNX/TensorRT 模型对比原始输出张量。如果这里就差了问题在导出或量化。解码与 NMS对比解码后的框。如果原始张量一致但框不一致问题在后处理。量化精度如果只有 INT8 出问题换回 FP16 对比确认是量化导致再回头检查校准集。数据分布以上都没问题那就是训练数据覆盖不足回到第 3 章补数据。这个顺序的核心逻辑是从输入端向输出端逐段隔离每段只验证一件事。我见过有人一上来就怀疑模型不行重新训了两次最后发现是部署代码里把 RGB 和 BGR 搞反了。老老实实按顺序排查比瞎猜快得多。6. 产线联调把模型塞进节拍里的工程细节模型跑通了工程上还有一堆事。这一章讲的是那些不会出现在论文里、但直接决定项目能不能验收的东西。6.1 判定策略从单帧阈值到多帧投票单帧置信度阈值是最粗糙的判定方式但它有个致命问题阈值调低了过杀高调高了漏检多没有中间地带。工业项目里我一般用三层策略。第一层是分类阈值分级。不同缺陷类别的危害程度不同阈值也应该不同。裂纹漏了会造成安全事故阈值设 0.15污渍漏了影响外观但可返工阈值设 0.4。每个类别的阈值单独配置写在配置文件里现场可以调。第二层是空间过滤。结合工件的 ROI 区域把不可能出现缺陷的位置排除掉。比如工件边缘 10 像素内的检出框大概率是边缘反光造成的误报可以直接过滤。这一层能砍掉相当一部分过杀。第三层是多帧投票。如果产线上同一件工件有多帧图像比如旋转拍摄或多工位对同一个位置的检出做投票连续 2 帧以上检出才判定为缺陷。这一层对大缺陷的漏检影响很小但能显著压过杀。# judge_config.yaml class_thresholds: crack: 0.15 scratch: 0.30 dent: 0.25 stain: 0.40 burr: 0.20 missing: 0.12 roi_margin: 10 vote_frames: 2 max_defect_area_ratio: 0.3这套策略的好处是把模型能力和业务规则解耦了。模型只负责给出候选和分数判定规则由工程侧配置现场调整不需要重新训练。6.2 误检漏检的线上治理闭环上线不是终点是起点。产线上的数据分布会缓慢变化模具磨损导致工件表面纹理变化光源老化导致亮度衰减新批次材料反光特性不同。这些变化会让模型的表现慢慢漂移。我一般会建一个线上样本回流机制每天从产线抽 200 张图包含检出和未检出的人工复核后加入待评估集。每周跑一次评估看漏检率和过杀率的变化趋势。如果某一类连续两周恶化超过 20%就触发增量训练。增量训练不是简单地把新数据加进去重训。我的做法是新数据占 30%历史数据占 70%用较低的学习率基线的 1/10微调 20 到 30 个 epoch。这样既能吸收新分布又不会把旧知识忘掉。微调后必须做回归测试在历史评估集上确认精度没有倒退才能上线。还有个治理细节误检样本要分类归因。是光照问题、工件污渍、还是模型真的分不清归因之后分别处理。光照问题调光源污渍问题加规则过滤模型分不清才回去补数据。不归因就盲目补数据往往是白费功夫。6.3 模型版本与漂移监控工业现场最怕的是不知道现在跑的是哪个模型。我见过一个项目现场跑了三个月某天精度突然下降排查半天发现是有人手动替换了 engine 文件换成了一个早期测试版本。所以版本管理必须做扎实。每次训练产出一个模型记录这几项训练数据集的哈希、配置文件、随机种子、评估指标、导出的 engine 文件哈希。现场部署时engine 文件的哈希要和记录对上启动日志里打印出来。这样出问题能快速定位。漂移监控我一般看三个信号。一是平均置信度分布如果整体分布往低处偏移说明输入数据分布变了。二是检出数量分布某类缺陷的日均检出数突然翻倍或归零都是异常。三是过杀率的滑动平均用 7 天窗口超过基线 50% 就告警。这些监控不需要多复杂一个简单的统计脚本加个告警就够。关键是有人看有人处理。我建议把这几项指标做成每日看板让现场的质量工程师也能看到比藏在服务器里强。7. 复盘这套流程里最容易被低估的三件事做了几个项目下来我发现真正决定成败的往往不是模型选型和调参而是三件听起来很土的事。第一件是成像方案。我统计过自己经手的项目最后达标困难的七成以上是成像没做到位而不是模型不行。把光源和相机参数调好很多原本要上大模型、高分辨率的场景用中等配置就能解决。所以项目启动阶段我宁可多花一周在光学调试上也不愿意后期花一个月调模型。第二件是标注一致性。模型学的是标注不是缺陷。标注规范含糊训出来的模型就含糊而且这种含糊没法通过调参解决。我现在的习惯是项目一开始就把标注规范写出来先标 200 张做一致性校验校验不过就不往下走。第三件是判定策略的工程化。模型输出的是分数业务要的是通过/不通过。中间这层转换规则如果能做成可配置的现场的调试效率会高一个数量级。我后来的项目都会把这层抽出来做成配置文件加热加载现场工程师改个阈值不用重启服务省了大量沟通成本。至于量化、蒸馏、切片这些技术手段它们确实有用但都是在前三件事做好的基础上才发挥价值。顺序搞反了再花哨的技术也救不回来。
阅读完成 · 觉得有帮助?
咨询建站