ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

YOLO电缆损坏检测实战:1318张图像数据集训练与避坑指南

YOLO电缆损坏检测实战:1318张图像数据集训练与避坑指南 简介这是一份面向YOLO系列算法学习者的电缆损坏目标检测数据集聚焦电力巡检场景下的电缆破损识别任务适合需要快速验证模型或开展工程实践的中初级开发者。压缩包共2000个文件约107.47MB其中1081个xml文件为VOC格式标注919个txt文件为YOLO格式标注两种标签一一对应可直接用于训练与验证测试。数据集已按训练集与验证集划分完毕并附带data.yaml配置文件兼容yolov5、yolov7、yolov8、yolov9、yolov10及yolo11等主流版本。YOLO格式采用归一化中心点与宽高表示便于直接读取VOC格式则方便与Pascal VOC生态工具衔接。目前已有78人学习下载读者可借此省去数据采集与标注成本快速搭建电缆损坏检测基线并在此基础上调整网络结构、优化超参数或迁移至其他电力设备缺陷识别任务。1. 电缆损坏数据集与 YOLO 检测1318 张带标签图像能跑出什么结果手里拿到一个名为「yolo算法-电缆损坏数据集-1318张图像带标签-雷电-打破.zip」的数据包时多数人的第一反应是解压、看目录、数图片然后直接套一个 YOLOv8 的训练脚本跑起来。但真正决定这个数据集能不能用的不是图片数量而是标签质量、类别定义和场景覆盖度。1318 张图像在目标检测里属于小规模数据集如果类别分布不均、标注框偏移严重训练出来的模型在验证集上 mAP 可能虚高一上真实电缆巡检场景就翻车。这个数据集的核心价值在于它聚焦「电缆损坏」这一工业巡检细分场景标签里包含雷电击穿、外破损伤等典型缺陷类型适合做电力巡检方向的算法验证和原型开发。适合谁用一是做电力巡检 AI 落地的工程师需要快速验证 YOLO 在小样本工业缺陷上的表现二是学生或研究者想找一个带标签的真实工业场景数据集做实验而不是拿 COCO 或 VOC 凑数。接下来的内容会从数据检查、格式转换、训练配置到避坑把这条链路走通。2. 拿到压缩包先别急着训练数据清洗与标签校验的完整流程2.1 解压后先看目录结构判断标注格式是 YOLO txt 还是 VOC xml拿到压缩包后第一步不是写训练脚本而是确认标注格式。常见做法是解压后看目录里有没有labels文件夹和images文件夹并列或者所有 xml 文件跟图片混在一起。YOLO 格式的标签是每张图对应一个同名.txt文件每行格式为class_id x_center y_center width height坐标是归一化到 0 到 1 之间的浮点数。VOC 格式则是.xml文件里面用bndbox存绝对像素坐标。这两种格式的处理路径完全不同先确认再动手。# 查看解压后的目录结构确认标注文件类型 find ./电缆损坏数据集 -maxdepth 2 -type d | head -20 # 统计图片数量和标签数量是否一致 find ./电缆损坏数据集 -name *.jpg -o -name *.png | wc -l find ./电缆损坏数据集 -name *.txt | wc -l find ./电缆损坏数据集 -name *.xml | wc -l上面命令的逻辑很直接先看目录层级再分别统计图片、txt 标签、xml 标签的数量。如果图片 1318 张txt 也是 1318 个说明是 YOLO 格式且配对完整如果 txt 数量明显少说明有图片没标或标签丢失。参数上注意-maxdepth 2只展开两层避免目录太深刷屏。如果发现 xml 文件就需要额外写转换脚本不能直接喂给 YOLO 训练。2.2 用 Python 脚本做标签完整性检查空标签、越界框、类别失衡确认格式后下一步是逐文件检查标签内容。空标签文件意味着这张图没有目标但 YOLO 训练时如果图片和空标签配对会被当作背景样本少量可以大量会拉偏模型。越界框是指归一化坐标小于 0 或大于 1这种框在训练时会被裁剪或报错。类别失衡则是看每个类别的实例数量如果「雷电损坏」有 2000 个框「外破」只有 50 个模型会偏向多数类。import os from collections import Counter label_dir ./电缆损坏数据集/labels class_counter Counter() empty_files [] out_of_range [] for fname in os.listdir(label_dir): if not fname.endswith(.txt): continue fpath os.path.join(label_dir, fname) with open(fpath, r) as f: lines f.readlines() if len(lines) 0: empty_files.append(fname) continue for line in lines: parts line.strip().split() if len(parts) ! 5: print(f格式异常: {fname} - {line}) continue cls_id int(parts[0]) coords list(map(float, parts[1:])) class_counter[cls_id] 1 # 检查归一化坐标是否越界 if any(c 0 or c 1 for c in coords): out_of_range.append((fname, line.strip())) print(类别实例统计:, class_counter) print(空标签文件数:, len(empty_files)) print(越界框数量:, len(out_of_range))这段脚本做了三件事统计每个类别的实例数、记录空标签文件、检查坐标越界。参数上class_counter的 key 是类别 id需要跟data.yaml里的names列表对应。如果空标签超过总图片数的 10%建议直接剔除这些图片否则训练时背景样本过多。越界框如果只是个别可以手动修正或直接删除该框如果大量越界说明标注工具或导出流程有问题需要重新导出。2.3 划分训练集、验证集、测试集别用随机划分坑自己1318 张图像按 7:2:1 划分训练集约 922 张验证集约 264 张测试集约 132 张。但随机划分有个隐患如果同一根电缆的不同角度图片被分到训练集和验证集验证指标会虚高。正确做法是按「电缆段」或「拍摄批次」分组划分同一组图片只出现在一个集合里。常见做法是先用感知哈希或简单的文件前缀分组再在组级别做划分。import os import random import shutil random.seed(42) img_dir ./电缆损坏数据集/images label_dir ./电缆损坏数据集/labels output_dir ./dataset_split # 按文件名前缀分组假设前缀代表同一根电缆或同一批次 groups {} for fname in os.listdir(img_dir): if not fname.endswith((.jpg, .png)): continue prefix fname.split(_)[0] groups.setdefault(prefix, []).append(fname) group_keys list(groups.keys()) random.shuffle(group_keys) train_groups group_keys[:int(len(group_keys)*0.7)] val_groups group_keys[int(len(group_keys)*0.7):int(len(group_keys)*0.9)] test_groups group_keys[int(len(group_keys)*0.9):] for split_name, split_groups in [(train, train_groups), (val, val_groups), (test, test_groups)]: for g in split_groups: for fname in groups[g]: src_img os.path.join(img_dir, fname) src_label os.path.join(label_dir, fname.rsplit(., 1)[0] .txt) dst_img_dir os.path.join(output_dir, split_name, images) dst_label_dir os.path.join(output_dir, split_name, labels) os.makedirs(dst_img_dir, exist_okTrue) os.makedirs(dst_label_dir, exist_okTrue) shutil.copy(src_img, dst_img_dir) if os.path.exists(src_label): shutil.copy(src_label, dst_label_dir)这段脚本的核心是按前缀分组后再划分避免同一电缆的图片泄漏到不同集合。参数上random.seed(42)保证可复现0.7/0.2/0.1是常见比例小数据集可以调成 8:1:1。注意prefix fname.split(_)[0]是假设文件名用下划线分隔如果实际命名规则不同需要先看几个文件名再调整。划分完成后检查每个集合的图片数和标签数是否一致。3. 用 YOLOv8 训练电缆损坏检测模型环境、配置与关键参数3.1 环境配置Anaconda 建虚拟环境装 ultralytics 和 PyTorchYOLOv8 的训练依赖 ultralytics 包和 PyTorch。常见做法是用 Anaconda 建一个 Python 3.9 或 3.10 的虚拟环境再装 GPU 版本的 PyTorch。如果机器有 NVIDIA 显卡先确认 CUDA 版本再选对应的 PyTorch 安装命令。没有 GPU 也能跑但 1318 张图在 CPU 上训练会非常慢建议至少用一张 8GB 显存的卡。conda create -n yolo_cable python3.10 -y conda activate yolo_cable # 根据 CUDA 版本选择下面以 CUDA 11.8 为例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics # 验证安装 yolo checksyolo checks会输出环境信息包括 PyTorch 版本、CUDA 是否可用、显卡型号。如果显示 CUDA 不可用检查驱动和 PyTorch 版本是否匹配。参数上注意--index-url指定 PyTorch 官方源避免装到 CPU 版本。ultralytics 会自动装 opencv、numpy 等依赖不需要手动装。3.2 写 data.yaml类别名、路径和 nc 参数怎么填YOLOv8 训练需要一个data.yaml文件里面指定训练集、验证集、测试集路径和类别名。路径可以是绝对路径或相对于训练脚本的路径。类别名列表的顺序必须跟标签里的 class_id 对应否则模型学到的类别会错位。# data.yaml path: ./dataset_split train: train/images val: val/images test: test/images nc: 3 names: 0: leidian 1: waipo 2: qitanc是类别数量names是类别名列表。如果数据集里只有「雷电损坏」和「外破」两类nc就改成 2names只保留前两个。注意path是根目录train和val是相对路径。如果路径写错训练启动时会报FileNotFoundError这时候先检查path拼接后的完整路径是否存在。3.3 启动训练yolov8n 还是 yolov8sepochs 和 batch 怎么定小数据集优先用轻量模型yolov8n参数量最少训练快过拟合风险相对低。如果yolov8n的 mAP 不够再换yolov8s。1318 张图epochs 设 100 到 200 之间batch 根据显存定8GB 显存可以用 batch164GB 用 batch8。yolo detect train \ data./data.yaml \ modelyolov8n.pt \ epochs150 \ imgsz640 \ batch16 \ lr00.01 \ patience30 \ project./runs/cable \ nameexp1imgsz640是输入分辨率电缆缺陷目标通常不大640 够用如果缺陷非常小可以试 1280但显存占用会翻倍。lr00.01是初始学习率小数据集可以降到 0.005 避免震荡。patience30表示 30 个 epoch 验证指标不提升就早停省时间。project和name控制输出目录方便对比不同实验。3.4 看训练日志loss 曲线、mAP 和混淆矩阵怎么读训练启动后终端会输出每个 epoch 的 box_loss、cls_loss、dfl_loss 和 mAP50、mAP50-95。box_loss 下降说明框回归在收敛cls_loss 下降说明分类在收敛。如果 box_loss 震荡不降检查学习率是否太大或标签框是否有问题。mAP50 到 0.6 以上算可用到 0.8 以上算不错但小数据集上 mAP 虚高很常见必须看测试集结果。训练结束后runs/cable/exp1目录下会有confusion_matrix.png、results.png、val_batch0_pred.jpg等文件。混淆矩阵能看出哪个类别容易被误判比如「雷电损坏」被误判成「外破」说明两类特征在图像上太接近需要增加区分度或补充样本。val_batch0_pred.jpg是验证集第一批图片的预测结果直接看框的位置和类别是否正确比看数字更直观。4. 电缆损坏检测的避坑与排查标注、训练和推理中的血泪经验4.1 标签类别 id 从 0 开始还是从 1 开始搞错直接白训现象训练 loss 正常下降但推理时所有框的类别都是错的或者 mAP 极低。原因YOLO 格式的 class_id 从 0 开始但有些标注工具导出时从 1 开始或者data.yaml里的names顺序跟标签 id 不对应。解决先用脚本统计标签里出现的 class_id 集合再跟data.yaml的names长度对比。如果标签里有 id3 但nc3说明 id 越界需要重新映射。4.2 图片和标签文件名不一致训练时静默跳过现象训练日志里显示的图片数量比实际少或者某些图片没有对应的标签。原因YOLO 训练时按文件名匹配图片和标签如果图片是img_001.jpg标签是img_001.txt但实际标签名是img_001_label.txt就匹配不上。解决写脚本检查每张图片是否有同名 txt 文件没有的要么补标要么从训练集剔除。注意扩展名大小写.JPG和.jpg在 Linux 下是不同文件。4.3 小目标缺陷在 640 分辨率下消失框回归学不到现象训练 mAP 还行但推理时小尺寸的电缆破损漏检严重。原因电缆损坏中的细微裂纹或小面积损伤在 640x640 输入下只有几个像素经过下采样后特征几乎消失。解决一是提高输入分辨率到 1280二是用切片推理把大图切成小块分别检测再合并。切片推理可以用 SAHI 库但会增加推理时间。如果缺陷确实很小建议在数据标注时就放大缺陷区域或者用专门的小目标检测头。4.4 验证集 mAP 很高但测试集崩了检查数据泄漏现象验证集 mAP50 到 0.9测试集只有 0.4。原因同一根电缆的不同角度图片被随机分到了训练集和验证集模型在验证集上看到的是「见过的电缆」不是真正的泛化。解决按电缆段或拍摄批次分组划分确保同一组图片只出现在一个集合里。如果已经随机划分了重新按前缀分组再跑一次对比测试集指标。4.5 训练到一半显存爆了batch 和 imgsz 的取舍现象训练几个 epoch 后报 CUDA out of memory。原因YOLOv8 训练时显存占用会波动如果 batch 或 imgsz 设得刚好卡在显存上限后期可能爆。解决先把 batch 减半或者把 imgsz 从 640 降到 512。如果都不想降可以开ampTrue混合精度训练显存占用能降 30% 左右。注意amp在 ultralytics 里默认开启如果手动关了可以重新打开。5. 从训练到部署用验证集调阈值、导出 ONNX 和推理加速5.1 在验证集上找最佳置信度阈值和 IoU 阈值训练完的模型默认置信度阈值是 0.25IoU 阈值是 0.7但这两个值不一定适合电缆损坏检测。如果漏检多降低置信度阈值到 0.1 到 0.15如果误检多提高到 0.3 到 0.4。IoU 阈值影响 NMS 合并框的力度缺陷框重叠多时可以降到 0.5。from ultralytics import YOLO model YOLO(./runs/cable/exp1/weights/best.pt) metrics model.val( data./data.yaml, conf0.15, iou0.5, splitval ) print(mAP50:, metrics.box.map50) print(mAP50-95:, metrics.box.map)这段代码在验证集上跑一次评估conf和iou是手动指定的阈值。可以写一个循环遍历conf从 0.05 到 0.5找 mAP50 最高的那个值。注意splitval表示用验证集改成test就是测试集。参数上conf越低召回越高但误检也越多需要根据实际场景权衡。5.2 导出 ONNX 模型并在 Python 里做推理YOLOv8 训练完的.pt文件可以用model.export(formatonnx)导出 ONNX方便在 C 或 TensorRT 里部署。导出时注意imgsz和dynamic参数如果部署时输入尺寸固定dynamicFalse导出静态图推理更快。from ultralytics import YOLO model YOLO(./runs/cable/exp1/weights/best.pt) model.export(formatonnx, imgsz640, dynamicFalse, simplifyTrue) # 用 ONNX 模型推理 onnx_model YOLO(./runs/cable/exp1/weights/best.onnx) results onnx_model(./test_image.jpg, conf0.2) for r in results: boxes r.boxes for box in boxes: cls_id int(box.cls[0]) conf float(box.conf[0]) xyxy box.xyxy[0].tolist() print(f类别: {cls_id}, 置信度: {conf:.2f}, 框: {xyxy})导出时simplifyTrue会优化计算图去掉冗余算子。dynamicFalse表示输入尺寸固定为 640如果部署时想支持不同尺寸改成dynamicTrue但推理速度会慢一些。推理时conf0.2是置信度阈值box.xyxy是左上角和右下角坐标box.cls是类别 id。注意 ONNX 推理结果跟 PyTorch 推理结果可能有微小差异部署前用同一张图对比一下。5.3 用 TensorRT 加速FP16 和 INT8 的取舍如果部署在 NVIDIA 边缘设备上TensorRT 能显著提速。FP16 精度损失小速度提升约 1.5 到 2 倍INT8 速度更快但需要校准数据集精度可能下降。电缆损坏检测对精度要求高建议先用 FP16如果速度不够再试 INT8。# 导出 TensorRT 引擎 yolo export model./runs/cable/exp1/weights/best.pt formatengine halfTrue imgsz640halfTrue表示 FP16 精度imgsz640跟训练时一致。导出后的.engine文件可以直接用 ultralytics 加载推理。注意 TensorRT 引擎跟硬件绑定换显卡需要重新导出。如果导出时报错先确认 TensorRT 版本跟 CUDA 版本匹配。5.4 一个具体技巧用 TTA 提升小缺陷召回测试时增强TTA在推理时对图片做翻转、缩放等变换合并多次预测结果能提升小目标召回。YOLOv8 的model.predict支持augmentTrue开启 TTA但推理时间会变成 3 到 4 倍。如果漏检是主要问题且推理时间不敏感可以开 TTA 试试。results model.predict(./test_image.jpg, conf0.15, augmentTrue)augmentTrue会做水平翻转和缩放合并预测框。注意 TTA 对已经很高的 mAP 提升有限主要针对漏检场景。如果开了 TTA 后误检增多说明置信度阈值需要调高。我一般会在验证集上对比开和关 TTA 的 mAP50 和召回率再决定是否在部署时开启。训练电缆损坏检测模型这件事最深的教训是别迷信 mAP 数字。1318 张图跑出 0.85 的 mAP50 不难难的是在真实巡检图片上不漏检、不误报。我现在的习惯是训练完先看val_batch0_pred.jpg再挑 20 张测试集图片手动过一遍最后才看指标。数据集的标签质量比模型结构重要得多如果标签框歪了换什么模型都救不回来。希望帮到你。本文还有配套的精品资源点击获取
返回列表