资讯动态

8712张局部放电信号图2分类:从PRPD谱图到ResNet18实战

发布时间:2026/10/15 7:34:03 来源:尧图企业网站定制
简介面向电力系统故障检测与机器学习研究者的电信号局部放电图像分类数据集共收录8712张jpg图片划分为无局部放电nopd8187张与有局部放电pd525张两类图片已按类别分文件夹存放无额外标注文件专用于图像分类而非目标检测场景。该压缩包共1个文件为docx格式说明文档总大小约1.41MB体积小巧、内容集中便于快速查看与部署使用。目前已有165人学习浏览适合图像识别算法训练、局部放电自动判别及电力设备状态监测等研究场景。借助该数据集研究者可直接开展二分类模型的训练与验证省去自行采集和整理图像的环节从而更高效地评估算法在局部放电识别任务上的表现对模式识别与电力故障诊断工作具有实用参考价值。1. 8712张局部放电信号图做2分类值不值得花两周时间入场做电力设备状态监测的同行应该都有过这种经历现场传感器装好了数据也采回了一大堆波形但一到算法阶段就卡住了。原因很直接——缺一份整理干净、类别明确、量级够用的样本集。所以当我看到“电信号图局部放电分类数据集8712张2类别”这个标题时第一反应是这份数据刚好卡在一个很舒服的规模上。8712张图做2分类不算大数据量但足够把“有没有放电”这件事训练出可用的模型也足够让刚接触这个方向的人在一台普通显卡上把完整流程跑通。这篇文章想聊的就是拿到这样一份数据后怎么把它变成能交付的分类模型以及中间那些不跑一遍就发现不了的坑。2. 读懂电信号图先把“局部放电的图谱”和“普通图片”区分开2.1 PRPD谱图与原始波形的区别为什么2分类能用图像模型局部放电的电信号传统上是一维时间序列。采样率动辄几十兆赫兹直接拿原始波形喂给深度学习模型要做对齐、降噪、变长处理非常折腾。行业里更常见的做法是把一个或多个工频周期的放电脉冲按相位和幅值累积投射到二维平面上形成相位分辨局部放电图谱业内一般叫PRPD谱图。横轴是0到360度的工频相位纵轴是放电幅值或放电量颜色或灰度表示该位置上放电脉冲出现的次数。这样处理后放电模式就变成了图像中的纹理和聚集形态图像分类模型就可以直接被拿来用。2分类任务在工程上对应的通常是一个很现实的问题这组信号里到底有没有威胁绝缘的放电活动。类别A可以定义为“存在局部放电”类别B定义为“噪声/干扰”或“无放电”也可能是“内部放电”对“电晕放电”这种更细的区分。具体取决于采集场景但模型结构不需要变化本质就是一个二选一的图像判别问题。用图谱而不是原始波形还有另一个好处图谱已经去掉了采样率、触发相位、幅值尺度这些现场变量模型学到的特征更稳定过拟合风险更低。2.2 8712张和2类别在工程上意味着什么规模、边界与验收标准8712张图放在图像分类领域是真的不多但2分类任务的困难程度也被这数字拉低了不少。同样8712张如果做10分类平均每类不到900张会相当难受而2分类平均每类约4300张在迁移学习下已经足够训练一个不太容易过拟合的轻量模型。一个最朴素的经验判断如果两类样本平衡并且采集来源不是单一设备这数据完全可以支撑“训练集6969张、验证集872张、测试集871张”这样的划分测试集结果能在92%以上。听起来指标很漂亮但工程验收不能只看准确率。局部放电检测属于负样本敏感的监控类任务漏放一个放电信号后果远比误报一次严重。所以验收要同时看灵敏度recall和特异性specificity最好配混淆矩阵判定。2分类的模型可以很简单但验收口径必须按设备状态监测的逻辑来定不能拿一个通用图像分类的报表糊弄过去。对刚接触这个方向的人来说这份数据的边界也很清楚它能帮你验证“有没有放电”的判断链路但它替代不了现场验证。图谱上的放电模式会随传感器类型、电压等级、环境噪声变化需要后续用自己设备采的样本做微调。我的建议是把它当做一个标准起点而不是终点。先把基准确立住后面加了新场景数据才知道往哪个方向调。3. 数据集落地第一步目录整理、划分策略与预处理参数3.1 按类别建目录一个脚本把散装图片整理成ImageFolder格式拿到这份数据集后第一件事不是训练而是先把目录结构理清。PyTorch的torchvision.datasets.ImageFolder可以直接按子目录名读取类别标签目录结构越规范后面代码越省事。比较理想的形态是dataset/class_a/*.jpg和dataset/class_b/*.jpg这样。但现实中的数据包往往不是这种形态。有的按采集日期分目录有的文件名里带标签有的用Excel记录对应关系。我一般会先整个目录扫描一遍统计文件分布再决定怎么抽取标签。如果标签可以从目录名或文件名里提取就用一个脚本统一整理# organize.py import shutil from pathlib import Path src Path(raw_samples) # 原始图片所在目录 label_map {label_a: discharge, label_b: noise} # 目录名到标准类别的映射 for f in src.rglob(*.jpg): raw_label f.parent.name # 先取上一级目录名 if raw_label not in label_map: print(f[skip] 未识别的目录: {f}) # 打印跳过的文件便于人工核对 continue dst_dir Path(dataset) / label_map[raw_label] dst_dir.mkdir(parentsTrue, exist_okTrue) shutil.copy(f, dst_dir / f.name)这里的rglob(*.jpg)会递归匹配所有jpg文件不关心原始目录嵌套多深。label_map是真实的分类映射按数据包附带的说明去填不要靠猜。打印跳过信息这一步很重要它能帮你发现哪些文件是放错位置或者命名不规范的后续做数据清洗时有个依据。如果数据包是用csv标注的就把raw_label f.parent.name换成去查表其他逻辑不变。整理完成后一定手动抽查一下文件夹里的图片内容。局部放电谱图长得很像像与不像要人眼过一遍不要想当然认为标注文件一定是对的。我见过二次整理时把两个类别的目录搞反的几十行脚本跑完整个数据集就废了那才是真的血泪教训。3.2 模型划分不能随机到底分层划分与同源样本的控制8712张图划分成训练、验证、测试很多人直接random.shuffle就切了这是很大的隐患。局部放电数据集经常按采集时段或设备编号组织同一个设备同一天采的图放电模式高度相似。如果这些图同时出现在训练集和测试集里模型的测试分数会被严重高估这叫重叠样本导致的“数据泄漏”。所以划分策略里必须加两个东西分层抽样和组划分。分层抽样保证两个类别在训练/验证/测试里的比例和全集一致避免某类全跑进训练集、另一类全跑进测试集。组划分则保证同一来源的样本不被拆开。如果数据包里有设备编号或文件名前缀这种来源信息优先按这个分组再组内划分# split.py from sklearn.model_selection import train_test_split from torchvision.datasets import ImageFolder dataset ImageFolder(dataset) # 自动按目录生成标签 targets dataset.targets # 每个样本的类别索引 # 第一次划分分出20%作为验证测试 train_idx, tmp_idx train_test_split( range(len(targets)), test_size0.2, stratifytargets, random_state42, ) # 第二次划分把20%再对半分得到10%验证、10%测试 tmp_targets [targets[i] for i in tmp_idx] val_idx, test_idx train_test_split( tmp_idx, test_size0.5, stratifytmp_targets, random_state42, ) print(ftrain{len(train_idx)}, val{len(val_idx)}, test{len(test_idx)})stratifytargets是分层抽样的关键参数它会按类别比例做随机切分random_state42固定随机种子保证每次跑结果一致方便复现对比。如果你的数据包里样本是按设备分组存储的就应该在train_test_split之前先对设备ID做划分再把同一个设备的样本整体划入同一侧而不是用上面的纯随机版本。这里宁可少拿几个训练样本也要保证测试集的独立性否则后面模型上线时落差会很大。3.3 resize、归一化与灰度转彩色预处理参数这样设最省事局部放电图谱的原始文件常见有两种形态单通道灰度图和RGB伪彩图。模型侧的输入通常固定为三通道、224×224像素。灰度图转三通道时不能直接np.stack三个相同通道再用全零填充而是把灰度值复制到RGB三个通道里让模型在三个通道上看到一致的信息。很多数据处理脚本在这步用了torch.zeros填充结果就是空白区域变成纯黑模型很容易把“纯黑边缘”当成分类特征。from torchvision import transforms train_transform transforms.Compose([ transforms.Resize((224, 224)), transforms.RandomAffine(degrees5, translate(0.05, 0.05)), transforms.RandomVerticalFlip(p0.5), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), ])Resize((224, 224))直接拉伸到固定尺寸而不是Resize后CenterCrop。局部放电谱图的放电区域有的集中在某个相位区段居中裁剪容易把放电区域裁掉直接拉伸虽然在比例上有点失真但对CNN来说通常更好学。RandomAffine只做小角度旋转和小幅平移模拟传感器相位偏移。RandomVerticalFlip可以翻但水平翻转不建议加因为PRPD谱图的左右对应工频正负半周翻转后物理意义就变了。Normalize用的是ImageNet的均值和方差这是迁移学习的常规配置除非你从零训练否则不要自定义均值和方差徒增调参难度。4. 用轻量CNN把2分类跑起来模型选型、训练脚本与三个必调参数4.1 模型选型为什么先试ResNet18而不是直接上EfficientNet8712张图、2类别、轻量部署这个组合下模型选型考虑的不是“谁的准确率最高”而是“谁最好调、最好部署、出问题好解释”。我一般第一版固定会用ResNet18理由很实际结构简单预训练权重多训练速度快显存占用低出bug时定位也快。MobileNetV3和EfficientNet虽然参数更少但训练时需要更多技巧才能发挥优势作为第一版基线并不划算。模型适用场景第一版选用的理由需要担心的点ResNet18中规模数据集的通用基线收敛快预训练权重稳定调试容易模型偏大但不影响CPU推理MobileNetV3嵌入式设备部署参数量小适合边缘端对训练技巧敏感容易欠拟合EfficientNet-B0追求高精度上限精度好FLOPs低预训练权重差异影响迁移效果调试周期长如果你是新手第一版直接用ResNet18把流程跑通后再考虑换小模型。如果是上边缘设备先拿ResNet18把准确率基线打出来再蒸馏或者换轻量模型这样你的每一步都有对比依据不会一上来就被MobileNetV3的玄学问题卡住。4.2 PyTorch最小训练脚本从加载8712张图到输出准确率有了整理好的目录和预处理流程训练代码可以收敛到一套固定套路。下面这个脚本是可运行的最小骨架核心结构不会因为换数据集而改变你只需要替换路径和类别数。import torch import torch.nn as nn from torch.utils.data import DataLoader from torchvision import models, datasets from torchvision.transforms import transforms # 预处理 transform transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), ]) # 加载数据集 fullset datasets.ImageFolder(dataset, transformtransform) # train_idx / val_idx / test_idx 来自 split.py 的输出 trainset torch.utils.data.Subset(fullset, train_idx) valset torch.utils.data.Subset(fullset, val_idx) testset torch.utils.data.Subset(fullset, test_idx) train_loader DataLoader(trainset, batch_size32, shuffleTrue, num_workers4, pin_memoryTrue) val_loader DataLoader(valset, batch_size32, shuffleFalse) # 模型 model models.resnet18(weightsmodels.ResNet18_Weights.IMAGENET1K_V1) model.fc nn.Linear(model.fc.in_features, 2) # 把1000分类改成2分类 device torch.device(cuda if torch.cuda.is_available() else cpu) model model.to(device) criterion nn.CrossEntropyLoss() optimizer torch.optim.AdamW(model.parameters(), lr3e-4, weight_decay1e-4) scheduler torch.optim.lr_scheduler.ReduceLROnPlateau( optimizer, modemin, patience3, factor0.5) for epoch in range(20): model.train() for images, labels in train_loader: images, labels images.to(device), labels.to(device) optimizer.zero_grad() loss criterion(model(images), labels) loss.backward() optimizer.step() # 验证 model.eval() val_loss, correct, total 0.0, 0, 0 with torch.no_grad(): for images, labels in val_loader: images, labels images.to(device), labels.to(device) outputs model(images) val_loss criterion(outputs, labels).item() * labels.size(0) correct (outputs.argmax(1) labels).sum().item() total labels.size(0) val_loss / total accuracy correct / total scheduler.step(val_loss) print(fepoch{epoch1}, val_loss{val_loss:.4f}, acc{accuracy:.4f})model.fc nn.Linear(...)是替换最后一层全连接把ImageNet的1000类输出改成2类这一步很多新手会漏掉结果输出维度对不上。AdamW从3e-4起步是迁移学习的安全区间。ReduceLROnPlateau监控验证集loss连续3个epoch不降就把学习率减半这个机制能明显减少手动调学习率的次数。训练阶段model.train()和验证阶段model.eval()必须成对出现dropout和BN层的行为依赖这个开关漏了会导致验证集指标异常跳变。跑完20个epoch把测试集也过一遍记录准确率、每个类别的精确率和召回率这组数字就是你的基线。4.3 影响收敛的3个参数学习率、batch size与权重衰减同样的数据和代码参数不同收敛速度能差出好几倍。3个参数要优先关注。学习率是头号敏感参数。用预训练权重时从头开始训练的学习率一上来就用0.01基本必炸loss会直接飞掉。从3e-4起步然后监控loss曲线的下降斜率。如果你的训练loss前三五个batch还在0.7附近不动大概率学习率偏小如果loss直接跳到nan那就是学习率大了。配ReduceLROnPlateau后基本不用手动干预。batch size影响的是收敛稳定性和显存占用。32对于224×224的ResNet18是安全值16也行但梯度噪声更大loss曲线会更抖64则要求显存至少6GB收敛速度不会成比例提升。2分类任务不必追求大batch稳定优先。权重衰减是很多人忽略的。局部放电图谱纹理比较单一模型容易死记硬背训练集中的细微模式2分类的过拟合信号还不明显但weight_decay从1e-4开始设好了后面省去一次重训的麻烦。AdamW自带解耦权重衰减效果优于传统AdamL2直接用它。5. 电信号图2分类避坑标签噪声、数据泄漏与过拟合的5个现场5.1 训练集92%、测试集69%八成是数据泄漏现象训练集和验证集的准确率都在90%以上换到测试集直接掉到70%不到模型看起来练得很好一上线就露馅。原因数据划分时没有考虑样本来源同一个设备、同一时段采集的图片同时出现在训练集和测试集模型记住了这套设备的特有模式而不是泛化的放电特征。解决回到第3.2节按设备ID或采集批次分组划分。如果没有这些信息一个补救办法是把文件名里的时间戳提出来用时间维度做划分。验证集提升到和测试集一致的水平后再继续调参这比任何trick都重要。5.2 验证集loss往下走准确率却不动标签噪声在现场的表现现象训练loss平稳下降验证loss也在降但验证准确率卡在某个值附近不动比如长时间在87%上下波动。原因数据集中存在标注错误的样本或者是边界样本比如很弱的放电信号和噪声在视觉上几乎一样。模型在努力拟合噪声标签但学不到更细的判别边界。解决先输出混淆矩阵看是哪一类被经常混淆。然后拿被错分的样本做人工复核。这类数据集常见的标签噪声来源是采集时的自动标注程序阈值设错。如果你有精力和时间重标一遍写不出来的类别比换任何模型都有效。5.3 只学图像不学信号模型把背景当成放电特征的翻车现场现象训练时准确率很高但把图片四周加了一圈黑边后预测结果全乱了或者新数据上一遇到不同的边框、字体、水印发型准确率骤降。原因图谱图片里除了放电区域还有坐标轴、刻度线、图例、水印这些“背景物”模型如果偷懒会直接学这些视觉标记因为它们跟标签之间存在偶然的相关性。解决预处理时把图片统一裁剪到只保留谱图主体区域或者用掩膜把坐标轴区域置为统一灰度值。再做一点随机扰动加轻微模糊、改变对比度。最终验证时一定准备一批从别的来源截取、样式更杂的图谱做鲁棒性测试模型不能只看样式不看内容。5.4 类别数量不均衡用加权采样而不是盲目复制样本现象两个类别数量如果差异大比如一类7000张、另一类1712张训练出来的模型对少数类基本不敏感少数类样本几乎全被预测成多数类。原因模型在最小化整体损失学到的决策边界天然偏向数量多的类别。对2分类的局部放电任务来说如果少数类恰好是“有放电”这在设备监测场景是致命的。解决优先用WeightedRandomSampler做加权采样让每个batch里两类样本数量接近而不是简单复制少数类图片。复制会造成模型对同一样本反复拟合泛化能力反而下降。代码里加两行即可。from torch.utils.data import WeightedRandomSampler # labels 是全量训练样本的标签 class_counts torch.bincount(torch.tensor(targets)) weights 1.0 / class_counts[targets].float() sampler WeightedRandomSampler(weights, num_sampleslen(weights), replacementTrue) train_loader DataLoader(trainset, batch_size32, samplersampler, num_workers4)5.5 过拟合信号图相位翻转增广不一定安全现象训练准确率接近100%验证准确率反而在某个epoch后开始下降典型的过拟合曲线。原因模型容量对8712张来说偏大训练轮次过长加上增广策略不当。很多人在PRPD谱图上顺手加水平翻转增广这会让模型把左右对称的放电模式当成同一个模式但真实场景中正负半周的放电特性是不同的物理过程学习被误导。解决把水平翻转去掉保留小幅度的垂直翻转和仿射扰动同时加EarlyStopping。ReduceLROnPlateau负责降学习率但后面仍然容易过拟合直接按验证集准确率连续5个epoch不升就保存当前权重并停止。别小看这个习惯能帮你避免深夜守着loss曲线干瞪眼的尴尬。6. 验证模型到底学到了什么混淆矩阵与Grad-CAM的行为分析6.1 五折交叉验证对8712张的2分类任务更可靠单次划分的测试集只有871张结论的置信度有限。8712张的规模正好可以跑五折交叉验证把五份测试结果合并统计得到的准确率和置信区间才是敢写在交付文档里的数字。每折训练一个ResNet18五个模型独立评估最后一并统计。这个操作能顺带暴露数据划分中的偶然偏差比如某一折明显偏低基本可以断定那一折里混入了难样本或脏样本。6.2 混淆矩阵与Grad-CAM可视化别只盯准确率准确率在2分类上很容易虚高尤其是类别不平衡时。交付前两个验证动作必须做一是打印混淆矩阵看模型把哪类样本误判成另一类二是用Grad-CAM类激活映射把模型判断“有放电”时关注的区域叠回原图确认高亮区域是否落在图谱的放电相位区间。比如电缆内部放电通常出现在第一、三象限的特定相位区间如果模型高亮的区域集中在坐标轴或图例上说明它又在偷看样式特征这个模型需要回炉重训。我自己做这类项目时最早也吃过亏。第一次跑完准确率94%心里很满意直到用Grad-CAM看了一张样本发现模型高亮的区域是右下角的采集时间水印。那次之后我再也不敢拿准确率作为唯一交付指标混淆矩阵、可视化、交叉验证一个都不少。做电信号图的分类模型不该只学会“认图”而是真的学会“认放电”。希望这篇笔记能帮你把8712张图的2分类任务一次跑通少走这些弯路。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑