☰
小波时频图+SwinTransformer:轴承故障诊断新实践
2026/10/20 4:21:12 网站建设 项目流程

做工业设备健康管理的朋友应该都有同感:轴承一坏,整条产线停摆,维护成本全堆上去,而且故障早期往往听不见、摸不着。最近我完整做了一个基于小波时频图与SwinTransformer的轴承故障诊断项目,流程是从振动信号出发,先把一维时序数据转换成二维时频图,再交给Transformer模型做分类识别。整套方案实测下来,比单纯用CNN做特征提取、或者拿原始波形直接喂循环神经网络都要稳,尤其是在强噪声、变工况场景下,泛化能力明显更好。这篇把技术选型、数据准备工作、模型搭建、训练逻辑和踩坑记录全部整理出来,适合刚接触故障诊断的算法工程师,也适合想从CNN切换到Transformer做图像分类的同行参考。

方案的核心思路其实不复杂:故障轴承在转动时会产生特定频率的冲击成分,这些成分在原始时域波形里经常被淹没,但通过时频分析可以清楚看到“什么时候出现了什么频率”,再让SwinTransformer学习时频图里的局部纹理和结构差异。整套技术栈都是Python生态里的常见库,PyTorch负责全流程,门槛比想象中低很多。

1. 为什么把振动信号变成时频图,又为什么选SwinTransformer

1.1 一维信号直接分类,问题出在哪

很多人拿到轴承振动数据,第一反应就是把一段波形直接丢给卷积网络或LSTM。我最初也这么试过,但很快就发现了瓶颈所在。轴承振动信号具有非常明显的非平稳特征,转频、故障特征频率、谐波成分和噪声混叠在一起,同一个故障在不同转速、不同负载下表现差异很大。时域波形只能告诉我们“振动有多剧烈”,频域谱只能告诉我们“有哪些频率成分”,但两者都丢失了另一维度的信息。

直接把一维波形丢给深度学习模型,实际上是在逼网络自己学“从被噪声污染的原始信号里提炼诊断特征”这件事。CNN在时序信号上做卷积,本质是学习局部波形模式,但轴承故障信号的关键信息往往分布在多个尺度上,比如外圈故障的特征频率可能只有几百赫兹,而冲击引起的共振频带则高达数千赫兹到上万赫兹。跨尺度的特征依赖很长,普通CNN很难建模这种关系。LSTM倒是能建模长时序依赖,但训练慢、收敛难,而且同样面临信号非平稳带来的分布漂移问题。

所以我把问题转换了一下:与其让模型从原始波形里硬憋特征,不如先用信号处理方法把信息整理成更适合图像模型识别的方式。时频图就是最合适的选择之一。它把频率随时间变化的情况完整保留下来,人眼可以直观看到故障冲击的周期性条纹,模型端也更容易学到稳定模式。

1.2 CWT与STFT:时频图到底选哪个

生成时频图有两种主流方案,短时傅里叶变换(STFT)和连续小波变换(CWT)。STFT的问题在于窗口大小一旦确定,时间分辨率和频率分辨率就互相牵制。窗口短,时间定位准但频率模糊;窗口长,频率清晰但时间精度下降。轴承故障信号里有瞬态冲击成分,用STFT处理这类非平稳信号,分辨率很尴尬,调参要反复试。

连续小波变换则没有这个烦恼。它通过尺度可变的母小波去匹配信号,在低频处用长窗口获得高频率分辨率,在高频处用短窗口保留高时间分辨率,更符合轴承冲击响应信号的特点。还有一个很实用的点,CWT对噪声的鲁棒性比STFT更好,尤其配合复数Morlet小波使用时,能保留相位信息,对微弱故障冲击的提取能力更强。

实际项目中我选了复数Morlet小波族,具体是cmor3-3。这里的“3-3”代表带宽参数和中心频率参数。较小的带宽让小波在频域上更聚焦,适合提取相对窄带的冲击响应。当然这里没有绝对最优的参数组合,不同采样率、不同轴承转速下需要相应调整,但在公开轴承数据集上,cmor3-3的效果已经足够稳。尺度序列可以统一映射到目标频段,再按实际需要裁剪。

1.3 SwinTransformer的核心优势

图像分类任务里SwinTransformer能在短短几年内跟CNN平分秋色,关键在两点:局部窗口自注意力和层级式结构。标准ViT对整张图做全局注意力,计算复杂度随分辨率平方增长,时频图虽然不算特别大,但工业界部署时往往要跑多通道多传感器数据,全局注意力并不划算。

SwinTransformer把图片划分成不重叠的小窗口,在每个窗口内部做自注意力。这个设计的直接好处是计算复杂度从平方级降到了线性级,高分辨率时频图也能轻松处理。更巧妙的是它在相邻层间引入了移位窗口机制,让窗口边界在两层之间“错位”,信息可以在窗口之间流动。这种设计既保留了Transformer建模长程依赖的能力,又强制模型关注局部相邻结构,恰好像极了CNN卷积核的局部归纳偏置,但表达能力更强。

另外,SwinTransformer从高分辨率小patch起步,通过patch merging逐层下采样,构建出类似CNN金字塔的多尺度特征。这个结构对时频图很友好,因为轴承故障信息既有局部的冲击纹理,也有大范围的周期性分布,多尺度特征可以让分类头同时取到这两类线索。在同样的数据量下,Swin-Tiny的精度通常能超过ResNet50,而且不易过拟合。

2. 数据准备:从原始振动波形到可训练的时频图数据集

2.1 故障类型与公开数据集解读

做轴承故障诊断绕不开公开数据集这个起点。目前学术圈和工业界用得最多的某高校公开数据集,包含正常状态和几种常见单点故障:内圈故障、外圈故障、滚动体故障。每种故障按损伤直径分几个等级,按负载不同还有多组工况。因为常用,相关论文多,对比结果方便,非常适合用来验证方法有效性。

拿到原始数据后先别急着切窗。第一步是理解数据的基本参数:采样频率、转速、故障特征频率。这些参数直接决定小波尺度范围和后续时频图的有效信息区间。例如采样频率如果是12kHz,奈奎斯特频率就是6kHz,那我们关心的共振频带和小波分析频段都要落在0到6kHz之间。如果采样频率更高,分析频段可以更宽,时频图上的分辨率分配策略也要跟着变。

需要特别注意的是,轴承故障特征频率不是随便拍的。外圈故障特征频率BPFO、内圈故障特征频率BPFI、滚动体故障特征频率BSF,都可以根据轴承几何参数和转频算出来。这些频率值前期算准了,后面看时频图“该在哪个位置出现条纹”就有谱了,否则时频图生成完看板起来像噪声,根本没法判断预处理流程是否可靠。比如某个工况下外圈特征频率约是转频的4.2倍,那在时频图上应该在对应频率附近找到清晰的横向条纹。如果找不到,十有八九是小波参数没调对,或者切窗长度太短。

2.2 小波参数的选型逻辑

小波分析里最让人头疼的就是参数选择。我用下来最核心的是三件事:小波基函数、尺度范围、和时频图归一化方式。

小波基函数直接决定时频图的“长相”。工具箱常用的小波基有morl、cmor、db系列、sym系列等。轴承振动信号中心思想是冲击成分,Morlet小波跟冲击响应形态最匹配,所以优先用cmor。带宽参数不能太大,太大频域分辨率就差了,太小时间分辨率不够,容易丢失冲击的起止时刻。实测3-3是一个稳定的起点,具体可以在样本可视化阶段多试几组,找一个冲击条纹最清晰的配置。

尺度范围需要和实际频段对应起来。pywt.cwt返回的freqs不是简单线性关系,我一般直接用采样周期参数,让函数把尺度换算成物理频率(Hz),然后只保留我们关心的频段。在12kHz采样率下,我常用目标是让分析频带覆盖100Hz到6000Hz左右。低频段保留转频和故障特征频率,高频段保留轴承结构共振信息。把整个频段都塞进一张图当然也可以,但会稀释细节,不利于模型区分相近故障类别。

归一化也是常被忽略的环节。小波系数的模值动态范围非常大,直接映射到0-255灰度时会全部堆在暗部。我的做法是先用对数或者分位数缩放压缩动态范围,再做最小最大归一化,必要时用直方图均衡化提高对比度。保存时统一使用RGB三通道图像,后续可以直接复用ImageNet预训练模型的权重。

2.3 用Python生成时频图的具体实现

这里给出一个可直接改用的数据预处理实现,依赖pywt和PIL,完整流程会保存成图像文件,方便后面走标准图像数据管线。代码里已经做了注释,参数按常见配置给了一组默认值。

import numpy as np import pywt from PIL import Image def generate_cwt_image(signal, sr=12000, width=224, height=224, wavelet='cmor3-3', freq_min=100, freq_max=6000): # 去均值和趋势项,避免直流分量和趋势漂移影响小波系数 signal = signal - np.mean(signal) # scales按目标频率范围设置,采样周期是关键参数 scales = np.arange(1, 256) coeffs, freqs = pywt.cwt(signal, scales, wavelet, sampling_period=1.0/sr) # 截取目标频段 mask = (freqs >= freq_min) & (freqs <= freq_max) coeffs = np.abs(coeffs[mask, :]) # 对数压缩,减小极大极小值悬殊带来的对比度问题 coeffs = np.log1p(coeffs) # 分位数归一化到0-255 p_low, p_high = np.percentile(coeffs, [2, 98]) coeffs = np.clip((coeffs - p_low) / (p_high - p_low), 0, 1) img = (coeffs * 255).astype(np.uint8) # 三通道复制,兼容ImageNet预训练模型的输入格式 img = np.stack([img] * 3, axis=-1) img = Image.fromarray(img, 'RGB').resize((width, height)) return img

这段代码的核心步骤就三步:CWT变换、频段裁剪、归一化保存。每一条原始信号样本独立生成一张时频图,互不干扰,后续可以用PyTorch的ImageFolder直接管理,或者重写Dataset类做在线切窗和变换。如果样本量很大,建议提前把图像生成好存成磁盘文件,训练时走数据加载器读取,避免训练过程中反复做小波变换消耗CPU时间。

2.4 训练集/验证集划分与数据增强

数据集划分这一步看着简单,但最容易埋雷。我身边的同行普遍踩过同一个坑:直接随机划分样本到训练集和测试集,结果精度高得离谱,但模型到现场真实数据上立刻垮掉。原因在于相邻滑动窗口之间存在极高的时间相关性,本质上是一条连续信号切出来的,随机划分相当于让模型“见过”测试样本的邻居,属于数据泄漏。

正确做法是先把长度较长的原始振动信号按段切分,确保同一原始信号段的数据要么全部进训练集,要么全部进验证集或测试集。比如把每段连续振动记录切成互不重叠的大段,大段内再滑窗生成样本,划分以“段”为单位而不是以“样本”为单位。这样模拟的才是模型面对新的、从未接触过的轴承运行数据时的表现。

数据增强方面,时频图比较保守的做法是轻度随机裁剪、水平翻转和轻微的灰度抖动。但要小心:过度的仿射变换会破坏频率轴和时间轴的物理意义,翻转尤其要注意——如果把频率轴上下翻转,等于把低频变高频,这完全违反物理逻辑。所以我通常只做水平翻转(时间方向)和随机擦除,不做垂直翻转。时间方向的翻转也有讲究,如果模型要应用于在线监测场景,实时时序数据本来就是不断往后推的,时间翻转倒没有太大问题。

类别不平衡在故障诊断里很常见。有些故障类型样本占比很低,训练时会偏向多数类。解决办法一是按类别权重采样,二是用Focal Loss替换标准交叉熵损失。我在处理故障等级细分任务时明显感到不均衡影响精度,用了类别加权采样之后,少数类的recall提升比较直观。

3. SwinTransformer模型搭建与训练细节

3.1 环境配置与模型载入

环境方面Python 3.8以上都可以,PyTorch建议2.0以上,因为自带了一些训练优化和精度改进。GPU我实测下来哪怕只有6GB显存的显卡也能跑Swin-Tiny,batch size设小一点就够用了。如果你用的是显存更大的卡,可以开更大的batch做梯度累积,训练稳定性会更好。

加载SwinTransformer非常省事,成熟的开源模型库timm直接提供预训练权重。我第一次用的时候是直接调用,几行代码就把模型拉起来了:

import timm import torch.nn as nn num_classes = 4 # 正常、内圈故障、外圈故障、滚动体故障 model = timm.create_model('swin_tiny_patch4_window7_224', pretrained=True, num_classes=num_classes)

模型名称里的各个字段是有含义的:patch4表示把输入图片切成4x4的小块,window7表示每个自注意力窗口是7x7的小格,224表示期望输入分辨率。这里其实暴露了关键问题:预训练模型学的是自然图像的特征,而时频图不是自然图像,那直接用ImageNet权重到底有没有用?

我的实测结论是:即使领域差异很大,预训练权重仍然大幅加速收敛。底层的浅层卷积和patch embedding学习的是边缘、纹理、色彩梯度这类通用结构,时频图里的条纹边界和冲击纹理跟自然图像的边缘有相通之处。真正要重新学习的是高层语义组合方式,也就是“什么样的纹理组合对应故障类别”。如果从头训练,收敛慢且小样本下容易过拟合;用了预训练后,通常十几个epoch就能看到很清晰的收敛趋势。

3.2 训练超参数与优化策略

SwinTransformer虽然能力强,但对超参数比CNN更敏感。我推荐一套稳定可靠的配置:优化器用AdamW,初始学习率用2e-5到3e-5,权重衰减0.05。别看学习率小,Transformer本来就不吃大学习率,如果照搬ResNet常用的1e-3起步,第一轮loss就可能直接飞到不收敛。

batch size尺寸方面,Swin-Tiny在224x224输入下,6GB显存用batch size 16没问题,显存充足可以用32。结合梯度累积等效更大的batch,可以提升训练稳定性。数据loader里建议开4到8个子进程做预处理,GPU利用率才拉得上来。时频图生成是一次性的,训练阶段就是标准图片读入,瓶颈在I/O和GPU计算,这点和普通图像分类任务没什么区别。

训练轮次方面,30个epoch基本能收敛。学习率调度用CosineAnnealing,前面加5个epoch的warmup。warmup很重要,尤其是加载了预训练权重后,如果一开始就用大学习率,容易把预训练特征破坏掉。warmup阶段建议把学习率从零线性增到目标值,让模型平稳过渡到新域上。

损失函数先用普通交叉熵,但如果类别不平衡明显,建议直接用标签平滑系数0.1的交叉熵,或者换Focal Loss。Focal Loss在故障等级细分、少数类样本很少的场景下,效果比加权采样更平滑,不大会引入过多噪声样本的负面作用。

3.3 训练流程与评估指标设计

训练流程用标准PyTorch写法即可,但有几个细节值得注意。第一个是梯度裁剪,max_norm设为5.0,尤其是前期warmup阶段数值不稳定,梯度爆炸的概率不低。第二个,验证集上不仅看准确率,还要看每个类别的召回率和混淆矩阵。故障诊断里最怕的是把轻微故障漏报成正常,因为漏报的代价远高于误报。

我用了一份简化但完整的训练代码,方便参考整体流程:

import torch from torch.utils.data import DataLoader def train_one_epoch(model, loader, optimizer, criterion, scaler, device): model.train() total_loss = 0.0 for images, labels in loader: images, labels = images.to(device), labels.to(device) optimizer.zero_grad() with torch.cuda.amp.autocast(): outputs = model(images) loss = criterion(outputs, labels) scaler.scale(loss).backward() scaler.unscale_(optimizer) torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=5.0) scaler.step(optimizer) scaler.update() total_loss += loss.item() * images.size(0) return total_loss / len(loader.dataset) def evaluate(model, loader, device): model.eval() preds, true_labels = [], [] with torch.no_grad(): for images, labels in loader: images = images.to(device) outputs = model(images) preds.extend(outputs.argmax(dim=1).cpu().tolist()) true_labels.extend(labels.tolist()) return compute_metrics(preds, true_labels)

测试阶段我用混合精度训练,在GPU上能省不少显存和速度。评估不能只看整体准确率,要画混淆矩阵,按类别拆开看precision、recall、F1。如果内圈故障总是被误判成外圈故障,说明时频图的某种纹理模式存在共性,需要回头分析是否特征频段截取不当,或者增强策略丢掉了关键细节。

如果追求上线部署,训练结束后还要做模型轻量化验证。Swin-Tiny本身参数量不算大,导出ONNX后再用OpenVINO或者TensorRT加速,推理速度可以跑到单张图像毫秒级,完全满足在线监测要求。这块虽然不属于核心技术点,但工业项目落地时基本都会遇到。

4. 训练过程中的常见问题与排查实录

4.1 小样本过拟合:瓶颈在哪里

工业场景最常见的问题就是故障样本太少,尤其是轻微故障和早期故障,根本不可能像公开数据集一样样本充沛。训练时表现最典型的就是:训练集准确率很快冲到99%,验证集准确率却卡在一个不太高的水平,且随着epoch推进不升反降。

这个现象的本质是模型把时频图里的噪声细节当成故障特征记住了。解决办法要从数据、模型、训练策略三个方向同时下手。数据层面增加滑窗重叠率,比如把重叠率从50%提到75%甚至87.5%,同时加入随机擦除、水平翻转等增强方式。模型层面可以开SwinTransformer自带的drop path,timm里通过drop_path_rate来控制路径丢弃比例,提高随机性,降低对特定纹理的依赖。训练层面把weight decay再调大一点,并提前用早停策略在验证集准确率不再提升时停止训练。

这里我想额外强调,drop path对Transformer是“救命”级别的正则化手段。Swin-Tiny在小型数据集上,如果不加drop path,很多情况下都会过拟合得很严重。我的做法是一开始就设0.1到0.2,然后看验证集曲线选择具体值。

4.2 模型不收敛、精度不涨怎么办

如果训练了十几个epoch,准确率还在随机水平附近,先不要急着换模型。按顺序排查三个问题:学习率是不是太大或太小,warmup是否生效,数据管线是否正确。我遇到过最离谱的一次是dataloader的shuffle参数忘了开,模型每个epoch都按相同顺序看到数据,等价于不断记忆固定序列,验证集表现当然不会好。

如果这些都正常,再检查一下时频图本身的质量。把训练集里每个类别的时频图随机挑几张出来,人眼看看类别间是否有肉眼可见的差异。如果所有类别的时频图都长得很像,那就是预处理环节出了问题,比如频段截取范围太窄,把所有故障特征成分都截掉了;或者归一化方式不对,把关键对比度信息压缩没了。

还有一个很容易忽略的点:时频图的尺寸。SwinTransformer虽然可以处理任何分辨率的输入,但不同patch size下的token数量不同,影响全局建模能力。224x224是常规选择,但如果你发现时频图里故障条纹非常细,可以试试256x256或者288x288。分辨率提升意味着窗口内能看到更多细节,但也有可能把噪声细节一起放大,所以要看验证集效果决定。

4.3 混淆矩阵乱成一团:内圈、外圈分不清

内圈故障和外圈故障在特征频率上确实相近,但时频图形态差异应该能区分。如果混淆矩阵把这两类混得很厉害,最常见的元凶是数据切窗长度太短。窗太短导致频域分辨率不足,特征频率附近区分不开。可以试着把单个样本的时窗长度加长到振动物理周期的5到10倍,让每个样本包含足够多的故障冲击周期。我用12kHz采样时,单个样本时长一般取1到2秒,也就是12000到24000个采样点。

另一个原因是故障严重程度跨越太大。比如同一类型的故障,按损伤直径分成了多个级别,如果把它们统成一个类别,特征分布就非常宽,模型学不到紧凑的类别边界。建议在数据充足时把故障等级也作为类别或标签的一部分来处理,哪怕是多标签方式,信息利用效率都会高很多。

从特征图可视化的角度也可以帮忙。把SwinTransformer倒数几层的attention map或者特征降维后用t-SNE投影,能直观看到类别聚不聚得拢。如果两类在特征空间里完全重叠,说明信息本身就无法区分,这时候要在输入数据上下功夫,而不是继续调模型结构。

4.4 数据泄漏是最隐蔽的坑

前面提过同段切分的泄漏问题,但我想展开说说为什么它这么隐蔽。很多人在模型评估时只看整体准确率,却忽略了训练和测试样本之间的关联性。轴承振动信号有很强的自相关性,相邻窗口几乎可以认为是同一段数据的重复采样。随机划分会让测试集的“陌生程度”大幅降低,模型等于做开卷考试。更迷惑的是,这种情况下验证集loss依然正常下降,准确率甚至异常地高,让人误以为模型很能打。

判断是否泄漏有一个简单办法:检查训练和验证数据是否有重叠的原始信号段。如果同一段连续信号同时出现在两边,几乎可以断定存在泄漏。修复方法也很直接,按信号段分组划分数据集。划分完成后,可以刻意降低训练数据量做一次小规模验证,如果精度掉得实在太离谱,有可能是验证策略和真实场景的差距没有被正确评估。

另外,跨工况测试是另一个很容易暴露泛化能力的手段。比如在负载0的工况上训练,在负载1的工况上测试,这种做法能避免模型只记住载荷相关的振动幅值分布。加入跨工况评估之后,很多模型的精度会大幅下跌,但这才是真实工业场景下正常的表现。

5. 经验总结与可扩展方向

5.1 这套流程的边界与效率心得

小波时频图加SwinTransformer的组合,适合解决以振动信号为主要诊断依据的旋转机械故障识别问题。它的优势在于不依赖大量人工特征工程,信号处理和深度模型分工明确:小波负责把物理信息组织成图像,SwinTransformer负责从图像里挖掘判别性特征。但要注意,这个方案不是万能的,如果设备振动信号本身信噪比极低,或者故障冲击被严重调制掩盖,那么再强的模型也救不回来,输入端能够提供的判别信息才是上限。

从开发效率角度看,全流程用Python生态实现非常顺畅。pywt做信号处理,PIL处理图像,timm加载模型,PyTorch训练,每个环节都有成熟库承接,没有额外造轮子的地方。我个人的体会是,80%的时间花在数据预处理和实验验证上,模型结构反而是最省力的一环。把时频图生成参数和数据集划分策略夯实了,哪怕用经典ResNet也能获得不错的基线。SwinTransformer是在此基础上进一步提升了精度上限和泛化能力,而不是一上来就拯救烂数据的银弹。

5.2 从实验室到现场:后续可以怎么扩展

如果要把这套方案推向实际产线,我认为值得扩展的方向有三个。

第一个方向是迁移学习和领域自适应。现场采集的数据和公开数据集大概率分布不一致,转速、负载、安装位置都会改变信号形态。可以先用公开数据预训练模型,再用少量现场数据微调。更进一步,可以用对抗训练或者域自适应方法让模型在源域和目标域之间对齐特征分布,减少工况切换带来的精度衰落。

第二个方向是结合其他监测信息。振动信号只反映机械动态特征,温度、电流、声发射信号能提供互补信息。把多种信号各自生成时频图或多通道组合后输入模型,往往比单一振动信号更鲁棒。配合注意力机制,还可以分析模型重点关注的是哪一个传感器或哪一个频段,增强解释性。

第三个方向是轻量化和边缘部署。Swin-Tiny虽然不大,但对嵌入式设备来说仍有压缩空间。知识蒸馏把SwinTransformer的能力迁移到一个小型CNN或轻量Transformer上,推理速度可以大幅提升。之后再结合滑动窗口和阈值判断做在线异常报警,整条诊断链路就闭环了。其实很多人都在说轴承故障诊断难落地,难的不是模型,而是数据、部署和实时性约束的平衡。把基础方案做扎实,后面每一步扩展都会顺很多。

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

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

立即咨询