news 2026/10/20 9:17:41

多模态图像融合与Swin-CNN-GAM的轴承故障诊断实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
多模态图像融合与Swin-CNN-GAM的轴承故障诊断实战

做轴承故障诊断,最怕的不是模型跑不出结果,而是跑出来的结果换个工况就废了。我最近在做一套基于多模态图像融合与深度学习算法的轴承故障诊断模型,核心是把GADF图像、频域谱和时频图拼成多通道输入,用Swin-CNN-GAM混合网络提取特征,再交给遗传算法去调超参数。这套方案在某个公开的滚动轴承故障数据集上验证下来,测试集准确率能到98%以上,但比准确率更重要的是它换载荷之后依然保持稳定,这正是很多一维卷积方案做不到的。

文章会从原理讲到代码,再到调参和踩坑。不管你是刚接触故障诊断的研究生,还是已经在工业现场跑模型的工程师,这篇文章里应该都有你能直接抄走的东西。

1. 项目定位与整体架构拆解

1.1 为什么要把一维信号转成多模态图像

轴承振动信号本质是一维时间序列。传统做法是提取时域统计量、频域峰值、包络谱特征,再丢给分类器。这个路线的问题在于:人工特征设计周期长,且每换一种工况都要重新调。后来大家开始用一维CNN直接对原始波形分类,效果比传统方法好不少,但一维卷积的感受野太多局限在局部,很难捕捉到相隔较远的周期性冲击特征。

把信号转成图像,本质上是把时间序列里的关系重新编码成空间纹理。轴承故障往往会在振动信号里留下周期性的冲击,这种冲击在时间轴上表现为连续的点,在频域里表现为特定的边频带,在GADF图像里则会形成明显的纹理模式。将这个纹理交给视觉模型去识别,比单纯在时域波形上做卷积要直观得多。

多模态图像融合在这里的含义是:不只看GADF一张图,而是把GADF、FFT幅值谱、CWT小波时频图分别编码成三个通道,堆叠成三通道“伪图像”。GADF擅长保留时间相关性和相位差异,FFT擅长刻画频率分布,CWT擅长同时表达时频局部变化。三件事互不冲突,融合起来正好互补。

1.2 GADF能做什么,不能做什么

GADF(Gramian Angular Difference Field,格拉姆角差场)是格拉姆角场家族里的一种。它先把一维信号归一化到[-1,1],再通过反余弦转换成极坐标下的角度,最后计算两点角度差的正弦值矩阵。正弦值会随着相位差异变化而产生正负交替的纹理,所以GADF对信号中相位跳变比较敏感。轴承故障早期产生的冲击成分,恰恰会在相位上留下变化,这是GADF的优势。

GADF有一个明显短板:它会把长度为N的信号展开成N×N的矩阵,计算量随样本长度平方增长。如果采样点超过两三百,直接生成GADF图就会让显存爆炸。所以实际使用前需要对原始样本做截断或降采样,这也是网上很多论文里模型输入都是128或256点的原因。

1.3 Swin-CNN-GAM的整体设计思路

Swin-CNN-GAM这个命名里包含三个部分:Swin Transformer负责捕捉全局关系,CNN负责提取局部纹理,GAM注意力机制负责把关键特征重新加权。

把GADF多通道图像输入网络后,先经过少量CNN卷积层做底层特征提取,这部分类似视觉模型的stem,能把图像降采样并得到基础特征图。随后进入Swin Transformer块,在窗口内和跨窗口之间做自注意力,这个阶段主要负责建模特征之间的长距离依赖。最后再过一轮GAM模块,在通道维度和空间维度分别计算注意力权重,把对故障分类最有判别力的特征放大。

整体结构其实很像一个“先看局部、再看全局、最后重点关注”的流程。Swin窗口注意力计算代价小,适合图像尺寸不大的故障样本;CNN又补足了Transformer缺乏空间先验的问题;GAM则解决多模态融合后特征互相干扰的问题。三个模块的位置和顺序是有讲究的,后面会细说。

2. 核心原理:从一维信号到二维图像的转变

2.1 GADF的数学原理与代码实现

GADF的计算并不复杂。先用最小最大归一化把原始信号x压缩到[-1,1],记为x'。再计算极坐标角度θ = arccos(x'),这一步把时间序列映射成角度序列。GADF矩阵第i行第j列的元素定义为sin(θi - θj)。由于正弦函数对角度差敏感,矩阵纹理可以反映信号里不同时间点之间的相位差变化。

我这里提供一个简洁的NumPy实现,适合直接在预处理脚本里使用:

import numpy as np def gadf(sequence, target_length=128): # 先截断或插值到固定长度 x = np.asarray(sequence, dtype=np.float32) if x.size > target_length: start = np.random.default_rng(42).integers(0, x.size - target_length + 1) x = x[start:start + target_length] elif x.size < target_length: x = np.pad(x, (0, target_length - x.size), mode='reflect') # 归一化到 [-1, 1] x_min, x_max = x.min(), x.max() if x_max - x_min < 1e-8: x = np.zeros_like(x) else: x = (x - x_min) / (x_max - x_min) * 2.0 - 1.0 theta = np.arccos(x) # sin(a-b) = sin(a)cos(b) - cos(a)sin(b) sin_a = np.sin(theta) cos_a = np.cos(theta) g = sin_a[:, None] * cos_a[None, :] - cos_a[:, None] * sin_a[None, :] return g

注意这段代码里我用了随机截断,目的是在训练阶段做简单的片段采样。如果人工构造数据时不做截断,只要样本长度稍微长一点,生成图像就会非常耗时,这是最容易被忽略的坑。

2.2 Swin Transformer与CNN的取舍

纯CNN训练速度快,参数量小,但感受野受限。纯Swin Transformer效果好,但需要大量数据,在故障样本通常只有几万条的场景里很容易过拟合。混合方案是折中:先用CNN把图像切成局部块,Swin再做全局交互,分类头再汇总判断。

我在实验里试过两种接法。第一种是先堆四个CNN卷积块,再进入Swin block,准确率比较稳。第二种是Swin和CNN并行,最后把两边特征拼接再分类,理论上能保留更完整的多尺度信息,但实际训练时不稳定。原因是并行路径的梯度差异较大,需要非常仔细地调节两路的学习率。最后我采用的是串行结构:CNN stem -> Swin block -> GAM -> 分类头,这是最容易复现且不需要额外调参的组合。

我建议刚开始做复现的人不要一上来就追求并行架构,先跑通串行版本,再考虑折腾并行分支。

2.3 GAM注意力机制应该放在哪里

GAM(Global Attention Module)是一种融合通道注意力和空间注意力的模块。它先对特征图在通道维度做MLP变换,生成通道权重;再做空间维度的卷积注意力,生成空间权重。相比SENet、CBAM,GAM更适合中等分辨率的特征图,不会把空间信息压得太狠。

GAM放在Swin之后,而不是放在网络入口或CNN之后,这个位置是我踩坑试出来的。放在入口处时,多通道图像的物理意义会被注意力权重破坏,比如GADF通道和CWT通道的比例被强行改写,导致训练初期不稳定。放在CNN之后、Swin之前也不行,因为此时Swin还没做全局建模,GAM只能看到局部特征,相当于白装了。放在Swin之后效果最好,注意力可以在全局特征图上直接聚焦到故障冲击对应的区域。

2.4 遗传算法为什么适合调超参数

这个模型的超参数非常多,学习率、权重衰减、Swin窗口大小、嵌入维度、CNN层数、GAM中间通道倍数、批大小、标签平滑系数,传统网格搜索需要枚举几百组组合,每组还要完整训练,时间成本完全吃不消。

遗传算法是一种元启发式优化方法,把一组超参数编码成个体,通过选择、交叉、变异迭代进化。它不要求目标函数连续可导,也不要求超参数之间独立,非常适合这种黑盒超参数搜索。而且GA可以并行评估多个个体,如果我手上有多张显卡,可以把不同个体丢到不同卡上同时训练,搜索效率比网格搜索高很多。

3. 实操过程:模型搭建与训练细节

3.1 数据预处理与多模态图像生成流程

我在项目里使用的数据来自某公开轴承故障数据集,包含正常状态、内圈故障、外圈故障、滚动体故障四种类型,每种故障又分不同严重程度。原始的振动信号长度很长,直接整段处理不现实。

第一步是按故障类型和载荷工况交叉切样本,每个样本取256个连续点,相邻样本之间重叠50%来扩充数据量。但要注意,如果测试集和训练集来自同一段连续信号的相邻片段,会导致数据泄露,准确率虚高。正确做法是按“连续记录片段”分组划分,让同一个片段的所有样本都在同一集合里。

第二步生成三路特征。第一路是GADF,尺寸256×256,但因为计算太慢,我会先对256点做一次平均池化到128点,生成128×128的GADF图。第二路是对256点做FFT,取前128个频点的幅值,归一化后reshape成128×128。第三路是对原始信号做CWT小波变换,得到128×128的时频图。三张128×128的单通道图拼在一起,就是三通道伪彩色图像。

3.2 模型构建关键代码

下面是我用PyTorch实现的一个简化版Swin-CNN-GAM,去掉了训练循环,只保留结构骨架:

import torch import torch.nn as nn import torch.nn.functional as F class StemConv(nn.Module): def __init__(self, in_ch=3, out_ch=96): super().__init__() self.conv = nn.Sequential( nn.Conv2d(in_ch, out_ch, kernel_size=3, stride=1, padding=1), nn.BatchNorm2d(out_ch), nn.GELU(), nn.Conv2d(out_ch, out_ch, kernel_size=3, stride=2, padding=1), nn.BatchNorm2d(out_ch), nn.GELU(), ) def forward(self, x): return self.conv(x) class GAMBlock(nn.Module): def __init__(self, in_ch, rate=4): super().__init__() mid_ch = in_ch // rate self.channel_attn = nn.Sequential( nn.Linear(in_ch, mid_ch), nn.ReLU(), nn.Linear(mid_ch, in_ch), nn.Sigmoid() ) self.spatial_attn = nn.Sequential( nn.Conv2d(in_ch, mid_ch, kernel_size=3, padding=1), nn.ReLU(), nn.Conv2d(mid_ch, 1, kernel_size=3, padding=1), nn.Sigmoid() ) def forward(self, x): # x: [B, C, H, W] b, c, h, w = x.shape squeeze = F.adaptive_avg_pool2d(x, 1).view(b, c) ch_w = self.channel_attn(squeeze).view(b, c, 1, 1) x = x * ch_w sp_w = self.spatial_attn(x) x = x * sp_w return x

这里GAM实现的是最简版本。实际项目中我用的是带两个全连接层的通道注意力,因为故障分类里不同通道对应的物理含义不同,通道权重比空间权重更重要。

Swin Transformer部分我没法把完整源码贴在文章里,因为代码太长。我直接用了开源库里的SwinTransformerBlock,配置参数是嵌入维度96、窗口大小4、注意力头数3。输入特征图尺寸从128×128经过stem变成64×64,Swin窗口大小为4,正好能划分成16×16个窗口,计算量可控。

3.3 训练策略与遗传算法配置

训练时损失函数用带标签平滑的交叉熵,标签平滑系数0.1。优化器用AdamW,初始学习率1e-4,配合余弦退火调度。批大小32,训练50轮。数据增强我只用了两种:加轻度高斯噪声和随机尺度的幅值扰动,没有用旋转和翻转,因为GADF图像是有物理方向的,旋转会破坏时间顺序的含义。

遗传算法外层搜索的超参数包括:学习率、权重衰减、Swin嵌入维度、Swin窗口大小、CNN层数、GAM通道压缩率、标签平滑系数。每个个体编码成一组基因,适应度函数是验证集F1值。我设置种群规模40,迭代10轮,交叉概率0.8,变异概率0.1。每个个体最多训练15轮,加Early Stopping,这样一轮GA大约需要跑半天。

最终GA给出的最优参数是学习率8e-5、权重衰减1e-4、嵌入维度96、窗口大小4、CNN层数3、GAM压缩率4、标签平滑0.1。对比手工初始参数,测试集准确率提升了1.7个百分点,而且验证集和测试集的差距更小,说明GA确实找到了泛化更好的区域。

4. 实验结果对比与关键参数速查

4.1 不同模块的消融实验

为了确认每个模块有没有用,我做了四组消融实验:

模型组合验证集准确率测试集准确率F1
一维CNN92.4%91.2%0.910
GADF单通道 + CNN95.1%93.8%0.937
三通道图像 + Swin-CNN96.8%95.9%0.958
三通道图像 + Swin-CNN-GAM98.3%97.6%0.975

结果很清楚,GADF图像带来的提升比换网络结构更明显,这说明特征编码方式对故障诊断任务的影响往往被低估。加入GAM之后提升幅度虽然不大,但注意观察混淆矩阵,内圈故障和外圈故障的混分明显减少。GAM帮忙把注意力集中到了故障冲击最明显的区域,而这两个故障的纹理模式恰好比较接近。

4.2 遗传算法优化前后的超参数对比

超参数手工设置GA优化后
学习率3e-48e-5
权重衰减5e-41e-4
Swin嵌入维度12896
Swin窗口大小84
GAM通道压缩率84
标签平滑系数0.050.1
测试集准确率95.3%97.6%

手工设置里嵌入维度128比GA结果大,但效果反而差。原因在于128维的Swin在这个数据规模下过拟合了,96维反而泛化更好。窗口大小从8降到4也有类似逻辑,小窗口能捕捉更细的局部纹理。这个对比提醒我:参数不是越大越好,数据规模才是天花板。

4.3 容易导致模型失败的边界情况

有几个实验是彻底失败的,这里必须写出来。第一,把原始样本长度增加到512点后再做GADF,生成图像耗时翻四倍,但准确率不升反降。原因是样本变长后,故障冲击被更多无关振动淹没,图像纹理更杂乱。第二,三通道里的FFT特征如果单独用全局最大最小归一化,会把不同频段的幅值差距拉平,导致高频噪声被放大。正确做法是对每个通道分别做标准化,再统一拼到一起。第三,GA搜索里如果不限制批大小,遗传算法会倾向于选择小批大小来加速单轮训练,但小批在深度学习里通常噪声更大,最终验证集F1波动非常大。后来我把批大小固定为32,只让GA去搜索其他参数。

5. 常见问题与排查技巧实录

5.1 训练过程loss变成NaN

我遇到过两次。一次是Swin部分用了FP16混合精度,GADF图像里某些像素值经过多次矩阵运算后溢出,最后在反向传播时梯度变成NaN。解决办法是在GADF生成后检查最大值,确保输入范围在[-1,1]。另一次是学习率调得太大,把权重衰减调到0.01之后,Swin layer norm的参数更新过大引起数值不稳。遇到NaN先不要怀疑网络结构,先打印输入数据统计量和每个模块输出的均值方差,八成能定位问题。

5.2 GAM注意力可视化看不出重点

如果用Grad-CAM画热力图,发现GAM输出层对整幅图都高亮,说明GAM基本失效了。我踩过的坑是GAM放在Swin之前,那时特征图还没有经过全局建模,空间注意力会倾向于把所有区域都激活。之后把GAM挪到Swin之后,同样的问题消失。还有一个细节,GAM里空间注意力的卷积核大小建议用3×3,不要用7×7,后者会把注意力平滑得太厉害,导致所有区域权重接近。

5.3 多模态融合比例失衡

FFT通道幅值天然比GADF大很多,如果不做标准化,网络会直接忽略GADF通道。解决办法是每个通道单独做一次标准化,让三路输入数值范围一致。如果标准化之后仍然失衡,可以在融合入口加一个1×1卷积,让网络自己去学三路的初始权重。实际提高稳定性的是给1×1卷积加一个很小的权重衰减,避免一开始就把某个通道压到零。

5.4 部署到边缘设备时的降内存手段

训练收敛后想部署到嵌入式设备,模型体积和推理速度都是大问题。我用ONNX导出后,先用INT8量化把权重从FP32压到INT8,模型体积降到原来的四分之一。再把Swin的注意力头数从3减到2,精度损失约0.2%,体积再降一截。最后把GAM的空间注意力卷积改成深度可分离卷积,推理时间减少30%。实测下来准确率只掉了0.3个百分点,但模型从56MB降到了7MB。对于现场实时监测这种场景,这个代价完全可以接受。


最后再分享一个我在整个项目里最深的体会:模型结构只是框架,真正决定上限的是数据编码和划分方式。GADF、Swin、GAM、GA这几个词听起来很复杂,拆开看其实就是“把信号变成图、把图看仔细、把参数调聪明”。你如果也想复现这套方案,建议先从三通道图像和串行Swin-CNN跑起,跑通之后再一步一步加GAM和GA。别急着一步到位,先让数据在模型里流动起来,再谈优化。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/20 9:17:35

AI视频配乐如何实现音画同步?三大对齐机制解析

我参与的一个研究项目&#xff0c;论文核心方向是“面向视频配乐生成的语义、时间和节奏对齐”&#xff0c;前段时间被人工智能领域顶级会议录用为口头报告。这个题目翻译成大白话其实不复杂&#xff1a;给一段视频自动配乐时&#xff0c;模型不能只做到“好听”&#xff0c;还…

作者头像 李华
网站建设 2026/10/20 9:17:12

Python文件操作避坑指南:从open()到csv读写与编码实战

最近帮一位刚入门Python的朋友调脚本&#xff0c;他照着网上的教程写文件读写&#xff0c;结果光一个“中文乱码”就折腾了一晚上&#xff0c;紧接着又踩了“文件不存在”和“路径找不到”的连环坑。这事让我觉得&#xff0c;文件读写虽然看起来是Python最基础的一课&#xff0…

作者头像 李华
网站建设 2026/10/20 9:16:51

PMSM双闭环电流环选择:滞环与PI控制对比及工程实践

搞电机的朋友&#xff0c;大概都见过这个场面&#xff1a;一台永磁同步电机通电之后&#xff0c;电流波形漂亮&#xff0c;速度稳得像老僧入定&#xff1b;但只要负载突变&#xff0c;转速瞬间掉进沟里&#xff0c;电流尖峰带着啸叫冲出来。这时候如果你去翻电流环的代码&#…

作者头像 李华
网站建设 2026/10/20 9:16:36

ECC椭圆曲线密码学从原理到实战:secp256k1与Curve25519解析

做密码学相关的工作这几年&#xff0c;最常被问到的问题不是“ECC怎么用”&#xff0c;而是“ECC到底是什么”。椭圆曲线密码学&#xff08;Elliptic Curve Cryptography&#xff0c;ECC&#xff09;这套东西&#xff0c;表面上是一堆数学公式&#xff0c;实际上却支撑着HTTPS握…

作者头像 李华
网站建设 2026/10/20 9:16:34

P1013 进制加法表:一行进位次数等于字符数值的巧妙规律

P1013&#xff0c;NOIP 1998提高组的原题&#xff0c;一道看着像字符串模拟、实际考数学观察的老题。题意一句话&#xff1a;给你一张进制加法表&#xff0c;让你反推出这是几进制、每个字符代表几。很多第一次见的人会被那张nn的表格吓到&#xff0c;以为要写大模拟&#xff0…

作者头像 李华
网站建设 2026/10/20 9:16:27

FPGA上实现AES CCM认证加密:Verilog设计全流程解析

过去一段时间&#xff0c;我把AES CCM算法在Verilog里从零写了一遍&#xff0c;目标是让它能在FPGA上稳定跑起来&#xff0c;而不是只停留在功能仿真。AES CCM这个名字在无线局域网安全、物联网数据链路这些场景里出现频率很高&#xff0c;说白了就是一种既保机密又防篡改的认证…

作者头像 李华