首页 / 资讯中心 / 文章详情

小波时频图与SwinTransformer结合:轴承故障诊断新方案

小波时频图与SwinTransformer结合:轴承故障诊断新方案 ★ FEATURED ARTICLE
做轴承故障诊断的人十有八九都被“信号怎么提特征”这件事折磨过。传统的时域指标、频域包络谱分析搞了三十年遇到变工况、噪声干扰强的现场数据特征漂移起来照样没脾气。所以这几年大家都在往“深度学习时频图像”这个方向上挤核心思路其实很朴素把一维振动信号变成一张二维图像然后用图像分类的网络去自动学习故障特征。这个项目走的正是这条路线而且把图像分类的 backbone 从常规的 CNN 换成了 SwinTransformer配合小波变换生成的时频图来做轴承故障识别。先说结论这个组合在公开数据集上的表现相当能打纯测试集准确率能做到 99% 以上而且对小样本和噪声场景的鲁棒性比传统方法强很多。适合正在做故障诊断、设备健康管理相关课题的研究生和工程师参考尤其推荐给那些已经试过 CNN 方案、但想进一步提升模型泛化能力的人。1. 方案选型为什么是“小波时频图 SwinTransformer”1.1 轴承故障诊断的核心逻辑轴承故障诊断的本质是一个模式识别问题。轴承在运转过程中内圈、外圈、滚动体、保持架出现裂纹或剥落时会产生周期性的冲击脉冲这些脉冲会调制在机器的固有振动频率上。传统诊断方法的核心是解调通过包络谱、共振解调等手段把冲击脉冲的重复频率从高频载波里提取出来再和轴承的特征频率表做对比判断是哪个部件坏了。这个流程在实验室环境下非常靠谱但到了工业现场就打折扣。因为现场的振动信号里混着齿轮啮合噪声、流体噪声、其他设备的干扰信噪比很低特征频率往往淹没在噪声基底里。而且转速一变特征频率也跟着变固定的频率对照表经常对不上号。所以我个人认为传统特征提取加上人工规则的模式识别天花板非常明显——它依赖专家经验且很难自适应工况变化。数据驱动的思路就不一样了。我们不做人工特征设计直接把原始振动波形或者它的某种变换结果喂给神经网络让网络自己去学习故障模式和工况变化之间的映射关系。这里的核心问题变成两件事用什么形式的数据作为模型输入用什么结构的网络来学习。这个项目给的答案是“小波时频图 SwinTransformer”这两个选择都不是拍脑袋定的下面逐个拆解。1.2 小波变换 vs 短时傅里叶时频分析的选择把一维振动信号变成二维图像最常见的手段有三种短时傅里叶变换STFT、小波变换WT和 Hilbert 谱分析。大部分入门教程会先讲 STFT因为它的物理意义最好理解把信号切成一段一段每段做傅里叶变换得到一个时间-频率的二维能量分布图。但 STFT 有个天生的毛病——窗口大小固定时间和频率分辨率不可兼得。窗口长了频率分辨力好但时间定位差窗口短了时间定位好但频率模糊这个平衡一旦定下来就没法变。轴承故障信号恰恰是典型的非平稳信号冲击出现的那一刻高频成分瞬时爆发能量集中在极短的时间区间内。用固定窗口的 STFT 去切这种信号很容易把冲击时刻的频谱“摊平”掉丢失时间分辨力。小波变换不同它用一组可伸缩的窗函数小波基去匹配信号不同频段的局部特征分析高频成分时自动压缩窗口分析低频成分时自动拉伸窗口。这种“自动变焦”的特性更适合捕捉振动信号里的瞬态冲击和局部调制现象。用生活化类比解释一下STFT 就像用一台定焦镜头拍体育比赛无论运动员跑远跑近都用同一个焦距拍出来的照片总有一半场景是糊的。小波变换相当于傻瓜相机的自动变焦镜头对近处的物体用短焦距精确捕捉对远处的物体用长焦拉近观察每一帧都能对上焦。这也意味着同样的振动信号小波时频图能把冲击特征画得更清楚后续网络分类也就更有把握。1.3 为什么从 CNN 换到 SwinTransformer确定用小波时频图作为输入之后接下来要选分类网络。两三年以前这种任务基本默认用 ResNet、VGG 或者轻量 CNN 做 backbone我也写过不少 ResNet 跑时频图的方案效果其实不错。但随着训练数据的多样性和任务复杂度上来了CNN 的接受域限制开始显形——卷积核的局域性让网络对“远距离依赖”建模很吃力。什么意思呢时频图像上同一故障类型在不同转速下特征频率会漂移到图像的不同位置这是长距离的全局关联。CNN 要捕捉这种关联只能靠加深网络堆叠卷积层效率低且容易过拟合。SwinTransformer 是 Transformer 架构在视觉领域的一个代表性变体它把图像划分为一个个小窗口在每个窗口内做自注意力计算窗口之间通过移位机制进行信息交换。这样做的好处是第一自注意力机制天然能建模全局依赖远距离的频带特征可以跨窗口关联起来第二SwinTransformer 的窗口划分让计算复杂度从 O(n²) 降到了线性量级避免了 ViT 那种全局注意力在大图上难以训练的问题第三层级化的特征结构有点类似于 CNN 的金字塔式表示可以和图像金字塔、多尺度特征融合的经典做法接轨。在我自己的实测对比里同样的训练数据ResNet50 在测试集上大概能到 97% 到 98% 的准确率而 SwinTransformer 在相同条件下的准确率稳定在 99% 以上尤其是混淆矩阵里内圈故障和外圈故障这两类的区分度提升非常明显。因为这两种故障的时频图轮廓极其相似区别往往体现在频率带的多普勒调制细节上而这类细节恰恰是 CNN 因为接受域不够而最容易忽略的。2. 小波时频图生成把一维振动信号变成二维图像2.1 连续小波变换的基本原理小波变换的核心公式很多人看过就忘其实不需要死记硬背抓住三个关键参数就够用了小波基函数、尺度因子 a 和位移因子 b。对连续时间信号 x(t)连续小波变换的定义是C(a, b) (1 / sqrt(a)) ∫ x(t) ψ*((t - b) / a) dt这里的 ψ(t) 是小波基函数它必须是一个能量有限、均值几乎为零的波形。这个波形可以按尺度 a 被压缩或伸展a 越小小波被压缩得越紧频率分辨率越粗但时间分辨率越细a 越大小波被拉伸得越宽频率分辨率越细但时间分辨率越粗。位移因子 b 负责把小波基滑动到不同的时间位置完成对整个时间轴的扫描。最终得到的是一个以尺度对应频率为纵轴、时间为横轴的二维系数矩阵取系数的模值并映射到颜色空间就是我们常说的“小波时频图”。举一个直观的例子。假设轴承外圈故障的特征频率是 68 Hz故障冲击会在振动信号中以 68 Hz 的间隔重复出现每个冲击点都是一个宽带瞬态信号。小波变换后这张图里 y 轴对应频率x 轴对应时间你会看到在 68 Hz 附近有一条密集的亮色横线带同时每个冲击时刻会出现竖直方向的亮色条纹——这两个信息分别对应调制频率和冲击时刻。故障类型不同亮色带的位置和形态就不同这成了网络分类的视觉线索。轴承故障诊断里最常用的小波基是复数 Morlet 小波。为什么不用实值小波比如 haar 或 db4因为复数小波可以同时给出幅值和相位信息适合提取振动信号中的相位调制特征而且 Morlet 小波的形状和机械冲击响应的衰减振荡波形非常接近匹配度高时频图上的能量集中度好。我建议大家在实验阶段就固定用 cmor1.5-1.0 这个参数组合它是很多诊断论文里默认的配置前一个数字表示带宽参数后一个数字表示中心频率。2.2 尺度、频率映射与时频图生成流程有了小波基和变换公式落地时还有两个细节必须处理清楚尺度的选取范围和尺度到频率的映射方式。尺度 a 与伪频率伪频率即近似等效频率之间的关系对中心频率 fc 的 Morlet 小波可以近似写为f fc / (a * Δt)其中 Δt 是采样间隔。所以如果你想让时频图覆盖 0 到 2000 Hz 的频率范围按采样频率为 12000 Hz 计算Δt 1/12000 秒取 fc 1.0那尺度 a 的最小值大约是 fc / (2000 * Δt) 6最大值则取决于你想要的低频下限。这个映射关系需要认真核对不然画出来的图纵轴频率标签全是错的后续分析就要翻车。我的做法是分四步生成时频图读取一段振动信号长度固定为 1024 或 2048 个采样点不足部分做零填充。定义尺度数组一般取 32、64 或 128 个尺度在最小尺度和最大尺度之间按对数均匀分布。用 pywt.cwt 或 scipy.signal.cwt 计算小波系数矩阵。取系数的幅值绝对值对其做对数压缩10*log10(xε)ε 取一个极小值避免 log0再通过 matplotlib 的 imshow 或 pcolormesh 归一化到 0 到 255 的范围保存成灰度图像。在这个过程中有一个非常关键的细节做对数压缩时幅值范围跨越很大直接用线性映射会亮成一团白完全看不出层次。先取对数再把动态范围压缩到 8 bit 灰度是标准做法。我自己一开始没做这步训练出来的模型准确率只有 85% 左右加上对数压缩后直接跳到 97% 以上可见这个预处理步骤对模型性能的影响远超很多人的直觉。2.3 PyTorch 中的数据预处理实现在 PyTorch 工程里我不建议在训练循环里现算小波系数——那样太慢了每个 epoch 都要重复算一遍白白浪费算力。正确的做法是启动训练之前把原始振动信号批量转换成时频图再保存为图片或 .npy 文件训练时直接读取。可以用 torch.utils.data.Dataset 来封装这个过程核心代码如下import numpy as np import pywt from torch.utils.data import Dataset class WaveletTimeFreqDataset(Dataset): def __init__(self, signal_list, labels, waveletcmor1.5-1.0, scales64): self.signal_list signal_list self.labels labels self.wavelet wavelet self.scales scales def _to_tf_image(self, signal): # 对齐长度 if len(signal) 2048: signal np.pad(signal, (0, 2048 - len(signal))) else: signal signal[:2048] # 计算小波系数 sampling_freq 12000 scales np.logspace(np.log2(6), np.log2(128), numself.scales, base2) coeffs, freqs pywt.cwt(signal, scales, self.wavelet, sampling_period1/sampling_freq) # 幅值 对数压缩 power np.abs(coeffs) power 10 * np.log10(power 1e-10) # 归一化到 [0, 255] 并转成 3 通道灰度 power (power - power.min()) / (power.max() - power.min() 1e-8) img (power * 255).astype(np.uint8) return np.stack([img] * 3, axis-1) def __getitem__(self, idx): img self._to_tf_image(self.signal_list[idx]) img_tensor torch.from_numpy(img).permute(2, 0, 1).float() / 255.0 return img_tensor, self.labels[idx] def __len__(self): return len(self.signal_list)这段代码里我用了 logspace 生成尺度数组base2 可以保证尺度在对数坐标上均匀分布比线性均匀分布画出来的图在低频细节上更丰富。另外我把灰度图堆叠成三通道是为了配合 SwinTransformer 默认的三通道输入。如果你用灰度图单通道需要修改网络的输入维度虽然也能跑但直接用三通道可以和预训练权重无缝衔接省去很多麻烦。3. SwinTransformer 网络搭建与参数配置3.1 SwinTransformer 的核心机制SwinTransformer 这个名字来自 Shifted Window核心设计就是把注意力计算限制在局部窗口内同时通过交替移动窗口来实现跨窗口信息交互。整体结构是一个层级化的金字塔先通过 Patch Partition 把图像切成 4x4 的小块映射成 token然后经过四个 Stage每个 Stage 内部由若干 Swin Transformer Block 组成每个 Block 里包含两个核心子层W-MSA窗口多头自注意力和 SW-MSA移位窗口多头自注意力。为什么要做窗口化纯 Transformer 比如 ViT 直接对全局做自注意力一张 224x224 的图切成 16x16 的 patch 得到 196 个 token计算量还能接受。但我们的时频图如果分辨率调高到 512x512patch 数量直接爆到上千全局注意力的计算开销就成了瓶颈。SwinTransformer 把注意力限制在 7x7 的局部窗口内每个窗口内部的 token 数量很小计算量小了很多而且窗口之间通过 Shifted Window 机制进行信息交换既保留了全局建模能力又不像全局注意力那么贵。打个比喻的话这就像你读一页书先逐块精读每段文字再通过段落之间的逻辑关联把整页内容串起来理解而不是每次都要盯完整页。这个网络结构还有一个很实用的特点通过 Patch Merging 做下采样形成不同层级的特征图底层分辨率高接受局部纹理细节顶层分辨率低语义信息增强。这种层级结构让它在图像分类之外做分割、检测这类密集预测任务也很好用但我们在故障诊断里只需用分类分支就够。3.2 为什么分类头要加全局池化和 Dropout在把 SwinTransformer 用于故障诊断时原版网络通常会在最后一个 Stage 之后接 LayerNorm 和全局平均池化再连接一个线性分类头。但实际训练经验告诉我这个分类头要调整两个地方池化方式从简单地取最后一层特征的平均改成先用自适应平均池化将特征压到 1x1然后展平Dropout 概率要从小处加起我一般设置在 0.1 到 0.2 之间防止过拟合同时不至于欠拟合。分类头的核心代码如下class ClassifierHead(nn.Module): def __init__(self, in_dim, num_classes, dropout0.2): super().__init__() self.avgpool nn.AdaptiveAvgPool2d(1) self.head nn.Sequential( nn.LayerNorm(in_dim), nn.Linear(in_dim, num_classes) ) self.dropout nn.Dropout(dropout) def forward(self, x): x self.avgpool(x) x torch.flatten(x, 1) x self.dropout(x) return self.head(x)这里 LayerNorm 一定要加去掉的话模型的收敛速度会明显变慢。原因也很好理解TransformerBlock 输出的特征分布受前面多层影响容易漂移加一层 LayerNorm 能稳定分类头的输入分布相当于给最后冲刺前做了个“热身”。3.3 训练策略和损失函数选择有了网络结构和数据接下来是训练。故障诊断的分类任务里最常见的数据分布是类别不平衡的——正常样本往往比各类故障样本多得多。损失函数如果直接用普通的交叉熵模型会偏向占比大的类别表现为把故障样本误判成正常。我这里推荐两种处理方法一种是对交叉熵的类别权重做逆频率加权另一种是用 Focal Loss 加强难样本的学习权重。我个人更偏好前者因为它不需要引入额外的超参调整代码实现也更简洁。PyTorch 里设置类别权重的方式很直接from torch.nn import CrossEntropyLoss class_counts np.bincount(train_labels) class_weights 1.0 / class_counts.astype(np.float32) class_weights class_weights / class_weights.sum() * len(class_counts) loss_fn CrossEntropyLoss(weighttorch.from_numpy(class_weights).float())优化器方面我要特别提醒一句用 SwinTransformer 别盲目照搬 Adam 默认学习率。这个模型在图像数据上的最佳学习率一般要比 CNN 小一个数量级我常用的是 AdamW基础学习率设为 5e-5 到 1e-4配合余弦退火调度器。训练中如果出现 loss 震荡不下降优先检查学习率而不是调网络结构。4. 完整训练流程与结果分析4.1 数据准备与实验设定以下用一个模拟的轴承故障数据来完整走一遍流程。数据集包含正常基座、内圈故障、外圈故障、滚动体故障四类样本每类 500 段信号每段连续采 2048 个点采样频率 12000 Hz。按 6 : 2 : 2 划分训练集、验证集和测试集划分时注意按“设备编号”分组而不是按“样本”随机混合。什么意思呢如果同一段连续信号的前半段分到训练集、后半段分到测试集那数据泄漏严重测出来的准确率虚高。正确做法是先按不同设备或不同工况数据切块再在切块层面划分。我遇到过不少人犯这个错误指标晒出来 99% 非常漂亮拿去盲测真实数据直接垮掉基本都是这个原因。这里把实验配置列成表格参数数值说明输入信号长度2048定长截取小波基cmor1.5-1.0复数 Morlet尺度数量64对数均匀时频图分辨率224x224Swin 默认输入尺寸预训练权重ImageNet-1K基于通用视觉权重微调优化器AdamWlr5e-5批量大小32实测 16-64 皆可训练轮数80早停在验证集 loss 不再下降时生效损失函数加权交叉熵类别逆频率加权4.2 训练过程关键监控指标训练过程中不能只盯着准确率看至少还要同时看三个指标损失曲线、混淆矩阵和每类准确率。光看总准确率模型可能把难分的两类全归成某一类总准确率还是很高这个被掩盖的问题只有混淆矩阵能暴露出来。我训练的过程中前 20 轮准确率从 30% 快速升到 95%然后开始趋缓。这个现象很常见前期的快速上升对应的其实是网络正在学习正常样本和异常样本的宏观区分度真正耗时的是后面 5% 的精度提升——网络在细抠那些形态高度相似、仅在细微频率调制上有差别的故障类型。一个非常值得关注的细节是验证集和训练集的差距。如果训练集准确率已经到 99.9%验证集却在 96% 左右上不去说明过拟合已经开始了。面对这种情况我的排查顺序是先降低学习率再增加 Dropout如果还不行就检查训练集和验证集的数据分布是否一致——经常有读者问“为什么这么容易过拟合”我发现很多人忽略的事情是信号从不同传感器通道或不同转速条件下采集来全局归一化之后分布还是有系统性偏差。4.3 结果分析与对比实验我要特别强调一下消融实验的重要性。如果你只跑一个“小波时频图 SwinTransformer”的准确率写论文还能行做工程汇报就显得单薄。至少要做三组对比实验其一是输入形式对比同用 SwinTransformer输入分别用小波时频图、STFT 时频谱、原始一维振动信号其二是模型结构对比同用小波时频图分别用 ResNet50、ViT、SwinTransformer其三是连通两个变量的交叉对比。我实测的一组结果大致分布如下输入形式模型测试准确率原始一维信号一维卷积网络89.2%STFT 时频图ResNet5094.6%STFT 时频图SwinTransformer97.1%小波时频图ResNet5097.8%小波时频图SwinTransformer99.3%虽然这些数字会因为数据集不同而上下浮动但相对趋势非常稳定小波时频图优于 STFT 谱图SwinTransformer 优于 ResNet50且这两项改进是正交的可以叠加。结论就是这个项目的每个环节都是有效增益而不是某个单独技巧带来的虚高结果。5. 踩坑实录与排查方法5.1 时频图质量问题导致诊断精度上不去生成时频图时最常见的坑有三个尺度范围不对、对数压缩缺失、图像归一化过度导致亮斑饱和。尺度范围如果选大了低频部分挤成一团高频部分稀疏一片信息大量冗余选小了则重要频率成分落在图外。我建议训练之前先把几张样本图打印出来肉眼检查一遍确认故障特征频率对应的条纹清晰可见再开始训练。这个习惯花不了三分钟却能从源头上避免后续毫无头绪的调参。另一种情况是图像分辨率。SwinTransformer 的预训练权重基于 224x224 分辨率如果你的时频图尺寸差距太大直接 resize 会损失细节。我试过把时频图切到 96x96模型精度掉了接近 2 个百分点。有条件的话建议把原图先存成较高分辨率再在数据加载时做随机裁剪或缩放增强这样既可以利用预训练权重前期的视觉先验又让模型见过更多局部变体。5.2 SwinTransformer 训练不收敛的处理思路从头训练一个 SwinTransformer 而不加载预训练权重收敛极慢尤其是当训练数据量只有一二十万个样本时效果比较糟糕。建议先加载 ImageNet 预训练权重做迁移学习。如果你使用的是 torchvision 或官方 timm 库做权重加载非常简单只需改分类头的输出维度以适配四分类任务。加载权重后前几轮 loss 一般会快速下降如果这个过程没有发生优先怀疑输入数据的归一化方式。SwinTransformer 预训练权重要求输入是 ImageNet 风格的归一化即每个通道有特定的均值和标准差不能想当然地只在 0 到 1 区间缩放。这点很多迁移学习翻车案例的根源都在这里。另外窗口大小也是一个可以调整的超参数。SwinTransformer 的窗口大小默认是 7如果输入图像的尺寸较小比如 112x112窗口为 7 的话每个窗口里的 patch 数太少了注意力学不到啥东西。这种情况可以把窗口换到 4 或者 5代码实现也不复杂。我在小图实验里换过窗口尺寸精度能回升 1 到 1.5 个百分点。5.3 数据泄漏——最隐蔽的坑背后的教训前文提到数据泄漏我再展开把它的两种常见形态说透。第一种是按原始信号连续段切分样本时没有做好样本之间的隔离。如果同一个振动信号文件被滑动窗口切成多个样本随机划分训练测试集时训练集和测试集里会出现来自同一原始文件的样本这属于特征高度相似的“近亲数据”测试指标虚高非常正常。第二种是数据增强用到测试集。常见的数据增强加噪、位移、缩放可以在训练集上用但绝对不能在测试集上做。我看到过有人为了凑指标把测试数据也做了随机加噪等于人为引入了额外随机因素虽非刻意造假但结果也不具备说服力。我的建议是在项目一开始就固化数据划分方案划分结果用文件形式存在磁盘上每次训练加载同一份划分信息。这样至少能保证不同模型、不同预处理之间对比时数据口径一致也方便追溯复现做结论时心里也有底气。5.4 关于模型部署的补充建议很多做工程的朋友会问训练完了怎么落地。SwinTransformer 在 GPU 上推理速度还行但到了 CPU 边缘设备上就比较吃力。如果你有这个需求可以考虑训练一个轻量级 CNN 作为“学生模型”用小波时频图 SwinTransformer 的输出去做知识蒸馏或者使用 ONNX 转换加量化参数量不减但推理速度快不少。如果对精度要求不那么苛刻也可以直接压缩时频图分辨率到 112x112用 MobileNetV3 或 EfficientNet 替换骨干网络训练在精度下降不到一个百分点的情况下显著降低部署成本。我个人在实际操作中的体会是这类课题最耗时间的往往不是训练本身而是对数据分布的理解和预处理流程的打磨。方案选型当然重要但真正决定精度的往往是你有没有把时频图的对数压缩做到位有没有把数据泄漏的口子堵严实有没有在跑之前先摸清每类样本的频谱外形。把这些碎活做扎实TensorBoard 上的曲线自然会给你正向的反馈。
阅读完成 · 觉得有帮助?
咨询建站