资讯详情

振动信号转灰度图+LBP+CNN故障诊断实战与softmax/SVM对比

📅 2026/10/20 5:48:49 | 华诺云谱 👁 阅读
振动信号转灰度图+LBP+CNN故障诊断实战与softmax/SVM对比
做故障诊断或信号处理的朋友十有八九都遇到过这样的事手里有一段振动信号想用深度学习分类但一维时序数据喂进模型效果总是差点意思。后来我做了个小项目把一维振动信号先变成二维灰度图再用局部二值模式LBP把灰度图的纹理特征深化一遍最后用CNN做特征提取分别接softmax分类器和SVM做对比。整套流程封装成Python代码解压后直接就能跑通省去了从零搭环境的麻烦。这篇文章就把这个项目的完整思路、实现细节和踩过的坑一次说清楚适合正在做旋转机械故障分类、结构健康监测或者打算在你自己项目里尝试“信号转图像CNN”路线的同学参考。1. 项目全貌与核心思路拆解1.1 从振动信号到灰度图的完整技术链路这个项目的整体链路并不复杂核心就五个环节信号预处理、图像化、纹理特征深化、深度特征提取、双分类器对比。信号采集与分段原始一维振动信号按固定长度切片每段独立样本。一维信号转灰度图将每段信号编码成矩形的灰度图像。LBP纹理深化对灰度图做局部二值模式变换提取更稳定的局部纹理结构。CNN特征提取把原始灰度图和LBP特征图送入CNN学习高层抽象特征。分类对比分别使用softmax分类器和SVM分类器完成最终分类对比两者的精度与鲁棒性。在实际代码中数据流是连续的raw_signal → gray_image → lbp_image → cnn_feature → softmax/svm。每条数据样本经过这条管线最终得到分类结果。中间没有手工特征工程所有特征都由CNN学出来而LBP的作用是为CNN提供一个更聚焦局部纹理变化的输入视角。1.2 关键技术选型为什么必须走“图像化”这条路如果你只用一维信号做分类传统做法是提取时域统计特征均值、方差、峰峰值、峭度、波形因子再进SVM或决策树。这种方案的问题在于振动信号的非平稳特征很难用几个标量描述完整尤其是复合故障、变工况场景下时域特征往往区分度不够。把信号变成图本质上是在换一个视角描述信号。一维信号只保留了幅度随时间的变化二维图中却能同时呈现在不同时间点上的相关性、频率变化模式和拓扑结构。这种“先升维、再学习”的设计恰恰让CNN的卷积核有了发挥空间卷积核在图像中扫描时能捕捉到局部纹理、边缘和周期性模式——这些结构在原始一维信号里是不透明的。至于为什么用LBP而不是直接把原始灰度图扔给CNN原因有两点原始灰度图的像素值受信号幅值影响较大幅值偏移会导致同一工况的图像外观明显变化这会干扰深层网络的学习。LBP对像素间的大小关系编码对灰度单调变化天然不敏感相当于提前做了“局部特征标准化”。你可以把LBP理解为一种预处理视角它把像素的绝对大小丢弃保留相对大小和空间排列关系这样CNN看到的是更纯的纹理信息而不是绝对值分布。在样本量有限的情况下这种约束往往比让CNN自己从头学习更稳。2. 一维振动信号转二维灰度图的完整实现2.1 常见转图方法对比GAF、MTF、RP与时频谱一维信号转二维图不是只有一种做法我试过四种常用方案做一张表直接对比转换方法基本思想输出特点计算复杂度适合场景格拉姆角场GAF把时间序列映射到极坐标再求角度差的三角变换类“热力图”风格保留时间相关性高矩阵尺寸随序列长度平方增长周期信号、趋势明显的数据马尔可夫转移场MTF统计量化状态之间的转移概率低分辨率网格纹理中非平稳、随机性强的信号递归图RP判断轨道点之间的相空间距离二值纹理图黑白分明高混沌系统、由确定性动态驱动的信号短时傅里叶变换STFT时频谱分段做傅里叶变换堆叠频谱频率-时间-幅值三维信息低非平稳信号、转速变化工况实际代码里我推荐先从GAF或STFT入手。GAF的优势是直接编码时间轴上的相互关系如果振动信号本身存在明显的周期冲击成分GAF图会出现规律性纹理很适合LBP二次增强STFT则更直观适合你希望保留频率语义信息的情况。二者选哪个你可以先做几张小图看看纹理再决定。2.2 灰度图生成的标准流程与归一化细节不管用哪种方法转灰度图的大步骤是一致的对一段长度为N的振动信号做零均值、单位方差归一化。按选定的方法计算二维矩阵。对矩阵做min-max归一化将像素值范围压缩到[0, 1]。乘以255并转成uint8得到灰度图。如果采用GAF注意一个工程细节GAF矩阵的尺寸是N×N其中N是参与变换的序列长度。别直接拿1024点信号去生成1024×1024的图矩阵会大到内存吃紧训练也慢通常先做降采样或分段把N控制在64到128之间。实际中我把每段信号取128个采样点生成128×128的灰度图信息密度和计算量比较均衡。伪代码如下import numpy as np def signal_to_gaf(signal, image_size128): 将一维信号转换为格拉姆角场灰度图 seg_len image_size seg signal[:seg_len] # 归一化到 [0, 1] seg (seg - seg.min()) / (seg.max() - seg.min() 1e-8) # 转为极坐标角度 arccos_val np.arccos(seg) # 生成内积矩阵GASF sin_a np.sin(arccos_val) cos_a np.cos(arccos_val) gasf cos_a[:, None] cos_a[None, :] - sin_a[:, None] sin_a[None, :] # min-max到0-255 gasf (gasf - gasf.min()) / (gasf.max() - gasf.min() 1e-8) * 255 return gasf.astype(np.uint8)注意GAF矩阵对角线上包含了部分冗余信息如果图像看起来“太对称”那是正常的本质上是极坐标表示带来的数学性质不影响后续LBP和CNN使用。2.3 数据划分与增强不要一上来就做数据增强很多同学拿到一维信号后直接随机切分训练集和测试集这种做法在这个项目里容易产生“数据泄漏”式的假高分。振动信号天然具有时间相关性同一段连续数据的相邻片段特征非常接近如果随机划分模型很大程度是在“记住”同一个时间窗口内的相似片段而不是学习不同工况的差异。正确做法是按记录的时间顺序划分假如一开始采集了5种工况的信号每种工况完整保存了连续10分钟的数据那就应该把前7分钟用作训练、中间1分钟用作验证、后2分钟用作测试而不是在所有数据里随机挑样本。至于数据增强我的建议是先不做。先把基准结果跑出来再看是否真的需要。如果你的样本量本来就很少每类几十个可以尝试对信号做小幅幅值抖动、时间轴拉伸或添加高斯噪声再转成灰度图。但要记住增强后的样本只会增加训练集的多样性不会凭空增加信息量过度增强反而会让模型更难收敛。3. LBP深化灰度图特征的原理与实操3.1 LBP是如何提取局部纹理信息的局部二值模式Local Binary Pattern最初用于纹理分类随后扩展到人脸识别、医学图像等领域。它的核心思想非常朴素对图像中的每个像素以它为中心在半径为R的圆周上取P个等间隔的邻域点逐个与中心像素的灰度值比较邻域点灰度大于等于中心像素记1否则记0然后按固定顺序把这一串0/1拼成二进制数再转成十进制这就是该像素的LBP值。举个例子取8个邻域点时某像素周围比较结果是11001011那它的LBP编码就是十进制的203。整张图每个像素都做一遍这个操作重新映射成一张灰度图就是“LBP特征图”。接下来统计这张特征图的灰度直方图就能作为整张图像的纹理特征描述。你可以把LBP理解成一套“放大镜规则”它在看每个像素周围灰度变化的模式而不是单个像素的强度。这种模式在光照变化、幅值漂移的情况下相对稳定所以LBP图能比原图更清晰地展示纹理骨架。一个重要的变体是“统一模式”uniform pattern。如果LBP二进制串中0/1之间的跳变次数不超过2次就称它为统一模式。比如00000000和11111111跳变0次00100000跳变2次都属于统一模式。统一模式在自然纹理图像中占了绝大多数使用这一性质可以把LBP直方图的维度从2^P降到P×(P-1)3大幅减少特征维度。我的代码里默认启用uniform模式就是利用了这个降维特性。3.2 LBP参数选择半径R与邻域点数P怎么定LBP有两个关键超参数邻域点数P和半径R。P决定了二进制编码的长度R决定了比较的邻域空间范围。PR感受野大小纹理粒度特征维度uniform813×3细粒度适合小尺寸图591625×5中等粒度2432437×7粗粒度适合大尺寸图555当你把信号转成128×128的灰度图时我建议优先试(P24, R3)因为GAF得到的大尺度纹理结构较多细粒度纹理信息相对有限邻域范围大一点才能覆盖到周期性的局部结构。但也要注意P和R变大后计算复杂度明显上升。我实际测过同样的数据从(8,1)换成(24,3)LBP处理阶段耗时增加了近5倍但在CNN训练阶段差异并不明显。所以在时间紧迫时可以先用(8,1)快速验证流程最后再换参数调精度。skimage库提供了现成的LBP实现细节代码这样写from skimage.feature import local_binary_pattern import numpy as np def apply_lbp(gray_image, P24, R3): lbp local_binary_pattern(gray_image, PP, RR, methoduniform) # 归一化到0-255显示或输入CNN lbp (lbp - lbp.min()) / (lbp.max() - lbp.min() 1e-8) lbp (lbp * 255).astype(np.uint8) return lbp3.3 原始灰度图与LBP特征图的融合策略LBP处理完后图像的纹理骨架出来了但原始灰度图中的绝对幅值信息也丢失了。为了让CNN既能看到纹理骨架又能参考原始灰度信息我建议做“双通道输入”把原始灰度图和LBP图作为两个通道叠在一起组合成形状为(2, height, width)的输入张量。这比只输入LBP图效果好不少因为CNN的第一个卷积层可以同时学习两个视角的滤波组合。还有两种做法可以考虑但效果不一定更好特征级融合对原图和LBP图分别跑CNN在最后一个全连接层前把特征拼接起来。这种方式灵活但网络参数翻倍更容易过拟合。直方图替代直接用LBP直方图作为特征送进SVM完全不用CNN。这种做法在样本极少的时候每类只有几十张图反而效果不错不过它丢了空间分布信息精度天花板较低。在实际工程里我最终选择了2通道输入。代码里只需要在构建数据集时把两张图用np.stack叠起来即可对后续网络结构没有任何额外负担。4. CNN特征提取与分类器对比实验4.1 针对小样本数据的轻量CNN结构设计如果样本量不大一个过深的CNN只会带来过拟合训练还会慢得让人怀疑人生。我用的网络结构刻意控制在几个卷积块以内核心段代码如下import torch.nn as nn class SimpleCNN(nn.Module): def __init__(self, in_channels2, num_classes5, feature_dim128): super().__init__() self.features nn.Sequential( nn.Conv2d(in_channels, 32, kernel_size3, padding1), nn.BatchNorm2d(32), nn.ReLU(inplaceTrue), nn.MaxPool2d(2), nn.Conv2d(32, 64, kernel_size3, padding1), nn.BatchNorm2d(64), nn.ReLU(inplaceTrue), nn.MaxPool2d(2), ) self.classifier nn.Sequential( nn.AdaptiveAvgPool2d(1), nn.Flatten(), nn.Linear(64, feature_dim), nn.ReLU(inplaceTrue), nn.Dropout(0.5), ) self.fc_out nn.Linear(feature_dim, num_classes) def forward(self, x): feat self.classifier(self.features(x)) out self.fc_out(feat) return out, feat两个卷积块加一个自适应池化输入是2通道的128×128图像逐层缩减到64通道的1×1特征向量。feature_dim128意味着CNN最终学到的“特征向量”只有128维远比原始像素维度低很多低维特征其实非常适合SVM在小样本下发挥。有一点要特别说明这个网络里没有在全局池化之前把图像强行压成小矩阵而是用AdaptiveAvgPool2d(1)把空间信息直接压平。目的是让不同尺寸的输入图像都能工作你在调试时即使把图改成64×64模型结构也不需要改。4.2 softmax分类器与SVM分类器对比的关键逻辑softmax和SVM在同一个项目里对比你需要先理解它们各自的工作机制。softmax分类器通常作为CNN的最后一个全连接层存在输出每个类别的预测概率。它的参数参与反向传播也就是说它是和CNN一起端到端训练的。优势是梯度信号能直接指导前面卷积层提取“对分类最有利”的特征劣势是它本质上是一个线性分类器在全连接输出层之前是线性变换如果特征线性不可分softmax层需要依赖前面网络层学习良好的非线性映射。SVM在这个项目里不是一个网络层而是从已经训练好的CNN中抽取特征后额外训练的分类器。具体流程是CNN先训练到收敛使用softmax损失然后去掉最后的fc_out层把feat向量当成特征数据用来训练一个RBF核SVM。SVM不需要再更新CNN的参数只是在高维特征空间里找一个最大间隔超平面。对比项softmax分类器SVM分类器训练方式与CNN联合端到端训练分两阶段CNN训练后再训练SVM输出类型类别概率决策函数可通过Platt缩放得到概率小样本表现依赖损失函数收敛易受样本不平衡影响通常更稳尤其RBF核对高维特征友好调参复杂度只需学习率、权重衰减等需要调节C和gamma可解释性概率分布直观支持向量个数可反映决策边界复杂度4.3 实验流程从训练到评估完整实验分四步训练CNN用交叉熵损失Adam优化器初始学习率1e-3BatchSize为32训练60个epoch。在训练中记录验证集准确率选验证集最优的模型保存权重。抽取深度特征重新加载最优模型去掉fc_out层对全部样本做一次前向传播得到128维特征矩阵。这个矩阵就是经典的“深度特征”。训练SVM用sklearn.svm.SVC指定kernelrbf用GridSearchCV在C[0.1, 1, 10, 100]、gamma[0.001, 0.01, 0.1, 1]范围内搜索最优参数5折交叉验证。对比评估计算softmax和SVM在测试集上的准确率、精确率、召回率和F1分数。这里最关键的一步是网格搜索。很多情况下SVM效果不如softmax并非方法不行而是C和gamma没调好。RBF核的gamma控制单个样本的影响半径C控制误分类惩罚两者组合的影响很大。在我跑的某轴承故障数据集上结果大致如下具体数据取决于实验条件和噪声水平仅供参考分类器测试准确率宏平均F1训练时长CNN softmax92.6%91.9%约25分钟CNN SVM (RBF)95.2%94.8%约5分钟SVM不仅精度略高训练还快了一个量级。原因不难理解在样本量只有几百到几千的场景下RBF SVM直接在高维特征空间找最大间隔不容易被少数离群样本带偏而softmax需要整个网络继续参与训练过拟合风险相对更高。5. 代码工程化与运行指南5.1 项目目录结构与运行环境当初给这个项目配代码时我要求做到“解压后直接运行”所以在工程结构上花了一点心思。项目主要文件如下signal_to_image_cnn/ ├── main.py # 全流程入口 ├── config.py # 全局参数配置 ├── data_process.py # 信号读取、分段、GAF转换、LBP处理 ├── dataset.py # 自定义Dataset划分训练/验证/测试 ├── cnn_model.py # CNN网络定义与特征抽取函数 ├── train_cnn.py # 训练CNNsoftmax ├── train_svm.py # 提取特征并训练SVM ├── evaluate.py # 生成对比报告 ├── requirements.txt └── data/ ├── class_0/ ├── class_1/ └── ...requirements.txt里主要装numpy、pandas、matplotlib、opencv-python、scikit-image、scikit-learn、torch。如果你的机器没有GPU把代码里的模型和数据都放到CPU上跑也行只是CNN训练时间会拉长。我自己在CPU上小规模试过60个epoch大概2小时。config.py里统一放参数例如分段长度、灰度图尺寸、LBP的P和R、批量大小、学习率、epoch数、SVM的C和gamma搜索范围。把所有可调参数集中在一个文件里后续调参时就不用到处翻代码了。5.2 核心代码逐步拆解关键逻辑一次说清在主流程main.py里大致逻辑如下from data_process import build_dataset from cnn_model import SimpleCNN from train_cnn import train_cnn_model from train_svm import train_svm_model from evaluate import evaluate_models # 1. 读取数据生成灰度图LBP图返回训练/验证/测试的分批数据 train_loader, val_loader, test_loader build_dataset(config) # 2. 训练CNN softmax cnn_model, history train_cnn_model(train_loader, val_loader, config) # 3. 抽取深度特征训练SVM svm_model, test_acc_svm train_svm_model(cnn_model, train_loader, test_loader, config) # 4. 评估分类器并保存结果 evaluate_models(cnn_model, svm_model, test_loader)在data_process.py里重点函数有两个signal_to_image负责转灰度图process_all_data遍历每个类别的数据文件对每段信号调用signal_to_image和apply_lbp再统一堆叠成(样本数, 2, 128, 128)的数组。要注意在dataset.py中划分数据集时是先按文件名排序再按8:1:1比例切分而不是随机打乱。这样能避免同一段信号的时间近邻样本同时出现在训练集和测试集。5.3 典型实验结果解读与分析当你跑通代码后会看到三组输出CNN/softmax的测试准确率、SVM的测试准确率、以及两者的精确率/召回率表。不要满足于只看准确率。一个高准确率可能只是因为它把占比较多的类别预测得很准少数类却一塌糊涂。我在实验中发现某类故障样本只有2个softmax干脆把所有样本都预测成正常类准确率照样98%。这种情况下F1分数和混淆矩阵反而是更诚实的指标。所以evaluate.py里我额外打印了归一化混淆矩阵方便你定位具体是哪个类别被混淆了。一般对常见故障数据集CNNsoftmax先会做出一个可接受的基线90%左右而CNNSVM往往能在此基础上提升2到5个百分点尤其是当你把SVM的C和gamma搜索范围放宽后。6. 踩坑记录与调参建议6.1 我在这个项目中踩过的坑这个部分是最想分享的因为一路做下来绕了不少弯。第一个坑GAF矩阵太大了。最开始我直接拿1024点信号做GAF生成1024×1024的矩阵几百个样本就占了不少内存训练起来也慢到离谱。后来改成128点生成128×128图训练速度和内存占用都降了一个量级精度没有明显损失。记住一个原则图像化只是为了方便CNN提取局部结构网格分辨率够用就行不必盲目追求大图。第二个坑SVM特征没归一化。CNN提取的128维特征虽然处于一定的数值范围但不同维度之间方差差异较大直接训练RBF SVM会让gamma搜索失灵。我加了个StandardScaler把特征标准化到零均值单位方差SVM精度立刻上了一个台阶。第三个坑随机划分数据集。刚开始随机划分后测试准确率达到了98%一度以为方法惊为天人直到用时间顺序划分后才发现真实水平只有93%。原因就是相邻时间片段的样本过于相似模型“偷看”了未来。这个问题在振动信号场景里非常典型一定要防。6.2 不同工程场景的调参速查表最后放一张速查表覆盖几种常见需求方便你快速定位参数起点应用场景推荐转图方法LBP参数CNN深度推荐分类器一般旋转机械故障诊断GAF或STFTP24, R32个卷积块SVMRBF强噪声环境STFT时频谱P16, R22-3个卷积块可对比两者噪声大时softmax略好每类样本极少50MTF或RPP8, R11个卷积块SVM实时嵌入式部署LBP直方图直接分类P8, R1无CNNSVM多工况复合信号GAF多通道输入P24, R33个卷积块多数情况下SVM泛化更好这个项目做下来我最深的体会是一维信号转二维图再交给CNN这条路并不是越深越好LBP这类“老方法”在新流程里依然有不可替代的价值。如果你在自己的数据上复现建议每一步都保存中间结果多看看生成的灰度图和LBP图长什么样很多问题一眼就能看出来根本不用等训练结束。祝你也跑出一个漂亮的对比结果。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑