简介本资源为面向电力巡检与计算机视觉方向的YOLO绝缘子缺陷检测数据集适合目标检测初学者、算法工程师及电力智能运维研究人员使用用于训练和验证绝缘子缺陷识别模型。压缩包共1257个文件约121.86MB包含314张jpg图像、314个txt标注文件、628个xml标签文件及1个yaml配置文件图像与标注一一对应可直接用于YOLO系列模型的训练与评估。数据集覆盖不同环境、光照与缺陷类型如裂纹、剥落、污秽、异物附着等有助于模型学习绝缘子缺陷特征。目前已有188人学习下载。通过该数据集读者可快速搭建绝缘子缺陷检测实验流程掌握从数据组织、标签解析到模型训练与验证的完整方法为输电线路智能巡检、事故损伤评估等场景提供可靠的数据支撑与排错参考。1. 314 张绝缘子缺陷图像这份 YOLO 数据集到底能跑出什么结果输电线路巡检这行有个共识绝缘子缺陷检测是典型的「样本难凑、场景难复现、标注难统一」三难问题。你让一个班组一年爬几百基塔拍回来的照片里真正带裂纹、剥落、污秽、异物附着的可能不到十分之一剩下的全是正常件。这份数据集直接给了 314 张带标签的绝缘子图像覆盖巢、绝缘体、铁塔三类目标文件名从 img_0723_72.jpg 到 img_0962_139.jpg 这种现场编号风格说明是从真实巡检素材里筛出来的。它解决的不是「有没有数据」的问题而是「能不能快速验证一个 YOLO 训练流程跑不跑得通」的问题。适合两类人一是刚接触 YOLO 目标检测、想拿电力场景练手的工程师二是做边缘部署前需要小样本快速验证模型收敛性的开发者。314 张不算多但足够你把标注格式、训练配置、验证指标这条链路完整走一遍。2. 从压缩包到训练集目录结构、标签格式与 YOLO 数据规范拿到一个 zip 包第一件事不是急着解压看图片而是先搞清楚它的组织方式。这份数据集的文件名是扁平的没有按 train/val 分目录标签大概率是 YOLO 格式的 txt 文件和图片同名同目录。如果你直接拿这种结构去喂 YOLOv8 或 YOLOv5训练脚本会在找标签那一步就报错。所以这一章的核心任务是把原始结构转成框架能吃的标准格式同时搞清楚标签里到底存了什么。2.1 解压后先做三件事文件清点、图片校验、标签配对解压之后别急着写训练脚本先跑一段清点代码。我一般会检查三件事图片能不能正常打开、标签文件是不是和图片一一对应、标签内容是不是合法的 YOLO 格式每行 5 个值类别 id、中心 x、中心 y、宽、高全部归一化到 0~1。import os from PIL import Image img_dir insulator_dataset/images lbl_dir insulator_dataset/labels img_files sorted([f for f in os.listdir(img_dir) if f.endswith(.jpg)]) lbl_files sorted([f for f in os.listdir(lbl_dir) if f.endswith(.txt)]) print(f图片数量: {len(img_files)}, 标签数量: {len(lbl_files)}) # 检查配对 img_stems {os.path.splitext(f)[0] for f in img_files} lbl_stems {os.path.splitext(f)[0] for f in lbl_files} missing_lbl img_stems - lbl_stems missing_img lbl_stems - img_stems print(f缺标签的图片: {len(missing_lbl)}, 缺图片的标签: {len(missing_img)}) # 校验图片可读性 bad_imgs [] for f in img_files: try: with Image.open(os.path.join(img_dir, f)) as im: im.verify() except Exception as e: bad_imgs.append((f, str(e))) print(f损坏图片: {len(bad_imgs)}) # 校验标签格式 bad_labels [] for f in lbl_files: with open(os.path.join(lbl_dir, f)) as fh: for line_no, line in enumerate(fh, 1): parts line.strip().split() if len(parts) ! 5: bad_labels.append((f, line_no, 字段数不对)) continue cls, cx, cy, w, h parts vals [float(cx), float(cy), float(w), float(h)] if any(v 0 or v 1 for v in vals): bad_labels.append((f, line_no, 坐标越界)) print(f异常标签行: {len(bad_labels)})这段代码的逻辑很直白先确认图片和标签数量是否一致再逐张验证图片文件完整性最后逐行检查标签的字段数和归一化范围。参数方面img_dir和lbl_dir按你实际解压后的路径改如果你的标签和图片混在同一个目录把两个路径都指向同一处即可。跑完如果missing_lbl不为零说明有图片没标如果bad_labels有输出那些行在训练时会被框架跳过或报错最好提前修掉。2.2 划分 train/val 并生成 data.yaml别让验证集变成「假验证」314 张图如果全拿去训练你连模型有没有过拟合都看不出来。常见做法是按 8:2 或 7:3 划分训练集和验证集但这里有个坑如果同一基塔、同一光照条件下拍的多张图被随机分到两边验证集里的样本和训练集高度相似指标会虚高。我一般会按文件名前缀做分组划分比如 img_0723 开头的归一组img_0962 开头的归另一组尽量让验证集覆盖不同的拍摄批次。import os import random import shutil from pathlib import Path random.seed(42) src_img Path(insulator_dataset/images) src_lbl Path(insulator_dataset/labels) dst_root Path(dataset_split) # 按文件名前缀分组 groups {} for f in sorted(os.listdir(src_img)): if not f.endswith(.jpg): continue prefix f.split(_)[1] # img_0723_xx - 0723 groups.setdefault(prefix, []).append(f) # 每组按 8:2 划分 train_files, val_files [], [] for prefix, files in groups.items(): random.shuffle(files) split int(len(files) * 0.8) train_files.extend(files[:split]) val_files.extend(files[split:]) for split_name, files in [(train, train_files), (val, val_files)]: (dst_root / images / split_name).mkdir(parentsTrue, exist_okTrue) (dst_root / labels / split_name).mkdir(parentsTrue, exist_okTrue) for f in files: shutil.copy(src_img / f, dst_root / images / split_name / f) lbl os.path.splitext(f)[0] .txt if (src_lbl / lbl).exists(): shutil.copy(src_lbl / lbl, dst_root / labels / split_name / lbl) print(f训练集: {len(train_files)}, 验证集: {len(val_files)})这段脚本的关键在prefix f.split(_)[1]这一行它把文件名里的批次号抽出来做分组依据。random.seed(42)保证每次划分结果一致方便复现。划分完成后目录结构是dataset_split/images/train、dataset_split/labels/train这种标准布局YOLOv8 直接认。接下来生成 data.yamlpath: ./dataset_split train: images/train val: images/val names: 0: nest 1: insulator 2: tower这里names的类别名和顺序必须和标签里的类别 id 严格对应。如果你不确定原始标签里 0、1、2 分别代表什么用下面这行命令统计一下每个类别出现的次数再结合文件名和图像内容判断awk {print $1} dataset_split/labels/train/*.txt | sort | uniq -c | sort -rn提示如果统计出来某个类别只有个位数样本训练时该类别的召回率会很难看考虑做数据增强或者合并类别。3. YOLOv8 训练配置从环境搭建到第一轮收敛数据准备好了接下来是训练。YOLOv8 是目前小样本目标检测里上手最快的选择ultralytics 库把训练、验证、导出串成了一条命令。但「能跑」和「跑出可用结果」之间隔着几个关键参数尤其是学习率、批次大小和输入尺寸这三项在 314 张图这种小数据集上特别敏感。3.1 环境搭建conda 建环境 ultralytics 安装我一般用 conda 建一个干净环境避免和系统里的 torch 版本打架。YOLOv8 对 PyTorch 版本有要求截至我写这篇笔记时ultralytics 最新版需要 torch1.8CUDA 版本按你显卡驱动来选。conda create -n yolo_insulator python3.10 -y conda activate yolo_insulator # 按你的 CUDA 版本装 torch这里以 CUDA 11.8 为例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 装 ultralytics pip install ultralytics # 验证 yolo checksyolo checks会输出当前环境、GPU 可用性、依赖版本等信息。如果 GPU 那一栏显示 not available先检查驱动和 CUDA 版本是否匹配别急着往下跑训练否则会用 CPU 硬扛314 张图虽然不多但 CPU 训练一轮也要好几分钟。3.2 训练命令与关键参数小数据集怎么设才不翻车环境好了训练命令本身不复杂yolo detect train \ data./data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ lrf0.01 \ patience20 \ projectinsulator_runs \ nameexp1逐项说参数。modelyolov8n.pt选的是 nano 版本参数量最小适合小数据集快速验证如果你后面要部署到边缘设备nano 也是首选。epochs100配合patience20意思是如果 20 轮验证指标没提升就提前停避免过拟合。imgsz640是默认输入尺寸314 张图里如果绝缘子目标本身很小可以试 1280但显存占用会翻倍。batch16在 8GB 显存上跑 640 尺寸基本稳如果 OOM 就降到 8。lr00.01是初始学习率小数据集上我一般会降到 0.005 甚至 0.001因为样本少、梯度噪声大学习率太高容易在损失面上跳来跳去。训练开始后终端会输出每一轮的 box_loss、cls_loss、dfl_loss 和 mAP50。box_loss 管的是边界框回归cls_loss 管分类dfl_loss 是分布焦点损失YOLOv8 用来细化边界。前 10 轮 loss 下降快是正常的如果 30 轮之后 mAP50 还在 0.1 以下大概率是标签有问题或者学习率太大。3.3 训练过程监控与指标解读mAP50 到多少算能用训练跑起来之后insulator_runs/exp1/目录下会生成results.csv和若干曲线图。我习惯用 pandas 快速看一眼关键指标的变化趋势import pandas as pd df pd.read_csv(insulator_runs/exp1/results.csv) df.columns df.columns.str.strip() # 看最后 10 轮的指标 print(df[[epoch, train/box_loss, train/cls_loss, metrics/mAP50(B), metrics/mAP50-95(B)]].tail(10)) # 找 mAP50 最高的那一轮 best df.loc[df[metrics/mAP50(B)].idxmax()] print(f最佳 epoch: {int(best[epoch])}, mAP50: {best[metrics/mAP50(B)]:.4f})mAP50是 IoU 阈值 0.5 时的平均精度mAP50-95是 IoU 从 0.5 到 0.95 每隔 0.05 取一次的平均值后者更严格。314 张图、3 个类别的场景下mAP50 能到 0.6~0.75 就算正常发挥mAP50-95 通常在 0.35~0.5 之间。如果 mAP50 高但 mAP50-95 很低说明框的位置不够准可以考虑加更多标注数据或者调 anchorYOLOv8 是无锚框的但可以通过增加 DFL 的回归范围来改善。注意验证集指标好看不代表实际巡检场景能用。如果验证集里全是晴天顺光图模型到了阴天逆光环境大概率翻车。有条件的话留几张完全不同光照条件的图做最终测试。4. 推理、验证与边缘部署前的检查清单训练完拿到 best.pt 只是第一步真正要落地还得过推理验证和部署适配两关。这一章讲怎么用训练好的模型跑单张图和批量图怎么调置信度门限以及导出到边缘设备前必须确认的几个参数。4.1 单张与批量推理置信度门限怎么调YOLOv8 的推理接口很直接from ultralytics import YOLO model YOLO(insulator_runs/exp1/weights/best.pt) # 单张推理 results model.predict( sourcetest_images/img_0962_92.jpg, conf0.25, iou0.45, imgsz640, saveTrue, projectinference_out, namesingle ) # 批量推理整个目录 results model.predict( sourcetest_images/, conf0.25, iou0.45, imgsz640, saveTrue, projectinference_out, namebatch )conf0.25是置信度门限低于这个值的检测框会被丢掉。绝缘子缺陷检测里这个值很关键调高到 0.5 以上漏检会明显增加尤其是小目标缺陷调到 0.1 以下误检会爆炸正常绝缘子上的纹理可能被当成裂纹。我一般先在验证集上跑一组 conf 从 0.1 到 0.6 的对比看 F1 曲线峰值在哪再定最终值。iou0.45是 NMS 的 IoU 阈值控制重叠框的合并程度密集目标场景可以适当调低到 0.3~0.4。4.2 导出 ONNX 与边缘设备适配输入尺寸和量化怎么选如果你要把模型部署到 RK3588、树莓派或者 Atlas 这类边缘设备通常需要先导出成 ONNX 格式yolo export \ modelinsulator_runs/exp1/weights/best.pt \ formatonnx \ imgsz640 \ opset12 \ simplifyTrueopset12是 ONNX 算子集版本RK3588 的 NPU 工具链对 12 支持比较好。simplifyTrue会做一层图优化去掉冗余算子。导出后你会得到一个.onnx文件输入尺寸是 1x3x640x640。如果边缘设备算力有限可以把imgsz降到 416 或 320但小目标检测精度会掉需要重新评估。导出前建议做一次「一致性检查」用同一张图分别跑 PyTorch 模型和 ONNX 模型对比检测框数量和类别是否一致。如果 ONNX 输出和原模型差异大大概率是 opset 版本或者算子不支持的问题。import onnxruntime as ort import numpy as np from PIL import Image # 预处理 img Image.open(test_images/img_0962_92.jpg).resize((640, 640)) input_data np.array(img).transpose(2, 0, 1)[None].astype(np.float32) / 255.0 sess ort.InferenceSession(best.onnx) outputs sess.run(None, {sess.get_inputs()[0].name: input_data}) print(fONNX 输出形状: {[o.shape for o in outputs]})这段代码只验证 ONNX 模型能不能正常推理、输出形状对不对。如果输出形状和预期不符检查导出时的imgsz和opset参数。提示边缘部署前务必在目标设备上跑一遍完整推理别只在 PC 上验证 ONNX。NPU 的算子实现和 CUDA 有差异PC 上正常的模型到了板子上可能出各种玄学问题。5. 避坑与排查314 张图训练时最容易翻车的五个地方小数据集训练目标检测模型翻车点比大数据集更集中。下面这五条是我自己在类似规模数据集上踩过的按「现象 → 原因 → 解决」整理。现象一训练 loss 正常下降但 mAP50 始终在 0.05 以下。原因标签类别 id 和 data.yaml 里的 names 顺序对不上模型学的是错位的分类映射。 解决用awk {print $1} labels/*.txt | sort | uniq -c统计标签里的类别 id 分布和 data.yaml 的 names 逐项核对。如果标签里只有 0 和 1但 names 写了三个类把多余的删掉。现象二验证集 mAP 很高但拿新图推理时大量漏检。原因训练集和验证集来自同一批次、同一光照条件模型过拟合到了特定场景。 解决按文件名前缀分组划分 train/val确保验证集覆盖不同拍摄批次。如果数据里只有一种光照条件做亮度、对比度、旋转增强来扩充。现象三训练到一半突然 OOM或者 loss 变成 NaN。原因学习率太大或者批次太大梯度爆炸。 解决把lr0从 0.01 降到 0.001batch从 16 降到 8加ampTrueYOLOv8 默认开启混合精度。如果还 NaN检查标签里有没有坐标值超出 0~1 范围的行。现象四推理时同一目标出现多个重叠框。原因NMS 的iou阈值设太高重叠框没被合并掉。 解决把iou从默认 0.7 降到 0.45 甚至 0.3观察框数量变化。如果降了之后目标被误合并说明模型对相邻目标的区分能力不够需要更多训练数据。现象五导出 ONNX 后推理结果和 PyTorch 不一致。原因opset 版本不兼容或者simplify改变了计算图。 解决先试opset12且simplifyFalse确认一致后再逐步开 simplify。如果仍然不一致用 onnxruntime 逐层对比输出定位是哪一层开始出现偏差。6. 小样本下的数据增强与模型微调把 314 张用出 1000 张的效果314 张图训练 YOLO最大的瓶颈不是模型结构是样本多样性不够。我后来养成一个习惯拿到任何小数据集先跑一轮 baseline看 mAP50 和各类别召回率然后针对弱类别做定向增强再跑第二轮对比。这个流程比盲目调参有效得多。YOLOv8 内置了增强参数可以在训练命令里直接开yolo detect train \ data./data.yaml \ modelyolov8n.pt \ epochs150 \ imgsz640 \ batch16 \ lr00.005 \ hsv_h0.015 \ hsv_s0.7 \ hsv_v0.4 \ degrees10.0 \ translate0.1 \ scale0.5 \ fliplr0.5 \ mosaic1.0 \ mixup0.1 \ projectinsulator_runs \ nameexp2_aughsv_h、hsv_s、hsv_v控制色调、饱和度、亮度的随机扰动绝缘子在不同光照下颜色差异大这三个值可以适当开大。degrees10.0做小角度旋转translate0.1和scale0.5做平移和缩放模拟不同拍摄距离。fliplr0.5是水平翻转概率绝缘子通常左右对称翻转不会改变缺陷语义。mosaic1.0是 YOLOv8 默认开启的马赛克增强把四张图拼成一张对小数据集特别有用能显著增加目标出现的上下文多样性。mixup0.1做图像混合进一步扩充样本。但增强不是越多越好。我做过一组对比在 314 张图上mosaic1.0 mixup0.1 的组合比纯 mosaic 的 mAP50 高了约 3 个百分点但 mixup 开到 0.3 之后反而掉了因为混合后的图像语义太模糊模型学不到清晰的特征。所以我的建议是先开 mosaic跑一轮看指标如果弱类别召回率低再加 mixup 和 HSV 扰动每次只改一到两个参数记录对比结果。另一个容易被忽略的点是「冻结层微调」。如果你用预训练的 yolov8n.pt 做起点前几轮可以冻结 backbone只训练检测头让模型先适应绝缘子数据的分布再解冻全量微调。YOLOv8 里通过freeze参数控制# 前 20 轮冻结 backbone yolo detect train data./data.yaml modelyolov8n.pt epochs20 freeze10 lr00.001 # 再解冻全量训练 yolo detect train data./data.yaml modelinsulator_runs/exp2_aug/weights/last.pt epochs100 lr00.005freeze10表示冻结前 10 层具体层数按模型结构调。这个策略在小数据集上能防止 backbone 被少量样本带偏尤其是当你用的预训练权重是在 COCO 这种通用数据集上训的时候。最后说一个验证技巧训练完成后别只看 mAP 数字把验证集里模型预测错的图挑出来一张一张看。我一般会跑一段脚本把 conf 低于 0.3 的检测框和漏检的 ground truth 画在一起肉眼判断是标注问题还是模型问题。十次里有三次能发现标注框画偏了或者类别标错了这种问题不修调再多参数也是白搭。从那以后我每次拿到新的小样本数据集都强制走一遍「清点 → 分组划分 → baseline → 定向增强 → 错误可视化」这个流程不再一上来就堆 epochs 和调学习率。希望帮到你。本文还有配套的精品资源点击获取
