ARTICLE DETAIL

资讯详情

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

基于深度学习的故障检测算法Python源码实战指南

基于深度学习的故障检测算法Python源码实战指南 简介基于多种深度学习的故障检测算法Python源码及项目说明面向故障诊断、工业智能运维方向的算法学习者和研究者适用于CWRU轴承数据集上的特征提取与故障分类任务帮助理解CNN、自编码器AE等模型在故障检测中的完整落地流程。压缩包共478个文件以py源码为主含254个py与166个pyc另含训练日志、TensorBoard事件文件、xml配置及说明文档等整体大小约1.16MB目录划分清晰包括AE_Datasets、CNN_Datasets、models、utils、checkpoint、logs等模块便于按网络类型和训练环节查阅。资源内置多套数据预处理方式提供训练脚本与可视化脚本并在原代码基础上增添了精确率、召回率、误报率、漏检率等指标记录还加入CWT与STFT变换分析可直观对比不同输入的诊断效果。目前已有874人学习下载适合希望借助PyTorch框架上手故障检测、复现并改进深度学习算法的中高级读者。1. 故障检测为什么值得用深度学习这个 Python 源码包能解决什么车间里最有经验的老师傅拿一把螺丝刀顶在轴承座上侧耳听几秒就知道设备有没有出问题。这种靠听觉、触觉积累起来的判断力正是故障检测要解决的核心问题从设备运行数据里提前发现异常的苗头而不是等设备坏了停产再修。深度学习做这件事的优势在于它不需要人工设计特征——不用你手工算峭度、算包络谱、挑频带而是让模型自己从原始信号里找到异常模式。标题里这个「基于多种深度学习的故障检测算法 Python 源码 项目说明」的压缩包我理解它是一个完整可跑的工程项目而不是某篇论文的零碎代码。这种源码包通常包含三类东西可用的模型代码、配套的数据处理脚本、以及说明文档。对做设备维护的工程师、搞算法落地的人、还有拿它做课设毕设的学生来说最有价值的不是模型本身有多 fancy而是你能不能在半天内把环境跑通、把数据换掉、看到属于自己的检测结果。这篇文章就顺着这条落地路径把选型、数据、代码、坑和验证一次讲清楚。2. 故障检测里到底该用哪种深度学习模型CNN、LSTM、自编码器的选型逻辑「多种深度学习」这个说法看着宽泛但放到故障检测这个具体场景里翻来覆去真正被反复验证、项目里真在用的其实是三套组合一维 CNN、LSTM/GRU 这类时序模型、以及自编码器这种无监督方案。下面把这三种模型的适用场景、物理直觉和工程代价拆开说。2.1 一维 CNN振动信号故障检测的默认首选振动信号是一维时序数据用一维卷积Conv1D去处理它是最自然的做法。它的物理含义可以这样理解卷积核在时间轴上滑动相当于一个带通滤波器组每个卷积核学到的就是某种频率模式的响应。轴承内圈故障、外圈故障、滚动体故障在振动信号上会激发出不同频率的冲击成分CNN 恰恰就是擅于捕捉这种局部特征的。工程上1D CNN 有三个明显优势。第一参数量比同深度的 2D CNN 小一个数量级振动信号长度通常只有几千个点训练起来一块普通显卡都绰绰有余第二对输入长度不敏感滑动窗口切出来的样本不需要统一成正方形第三推理速度快部署到工控机甚至边缘设备上都行——这一点跟热搜里 esp32 轴承故障检测那种嵌入式场景直接相关1D CNN 的模型体积和计算量是三种模型里最适合下放到边缘设备的。代码层面的典型结构是这样import torch.nn as nn class FaultCNN1D(nn.Module): def __init__(self, n_classes4, input_length1024): super().__init__() self.features nn.Sequential( # 第一层1024个点 - 512个点卷积核64相当于覆盖64个采样点 # 在12kHz采样率下约5ms正好对应一个冲击响应的衰减长度 nn.Conv1d(1, 16, kernel_size64, stride2, padding32), nn.BatchNorm1d(16), nn.ReLU(), nn.MaxPool1d(2), # 第二层通道数翻倍卷积核缩短捕捉更细的局部模式 nn.Conv1d(16, 32, kernel_size3, stride1, padding1), nn.BatchNorm1d(32), nn.ReLU(), nn.AdaptiveAvgPool1d(1) ) self.classifier nn.Sequential( nn.Flatten(), nn.Linear(32, 64), nn.ReLU(), nn.Dropout(0.3), nn.Linear(64, n_classes) ) def forward(self, x): return self.classifier(self.features(x))关于上面的结构和参数有三点值得说明。kernel_size64不是随手拍的卷积核在时间轴上的物理覆盖范围要和故障冲击的持续时间匹配12kHz 采样率下轴承外圈故障的冲击通常持续 1 到 3ms64 个采样点约为 5ms能包住完整冲击响应stride2是为了降采样把 1024 点压到 512 点减少后续计算量AdaptiveAvgPool1d(1)的作用是把最后一层特征图压成单一向量这样模型就不要求输入窗口必须是固定的 1024 点换个窗口长度也能跑。相比 2D CNN 把信号画成频谱图再识别1D CNN 直接在原始波形上处理省掉了短时傅里叶变换这一步这条链路更短出问题也更好排查。2.2 哪些故障场景更适合用 LSTM 或自编码器CNN 处理的是局部特征但它对时间顺序的建模能力有限。有些故障信号的特征不在某个局部的冲击形状而在样本与样本之间的变化趋势——比如齿轮箱的早期磨损振动幅值随着载荷变化呈现缓慢漂移比如往复式压缩机的气阀故障每个工作周期的波形都存在细微的相位差异。这种场景下LSTM 的门控结构能记住一段时序内的上下文效果会比 CNN 好。自编码器则解决的是另一类问题故障样本稀缺。工业现场最大的痛点是正常数据一大堆故障数据没几条——因为设备不能为了采故障数据故意去损坏。自编码器只拿正常样本训练学习正常模式的压缩表示推理时如果重构误差超过阈值就判为异常。它的优势是不需要任何故障标签就能做异常检测很适合做设备健康状态的初期预警。下表是三种模型在故障检测中的选型对比模型输入形式核心优势主要局限典型应用场景1D CNN原始波形/分段信号局部特征提取强、参数少、推理快对长程依赖建模弱轴承、齿轮等旋转机械故障分类LSTM/GRU多通道时序/序列切片建模时序依赖和趋势变化训练慢、易过拟合、部署体积大工况变化下的早期缓慢退化检测自编码器原始波形/特征矩阵无监督、不需故障标签阈值难定、对微弱故障不敏感故障样本稀缺时的异常预警2.3 信号特征和模型怎么匹配原始波形、频谱还是包络谱这是一个容易被忽视但直接影响结果的问题。故障信号通过不同的特征表达进入模型效果差异可以超过 15 个百分点。常见的选择有三种。最直接的是原始波形直接进 1D CNN这是当前的主流做法因为 CNN 能从原始数据里自己学出频域特征。第二种是把信号做短时傅里叶变换或小波变换得到时频谱图然后送 2D CNN 或者视觉模型处理——但这里的问题是你引入了额外的超参数窗函数类型、窗长、重叠率每一项都可能让结果产生显著波动。第三种是包络谱先对原始信号做希尔伯特变换取包络再求频谱这样能把高频冲击调制信号解调出来让故障特征在频域里更清晰。对于轴承故障将包络谱作为 1D CNN 的输入往往比喂原始波形收敛更快、准确率更稳定。说穿了信号处理的前处理不是多此一举它是在帮模型减少要学的东西。3. 把传感器数据变成可训练的样本数据集构建与预处理全流程模型选型的下一步是把现场采集的连续传感器数据变成一个个独立的训练样本。这一步看着简单却是整个项目里最决定成败的环节——我见过太多人在模型上反复调参最后发现是数据切分方式本身就有问题。3.1 滑动窗口切分从连续信号到独立样本传感器采集到的原始数据是一条很长的连续时间序列比如以 12kHz 采样率连续采一分钟就有 72 万个采样点。你不能把这 72 万个点直接丢给模型训练因为模型要求输入是独立的样本而一整条长序列既没法批量处理也没有标签粒度。正确做法是用滑动窗口把长序列切成固定长度的片段每个片段作为一个独立样本。import numpy as np def sliding_window_sampling( signal: np.ndarray, window_size: int 1024, stride: int 256, start_idx: int 0, n_samples: int 1000 ) - np.ndarray: 把一维长信号切分为定长样本。 Args: signal: 一维原始信号数组 window_size: 单个样本的长度对应时间长度 window_size / fs stride: 窗口滑动步长窗口重叠率 1 - stride / window_size start_idx: 起始位置索引通常跳过设备启动阶段的数据 n_samples: 需要生成的样本数量 Returns: samples: 形状为 (n_samples, window_size) 的 ndarray samples [] pos start_idx while len(samples) n_samples: if pos window_size len(signal): break # 数据不够了提前结束 samples.append(signal[pos : pos window_size]) pos stride return np.stack(samples)这个切分逻辑有三个关键参数每个参数的取值后面都有对应的代价。window_size决定单个样本包含多少信息窗口太短可能截不完整一个完整的故障冲击序列窗口太长又要求快速推理的场景下延迟变大。按 12kHz 采样率算1024 点约 85 毫秒对旋转机械的故障检测来说是够用的下限。stride决定样本间的重叠程度stride 越小样本重叠率越高相当于把同一段信号以略微偏移的方式重复使用数据量上去了但也意味着相邻样本高度相关训练集和验证集如果切得不小心验证指标会虚高到没意义这点后面避坑章节详细展开。start_idx这个参数容易被忽略但实际现场数据的前几秒往往是设备启动、转速不稳定的过渡段直接切进去会往训练集里塞入大量噪声样本。3.2 数据标准化与归一化别把量纲问题甩给模型同一台设备在不同负载下振动幅值可能差出几倍不同设备之间传感器灵敏度不同量纲更是对不上。如果原始信号直接进网络模型需要额外学习去适应不同幅值范围这会对收敛速度产生明显影响。处理方式是在切窗之后做 z-score 标准化统计量和应用分开。注意这里有个工程细节统计量只能从训练集算然后拿它去标准化验证集和测试集。如果你把整个数据集混在一起做标准化会发生信息泄漏——验证集的均值方差信息已经参与了模型输入变换训练时模型等于提前看到了验证集的分布特征。from sklearn.preprocessing import StandardScaler # 只对训练集拟合 scaler验证集/测试集仅调用 transform scaler StandardScaler() train_samples scaler.fit_transform( train_samples.reshape(-1, window_size) ).reshape(-1, 1, window_size) val_samples scaler.transform( val_samples.reshape(-1, window_size) ).reshape(-1, 1, window_size)StandardScaler 的 fit_transform 和 transform 分离是这套流程里最不能妥协的一步。fit_transform 会在训练数据上计算每个采样点的均值和标准差并完成变换验证集和测试集用同样参数做变换保证模型看到的输入分布一致。这就相当于恒流源里不能用万用表直接测电流——测试手段不能影响被测对象本身。3.3 利用公开数据集快速验证流程拿 CWRU 轴承数据跑通全链路刚开始没有现场数据时我建议用凯斯西储大学CWRU的轴承数据中心公开数据集来跑通整个流程。这是一套 1990 年代就建立的标准数据集几个工况、内圈故障、外圈故障、滚动体故障和正常状态都有对应的振动信号几乎成了故障检测领域的 MNIST。它的好处是数据质量高、标签明确、样本量大足够支撑模型选型和参数摸索。从 CWRU 数据到可训练样本的流程是下载 mat 文件读取 DE驱动端传感器信号按上面的滑动窗口切分给每个窗口打上工况标签再按比例划分训练集验证集和测试集。下面这段代码展示了从 mat 文件到 npy 的完整转换import scipy.io as sio def load_cwru_mat(mat_path: str, channel: str DE_time) - np.ndarray: 读取 CWRU 数据集 mat 文件返回指定通道的振动信号。 Args: mat_path: mat 文件路径 channel: 通道名常用 DE_time驱动端或 FE_time风扇端 Returns: signal: 一维信号数组 raw sio.loadmat(mat_path) signal raw[channel].flatten() return signal在 12kHz 采样率下CWRU 单个 mat 文件通常包含十几秒的信号滑动窗口切分后能生成几千个样本足够训练一个中小规模的 1D CNN。用公开数据先跑通再到现场替换自己的数据这是最稳妥的推进路线不要一上来就拿着现场采的数据折腾否则环境噪声、工况波动、传感器问题这些干扰因素会让你分不清到底是模型的问题还是数据的问题。4. 跑通故障检测 Python 源码环境搭建、模型训练与推理的一步步操作前面把模型和数据说透了这章落到实操拿到源码包之后从解压到跑出第一个训练曲线每一步怎么走。4.1 环境搭建与项目目录结构故障检测的深度学习项目依赖不算复杂核心是 PyTorch 或 TensorFlow 二选一再加上数据处理常用的 NumPy、SciPy、scikit-learn。如果你在安装环节就卡住了先解决 Python 版本问题PyTorch 对 Python 版本有要求建议直接用 Anaconda 创建独立环境版本按照你安装的 PyTorch 官方要求对应好避免系统 Python 环境的依赖冲突。# 创建独立虚拟环境避免污染系统 Python conda create -n fault_detection python3.9 conda activate fault_detection # 安装核心依赖 pip install torch --index-url https://download.pytorch.org/whl/cu118 pip install numpy scipy scikit-learn matplotlib pandas依赖安装的常见问题是 CPU 和 GPU 版本装错。上面第一行指定了 cu118CUDA 11.8如果你的机器没有 NVIDIA 显卡去掉--index-url参数直接pip install torch会自动装 CPU 版本。验证安装是否成功用一行命令python -c import torch; print(torch.__version__, torch.cuda.is_available())输出2.x.x True说明 GPU 可用如果是False后面训练会慢很多但代码逻辑不变。环境装好之后建议先看项目里的说明文档它通常会写清楚目录结构和每个脚本的入口参数。4.2 训练循环代码解读关键参数与模型保存逻辑大部分故障检测项目的训练代码结构是相似的核心是一个 fit 函数里面嵌套 epoch 和 batch 两层循环。下面是一段标准的 PyTorch 训练循环注释标记了故障检测场景下尤其要注意的位置import torch import torch.nn as nn from torch.utils.data import DataLoader, TensorDataset def train_model( model, # 实例化的模型对象 train_x: np.ndarray, # 训练数据形状 (N, 1, window_size) train_y: np.ndarray, # 训练标签形状 (N,) val_x: np.ndarray, val_y: np.ndarray, epochs: int 30, batch_size: int 64, lr: float 1e-3 ) - nn.Module: 训练并返回验证集上准确率最高的模型。 dataset TensorDataset( torch.FloatTensor(train_x), torch.LongTensor(train_y) ) loader DataLoader(dataset, batch_sizebatch_size, shuffleTrue) criterion nn.CrossEntropyLoss() optimizer torch.optim.Adam(model.parameters(), lrlr) scheduler torch.optim.lr_scheduler.StepLR(optimizer, step_size10, gamma0.5) best_val_acc 0.0 best_state None for epoch in range(epochs): model.train() total_loss 0.0 for batch_x, batch_y in loader: optimizer.zero_grad() # 前向传播 损失计算 反向传播 outputs model(batch_x) loss criterion(outputs, batch_y) loss.backward() optimizer.step() total_loss loss.item() # 每个 epoch 结束在验证集上评估保存最优模型 model.eval() val_pred model(torch.FloatTensor(val_x)) val_acc (val_pred.argmax(1) torch.LongTensor(val_y)).float().mean().item() if val_acc best_val_acc: best_val_acc val_acc best_state {k: v.clone() for k, v in model.state_dict().items()} print(fEpoch {epoch1}/{epochs} | Loss {total_loss/len(loader):.4f} | Val Acc {val_acc:.4f}) scheduler.step() model.load_state_dict(best_state) return model这段代码的逻辑说明集中在三个关键点。第一TensorDataset把 numpy 数组包装成 PyTorch 的数据集DataLoader里的shuffleTrue在每个 epoch 打乱样本顺序——这个必须保持打开否则模型每个 epoch 看到的样本顺序相同容易陷入局部最优。第二scheduler是学习率衰减策略每 10 个 epoch 学习率降一半。故障检测模型训练后期容易出现震荡固定学习率会让准确率在某个区间来回跳衰减策略能让它在后期收敛得更稳。故障检测数据通常是高维小样本学习率的设置比网络结构的影响更明显。第三训练结束前保存的是验证集上表现最好的模型权重best_state的拷贝方式避开了直接引用导致的原地修改——这是 PyTorch 里一个隐蔽的坑如果不clone()之后模型继续训练时best_state里的值也会被同步修改。4.3 推理脚本加载权重对新样本做预测训练结束后面对一段实时采集的新数据需要加载模型权重做批量推理。这一段看似简单但有两处必须注意归一化参数要跟训练时保持一致窗口切分方式也不能变化。下面的代码是标准的推理流程import numpy as np def predict_fault( model, new_signal: np.ndarray, scaler, window_size: int 1024, stride: int 256, device: str cpu ) - np.ndarray: 对一段连续信号做滑窗预测返回每个窗口的故障类别。 Args: model: 已训练好的模型 new_signal: 新采集的一维信号 scaler: 训练时拟合好的 StandardScaler window_size: 窗口大小必须与训练时一致 stride: 滑动步长 device: 推理设备cpu 或 cuda Returns: preds: 每个窗口的预测类别索引 model.eval() model.to(device) windows sliding_window_sampling( new_signal, window_sizewindow_size, stridestride, n_samples(len(new_signal) - window_size) // stride 1 ) windows scaler.transform(windows.reshape(-1, window_size)) windows windows.reshape(-1, 1, window_size) x torch.FloatTensor(windows).to(device) with torch.no_grad(): logits model(x) preds logits.argmax(dim1).cpu().numpy() return preds推理脚本有三个参数要格外留意。window_size和stride必须跟训练时的取值完全一致否则模型看到的输入分布变了预测结果没有参考意义——这类问题在更换数据源或者换人维护代码后特别常见scaler必须是训练时拟合过的那一个不能在新数据上重新 fit否则输入分布发生整体偏移device的切换要发生在模型和数据上保持统一最隐蔽的错误就是模型在 cuda 上但数据还在 cpu通常会报错但更坑的是 pin_memory 和 to(device) 不一致导致的静默错误那种时候预测结果乱七八糟但程序不崩溃。with torch.no_grad()能显著加快推理速度并减少显存占用因为推理阶段不需要保存中间梯度信息。4.4 批量预测结果的可视化与初步判断推理脚本是一段连续预测输出的是每个窗口的类别序列。直接看这一串数字很难直观判断模型效果一般我会把原始信号和预测类别画在同一张图上这样能一眼看出哪些时间段被判成了故障类别、故障段和正常段是否连续、有没有孤立的误报点。用 matplotlib 画图时把时间轴统一换算成实际秒数方便对照设备的运行日志判断误报是否对应到某些特定工况——这个对照是判断模型可靠性的第一步。5. 故障检测项目里最容易翻车的 5 个坑以及对应排查方法故障检测项目的代码结构不复杂真正让人反复折腾的是那些隐藏得很深的工程细节。这一章列出的五个问题是我在多个项目里遇到过的真实采坑记录。5.1 验证集指标虚高随机切分是最隐蔽的作弊现象模型在验证集上准确率 99%一到现场或者拿到新设备数据上准确率直接掉到 60% 多完全不可用。 原因切分样本时用了随机划分而滑动窗口切出的相邻样本之间高度相似——它们本来就是从同一段信号里切出来的有大量重叠。模型相当于「见过」验证集里的大部分内容验证指标自然虚高。这不是模型的问题是数据切分方式泄题了。 解决先按连续信号段划分再把每个信号段内的窗口放进同一个集合。具体做法是采集多条独立信号段按信号段维度划分比如 8 条信号段里 6 条做训练、1 条做验证、1 条做测试然后再在各自集合里做窗口切分。训练、验证、测试三条数据流真正实现了互不重叠的独立同分布评估。5.2 故障类别极不平衡把少数类故障全部判成正常现象训练过程中 loss 一直下降但查看每个类别的分类报告后发现故障类别样本几乎全被模型判成了正常。总准确率看着有 85% 上下但正常类占 90% 以上这个数字没参考价值。 原因设备数据天然不平衡正常样本远多于故障样本。模型发现把所有样本判成正常类就能获得很低的 loss于是偷懒走捷径故障类的梯度信号被淹没。 解决最有效的手段是加权损失函数把类别样本数量的倒数作为权重传给 CrossEntropyLoss。代码改动很小效果立竿见影# 计算每个类别的样本数反比作为权重 from sklearn.utils.class_weight import compute_class_weight class_weights compute_class_weight( class_weightbalanced, classesnp.unique(train_y), ytrain_y ) criterion nn.CrossEntropyLoss( weighttorch.FloatTensor(class_weights) )compute_class_weight计算每个类别权重的逻辑是样本总量的倒数归一化让少数类样本在 loss 中占据更大比重。这一步处理完之后再看分类报告里每个类别的 recall 是否接近才算真正解决了不平衡问题。还可以考虑 Focal Loss它对难分类样本额外加重在故障检测场景下也能用但先试加权交叉熵改动量最小。5.3 模型训练不收敛loss 不降准确率在随机水平徘徊现象训练了二三十个 epochloss 几乎不动准确率在某个水平比如四分类就是 25% 左右附近震荡模型完全没学到东西。 原因输入数据尺度差异过大是最常见的原因原始信号数值范围在正负几千之间网络权重初始化在零点几的量级梯度一传播直接爆炸或消失其次是学习率设置不合理太大导致 loss 震荡甚至发散太小导致收敛缓慢到看起来不收敛。 解决检查标准化——回到第 3.2 节确认信号是否经过了 z-score 标准化平均数是不是接近 0、标准差是不是接近 1然后换一个更小的学习率重试从1e-4开始同时把 BatchNorm 放到卷积层后面。另外把输入信号画出来看一眼数值范围排除传感器数据本身问题——遇到过现场数据因为接线接触不良导致信号截断训练自然不收敛。5.4 训练集上效果很好测试集上一塌糊涂过拟合的边界在哪里现象训练集准确率接近 100%验证集上也能维持 90% 以上但换一批新工况的数据就崩了准确率掉到 50% 以下。 原因传统意义的过拟合是模型记住了训练样本但故障检测里更常见的是「工况过拟合」——模型学到的是这台设备、这个转速、这个负载下的响应模式而不是真正的故障物理特征。换台设备或者变个转速数据分布整体偏移模型直接失效。这就是领域适应domain shift的问题在故障检测里比单纯的过拟合更致命。 解决一是数据层面做数据增强对原始信号添加小幅噪声、随机幅值缩放、时间轴轻微拉伸模拟不同工况下的变化二是模型层面加大 Dropout 比例到 0.5 以上并配合权重衰减weight decay三是更彻底的做法是引入领域对抗训练但工程上先做前两步。验证过拟合是否缓解的方法很直观用完全没参与训练的另一台设备数据来测试。5.5 部署上线后推理延迟超标实时性瓶颈出在哪现象模型在训练机器上单次推理 5ms部署到工控机以后变成 80ms达不到产线的实时检测要求。 原因两个问题叠加第一个是部署机器的 CPU 指令集和训练机器不同有些算子没有走底层优化可以在部署脚本里启用 torch 的推理优化相关配置第二个更常见是数据预处理和推理串行执行每次推理前都实时加载传感器数据再做标准化IO 和算力混在一起互相阻塞。 解决把预处理放到独立线程用一个固定长度的环形缓冲区缓存最近的数据窗口推理线程每次直接取现成的窗口数据不要等 IO。另一个常用手段是减小模型输入规模把 window_size 从 4096 降到 1024推理速度通常能提升一倍左右代价是准确率可能下降几个点——这个取舍要在真实数据上测不能拍脑袋决定。还有一招是模型量化用 PyTorch 自带的量化工具把权重从 FP32 压到 INT8在支持的硬件上推理速度提升 2 到 4 倍准确率损失一般控制在 3% 以内。提示如果你的部署目标是嵌入式设备比如 ESP32 这类带 AI 加速器的 MCU1D CNN 量化后的模型通常是唯一现实的选择。LSTM 和自编码器的激活函数计算在边缘端支持度差一些部署成本明显更高。6. 模型有效性的验证方法混淆矩阵、t-SNE 可视化与跨工况泛化测试模型训练完准确率数字看起来不错但这不能证明模型真的有效。故障检测是一个对可靠性要求极高的领域——误报一次现场人员就会对系统失去信任漏报一次设备可能直接损坏。这一章给出三种验证方法由浅入深逐层确认模型的有效性边界。6.1 先读混淆矩阵故障检测里 Recall 比 Accuracy 重要故障检测场景下不同类别之间不是等价的。把故障样本判成正常代价是设备带病运行直到损坏把正常样本判成故障代价是停机检查浪费工时。错误矩阵比整体准确率更能反映问题。读混淆矩阵时重点看两个位置对角线的数值能被正确识别的比例是否均匀——如果某个故障类别明显偏低说明这类样本的特征不足或数量不够故障类被误判成正常类的比例——这个数字就是漏报率一定要控制在项目要求的范围内。6.2 特征可视化用 t-SNE 看模型学到的类别是否真的分开混淆矩阵看的是最终分类结果特征可视化看的是模型内部的表征质量。提取模型倒数第二层的输出也就是输入分类层之前的特征向量用 t-SNE 降维到二维平面画散点图不同类别如果在平面上分成了几个簇说明模型学到了有效的判别特征如果所有类别的点混在一起说明模型在瞎猜哪怕准确率还可以也可能是过拟合出来的假象。from sklearn.manifold import TSNE def visualize_features(model, data, labels, save_pathtsne.png): 提取模型倒数第二层特征t-SNE 降维后可视化。 # 截断分类层只保留特征提取部分 feature_extractor nn.Sequential(*list(model.children())[:-1]) feature_extractor.eval() with torch.no_grad(): feats feature_extractor(torch.FloatTensor(data)) feats feats.numpy().reshape(len(data), -1) tsne TSNE(n_components2, perplexity30, n_iter300, initpca) emb tsne.fit_transform(feats) import matplotlib.pyplot as plt plt.figure(figsize(8, 6)) for cls in np.unique(labels): mask labels cls plt.scatter(emb[mask, 0], emb[mask, 1], s4, labelfClass {cls}) plt.legend() plt.tight_layout() plt.savefig(save_path, dpi150)6.3 跨工况泛化测试这是最后一道关混淆矩阵和 t-SNE 都通过了接下来做最关键的一步验证跨工况测试。把模型放到不同工况不同转速、不同负载、不同设备型号的数据上测试看准确率保持情况。这一步通过模型才算真正意义上的可用。具体操作是训练集只用工况 A比如 1797 rpm0 负载的数据测试集直接用工况 B比如 1750 rpm1 马力负载的数据中间不做任何微调。如果准确率从 98% 掉到 70%说明模型学到的是转速相关的模式不是故障本身的物理特征——这种情况下回到数据增强或者引入多工况混合训练是更稳妥的处理方向。做过的故障检测项目越多越觉得「模型选型」只是整个项目里最不值得纠结的一环。真正拉开交付质量差距的是数据切分是否严谨、类别权重是否处理、验证方法是否覆盖跨工况以及遇到问题时能不能沿着「现象→原因→解决」的路径一步步定位。先拿公开数据跑通闭环再换自己的数据再逐步引入现场噪声和工况变化——这套顺序我建议你保持。希望这篇文章能帮到你少走几段我当年走过的弯路。本文还有配套的精品资源点击获取
返回列表