
简介《工业控制计算机》2017 年刊出的一篇技术论文围绕概率神经网络PNN在变压器故障诊断中的应用展开适合电力系统运维人员、电气工程及机器学习方向的师生阅读。全篇以油中溶解气体分析法DGA为基础将 H2、CH4、C2H6、C2H4、C2H2 五种气体浓度作为 PNN 输入构建可区分高能放电、低能放电、过热及正常状态的诊断模型并给出 Matlab 中 newpnn、sim 函数的仿真流程与 Spread 参数优化结论。PNN 基于贝叶斯判别准则无需对原始数据做复杂预处理运行速度与分类效率优于传统方法。整包仅 1 个 PDF 文档大小约 1.44MB内容涵盖网络层次结构、正态分布假设下的密度函数推导以及 27 组训练、46 组检测样本的实证分析并同 ANN、SVM 等方法比较了准确率和训练时间工程参考价值较强。目前已有 148 人学习下载。1. 概率神经网络与变压器故障诊断为什么这个小众模型还值得用油色谱在线监测装置一天能吐出来几千条DGA数据可现场真正拍板的还是那套IEC三比值法加老师傅的经验。三比值法有明确边界——编码组合匹配不上就判不出来局部放电和过热并存时更是顾此失彼。概率神经网络PNN在这个场景里属于典型的小而美训练不需要反向传播几十个样本就能收敛新来的故障样本可以直接增量挂进模式层而不用重训在“样本少、要快、要能解释”的故障诊断任务里它比BP网络和SVM都更顺手。这篇笔记把从DGA原始数据到PNN模型、再到可发表结果的完整路径拆开讲透适合正在做设备状态监测、写故障诊断方向论文、或者准备用模式识别方法替代传统比值判据的工程师。2. 从油中溶解气体到故障标签构造PNN能消化的输入输出2.1 变压器故障类型与DGA特征气体的对应关系变压器内部绝缘油在电热故障下会裂解产生特征气体这是DGA诊断的物理基础。工程上关注的气体有七种氢气H2、甲烷CH4、乙烷C2H6、乙烯C2H4、乙炔C2H2、一氧化碳CO和二氧化碳CO2。其中乙炔是电弧放电的特征产物乙烯是高温过热的主标志甲烷和氢气在局部放电阶段就会出现。故障类型的划分大家通常直接沿用IEC 60599把状态分为七类这个标签体系在论文和现场之间是通用的。类别故障类型典型气体特征0正常老化各气体浓度均低CO/CO2缓慢上升1局部放电PDH2 升高CH4 少量2低能放电D1C2H2 升高H2 明显3高能放电D2C2H2 高C2H4 与 H2 同步高4低温过热 T1300℃CH4、C2H6 为主5中温过热 T2300~700℃C2H4 升高CH4 仍占相当比例6高温过热 T3700℃C2H4 主导C2H2 开始出现做概率神经网络分类时这七类就是输出层的决策目标标签编码用0到6的整数即可。需要提醒的是同一台变压器可能同时存在过热和放电模型预测的类别代表“主导故障”这点在论文里要写明否则审稿人会拿复合故障场景来质疑。2.2 三套特征方案编码比值、无编码比值与浓度向量把原始气体浓度变成特征向量常见做法有三套各有取舍第一套是IEC三比值编码。把C2H2/C2H4、CH4/H2、C2H4/C2H6三个比值按IEC 60599的编码表转换成0、1、2码得到三维编码向量。优点是和传统判据兼容现场老师傅容易看懂最大问题是比值落在编码表范围之外时直接找不到对应代码一条样本就这么废了而且比值编码丢掉了气体浓度的绝对信息小故障和严重故障可能映射成同一个码。第二套是无编码比值特征。直接用原始比值的数值CH4/H2、C2H2/C2H4、C2H4/C2H6、CO/CO2再加H2和C2H2的浓度。这套保留了渐变信息也解决了编码表覆盖不全的问题但比分母为零的情况要处理工程上常见的做法是分母低于检测下限时做截断加0.01的平滑。第三套最省事直接把七种气体浓度值或它们的对数拼成7维向量进模型前做标准化。浓度向量的优势是信息无损、无需人工设计比值PNN本身能处理高维输入缺点是不同气体的量级差异太大CO2动辄几千ppm而乙炔只有几ppm所以标准化是硬前提。我一般默认用第三套方案7维浓度加Z-score标准化在对比实验里再补一套无编码比值方案看鲁棒性。三比值编码在PNN里反而不是最优选择因为它压缩掉的信息恰恰是小样本分类最需要的气体浓度梯度。2.3 数据集切分与标签编码别把小样本玩成自嗨手头DGA样本通常只有几十到两三百条这时候数据集怎么切比模型选型还关键。先把标签编码固定下来正常0局部放电1低能放电2高能放电3低温过热4中温过热5高温过热6。然后做分层切分保证每一类在训练集和测试集里的比例一致防止某一类全被切到测试集里。import numpy as np from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler # gas_names: H2, CH4, C2H6, C2H4, C2H2, CO, CO2 X np.array([ [120.0, 45.0, 20.0, 15.0, 0.5, 300.0, 900.0], # 局部放电 [90.0, 30.0, 12.0, 10.0, 0.2, 250.0, 750.0], # 局部放电 [50.0, 80.0, 60.0, 180.0, 8.0, 400.0, 1200.0], # 高能放电 [45.0, 70.0, 55.0, 160.0, 6.5, 380.0, 1100.0], # 高能放电 [30.0, 150.0, 90.0, 200.0, 1.0, 450.0, 1300.0] # 高温过热 ]) y np.array([1, 1, 3, 3, 6]) # 分层切分小样本场景下stratify必须开 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, stratifyy, random_state42 ) # 先切分再fit标准化器防止数据泄漏 scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test)代码里的逻辑顺序值得多说一句train_test_split的stratify参数按y的类别比例采样避免随机切分把某一类样本全留在训练集里StandardScaler必须先fit在训练集上再把同一组均值和方差套到测试集上。很多人习惯先对整个X做标准化再切分这会让测试集的信息通过均值和方差间接参与训练准确率虚高一截这个坑到避坑章节再展开讲。3. 用Python从零实现概率神经网络训练、预测与混淆矩阵3.1 PNN的四层结构输入层、模式层、求和层、决策层概率神经网络的结构比BP网络直观得多四个层级各干各的活。输入层接收特征向量维度就是气体浓度特征的个数上面方案里是7。模式层是PNN的核心每一个训练样本在该层对应一个神经元存放的是这个样本的原始特征向量查询样本进入后模式层神经元用高斯径向基函数计算它与每个训练样本的相似度。求和层按类别把属于同一类的模式层输出做平均得到该类别的概率密度估计。决策层比较所有类别的密度值取最大者作为预测类别。这里的本质是Parzen窗密度估计加贝叶斯决策PNN不需要假设数据服从某个固定分布直接用高斯核函数叠出各类别的概率密度再按后验概率最大来判类。相比BP网络靠反向传播迭代逼近PNN的fit阶段只需把训练样本存起来预测阶段做一次前向计算就行没有梯度消失没有局部极小调参压力也小得多。模式层高斯核的宽度由一个参数控制就是下面代码里的sigma也叫spread。sigma越小核函数衰减越陡只有离查询样本很近的训练样本才对结果有影响sigma越大远处样本也能参与平滑密度估计越均匀。这个参数直接决定决策边界的形状第4章专门讲怎么选。3.2 最小可运行代码30行numpy写完一个PNNscikit-learn里没有现成的PNN类最直接的方式是用numpy手写一个。这个实现不依赖任何深度学习框架fit阶段就是记住训练数据predict阶段算密度逻辑清晰也方便后续改造加权决策层。import numpy as np class ProbabilisticNeuralNetwork: def __init__(self, sigma0.1): self.sigma sigma self.X_train None self.y_train None self.classes None def fit(self, X, y): # PNN的训练阶段保留所有训练样本作为模式层神经元 self.X_train np.array(X, dtypefloat) self.y_train np.array(y) self.classes np.unique(y) def _gaussian_kernel(self, x, x_i): # 高斯径向基距离越近输出越接近1sigma控制衰减速度 distance np.linalg.norm(x - x_i) return np.exp(-distance**2 / (2 * self.sigma**2)) def predict_proba(self, X): X np.array(X, dtypefloat) proba np.zeros((len(X), len(self.classes))) for i, x in enumerate(X): for j, cls in enumerate(self.classes): # 取当前类别的所有训练样本 class_samples self.X_train[self.y_train cls] # Parzen窗密度估计该类所有核输出取平均 density np.mean([ self._gaussian_kernel(x, x_i) for x_i in class_samples ]) proba[i, j] density # 归一化成概率分布 row_sums proba.sum(axis1, keepdimsTrue) row_sums[row_sums 0] 1e-12 return proba / row_sums def predict(self, X): proba self.predict_proba(X) return np.array([self.classes[i] for i in np.argmax(proba, axis1)])predict_proba里对每个类别单独取样本、单独算密度再取平均这是PNN和KNN最本质的差别KNN直接数邻居个数PNN则用核密度估计出“该类别产生这个样本的可能性”。代码中sigma传入0.1只是初始值实际使用必须经过交叉验证搜索直接拍脑袋的sigma会让模型要么退化成最近邻、要么变成掷骰子。另外注意密度做了归一化这样输出的proba可以当作置信度来用现场如果要设置告警阈值就靠它。3.3 在构造的样本上验证流程并输出混淆矩阵有了模型类接下来跑一个最小验证流程。用上一节准备的数据训练后输出在测试集上的预测类别和混淆矩阵。这里之所以强调混淆矩阵而非只看准确率是因为变压器故障样本天然不平衡——正常样本和高温过热样本往往占大头局部放电样本稀缺准确率会被多数类牵着走。from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay # sigma先用0.1跑通流程正式实验时替换为交叉验证选出的最优值 model ProbabilisticNeuralNetwork(sigma0.1) model.fit(X_train_scaled, y_train) y_pred model.predict(X_test_scaled) print(预测类别, y_pred) print(真实类别, y_test) cm confusion_matrix(y_test, y_pred, labelsmodel.classes) print(混淆矩阵) print(cm)运行这个流程你会看到预测类别和真实类别的对应情况以及一个6乘6或者7乘7的混淆矩阵对角线上的数字越大说明该类别判得越准。如果某一整行都是零说明该类别的测试样本全被错判这时候先不要急着调sigma回头检查训练集里这个类别的样本数量——如果只有一两条模型没有足够的模式层神经元来支撑密度估计再调参数也没用。3.4 为什么这里不直接调库有些工程里会用neupy库的algorithms.PNN直接声明网络但我自己动手写实现的原因有三条。其一调库版本高度依赖项目维护状态接口变化时排查成本比手写代码高得多。其二论文实验需要展示算法细节审稿人看到手写实现会比黑匣子更放心。其三后面讲到的不平衡样本加权决策层、增量学习等改进都需要改求和层或决策层的内部逻辑自己写的代码改起来顺手。如果你只是想快速验证PNN在某个数据集上的效果用neupy也可以但要做对比实验和算法改进我还是建议从numpy版本起步。4. 概率神经网络的3个必调参数σ、特征尺度与样本覆盖4.1 σ怎么影响决策边界从过拟合到过度平滑PNN真正需要调的核心参数只有一个sigma。但这个参数就像玄学调不好模型就翻车。从机制上看sigma控制的是高斯核的带宽等价于密度估计的平滑程度。sigma趋近于0的时候核函数只在查询样本与训练样本几乎重合时才输出非零值模型退化成最近邻分类器训练集准确率极高测试集上对噪声极其敏感样本稍微扰动类别就变。sigma过大的时候所有核输出都趋于1每个类别的密度估计都差不多决策边界变成一条直线模型忽略所有局部结构表现得像在猜先验概率。中间存在一个“甜点区间”让核宽度刚好覆盖同一类样本的典型距离又不会串到邻近类别的样本上。实际项目中我一般先看数据的类内平均距离再按这个距离的0.1倍到1倍范围去搜sigma。一个取巧的参考值是1.0附近——因为标准化后的特征大致服从标准正态分布样本间的典型距离在1到3之间sigma在这个量级通常不会太离谱。4.2 网格搜索σ5折交叉验证代码与结果解读选sigma的可靠做法是交叉验证不是看训练集准确率。下面这段代码对候选sigma列表逐个做5折交叉验证输出每个sigma下的平均准确率选最高的那个作为最终参数。from sklearn.model_selection import KFold # 候选sigma按指数步长覆盖从0.01到5.0 sigma_candidates [0.01, 0.03, 0.05, 0.1, 0.3, 0.5, 1.0, 1.5, 2.0, 3.0, 5.0] kf KFold(n_splits5, shuffleTrue, random_state42) results [] for sigma in sigma_candidates: fold_scores [] for train_idx, val_idx in kf.split(X_train_scaled): model ProbabilisticNeuralNetwork(sigmasigma) model.fit(X_train_scaled[train_idx], y_train[train_idx]) pred model.predict(X_train_scaled[val_idx]) fold_scores.append(np.mean(pred y_train[val_idx])) avg_acc np.mean(fold_scores) results.append((sigma, avg_acc)) print(fsigma{sigma:.2f} 交叉验证准确率{avg_acc:.4f}) best_sigma max(results, keylambda x: x[1])[0] print(f最优sigma {best_sigma})这段代码里有两个参数要说明一下。KFold的n_splits在样本总量不足50条时建议改成3或4否则每折训练集样本太少密度估计不稳定shuffleTrue保证样本顺序不产生偏置random_state固定后实验可复现。sigma_candidates的覆盖范围要根据特征尺度调整如果特征本身做了归一化0.01到5.0基本够用如果用原始浓度值但不归一化sigma需要放大到几十甚至上百这就是为什么特征尺度在前面章节被单独列为必调项。实际跑出来的结果往往会有一个明显的峰值区间。我记得有一次手头样本量90条sigma从0.05开始准确率只有62%到0.3跳到81%1.0回落到74%整个曲线是一个单峰。这个单峰的存在说明PNN在这个数据上是可靠的峰值对应的sigma可以直接用于测试集预测。4.3 进阶粒子群或遗传算法找σ值得吗不少论文用PSO或遗传算法对sigma做寻优理论上确实能找到更优参数但要在小样本场景里权衡值不值得。交叉验证网格搜索的计算量是候选sigma个数乘以折数乘以样本数对一百条样本来说十一组候选参数五折交叉验证在普通笔记本上几秒就跑完完全不需要上优化算法。粒子群优化sigma的场景应该是特征维度高、样本量上千、且分类器要反复重训的在线诊断系统。这时候网格搜索的粒度不够粒子群可以在连续空间里迭代逼近最优值。一个折中的做法是先网格搜索定位sigma的大致区间再用粒子群或贝叶斯优化在区间内精搜这样既避免了全局搜索的低效又比纯网格更细。论文里如果你写了PSO-PNN审稿人通常会追问初始种群数量和迭代次数这些参数在实验章节里需要交代清楚。提示sigma的最优值和训练样本数直接相关。样本越多模式层神经元越密集sigma可以适当调小核只覆盖到邻近的少数样本就足够稳定样本越少sigma反而要调大一些让有限的样本信息能平滑地扩展到整个特征空间。5. 概率神经网络变压器故障诊断避坑指南5个血泪经验5.1 数据泄漏先标准化再切分准确率集体虚高现象训练集准确率98%测试集准确率也高达95%模型在混淆矩阵上完美得可疑。换了真实新数据一测准确率直接跌到70%。原因代码里先对整个数据集做了StandardScaler那一步均值和方差把测试集的信息带进了训练过程——测试集的浓度分布特征已经从标准化参数里被模型间接看到。解决标准化器只fit在训练集上测试集用同一组均值和方差做transform顺序永远固定在切分之后。这条规则适用于所有涉及距离计算的模型PNN尤其敏感因为高斯核直接依赖欧氏距离。5.2 三比值编码匹配不上的样本被直接丢弃现象用IEC三比值做特征时一批样本的C2H2/C2H4或CH4/H2比值落在编码表边界外程序报错于是顺手把样本删掉。原本220条数据删到170条局部放电类几乎被删光训练出来的模型这这一类完全失去判别能力。原因变压器实际运行数据有噪声和气体交叉溶解比值在编码表边界附近浮动非常正常编码表是理想判据不是数据清洗规则。解决换用7维浓度特征或原始比值数值特征让模型自己学习边界如果论文里必须用编码输入对边界外的样本做最近边界码的截断映射别直接删。5.3 类别不平衡90%的准确率可能只学懂了多数类现象测试集准确率89%看起来不错打开混淆矩阵发现高温过热和正常两个大类占满了对角线局部放电类的召回率是0所有局部放电样本都被判成了正常。原因PNN决策层默认取密度最大的类别多数类样本多、模式层神经元密集密度天然被抬高少数类的密度被压低决策边界被“挤”到少数类一侧。解决看按类别的召回率和F1而不是只盯总体准确率。模型层面可以改成加权决策——在求和层对每个类别的密度乘以一个与样本量成反比的系数等价于给先验概率做修正数据层面用SMOTE对少数类过采样但注意PNN的模式层会直接复制合成样本过采样策略要谨慎简单重复合成样本会让sigma选择失真。5.4 sigma凭感觉拍脑袋训练集和测试集表现天差地别现象sigma取0.01时训练集准确率100%测试集准确率53%决策边界把每个训练样本单独圈了一块领地sigma取5.0时两边都只有60%上下曲线平得像白噪声。原因sigma是PNN的平滑程度开关过小的sigma把噪声当成信号过大的sigma把信号磨成噪声训练集准确率在这里不是有效的模型选择依据。解决用4.2节的交叉验证网格搜索让数据自己选sigma。注意一个细节交叉验证选sigma要用训练集内部再切分不碰测试集否则又变成变相的数据泄漏。5.5 不同来源的DGA数据混在一起不做尺度校正现象把实验室油样数据和现场在线监测数据混合训练总准确率只有60%。单独看现场数据的准确率80%实验室数据只有40%两套数据的分布完全不同。原因在线监测装置的检测下限、脱气方式、取样时间与实验室气相色谱标准不一同样一个故障两套源给出的气体浓度可能差几倍这些差异在欧氏距离里被当成类间差异放大。解决两套数据合并前先看各气体浓度的分布箱线图差异明显时优先做分源标准化或者按数据源做归一化后再合并实在要混合训练至少用无编码比值特征压低绝对浓度差异比值特征对尺度不敏感这一点在现场场景里比浓度向量更抗造。6. 从复现到论文把结果设计成审稿人挑不出刺如果你准备投故障诊断方向二区或三区的SCI期刊PNN的实验设计有几个隐藏要求。对比算法至少要包含BP神经网络和SVM这是故障诊断领域的标准基线有条件再补随机森林和XGBoost。划分方式用5折交叉验证并重复3次报告平均准确率加减标准差单次随机划分的结果在审稿人那里没有说服力。指标方面准确率之外必须给混淆矩阵和各类别的召回率最好补一个Kappa系数它比准确率更能反映不平衡样本下的真实一致性。模型对比的显著性检验是个加分项。配对样本用McNemar检验或Wilcoxon符号秩检验能说明你的PNN相较基线提升在统计上不是偶然。小样本是PNN论文最常见的审稿质疑点我的处理方式是专门做一组“训练样本数量从20%变化到90%”的曲线实验展示PNN在样本缩减时准确率下降比BP平滑。这比反复强调原理更有说服力。我早期做实验时走过一段弯路——为了在表上做出高准确率反复调sigma、换特征组合直到有一次交叉验证把最好的结果打回原形才意识到所有参数的最终裁判都应该是交叉验证而不是测试集。后来我把流程固定成先分层划分再标准化然后只碰训练集做网格搜索选sigma最后测试集只跑一次。这个习惯省掉了大量自我怀疑的时间也过滤掉了很多“好看但不真实”的数字。如果特征维度更高、数据量更大PNN还可以接PCA降维后再分类或者把求和层的简单平均换成加权平均给近邻样本更高权重。这些改进方向都值得试一试但前提是把前面这些基础流程做扎实。希望帮到你。本文还有配套的精品资源点击获取