☰
小波时频图与SwinTransformer结合:轴承故障诊断新方案
2026/10/19 3:23:57 网站建设 项目流程

做轴承故障诊断的人,十有八九都被“信号怎么提特征”这件事折磨过。传统的时域指标、频域包络谱分析搞了三十年,遇到变工况、噪声干扰强的现场数据,特征漂移起来照样没脾气。所以这几年大家都在往“深度学习+时频图像”这个方向上挤,核心思路其实很朴素:把一维振动信号变成一张二维图像,然后用图像分类的网络去自动学习故障特征。这个项目走的正是这条路线,而且把图像分类的 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,最大值则取决于你想要的低频下限。这个映射关系需要认真核对,不然画出来的图纵轴频率标签全是错的,后续分析就要翻车。

我的做法是分四步生成时频图:

  1. 读取一段振动信号,长度固定为 1024 或 2048 个采样点,不足部分做零填充。
  2. 定义尺度数组:一般取 32、64 或 128 个尺度,在最小尺度和最大尺度之间按对数均匀分布。
  3. 用 pywt.cwt 或 scipy.signal.cwt 计算小波系数矩阵。
  4. 取系数的幅值绝对值,对其做对数压缩(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, wavelet='cmor1.5-1.0', scales=64): 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), num=self.scales, base=2) coeffs, freqs = pywt.cwt(signal, scales, self.wavelet, sampling_period=1/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 生成尺度数组,base=2 可以保证尺度在对数坐标上均匀分布,比线性均匀分布画出来的图在低频细节上更丰富。另外我把灰度图堆叠成三通道,是为了配合 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,计算量还能接受。但我们的时频图如果分辨率调高到 512x512,patch 数量直接爆到上千,全局注意力的计算开销就成了瓶颈。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, dropout=0.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(weight=torch.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基于通用视觉权重微调
优化器AdamWlr=5e-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 上的曲线自然会给你正向的反馈。

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

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

立即咨询