基于人工神经网络的电力变压器故障诊断:从DGA特征工程到PyTorch实战
2026/9/18 16:58:11 网站建设 项目流程

简介:这份PDF文献面向电力系统运维人员、电气工程专业学生及从事机器学习数据建模的技术人员,聚焦变压器热性故障与电性故障的自动识别问题。资源为单文件PDF,大小约1.85MB,内容完整呈现了基于BP神经网络的诊断方案:输入层选取油中H2、CH4、C2H4、C2H2、C2H6五种特征气体,输出层对应无故障、中低温过热、高温过热、低能放电、高能放电五类状态,隐含层节点数按经验公式取13,并给出70组故障数据的样本定义、标准化预处理与主元分析降维思路。文中还梳理了权值初始化、误差反向传播、误差平方和判定等训练流程,以及MATLAB训练参数设置与20组测试集验证结果,诊断准确率达90%。目前已有146人学习,适合作为神经网络入门到电力故障诊断落地的参考案例。

1. 从油色谱数据到故障标签:电力变压器诊断为什么绕不开人工神经网络

一台 110kV 主变投运三年后,油中溶解气体在线监测装置报出乙炔含量缓慢爬升,从 0.2μL/L 涨到 3.5μL/L。运维班组的第一反应是翻 DL/T 722 的三比值表,结果落在「低能放电」和「过热」的边界上,两种判断对应的检修策略完全不同——一个要停电做局放定位,一个只需加强油温监视。这种「卡在表格缝里」的场景,正是电力变压器故障诊断最真实的痛点:传统阈值法和比值编码法规则硬、边界死,遇到多故障并发或早期潜伏性缺陷时,误判率居高不下。

人工神经网络在这里的价值,不是替代规程,而是把溶解气体、绕组温度、局部放电、振动等多源特征映射到一个可学习的非线性决策面上。它擅长处理「特征之间互相耦合、标签边界模糊」的问题,恰好对上变压器故障诊断的胃口。这篇内容面向两类人:一类是电力系统运维或检修工程师,想搞明白神经网络模型到底怎么落地到自己的台账数据上;另一类是算法工程师,接到「故障诊断」需求却对变压器业务不熟。全文按「特征工程 → 网络搭建 → 训练调参 → 部署排错」的路径推进,代码可直接跑,参数会逐个解释。

2. 电力变压器故障诊断的特征工程与标签体系

2.1 油中溶解气体分析(DGA)的输入特征怎么构造

变压器故障诊断最主流的输入是油中溶解气体分析数据,核心气体是 H₂、CH₄、C₂H₆、C₂H₄、C₂H₂、CO、CO₂ 七种。直接把这七个浓度值丢进网络效果一般,因为浓度量纲差异大,而且故障类型更多体现在气体之间的比例关系上。常见做法是构造「比值特征 + 浓度特征」的组合向量。

特征类型具体特征物理含义是否归一化
浓度特征H₂、CH₄、C₂H₆、C₂H₄、C₂H₂、CO、CO₂各气体绝对含量是(对数归一化)
三比值特征C₂H₂/C₂H₄、CH₄/H₂、C₂H₄/C₂H₆反映故障能量密度与温度是(编码或比值)
总烃特征总烃、总烃产气速率反映整体劣化程度
工况特征油温、负载率、运行年限修正环境干扰

三比值法的编码规则来自 DL/T 722,把三个比值按区间编码成 0/1/2 的组合,共对应 9 种典型故障。神经网络可以直接吃连续比值,也可以吃编码后的离散值,前者信息损失小,后者更贴近规程、可解释性强。我一般会两套都做,用连续比值训练主模型,用编码值做交叉验证。

2.2 故障标签的类别定义与样本不均衡处理

标签体系通常按规程划分为六类:正常、低能放电、高能放电、低温过热、中温过热、高温过热。实际台账里「正常」样本占八成以上,放电类故障可能只有几十条,直接训练会让网络偏向多数类。

处理不均衡的常见手段有三种:一是对少数类做 SMOTE 过采样,在特征空间插值生成合成样本;二是给损失函数加类别权重,让少数类误判的惩罚更大;三是在划分数据集时用分层抽样,保证每折里各类别比例一致。下面这段代码演示特征构造和分层划分的完整流程。

import numpy as np import pandas as pd from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler # 假设 df 列:h2, ch4, c2h6, c2h4, c2h2, co, co2, oil_temp, load_rate, label def build_features(df): eps = 1e-6 # 防止除零 feats = pd.DataFrame() # 对数归一化浓度特征,压缩量纲差异 for gas in ['h2', 'ch4', 'c2h6', 'c2h4', 'c2h2', 'co', 'co2']: feats[gas + '_log'] = np.log1p(df[gas]) # 三比值特征,加 eps 避免分母为零 feats['r1'] = df['c2h2'] / (df['c2h4'] + eps) # 乙炔/乙烯 feats['r2'] = df['ch4'] / (df['h2'] + eps) # 甲烷/氢气 feats['r3'] = df['c2h4'] / (df['c2h6'] + eps) # 乙烯/乙烷 # 总烃 feats['total_hc'] = df[['ch4', 'c2h6', 'c2h4', 'c2h2']].sum(axis=1) # 工况特征 feats['oil_temp'] = df['oil_temp'] feats['load_rate'] = df['load_rate'] return feats X = build_features(df).values y = df['label'].values # 分层划分,保证训练集和测试集类别比例一致 X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, stratify=y, random_state=42 ) scaler = StandardScaler() X_train = scaler.fit_transform(X_train) # 只在训练集上拟合,避免数据泄漏 X_test = scaler.transform(X_test)

这段代码的关键点有三个。第一,np.log1p对浓度做对数变换,因为气体浓度跨度可能从 0.1 到上千 μL/L,对数化后分布更接近正态,网络更容易收敛。第二,比值特征加eps是必须的,现场数据里 H₂ 或 C₂H₆ 为零的情况很常见,不加保护会直接产生 inf 污染整个训练集。第三,StandardScaler只能在训练集上fit,测试集用transform,这是很多人踩过的数据泄漏坑——如果全量数据一起标准化,测试集的统计信息就泄漏进了训练过程,评估结果会虚高。

提示:如果台账里某些气体字段大面积缺失,不要简单填零。填零会让网络误以为「该气体不存在」,而实际可能是「未检测」。建议加一个缺失指示列,或者用同类设备的均值填充并记录填充标记。

3. 用 PyTorch 搭建变压器故障诊断网络并跑通训练

3.1 网络结构选型:MLP 还是 1D-CNN

变压器故障诊断的输入是结构化特征向量,不是原始时序信号,所以多层感知机(MLP)是最直接的选择。但如果你的数据来自在线监测装置,每个样本其实是一段时序窗口的统计量,这时用一维卷积(1D-CNN)在时间维度上提取局部模式会更合适。轴承故障诊断里常用的 CNN 思路在这里同样适用,区别只是输入从振动波形换成了气体浓度序列。

对于大多数以 DGA 单次检测为样本的场景,我建议先用 MLP 打底,结构不用深,两到三个隐藏层足够。特征维度通常只有十几维,网络太深反而容易过拟合。隐藏层神经元数量按「输入维度 × 2」起步,逐层递减。

3.2 完整训练代码与损失函数选择

import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader, TensorDataset class TransformerFaultNet(nn.Module): def __init__(self, input_dim, num_classes=6): super().__init__() self.net = nn.Sequential( nn.Linear(input_dim, 64), nn.BatchNorm1d(64), # 加速收敛,缓解内部协变量偏移 nn.ReLU(), nn.Dropout(0.3), # 防止过拟合,小样本场景必备 nn.Linear(64, 32), nn.BatchNorm1d(32), nn.ReLU(), nn.Dropout(0.3), nn.Linear(32, num_classes) ) def forward(self, x): return self.net(x) # 类别权重:正常类权重低,故障类权重高,缓解不均衡 class_counts = np.bincount(y_train) weights = torch.tensor(1.0 / class_counts, dtype=torch.float32) weights = weights / weights.sum() * len(class_counts) criterion = nn.CrossEntropyLoss(weight=weights) model = TransformerFaultNet(input_dim=X_train.shape[1]) optimizer = optim.Adam(model.parameters(), lr=1e-3, weight_decay=1e-4) train_ds = TensorDataset(torch.tensor(X_train, dtype=torch.float32), torch.tensor(y_train, dtype=torch.long)) train_loader = DataLoader(train_ds, batch_size=32, shuffle=True) for epoch in range(200): model.train() total_loss = 0 for xb, yb in train_loader: optimizer.zero_grad() out = model(xb) loss = criterion(out, yb) loss.backward() optimizer.step() total_loss += loss.item() if (epoch + 1) % 20 == 0: print(f"Epoch {epoch+1}, Loss: {total_loss/len(train_loader):.4f}")

逻辑说明:BatchNorm1d放在Linear之后、激活函数之前,是标准做法,能让每层输入分布稳定,学习率可以设大一点。Dropout(0.3)在小样本下很关键,变压器故障样本往往只有几百条,不加 dropout 训练集准确率能到 99% 但测试集惨不忍睹。损失函数用带权重的交叉熵,权重按类别频率的倒数计算,这样少数类故障的梯度不会被多数类淹没。

参数说明:学习率1e-3是 Adam 的常用起点,如果 loss 震荡就降到5e-4weight_decay=1e-4是 L2 正则,配合 dropout 一起压制过拟合;batch_size=32在几百条样本下比较稳,样本更少时可以降到 16。训练轮数不用死守 200,建议加早停——监控验证集 loss,连续 20 轮不下降就停。

3.3 训练过程中的验证与早停实现

best_loss = float('inf') patience, wait = 20, 0 for epoch in range(300): model.train() for xb, yb in train_loader: optimizer.zero_grad() loss = criterion(model(xb), yb) loss.backward() optimizer.step() # 验证阶段 model.eval() with torch.no_grad(): val_out = model(torch.tensor(X_test, dtype=torch.float32)) val_loss = criterion(val_out, torch.tensor(y_test, dtype=torch.long)).item() if val_loss < best_loss: best_loss = val_loss wait = 0 torch.save(model.state_dict(), 'best_model.pth') # 只保存最优权重 else: wait += 1 if wait >= patience: print(f"Early stop at epoch {epoch+1}") break

早停的核心是「保存验证集最优的权重,而不是最后一轮的权重」。很多人训练完直接用最终模型评估,结果比训练中途的最优模型差好几个点。patience=20是经验值,数据噪声大可以放宽到 30,数据干净可以收紧到 10。

4. 故障诊断模型的评估、可解释性与现场排错

4.1 不看准确率:用混淆矩阵和召回率评估诊断效果

变压器故障诊断里,准确率是最容易骗人的指标。正常样本占八成,模型全预测「正常」也能有 80% 准确率,但放电故障一个都抓不到,这种模型上线就是事故。真正要看的是少数类的召回率——高能放电、低能放电这些类别的召回率必须单独看。

from sklearn.metrics import classification_report, confusion_matrix model.eval() with torch.no_grad(): pred = model(torch.tensor(X_test, dtype=torch.float32)).argmax(dim=1).numpy() print(confusion_matrix(y_test, pred)) print(classification_report(y_test, pred, digits=3))

classification_report会输出每个类别的 precision、recall、f1-score。重点关注 recall:如果「高能放电」的 recall 低于 0.85,说明模型漏报严重,需要回头检查这类样本是不是太少,或者特征里有没有能区分放电和过热的关键量(比如 C₂H₂ 的权重)。混淆矩阵则能看出模型把哪两类搞混了,比如「低温过热」和「中温过热」经常互相误判,这提示可能需要合并这两个类别,或者补充温度相关特征。

4.2 用 SHAP 解释模型到底学到了什么

现场工程师最常问的一句话是「你这模型凭什么说它是放电」。如果答不上来,模型就没法被信任。SHAP 是目前解释结构化数据模型最实用的工具,它能给出每个特征对单次预测的贡献值。

import shap model.eval() # 用训练集背景分布初始化解释器 explainer = shap.DeepExplainer(model, torch.tensor(X_train[:100], dtype=torch.float32)) shap_values = explainer.shap_values(torch.tensor(X_test[:50], dtype=torch.float32)) # 查看某个高能放电样本的特征贡献 sample_idx = 0 for i, feat_name in enumerate(feature_names): print(f"{feat_name}: {shap_values[2][sample_idx][i]:.4f}") # 类别2假设为高能放电

如果某个高能放电样本里c2h2_logr1的 SHAP 值特别大,说明模型确实是靠乙炔和乙炔/乙烯比做出的判断,这和规程里「乙炔是放电特征气体」的结论一致,工程师就能放心采信。反过来,如果模型靠load_rate这种工况特征做判断,那就要警惕了——负载率跟故障类型没有直接因果关系,很可能是数据里存在某种采集偏差。

4.3 现场部署常见报错与排查清单

现象可能原因排查动作
推理结果全是同一类输入特征未归一化或归一化参数不匹配检查 scaler 是否和训练时一致
某类故障永远不报训练样本该类过少或权重设置错误查 class_counts 和 loss weight
线上效果远差于离线训练测试数据同源,存在泄漏按时间划分数据集重测
比值特征出现 inf分母气体浓度为 0确认 eps 保护是否生效
模型输出置信度普遍偏低过拟合或类别边界模糊加 dropout、检查标签质量

注意:现场部署时,归一化用的均值和方差必须固化成配置文件,和模型权重一起版本管理。我见过太多案例是模型更新了但 scaler 没更新,导致线上输入分布和训练分布对不上,诊断结果直接崩掉。

5. 小样本下的迁移学习与在线增量更新技巧

变压器故障诊断最现实的约束是:带标签的故障样本永远不够。一个供电局一年可能就攒下几十条放电故障记录,靠这点数据训练深度网络,泛化能力很难保证。一个实用的技巧是迁移学习——先在公开的变压器 DGA 数据集或同网省的历史台账上预训练一个特征提取器,再用本地少量样本微调最后的分类层。

具体做法是冻结前面几层,只训练最后两层,学习率设小一点(比如1e-4),训练轮数控制在 50 轮以内。这样既利用了外部数据的通用特征,又适配了本地设备的个性分布。微调时建议用较小的 batch size(8 或 16),因为本地样本少,大 batch 会让梯度更新过于粗糙。

另一个技巧是在线增量更新。变压器状态是缓慢变化的,今天正常的设备半年后可能进入潜伏期。可以设计一个滑动窗口机制,把最近三个月的新样本按一定比例混入训练集重新训练,同时保留旧样本防止灾难性遗忘。重训练频率不用太高,季度一次足够,每次重训练后必须用固定的回归测试集验证,确保老故障类型的召回率没有下降。

验证模型是否真的可用的方法很朴素:拿最近一年实际发生并已确认的故障案例做盲测,看模型能不能在故障发生前的那次检测中就给出正确预警。这个指标比任何离线准确率都有说服力。如果盲测召回率能稳定在 85% 以上,这套基于人工神经网络的电力变压器故障诊断方案就具备上线价值了。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询