尧图精选

YOLOv7绝缘子缺陷检测实战:从数据集配置到推理部署全流程

🕒 发布时间:2026/9/26 16:13:25 📁 来源:尧图网络
简介本资源面向电力巡检与计算机视觉方向的研究人员、工程师及学生提供一套可直接运行的YOLOv7绝缘子缺陷检测完整方案用于识别绝缘子裂纹、腐蚀、磨损等缺陷降低人工巡检成本与风险。压缩包共166个文件约231.59MB包含31个Python脚本、36个yaml配置、35张jpg样本图、14个ipynb实验笔记、11张png可视化图、5个xml标注文件以及pt权重、sh脚本、md说明与Dockerfile等覆盖数据、训练、推理与部署全流程。目前已有1369人学习下载。资源内含针对绝缘子场景训练好的模型权重与配套数据集可直接复现训练曲线与TensorBoard指标并借助ONNXRuntime、TensorRT等notebook完成动态批量推理与YOLOv7与YOLOv5的对比实验便于读者快速验证、二次调参与迁移到自有电力数据是入门与进阶目标检测落地的实用参考。1. 绝缘子缺陷检测为什么值得用 YOLOv7 重做一遍输电线路巡检里绝缘子破损、掉串、自爆这类缺陷一旦漏检后果不用我多说。过去几年大家普遍用 YOLOv5 或者更早的 Faster R-CNN 做这件事能跑但精度和速度总有一头不满意。YOLOv7 在 2022 年出来后我拿它在一批航拍绝缘子数据上重训了一版同样的数据量mAP0.5 比 YOLOv5s 高了将近 4 个点推理速度在单张 3060 上还能维持在 40 FPS 以上。这不是玄学是 YOLOv7 的 ELAN 结构和辅助训练头确实在中小目标上更吃得开而绝缘子缺陷——尤其是自爆点——在整张图里往往只占几十个像素。这套「YOLOv7 绝缘子缺陷检测模型代码数据集」的方案适合两类人一类是电力巡检方向的研究生或工程师手头有几百到几千张标注图想快速搭一个能用的基线另一类是已经跑过 YOLOv5 但卡在精度瓶颈上想换架构试试的从业者。数据集方面公开的绝缘子缺陷数据不算多常见做法是自己从航拍视频抽帧再标或者用 CPFL 那类公开电力数据集做迁移。代码层面YOLOv7 官方仓库的结构比 YOLOv5 稍微绕一点配置文件、权重、数据 yaml 三者的对应关系容易搞混这也是后面要重点拆的地方。2. 从数据到配置YOLOv7 绝缘子检测的落地链路2.1 绝缘子缺陷数据集的组织与标注格式转换绝缘子缺陷检测的数据集我一般按三类来标正常绝缘子、自爆/破损、掉串。标注工具用 LabelImg 或者 X-AnyLabeling 都行导出 VOC 格式的 XML。但 YOLOv7 吃的是 YOLO 格式的 txt每行是class_id x_center y_center width height全部归一化到 0~1。这个转换脚本我写过不下五遍每次都有新坑下面这版是稳定能用的。import os import xml.etree.ElementTree as ET # 类别映射顺序必须和训练时 data.yaml 里的 names 一致 CLASS_MAP {normal: 0, broken: 1, flashover: 2} def voc_to_yolo(xml_dir, out_dir, img_w, img_h): os.makedirs(out_dir, exist_okTrue) for xml_file in os.listdir(xml_dir): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(xml_dir, xml_file)) root tree.getroot() # 有些数据集 size 字段缺失这里用传入的 img_w/img_h 兜底 size root.find(size) w int(size.find(width).text) if size is not None else img_w h int(size.find(height).text) if size is not None else img_h lines [] for obj in root.iter(object): name obj.find(name).text.strip() if name not in CLASS_MAP: continue cls_id CLASS_MAP[name] bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 归一化并转中心点格式 x_c (xmin xmax) / 2.0 / w y_c (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h # 边界裁剪防止标注越界导致训练报错 x_c, y_c min(max(x_c, 0), 1), min(max(y_c, 0), 1) bw, bh min(max(bw, 0), 1), min(max(bh, 0), 1) lines.append(f{cls_id} {x_c:.6f} {y_c:.6f} {bw:.6f} {bh:.6f}) out_path os.path.join(out_dir, xml_file.replace(.xml, .txt)) with open(out_path, w) as f: f.write(\n.join(lines)) voc_to_yolo(./annotations, ./labels, 1920, 1080)这段代码的关键在CLASS_MAP和边界裁剪。类别映射一旦和data.yaml里的names顺序对不上训练时 loss 会正常降但推理结果全是错类这种翻车我见过太多次。边界裁剪是防标注框超出图像范围YOLOv7 的 dataloader 对越界坐标不会报错但会算出负面积导致某些 batch 的 loss 直接变 NaN。转换完之后目录结构建议这样组织dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── insulator.yamlinsulator.yaml的内容train: ./dataset/images/train val: ./dataset/images/val nc: 3 names: [normal, broken, flashover]注意nc必须等于names的长度且names的顺序要和转换脚本里的CLASS_MAP完全一致。改类别时两处一起改别只改一处。2.2 YOLOv7 模型配置文件的选择与修改YOLOv7 官方仓库里配置文件不少yolov7.yaml、yolov7x.yaml、yolov7-tiny.yaml等等。绝缘子缺陷检测我一般从yolov7.yaml起步如果显存吃紧或者要上边缘设备再换yolov7-tiny.yaml。配置文件里唯一必须改的是nc在 head 部分的三个检测头前面各有一处。# yolov7-insulator.yaml 片段 head: - [-1, 1, Conv, [512, 1, 1]] - [-1, 1, nn.Upsample, [None, 2, nearest]] - [[-1, 51], 1, Concat, [1]] - [-1, 3, Conv, [256, 3, 1]] # 128 - [-1, 1, Conv, [256, 1, 1]] - [-1, 3, Conv, [256, 3, 1]] - [-1, 1, Conv, [256, 1, 1]] - [-1, 1, Conv, [255, 1, 1]] # 这里 255 3 * (5 nc)nc3 时是 24不是 255上面这个片段是官方原版的255对应的是 COCO 的 80 类。改成绝缘子 3 类时要把三个检测头前的255改成3 * (5 3) 24。这个5是x, y, w, h, obj3是类别数。改错这个数模型能加载但输出维度对不上训练时直接报 shape mismatch。# 训练命令单卡 3060 12G 的配置 python train.py \ --weights yolov7.pt \ --cfg cfg/training/yolov7-insulator.yaml \ --data data/insulator.yaml \ --hyp data/hyp.scratch.p5.yaml \ --epochs 150 \ --batch-size 8 \ --img-size 640 640 \ --device 0 \ --workers 4 \ --name insulator_v7参数说明--weights用官方 COCO 预训练权重迁移学习收敛快很多--batch-size 8是 12G 显存下 640 分辨率的稳妥值想再大就开--img-size 512--hyp用hyp.scratch.p5.yaml如果数据量少于 1000 张建议把里面的mosaic概率从 1.0 降到 0.5否则小数据集上 mosaic 增强会引入太多噪声。2.3 训练过程监控与关键指标解读训练启动后runs/train/insulator_v7/下会生成results.txt和results.png。重点看三个指标box_loss、obj_loss、mAP0.5。绝缘子缺陷检测里obj_loss比box_loss更值得盯因为缺陷目标小obj 分支的梯度容易震荡。# 实时看训练日志里的关键行 tail -f runs/train/insulator_v7/results.txt | awk {print $1, $2, $3, $8, $9}如果obj_loss在前 20 个 epoch 一直不降常见原因是 anchor 和你的数据不匹配。YOLOv7 默认 anchor 是基于 COCO 的绝缘子缺陷的宽高比偏极端细长条这时候跑一遍 k-means 重新聚类 anchor 会有明显改善。# anchor 聚类用你的训练集标注跑 import numpy as np def kmeans_anchors(labels, k9, img_size640): # labels: N x 2 的数组每行是归一化的 w, h boxes labels * img_size # 初始化随机选 k 个点 np.random.seed(42) centers boxes[np.random.choice(len(boxes), k, replaceFalse)] for _ in range(100): # 计算每个框到各中心的 IoU 距离 distances 1 - np.array([iou(boxes, c) for c in centers]).T labels_idx distances.argmin(axis1) new_centers np.array([boxes[labels_idx i].mean(axis0) for i in range(k)]) if np.allclose(centers, new_centers): break centers new_centers return centers def iou(boxes, center): # 简化版用面积比近似 w np.minimum(boxes[:, 0], center[0]) h np.minimum(boxes[:, 1], center[1]) inter w * h union boxes[:, 0] * boxes[:, 1] center[0] * center[1] - inter return inter / union聚类出来的 9 个 anchor 按面积从小到大排替换配置文件里anchors那三行。这一步做完obj_loss通常能在 30 个 epoch 内降到 0.05 以下。3. 推理部署与效果验证从权重到实际巡检画面3.1 用 detect.py 跑通单张与批量推理训练完的权重在runs/train/insulator_v7/weights/best.pt。推理直接用官方detect.py但有几个参数必须调。python detect.py \ --weights runs/train/insulator_v7/weights/best.pt \ --source ./test_images \ --img-size 640 \ --conf-thres 0.35 \ --iou-thres 0.45 \ --device 0 \ --save-txt \ --project runs/detect \ --name insulator_test--conf-thres 0.35是我在绝缘子数据上试出来的平衡点。低于 0.3 会冒出大量误检尤其是把正常绝缘子的阴影当成破损高于 0.5 又会漏掉一些对比度低的自爆点。--iou-thres 0.45控制 NMS 的合并力度绝缘子串上相邻缺陷离得近时这个值调太低会把两个缺陷合并成一个。批量推理时--source指向文件夹--save-txt会把每个图的检测框存成 txt格式和训练标签一样方便后续做统计。3.2 验证集评估与混淆矩阵分析训练脚本在最后一轮会自动跑验证输出confusion_matrix.png和PR_curve.png。绝缘子检测里混淆矩阵最有价值的是看broken和flashover之间的误判。这两类在低分辨率下纹理相似如果混淆矩阵显示它们互相误判超过 15%说明 640 分辨率不够得把--img-size提到 768 或者 896。# 单独跑验证输出详细指标 python test.py \ --weights runs/train/insulator_v7/weights/best.pt \ --data data/insulator.yaml \ --img-size 640 \ --batch-size 8 \ --device 0 \ --task val \ --verbose--verbose会打印每一类的 P、R、mAP0.5、mAP0.5:0.95。我一般要求broken类的 Recall 不低于 0.85因为漏检一个破损绝缘子的代价远大于误检。如果 Recall 不够优先加数据其次是调低conf-thres再配合后处理。3.3 模型导出与低显存部署的取舍如果要在 Jetson 或者低显存设备上跑导出 ONNX 或 TensorRT 是常规操作。# 导出 ONNX python export.py \ --weights runs/train/insulator_v7/weights/best.pt \ --img-size 640 640 \ --batch-size 1 \ --device 0 \ --include onnx \ --simplify--simplify会调 onnx-simplifier 做图优化导出后的 ONNX 在 TensorRT 里跑通常比 PyTorch 快 1.5 到 2 倍。但注意YOLOv7 的某些算子比如nn.Upsample的nearest模式在 TensorRT 8.4 以下版本支持不好导出后可能报 unsupported op。遇到这种情况要么升级 TensorRT要么在导出时把--grid关掉。低显存运行模型时除了换 tiny 版本还可以把--img-size降到 416但绝缘子缺陷小目标多416 下 mAP 会掉 5 到 8 个点这个取舍要看你的实际场景能不能接受。4. 绝缘子缺陷检测的避坑与排查记录4.1 训练 loss 正常但 mAP 始终为 0现象训练日志里 box_loss 和 obj_loss 都在降但验证时 mAP0.5 一直是 0 或者极低。原因最常见的是data.yaml里的val路径写错验证集加载的是空目录或者图片和标签没对上。YOLOv7 在验证集为空时不会报错只会输出 0。解决跑训练前先用ls dataset/images/val | wc -l和ls dataset/labels/val | wc -l确认两边数量一致且文件名除扩展名外一一对应。4.2 推理结果框全挤在图像左上角现象detect.py 输出的图里所有检测框都堆在左上角尺寸也不对。原因训练时的--img-size和推理时的--img-size不一致或者导出 ONNX 时用了 letterbox 但推理端没做同样的预处理。解决训练和推理的 img-size 保持一致。如果用 ONNX 推理预处理必须复现 YOLOv7 的 letterbox 逻辑等比缩放后填充灰边到 640x640推理完再把框映射回原图坐标。4.3 自爆缺陷漏检严重现象正常绝缘子和掉串都能检出但自爆点 Recall 只有 0.5 左右。原因自爆点在图像里往往只有 20 到 40 像素YOLOv7 的 P3 特征图80x80下采样 8 倍后这些小目标的信息已经丢了不少。解决把--img-size提到 896 或 1024同时把hyp里的scale增强范围调窄比如 0.2 到 0.5避免小目标被过度缩放。另一个办法是在配置文件里把 P3 检测头的 anchor 换成更小的值。4.4 训练到一半 loss 突然变 NaN现象前几十个 epoch 正常突然某个 batch 后 loss 变成 NaN之后再也降不下来。原因标注框越界导致负面积或者学习率在 warmup 阶段跳得太猛。绝缘子数据集里如果有标注框的 xmax 小于 xmin转换脚本没做校验就会出这个问题。解决在转换脚本里加一行校验if xmax xmin or ymax ymin: continue。另外把hyp里的lr0从 0.01 降到 0.005warmup_epochs 从 3 提到 5。4.5 验证集 mAP 高但实际巡检图效果差现象验证集 mAP0.5 有 0.9但拿现场巡检图跑误检和漏检都很多。原因验证集和训练集同分布但现场图的背景、光照、拍摄角度和训练数据差异大。绝缘子检测里背景从山林到农田到城市变化极大。解决从现场视频里抽 200 到 300 帧标一部分加入训练集哪怕只标正常和明显缺陷两类也能显著提升泛化。另一个办法是加背景图无目标的负样本比例控制在 10% 左右能压误检。5. 把绝缘子检测模型推到可用的几个进阶习惯模型训出来只是第一步真正让它在巡检场景里可用我踩过的坑比训练本身还多。第一个习惯是永远保留一份「困难样本集」。每次现场跑完把误检和漏检的图单独存一个文件夹标好后加入下一轮训练。这个习惯坚持三个月mAP 能再涨 5 到 8 个点比调任何超参都管用。第二个习惯是推理时开 TTATest Time Augmentation。YOLOv7 的 detect.py 不直接支持但可以自己包一层对同一张图做水平翻转和 1.1 倍缩放各跑一次推理再用 NMS 合并三组框。代价是推理时间翻三倍但在离线巡检场景里完全可接受Recall 通常能提 2 到 3 个点。# 简易 TTA 推理封装 import cv2 import numpy as np def tta_inference(model, img, conf0.35, iou0.45): results [] # 原图 results.append(model(img, conf, iou)) # 水平翻转 flip cv2.flip(img, 1) r_flip model(flip, conf, iou) # 翻转回来再收集 for box in r_flip: box[0] img.shape[1] - box[0] box[2] img.shape[1] - box[2] results.append(box) # 缩放 1.1 倍 h, w img.shape[:2] scaled cv2.resize(img, (int(w * 1.1), int(h * 1.1))) r_scale model(scaled, conf, iou) for box in r_scale: box[0] / 1.1 box[1] / 1.1 box[2] / 1.1 box[3] / 1.1 results.append(box) # 合并所有框做 NMS return nms(results, iou)第三个习惯是给模型加一个「置信度分级」输出。巡检业务里0.35 到 0.5 之间的框标记为「疑似」0.5 以上标记为「确认」。这样现场人员可以优先处理确认缺陷疑似缺陷二次复核既不漏也不至于被误检淹没。最后一个习惯也是我血泪教训换来的每次改完配置文件先跑 1 个 epoch 的 sanity check确认 loss 能正常降、验证能跑通再开完整训练。YOLOv7 的配置文件层级深改错一个数字可能要跑半天才发现1 个 epoch 的检查能省下大量时间。希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →