
1. 从一张航拍图说起绝缘子缺陷识别到底难在哪1.1 一个几十像素的缺口决定了整个方案的上限做绝缘子缺陷识别这个方向很多人的第一反应是这不就是个目标检测任务吗拿个现成模型跑一跑就行。我最初也是这么想的直到真正把一张 4000×3000 的巡检原图摊在屏幕上才意识到问题的量级完全不是一回事。一整张图里可能有十几基杆塔、几十串绝缘子而单串绝缘子在原图中往往只占 200 到 600 像素宽单片伞裙的直径可能只有 30 到 50 像素真正需要识别的破损缺口、裂纹、自爆点落在图上是十几到二十几个像素的一小块区域。这个尺度意味着什么意味着你把图直接缩放到 640×640 送进网络绝缘子串本身可能只剩几十像素缺陷区域已经被插值算法抹平了模型根本没有任何可用的纹理信息。这是整条技术路线上第一个、也是最容易被忽视的卡点不是模型不够强而是信息在预处理阶段就丢干净了。所以在方案设计的第一天我就把如何在保留足够分辨率的前提下完成全图覆盖作为核心约束而不是事后补救。另一个麻烦是类内差异极大。玻璃绝缘子、瓷绝缘子、复合绝缘子三种材质在图像上的表现完全不同玻璃串反光强、边缘锐利自爆后留下的缺口边界清晰但和背景天空容易混瓷串表面有釉面破损处呈现灰白色粉末状和鸟粪、灰尘污渍高度相似复合绝缘子的伞裙是硅橡胶材质破损常表现为撕裂、缺角、粉化边界模糊且颜色和正常伞裙接近。你用一套统一的视觉特征去描述缺陷这个词本身就是不成立的。所以我在项目前期花了整整两周只做一件事把历史巡检影像翻出来按材质、缺陷类型、拍摄条件分桶统计看清楚每一类缺陷在各种条件下的成像表现。这个动作看起来不产出任何代码但它决定了后面所有的类别定义、标注规范和模型选型。跳过这一步直接开训最后的结局一定是模型在验证集上 mAP 挺好看上线后运维班组反馈一天报几百条全是误报。1.2 检测、分割还是分类三条路线的取舍逻辑明确了难点之后技术路线其实有三条可选我在方案评审时把三条路都摆出来对比过最后的选择是基于真实约束做出来的而不是追新。路线典型做法优势落地阻力端到端目标检测单阶段检测器直接输出绝缘子/破损/自爆等类别框一次前向搞定工程链路短推理快小目标召回率上不去缺陷类和背景类极度不平衡标注成本高但有效样本少语义/实例分割分割出绝缘子串区域再在区域内找异常对不规则破损边界友好可解释性强像素级标注成本极高一个班组一天标不了几十张模型重、推理慢两级级联定位分类先检测绝缘子串 ROI裁切放大后做缺陷分类或细粒度检测分辨率问题自然解决两级任务各自简单样本可复用链路变长级联误差会传导需要处理裁切边界和重复框我最后选的是第三种的变体串级定位 ROI 细粒度判别也就是先用一个轻量检测器把图中所有绝缘子串框出来按框裁切并放大到统一尺寸再用第二个模型判断这一串是否存在缺陷、属于哪一类。这个选择背后的逻辑很朴素把一个大而难的问题拆成两个小而可控的问题。第一级只关心绝缘子在哪这个任务的特征非常稳定颜色、纹理、长条状轮廓模型几百张图就能收敛得不错第二级输入的是裁切放大后的局部图缺陷区域从 20 像素变成 100 多像素纹理信息终于够用了。有人会问为什么不直接上 RT-DETR 或者更大主干的检测器一步到位我实测过在同样 2000 多张标注图的数据量下端到端方案对自爆这种边界清晰的缺陷勉强能到 0.6 左右的召回对伞裙破损裂纹这类边界模糊的类别基本崩盘召回不到 0.3。而级联方案在同样数据下第二级分类器的破损召回能到 0.78这个差距不是调参能抹平的是分辨率和任务复杂度决定的。当然代价是推理耗时翻倍所以后面在部署环节做了不少优化这部分在第 4 章详细讲。提示级联方案有个隐含前提——第一级的召回必须足够高宁可在第一级多框一些置信度阈值放低也不能漏掉串。因为第一级漏了第二级再准也没用。我一般把第一级阈值设在 0.25 左右配合后面的规则过滤整体误框率是可以接受的。1.3 系统的分层结构与工程边界把方案定下来之后我在设计文档里把整个系统切成五层这个分层不是为了好看是为了让每一层的问题可以被独立定位和替换。采集层无人机或人工手持设备拍摄的原始影像涉及拍摄距离、角度、曝光参数这一层的质量直接决定上限。数据层清洗、去重、标注、划分、增强是投入产出比最高也最枯燥的一层。训练层模型结构、损失、超参、评估这一层反而是最标准化的。推理层切片、批处理、量化、后处理、跨片合并工程坑最多的一层。业务层置信度分级、人工复核队列、误报回流、报表输出。之所以强调这个分层是因为我在实际推进中发现大部分模型效果不好的抱怨根因都不在训练层。有一次连续两周指标上不去最后查出来是数据层的问题同一基杆塔的多张连拍图被随机划分到了训练集和验证集模型等于提前看过答案验证集分数虚高换到真实新线路上直接掉 20 个点。这个坑后面在第 2 章会详细展开。还有一点需要提前说清楚这个系统在业务上属于辅助排查不是全自动判定。任何一条识别结果都要经过人工复核才能进入检修工单。这个定位非常关键它决定了我们对指标的要求——召回优先于精确率宁可多报一些让人去筛也不能漏掉真实的危急缺陷。这个原则后面贯穿了阈值设定、损失函数设计和评估体系。2. 数据这一关八成的工作量都在这里2.1 采集侧的约束比算法约束更硬很多人拿到一批巡检图就开始标标完就训训完发现模型换个季节、换个光照就失效。问题的根子在采集环节这批图的成像条件太单一了。我在项目启动时做过一次统计手上两万多张历史图里晴天顺光的占比超过 70%阴天和逆光不到 15%雨雾天气几乎没有。这种分布下训出来的模型本质上是在学晴天顺光下的绝缘子长什么样而不是绝缘子长什么样。所以我在采集规范里补了几条硬性要求这些条目不涉及任何设备和流程的具体参数都是通用的成像原则同一基杆塔至少覆盖两个以上的拍摄角度避免模型只认某个固定视角下的伞裙排列。逆光和侧逆光场景必须专门补拍因为玻璃绝缘子在逆光下会呈现强烈的边缘光晕是最容易误判的工况之一。拍摄距离要保证单串绝缘子在图上的短边不少于 150 像素低于这个值基本没有判别价值强行标注只会污染数据集。避免大面积遮挡导线、横担、植被挡住超过一半伞裙的样本标注意义不大直接剔除。保留一定比例的空图也就是画面里只有天空、植被、杆塔但没有绝缘子的图这类负样本对抑制误报的作用被严重低估。最后这条我要多说两句。早期我只用含绝缘子的图训练结果模型在纯背景图上也会硬框出几个绝缘子因为 softmax 式的分类头天然倾向于给每个区域分配一个类别。后来混入了约 15% 的纯负样本图误报率直接降了一大截。这个成本极低效果却很明显属于性价比极高的操作。另外补充一个实操心得连拍图必须去重。无人机巡检经常对同一目标连拍十几张这些图之间差异极小如果不去重它们会以极高概率同时进入训练集和验证集造成严重的数据泄漏。我的做法是先算图像感知哈希把汉明距离小于阈值的图聚成一簇一簇只保留最清晰的一张。这一步做完数据集规模通常会缩水 30% 到 40%但模型在真实新数据上的表现反而更稳。2.2 缺陷类别定义标注规范比标注工具重要标注这件事最怕的不是慢是不一致。三个人标同一批图一个人觉得伞裙边缘缺了一点点算破损另一个人觉得不算模型学到的东西就是矛盾的。所以我在正式开标之前先写了一份三四页的标注规范文档把每一类的判定边界写死。类别视觉特征最小可标尺寸主要易混淆项玻璃件自爆伞盘整体碎裂脱落留下明显缺口或空洞边缘锐利缺口短边不小于 8 像素强反光形成的高光斑、天空透光形成的亮区伞裙破损伞裙边缘撕裂、缺角、断裂形状不规则缺失部分不小于单片的 1/5生产制造的自然缺口、遮挡造成的视觉缺失裂纹表面线状痕迹深浅不一常沿伞裙径向延伸长度不小于 10 像素且宽度可辨釉面开片纹、污渍流痕、雨水流线异物悬挂缠绕或悬挂在串上的塑料、绳索、枝条、鸟巢面积不小于 15 像素见方与背景植被重叠、导线上的飘挂物烧伤/放电痕局部发黑、灰化、有熔融痕迹面积不小于 10 像素见方污秽沉积、阴影、锈迹这张表最右边一列才是核心。标注规范的价值不在于告诉标注员什么该标而在于告诉他什么不该标。我见过太多项目类别定义只写了伞裙破损没写制造公差造成的自然缺口不算结果标注集里混进大量正常件模型学到的破损特征就是错的。具体操作上我采用三人交叉复核的方式每个人独立标 100 张然后互相比对凡是两人以上判断不一致的样本拿出来开会讨论把结论回写到规范文档里再进入下一轮。这个流程走两到三轮标注一致性通常能稳定下来。衡量一致性的指标我用的是框级 IoU 匹配后的类别一致率目标定在 90% 以上低于这个值说明规范还有模糊地带。注意标注时一定要保留困难样本而不是只挑清晰的图标。那些模糊的、遮挡的、光照极端的图恰恰是模型上线后最容易翻车的地方。全部剔除的话离线指标会很好看真实表现会很难看。2.3 数据集划分按杆塔切别给模型背答案这一节我要单独讲因为这是我踩过最贵的一个坑。第一次训完模型验证集 mAP0.5 到了 0.87我当时挺得意直接拿了一批新线路的图去测结果掉到 0.52。查了两天才发现问题我是按图片随机划分数据集的而无人机对同一基杆塔会拍多张不同角度的图这些图在视觉上高度相似。模型在训练集里见过这基杆塔的正面在验证集里遇到它的侧面几乎等于开卷考试。正确的做法是按物理实体划分以杆塔为最小单位同一基杆塔的所有影像必须整体进入同一个子集。如果数据量足够还可以再往上提到线路级别。我后来的划分策略是这样的先按杆塔 ID 聚合成组得到若干组。按组的维度做分层抽样保证训练/验证/测试三大集合里各缺陷类别、各材质、各拍摄条件的大致比例一致。比例采用 7:1.5:1.5测试集单独封存训练过程中绝不碰。另外留一批跨域集来自完全不同的时间跨度和拍摄设备专门用来模拟真实上线时的分布偏移。这个划分方式会让离线指标明显变丑但它反映的是真实水平。我经常跟团队说验证集分数虚高是一种债务迟早要在现场还不如一开始就诚实一点。还有一个细节测试集不要只统计总体指标要按类别、按材质、按光照条件拆开看。我做过一次拆解发现整体召回 0.81 看起来还行但复合绝缘子伞裙破损这一类只有 0.54被其他类别的高分掩盖了。如果不拆开这个短板会一直藏到上线。2.4 长尾分布与小样本增强的实操打法绝缘子缺陷识别是一个典型的长尾问题。正常绝缘子样本占了绝大多数自爆、异物这类危急缺陷一年也出不了多少例。我手上的数据分布大概是 100:1 到 300:1 的量级直接训的话模型会倾向于把所有东西都判成正常因为这样 loss 最低。处理长尾我有几个固定套路按优先级排列第一优先是补充真实样本任何合成手段都比不上真数据。具体做法是从历史归档里往前翻几年把不同年份、不同季节的缺陷案例都捞出来哪怕分辨率低一点也比没有强。第二是重采样。不是简单复制而是采用类别感知的采样权重让每个 batch 里稀有类别至少出现一到两个样本。这个在数据加载器里几行代码就能实现效果立竿见影。第三是 Copy-Paste 增强这个对缺陷检测特别有效。做法是把标注好的缺陷区域抠出来随机贴到其他正常的绝缘子串图的合理位置上同时更新标注框。关键在于贴合要自然要匹配目标区域的光照方向和色温边缘做羽化缩放比例控制在 0.8 到 1.2 之间。我实测下来用这种方式把破损类样本从 80 张扩到 600 张该类召回提升了大概 12 个点而且没有明显引入虚假特征。第四是常规的几何与光度增强包括随机缩放、旋转、翻转、色彩抖动、高斯模糊、亮度对比度扰动。这里有个细节翻转要慎用。绝缘子的伞裙排列在某些安装方式下是有方向性的水平翻转可能造出物理上不存在的形态模型会学到错误的先验。我的做法是只做小幅度的旋转正负 15 度以内和亮度扰动翻转只在复合绝缘子类别上开。# 数据增强配置片段示意 augment: hsv_h: 0.015 hsv_s: 0.5 hsv_v: 0.4 degrees: 15.0 translate: 0.1 scale: 0.4 shear: 0.0 perspective: 0.0 flipud: 0.0 fliplr: 0.0 # 绝缘子有方向性默认关闭 mosaic: 0.8 mixup: 0.1 copy_paste: 0.3 # 缺陷类专用只在稀有类别上触发Mosaic 这个增强我要特别提醒一句它对小目标检测帮助很大因为它把四张图拼成一张相当于变相提高了小目标的出现频率。但它也会带来副作用——拼接边界处可能出现半截的绝缘子如果标注处理不当会教模型把被裁断的物体当成完整目标。我的处理方式是在拼接后重新过滤标注框把被裁切超过 40% 的框直接丢弃。3. 模型选型与训练把功夫花在刀刃上3.1 主干网络与检测头的取舍别盲目追大第一级串检测的任务相对简单我对比过几个方案结论是不需要大模型。用轻量主干的单阶段检测器在 2000 张标注图上就能到 0.95 以上的召回再往上堆参数量收益极小反而拖慢推理。第二级缺陷判别才是重头戏。这里我试过两种形态一种是把它做成细粒度检测输出缺陷框另一种是做成图像分类输出这一串的缺陷标签。前者信息更丰富能定位缺陷位置后者更简单样本利用率高。我最终采用的是混合策略对于边界清晰、位置明确的类别自爆、异物用检测头输出框对于边界模糊、位置不定的类别裂纹、粉化用分类头输出串级标签再配合热力图标出大致关注区域。这个设计的好处是标注成本可以分层——清晰类别做框标注模糊类别只做图级标注数据利用率大大提高。主干网络方面我选的是带跨尺度特征融合的结构重点强化浅层高分辨率特征的利用。原因很直接缺陷是小目标深层特征图上的空间信息早就被下采样磨没了必须依赖浅层特征。具体做法是把 stride 为 4 的那层特征也接入检测头代价是计算量增加约 20%但小目标召回提升明显这笔账算得过来。有个参数值得一提输入分辨率。我做过一组对照实验同一份数据在 640、896、1280 三个分辨率下的表现差异很大。输入尺寸自爆召回破损召回单图耗时相对值640×6400.710.521.0896×8960.830.661.91280×12800.880.743.8从 640 提到 896召回涨得很值从 896 提到 1280涨了但耗时翻倍。所以我把 896 作为第二级的默认输入1280 只在离线批量复核时启用。这种分级分辨率的策略在实际工程里很实用线上快速筛查用低分辨率人工复核环节用高分辨率重跑一遍。3.2 应对小目标和密集排列的几个具体手段绝缘子串的排列非常密集伞裙之间间距很小用常规的 NMS 后处理经常出现两个相邻伞裙的框被互相抑制掉的情况。针对这个我做了三件事。第一切片推理。对 4000×3000 的原图按 1024×1024 的窗口切片重叠率设 25%。重叠的作用是保证跨越切片边界的绝缘子串至少在一个切片里是完整的。所有切片的检测结果汇总后用全局 NMS 合并。这里的关键参数是重叠率太低会有边界漏检太高会显著增加耗时和重复框。我实测 20% 到 30% 是比较好的平衡点。# 切片推理的核心逻辑示意 def slice_inference(image, model, tile1024, overlap0.25): step int(tile * (1 - overlap)) h, w image.shape[:2] all_boxes, all_scores, all_cls [], [], [] for y in range(0, h, step): for x in range(0, w, step): patch image[y:ytile, x:xtile] if patch.shape[0] tile // 2 or patch.shape[1] tile // 2: continue boxes, scores, clses model(patch) boxes[:, [0, 2]] x boxes[:, [1, 3]] y all_boxes.append(boxes) all_scores.append(scores) all_cls.append(clses) # 跨片合并先按类别分组再统一做 NMS return merge_and_nms(all_boxes, all_scores, all_cls, iou_thr0.5)跨片合并这里有个坑同一串绝缘子在两个切片里各被检出一次框的位置有轻微偏移IoU 可能在 0.4 到 0.6 之间浮动。如果 NMS 阈值设得太严比如 0.7合并不掉会出现重复框设得太松比如 0.3又会把相邻的两串误合并。我的解决办法是按框中心距离 长宽比相似度做二次判定中心距离小于短边的 0.3 且长宽比接近的直接合并取平均。这个规则比单纯的 IoU 更稳。第二调整正样本匹配策略。密集小目标训练时同一个 anchor 可能同时匹配到多个真值框导致标签分配混乱。我换成了基于中心点距离的动态分配方式让每个真值框匹配到最近的若干个预测点而不是依赖固定的 IoU 阈值。这个改动对密集场景的提升挺明显训练收敛也更稳。第三后处理加规则过滤。纯靠模型输出的框总有那么几个奇形怪状的。我加了几条几何约束长宽比不在合理范围内的丢弃面积小于阈值的丢弃与图像边缘大面积重合的丢弃。这几条规则看起来粗暴但实际能砍掉相当一部分低级误报而且计算成本几乎为零。实操心得规则过滤的阈值不要拍脑袋定要从验证集的误报样本里统计出来。我的做法是把所有误报框的长宽比、面积、置信度画成分布图找出正常框分布的尾部边界把阈值定在尾部之外一点这样既能砍误报又不会误伤真阳性。3.3 损失函数与超参配置第二级分类任务的长尾问题严重标准的交叉熵在这里不够用。我采用的是类别平衡加焦点损失的组合让模型把注意力放在难分的样本上同时通过类别权重补偿样本量差异。权重不是按样本数倒数直接算而是取倒数再开方避免稀有类别权重过大导致训练震荡。# 第二级分类器训练配置示意 train: epochs: 120 batch_size: 64 optimizer: AdamW lr0: 0.0008 weight_decay: 0.02 warmup_epochs: 5 scheduler: cosine ema: true amp: true loss: type: focal gamma: 1.6 alpha: 0.35 class_weight_mode: inv_sqrt label_smoothing: 0.05 val: interval: 2 metric: macro_recall # 长尾场景看宏平均召回更真实几个参数的选择理由说一下。学习率 0.0008 是试出来的太高会在前 20 个 epoch 就过拟合到多数类太低则收敛太慢warmup 5 个 epoch 是为了避免初期稀有类别的梯度被淹没label smoothing 设 0.05 而不是常用的 0.1因为缺陷判别本身就存在标注噪声平滑太狠会让模型对真实缺陷也不够自信。评估指标我特别强调用宏平均召回而不是整体准确率。原因很简单正常样本占 95%一个把所有东西都判成正常的模型准确率就有 0.95但这个模型毫无价值。宏平均召回会让每个类别权重相同稀有类别的短板立刻暴露出来。训练过程中我固定监控三个东西每个类别的召回曲线、混淆矩阵、以及验证集上的误报样本可视化。第三个最重要光看数字看不出问题把误报图拉出来一张张看经常能发现系统性的偏差比如模型总是把带阴影的伞裙边缘判成破损。发现这种情况要么针对性补样本要么在增强里加强阴影模拟比盲目调参有效得多。3.4 训练过程的监控与调参实录说几个我在训练中真实遇到的现象和对应的处理方式这些在文档里基本查不到。现象一前 30 个 epoch 指标涨得很快之后长时间平台期。一开始我以为是学习率的问题调了几轮没效果。后来发现是数据增强太强了Mosaic 加 Copy-Paste 的组合让模型一直在学难样本简单样本的信息没有被充分吸收。解决办法是在训练最后 20 个 epoch 关闭 Mosaic让模型在接近真实分布的数据上做最后收敛。这个技巧叫 close mosaic效果非常明显。现象二验证集 loss 在降但召回在降。这是典型的过拟合到多数类。查了一下验证集里正常样本占的比例比训练集还高导致 loss 被多数类主导。处理办法是重新做分层采样让验证集和训练集的类别分布一致同时把监控指标从 loss 换成宏平均召回。现象三同类缺陷在不同批次间表现波动很大。排查发现是不同批次的影像来自不同设备色彩响应有差异。这在巡检场景里很常见换一批设备、换一个季节图像的整体色调就变了。我的应对是加强色彩相关的增强包括色温偏移、饱和度扰动、直方图匹配。更彻底的办法是在输入端做一次轻量的色彩归一化把每张图的亮度均值方差拉到一个统一区间这个改动让跨批次稳定性好了不少。现象四模型对某些杆塔的绝缘子系统性误判。把图调出来看发现那批杆塔的绝缘子表面有较厚的污秽沉积颜色偏暗和训练集里的破损样本很像。这是典型的域偏移。短期靠补样本解决长期还是要在采集规范里要求覆盖不同污秽等级。4. 训练完成只是起点推理加速与业务落地4.1 模型导出与量化精度和速度的平衡模型训完直接拿框架原生格式去跑推理速度往往没法看。我的流程是标准的四步先导出成通用的中间格式再用推理引擎做图优化然后做量化最后做精度回归验证。导出这一步最容易出问题的是自定义算子和动态 shape。我遇到过导出后输出维度对不上的情况查了半天是某个后处理步骤被错误地包含进了计算图。经验是导出时只保留纯前向计算所有后处理解码、NMS、阈值过滤都放到图外面用代码实现。这样图结构简单量化也更容易做。量化方面FP16 基本是无损的速度能提升接近一倍这个没有争议直接上。INT8 就复杂一些需要准备校准集。校准集的选取有讲究不能只用正常样本必须包含各个类别、各种光照条件的代表性样本一般两三百张就够但分布要覆盖全。我校准的时候吃过亏第一批只用了晴天样本结果模型在阴天图上量化误差特别大某些通道的激活值直接饱和了。精度模式相对速度自爆召回变化破损召回变化适用场景FP321.0基准基准离线批量复核FP161.9-0.3%-0.5%线上默认INT83.2-1.1%-2.4%边缘设备实时筛查从表里能看出来INT8 对边界模糊类别的损伤更明显。所以我的策略是分级边缘设备用 INT8 做初筛把可疑目标上传中心侧用 FP16 重跑一遍确认。这样既保证了实时性又不牺牲关键判定的准确性。4.2 端侧部署与吞吐优化部署环境通常是资源受限的边缘设备内存和算力都不宽裕。我在这块做了几件事。流水线并行。把图像解码、预处理、推理、后处理拆成独立的阶段用多线程做成流水线。单看每一步都不快但并行起来整体吞吐能提升 40% 以上。关键是要控制队列长度队列太长会吃满内存太短又起不到流水效果我一般设成 4 到 8。批处理。单张推理的 GPU 利用率很低把多张图拼成一个 batch 能显著提升吞吐。但批大小不能无限加受显存限制而且批太大会增加单张延迟。实测批大小 4 到 8 是比较好的点。内存复用。推理过程中反复申请释放显存会造成碎片跑久了就 OOM。解决办法是预先分配好输入输出缓冲区循环复用不动态申请。这个改动看起来很小但长时间运行的稳定性提升巨大。输入尺寸自适应。不是所有图都需要高分辨率处理。我的做法是先看第一级串检测的结果如果框出来的绝缘子串本身就很小说明拍摄距离远那第二级再怎么放大也没用直接降级处理或者标记为需人工复核。这个策略能省下不少算力。# 推理服务启动参数示例示意 infer_server \ --model ./models/insulator_fp16.engine \ --batch-size 8 \ --num-workers 4 \ --queue-size 8 \ --tile-size 1024 \ --tile-overlap 0.25 \ --conf-thr 0.25 \ --nms-thr 0.5 \ --max-memory-mb 40964.3 与巡检业务流程的对接技术做完不等于能用。我在这块最大的体会是输出结果的呈现方式决定了运维班组愿不愿意用。早期我直接把检测框和置信度丢出去结果反馈很糟——一基杆塔报了几十个框人根本没法看。后来改成三级呈现高置信度且属于危急类别的红色置顶中等置信度的黄色待确认低置信度的折叠收起。同时把结果按杆塔聚合一张图上只显示该杆塔的汇总状态点开才能看细节。还有一点很重要误报回流机制。运维人员复核时标记的这是误报必须能自动回流到数据集进入下一轮训练。这条链路打通之后模型每个月都在变好而不是上线即巅峰。我设计回流时加了一个保护回流样本要经过抽检确认防止有人图省事批量点误报把真样本也污染了。另外识别结果的时效性也要考虑。巡检通常是当天完成、当天回传如果推理排队太久第二天才能出结果业务价值就打折了。所以我在调度上做了优先级危急类别优先处理普通样本走批量队列。5. 指标评估与问题排查实录5.1 别被 mAP 骗了业务指标才是真指标离线评估这块我见过太多团队只报一个 mAP0.5然后拿去汇报。这个数字在实际业务里参考价值有限原因有两个一是它不区分漏检和误报的代价二是它对长尾类别不敏感。我实际用的评估体系是分层的层级指标目标值说明模型层mAP0.5参考用只用于横向对比不同版本模型层各类别召回危急类不低于 0.85宏平均按类别单独看业务层单图误报数不高于 0.5直接影响人工复核工作量业务层单基杆塔漏检率不高于 3%以杆塔为单位统计不是以框为单位业务层端到端时延分钟级从图像上传到结果返回这里重点说单基杆塔漏检率。模型层的召回是按框算的但业务关心的是这基杆塔上有没有缺陷被漏掉。一基杆塔可能有多串绝缘子只要有一串的缺陷没被检出这次巡检就是失败的。所以统计口径必须上提到杆塔级别这个数字通常比框级召回低不少但它是真实的。还有一个指标容易被忽略误报的分布集中度。如果误报集中在少数几基杆塔上那可能是这几基的成像条件特殊针对性处理就行如果误报均匀散布在所有杆塔上那就是模型的系统性问题得回去查数据和损失函数。这两种情况的处理方式完全不同不拆开看就找不到方向。5.2 典型问题速查表下面这张表是我这两三年积累下来的按出现频率排序基本覆盖了八成的排查场景。现象可能原因排查动作玻璃串自爆漏检严重逆光高光被当成正常反光缺口区域和天空颜色接近检查该类样本的逆光占比在增强中加强高光模拟尝试加入边缘特征监督破损类误报集中在伞裙边缘阴影和自然边缘被误判制造公差缺口混入正样本拉出误报图逐张确认清洗标注集增加负样本中正常但有阴影的图同一串出现多个重叠框跨片合并阈值不当NMS 参数过松检查切片重叠率改用中心距离长宽比合并调低 NMS 阈值某些线路整体表现差域偏移设备或污秽等级不同做色彩归一化补该线路样本检查是否有新的材质类型模型把导线金具判成绝缘子第一级训练集缺少负样本类别边界不清补充含金具的背景图作为负样本在标注规范中明确排除项推理服务跑几小时后崩溃显存碎片内存泄漏队列积压检查是否动态申请显存限制队列长度加定时重启兜底换季后指标突然下降光照角度变化植被背景颜色变化按季节拆分评估增加季节相关的色彩增强夜间红外图完全失效训练集没有红外数据成像原理不同红外单独建模不要和可见光混训5.3 几个印象深刻的坑以及我是怎么爬出来的第一个坑是鸟巢误判。有一批图里杆塔横担上的鸟巢被模型高置信度识别成异物悬挂。这个从视觉上看确实像都是不规则的团状物挂在结构上。单纯加负样本能压下去一部分但压不干净。我最后的解法是在第二级判别里加入上下文特征异物悬挂通常出现在绝缘子串的中下部伞裙之间而鸟巢基本都在横担上方。把目标相对绝缘子串的位置作为一个特征维度输入这个误判率降了七成多。这个思路本质上是引入了先验知识在很多工业检测场景里都好用。第二个坑是裂纹和釉面开片纹的混淆。瓷绝缘子表面的釉面本身就有细密的开片纹理在特定光照下非常像裂纹。这个问题靠图像层面几乎无解因为两者在视觉上确实高度相似。我的处理是把它降级从自动判定改成标记提示输出给人工复核时明确标注疑似裂纹需现场确认。同时把这类样本单独拿出来在训练时赋予更高的损失权重让模型至少能把它和正常件区分开。承认模型的能力边界比硬撑着一个不可靠的指标更负责任。第三个坑是阈值设定的反复。我一开始全类别用统一的置信度阈值结果危急类别漏检多普通类别误报多。后来改成按类别分别设阈值危急类阈值放低到 0.2保证不漏普通类阈值提到 0.45压误报。这个改动的效果立竿见影但代价是需要为每个类别单独做阈值寻优。我的做法是在验证集上画 precision-recall 曲线按业务能接受的工作量反推阈值位置而不是追求 F1 最大。F1 最大点在小样本类别上往往偏保守不适合巡检这种漏检代价远大于误报的场景。第四个坑是数据回流污染。前面提到误报回流机制运行了两个月后发现模型在某些类别上反而变差了。查下来是有复核人员为了省事把一些边界模糊的真样本也标成了误报这些样本回流进训练集后模型对真实缺陷的敏感度被削弱了。后来加了两道保险回流样本必须带复核人标识且每月抽检 10%发现异常率过高的复核人其回流的样本先冻结。这个机制听起来有点重但在多人协作的场景下是必要的。最后分享一个我觉得最有价值的经验在做任何模型改动之前先花半天时间把误报和漏检的样本一张张看一遍。我做过统计我调参和改结构的灵感有八成来自看样本只有两成来自看指标曲线。指标告诉你有问题但只有样本告诉你是什么问题。这个习惯我从项目开始坚持到现在省下的试错时间远超过那半天。后续这个方向还能往下走的地方不少比如把多视角的同一基杆塔影像做融合判断比如引入部件级的空间关系约束来抑制不合理组合再比如把置信度校准做起来让输出的分数真正具备概率意义。这些我都在小范围试过有些有效有些还没跑通等数据积累到一定量再展开。