基于1D-CNN与SVM的滚动轴承智能故障诊断实战指南
2026/8/30 8:30:06 网站建设 项目流程

简介:本资源面向机械故障诊断方向的本科生、研究生及工业智能运维工程师,聚焦滚动轴承振动信号的自动化故障识别问题,提供一套轻量级但完整的1D-CNN与SVM融合诊断方案。压缩包仅2个文件(1个Python主程序+1个数据链接说明文本),总大小3KB,结构极简:main.py实现端到端建模流程,涵盖振动信号特征自动提取、CNN-SVM两级分类架构搭建、模型编译训练及评估;数据链接.txt则明确指向公开轴承数据集(如CWRU),便于用户快速获取原始时序信号并复现实验。已有3533人学习下载,适合初学者理解深度特征提取与传统分类器协同设计的核心思想,亦可作为课程设计、毕设或工业边缘诊断原型的可扩展基础代码——无需复杂依赖,仅需TensorFlow环境即可运行,附带关键注释与模块化函数,便于调试、替换特征层或对接实际传感器数据流。

1. 项目概述:当轴承“说话”时,我们如何听懂?

在工业设备运维领域,滚动轴承就像旋转机械的“关节”,它的健康状态直接决定了整台设备的运行寿命与安全。想象一下,一台大型风机或一台高速列车的关键轴承,一旦发生故障,轻则停机停产造成巨大经济损失,重则可能引发严重的安全事故。传统的故障诊断,往往依赖老师傅“听音辨位”的经验,或者是在设备彻底“趴窝”后进行拆解检查,这种方式不仅滞后,而且对人员经验依赖极高,难以规模化应用。

于是,基于振动信号的智能故障诊断应运而生。这个项目的核心,就是利用1D-CNN(一维卷积神经网络)SVM(支持向量机)这两把“利器”,构建一个能够自动、精准识别滚动轴承早期故障的智能诊断系统。简单来说,就是让计算机学会“听”轴承振动的声音,并判断它是否“生病”了,以及生了什么“病”(比如内圈故障、外圈故障、滚动体故障等)。这个组合非常巧妙:1D-CNN擅长从原始的一维振动信号中自动提取深层次的、与故障相关的特征,而SVM则是一个强大的分类器,能基于这些特征做出精准的分类决策。这比单纯使用传统信号处理方法(如傅里叶变换提取频谱特征)再喂给分类器,往往能获得更高的准确率和更强的泛化能力。

无论你是从事设备预测性维护的工程师,还是对机器学习在工业应用感兴趣的研究者或学生,这个项目都是一个绝佳的实践案例。它不仅涵盖了从数据预处理、特征工程到模型构建、训练评估的完整机器学习流水线,更关键的是,它直击工业场景中的真实痛点,具有极高的实用价值。接下来,我将以一个从业者的视角,带你深入拆解这个项目的每一个环节,分享我在实操中积累的经验和踩过的坑。

2. 核心思路与技术选型:为什么是1D-CNN+SVM?

在开始动手写代码之前,我们必须先想清楚架构。面对滚动轴承故障诊断这个问题,可选的方案很多,为什么最终锁定了“1D-CNN特征提取 + SVM分类”这条技术路线?这背后是对于问题本质、数据特性以及模型特点的综合考量。

2.1 问题本质与数据特性分析

滚动轴承的振动信号是一维时序信号。当轴承出现局部损伤(如点蚀、剥落)时,在运行中会产生周期性的冲击,这些冲击会调制轴承系统的固有振动,在振动信号中表现为特定的频率成分(如故障特征频率)及其谐波。我们的任务就是从这段看似杂乱无章的波形中,找到这些微弱的、代表故障的“指纹”。

传统方法通常分两步走:第一步是信号处理与特征提取,比如计算信号的时域指标(均方根、峭度等)、频域指标(通过FFT得到频谱,再计算重心频率等),或者进行更复杂的时频分析(如小波变换);第二步是模式识别,将提取出的这些手工特征(可能是一个几十甚至上百维的向量)输入到分类器(如SVM、随机森林)中进行训练和分类。

这种方法的最大问题在于特征工程高度依赖专家知识。哪些特征对当前轴承、当前工况最有效?特征之间是否存在冗余?这需要大量的试错和领域经验。而且,手工设计的特征往往泛化能力有限,换一个型号的轴承或不同的负载转速,效果可能就大打折扣。

2.2 1D-CNN:自动特征提取的“火眼金睛”

卷积神经网络(CNN)在图像识别领域的成功,源于其强大的局部感知和层次化特征提取能力。对于图像这种二维数据,CNN使用二维卷积核在空间维度上进行滑动扫描。而我们的振动信号是一维的,自然就用到其变体——1D-CNN。

1D-CNN的核心优势在于“端到端”的自动特征学习。我们不需要再费尽心思去设计各种时域、频域特征,而是直接将原始的一维振动信号(或经过简单预处理,如去噪、归一化)输入网络。网络浅层的卷积核会学习到类似边缘检测器(在信号里可理解为某种滤波器)的特征,捕捉信号中的局部模式(如冲击的上升沿);深层的卷积核则能够组合这些局部模式,形成更抽象、更高阶的特征表示,这些特征最终能够很好地对应不同的故障类型。

注意:这里有一个关键点,1D-CNN的输入通常是一段固定长度的信号片段(例如,包含若干个旋转周期的数据)。这要求我们在数据预处理阶段进行合理的样本分割,确保每个样本既能包含完整的故障冲击信息,又不会因过长而引入过多无关噪声或导致样本量不足。

2.3 SVM:稳健分类的“最终裁决者”

支持向量机(SVM)是一种经典的、非常强大的监督学习模型,尤其适用于小样本、高维度的分类问题。它的核心思想是寻找一个最优的超平面,使得不同类别的样本之间的“间隔”最大化。

在“1D-CNN + SVM”的架构中,1D-CNN扮演了“特征工程师”的角色,而SVM则扮演了“分类法官”的角色。我们通常将1D-CNN的最后一个全连接层(用于分类的层)移除,取其前面的某个层(通常是全局平均池化层或最后一个卷积层的输出)的输出作为“深度特征”。将这些特征提取出来,再单独训练一个SVM分类器。

为什么不用1D-CNN直接输出分类结果,而要接一个SVM?这主要是出于性能和稳健性的考虑:

  1. 小样本优势:工业场景下,高质量的故障数据往往获取成本高,样本量有限。SVM在小样本数据集上通常表现出比深度神经网络末端Softmax分类器更好的泛化能力,更不容易过拟合。
  2. 决策边界清晰:SVM致力于最大化分类间隔,其决策边界往往更加清晰和稳健,对噪声和异常值相对不敏感。
  3. 灵活性:我们可以轻松尝试SVM的不同核函数(线性、多项式、RBF等),以找到最适合当前特征空间的分类界面,而无需重新训练整个深度网络。

当然,这个架构并非唯一选择。你也可以使用纯粹的深度网络(如更深的1D-CNN或1D ResNet),或者使用其他传统分类器(如随机森林、XGBoost)。但“1D-CNN+SVM”的组合在多数公开轴承数据集(如凯斯西储大学CWRU轴承数据)的测试中,都展现出了优异且稳定的性能,是平衡了性能、复杂度和实现成本的一个非常实用的方案。

3. 实战环境搭建与数据准备

理论清晰后,我们进入实战环节。任何机器学习项目都始于环境和数据。这里我会给出一个兼顾效率和可复现性的环境配置方案,并详细讲解如何处理滚动轴承振动数据。

3.1 开发环境与工具链选型

我个人的工作流基于Python,因为它拥有最丰富的机器学习库生态。以下是核心工具栈:

  • Python 3.8+: 主流版本,稳定性好。
  • 深度学习框架:PyTorch。我选择PyTorch而非TensorFlow,主要因为其动态图机制让调试更加直观灵活,对于研究和快速原型开发非常友好。当然,你也可以使用TensorFlow/Keras,原理相通。
  • 科学计算与数据处理:NumPy, Pandas。数据读入、处理和预分析的基石。
  • 信号处理:SciPy。用于必要的信号滤波、重采样等操作。
  • 机器学习库:scikit-learn。用于SVM模型的实现、数据划分、评估指标计算等,它是Python机器学习的事实标准。
  • 可视化:Matplotlib, Seaborn。用于绘制振动信号波形、频谱图、模型训练过程曲线和混淆矩阵等。

你可以使用condapip来管理环境。我推荐使用conda创建独立环境,避免包冲突。

# 使用conda创建并激活环境 conda create -n bearing_fault python=3.8 conda activate bearing_fault # 安装核心库 pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu # 根据你的CUDA版本选择,此处以CPU为例 pip install numpy pandas scipy scikit-learn matplotlib seaborn jupyter

实操心得:在安装PyTorch时,务必去 官网 根据你的操作系统、包管理工具、CUDA版本(如果有GPU)生成对应的安装命令。直接pip install torch可能会安装不匹配的版本。对于故障诊断这类任务,如果数据量不大,CPU训练通常也可接受;但如果追求速度,配置CUDA环境的GPU训练会快很多。

3.2 数据获取与理解

公开的轴承数据集是我们的起跑线。最著名、最常用的是美国凯斯西储大学(CWRU)的滚动轴承数据中心的数据。它提供了不同故障位置(内圈、外圈、滚动体)、不同故障尺寸(0.007英寸,0.014英寸等)、不同负载条件(0HP, 1HP, 2HP, 3HP)下的驱动端和风扇端振动数据。

数据关键信息

  • 采样频率:通常为12 kHz或48 kHz。
  • 数据格式.mat文件(MATLAB格式)或已转换的文本文件。
  • 类别:通常包括正常(Normal)内圈故障(IR)外圈故障(OR)滚动体故障(B)。外圈故障又可能根据故障点位置(相对于负载区)细分为不同类别。

第一步是下载并加载数据。以CWRU数据为例,我们使用scipy.io加载.mat文件。

import numpy as np import scipy.io as sio from pathlib import Path # 假设数据文件结构已组织好 data_dir = Path('./CWRU_data') normal_path = data_dir / '97.mat' # 举例:正常状态数据 ir_fault_path = data_dir / '105.mat' # 举例:内圈故障数据 # 加载数据,CWRU数据中键名通常是‘X***_DE_time’(驱动端振动信号) normal_data = sio.loadmat(normal_path)['X097_DE_time'].flatten() # 展平为一维数组 ir_data = sio.loadmat(ir_fault_path)['X105_DE_time'].flatten() print(f"正常信号长度:{len(normal_data)}, 内圈故障信号长度:{len(ir_data)}") print(f"正常信号片段示例:{normal_data[:10]}")

3.3 数据预处理与样本构建

这是整个项目中最关键、最需要细致对待的环节之一。原始的长时序信号不能直接扔给模型,我们需要将其构建成一个个适合模型输入的样本。

1. 样本分割 (Segmentation)我们采用滑动窗口的方法,将长信号切割成固定长度(如1024、2048个点)的、可能部分重叠的短样本。窗口长度需要能覆盖至少几个故障冲击周期。

def create_samples(signal, label, window_size=1024, step_size=512): """ 将一维信号切割成多个样本。 参数: signal: 一维振动信号数组 label: 该信号对应的标签(整数) window_size: 样本长度(点数) step_size: 滑动步长(点数),步长小于窗口长度会产生重叠样本,增加数据量。 返回: samples: 样本数组,形状为 (n_samples, window_size) labels: 标签数组,形状为 (n_samples,) """ samples = [] labels = [] n = len(signal) for start in range(0, n - window_size + 1, step_size): end = start + window_size sample = signal[start:end] samples.append(sample) labels.append(label) return np.array(samples), np.array(labels) # 为不同状态的数据创建样本 window_size = 1024 step_size = 512 # 50%重叠 normal_samples, normal_labels = create_samples(normal_data, label=0, window_size=window_size, step_size=step_size) ir_samples, ir_labels = create_samples(ir_data, label=1, window_size=window_size, step_size=step_size) # ... 同理处理其他故障类型数据

2. 数据标准化 (Normalization)不同工况下的振动信号幅值差异可能很大。为了加速模型收敛并提高性能,我们需要对每个样本进行标准化。通常使用Z-score标准化(减去均值,除以标准差),使其均值为0,标准差为1。

from sklearn.preprocessing import StandardScaler # 注意:拟合时只使用训练集数据,避免数据泄露 # 这里先演示对整个数据集的操作,实际应在划分训练测试集后进行 all_samples = np.vstack([normal_samples, ir_samples, ...]) # 合并所有样本 all_labels = np.hstack([normal_labels, ir_labels, ...]) # 初始化标准化器 scaler = StandardScaler() # 重塑为二维以适配scaler: (n_samples, window_size) -> (n_samples, window_size) all_samples_scaled = scaler.fit_transform(all_samples)

重要注意事项StandardScalerfit方法必须且只能在训练集数据上调用。然后用这个训练集拟合好的scaler去转换(transform)验证集和测试集。绝对不能用测试集的数据去fit标准化器,否则就构成了严重的数据泄露,模型评估结果会严重失真。

3. 数据集划分按比例(如7:2:1或8:1:1)随机划分训练集、验证集和测试集。务必使用分层抽样stratify),确保每个集合中各类别的比例与原始数据集一致。

from sklearn.model_selection import train_test_split # 第一次划分:分出训练集和临时集(验证+测试) X_train, X_temp, y_train, y_temp = train_test_split( all_samples_scaled, all_labels, test_size=0.3, random_state=42, stratify=all_labels ) # 第二次划分:将临时集分为验证集和测试集 X_val, X_test, y_val, y_test = train_test_split( X_temp, y_temp, test_size=0.5, random_state=42, stratify=y_temp ) print(f"训练集: {X_train.shape}, 验证集: {X_val.shape}, 测试集: {X_test.shape}")

至此,我们得到了形状为(n_samples, window_size)的样本数据和对应的标签,数据准备工作全部完成。接下来,就是搭建模型的核心部分。

4. 模型构建:1D-CNN与SVM的深度解析

在这一部分,我们将亲手搭建1D-CNN特征提取器,并设计SVM分类器。我会详细解释每一层的作用、参数选择的考量,并分享一些网络设计上的经验。

4.1 1D-CNN特征提取网络设计

我们的目标是设计一个既能有效提取特征,又不会过于复杂(避免在小数据集上过拟合)的网络。一个典型的用于故障诊断的1D-CNN结构包含卷积层、池化层、激活函数和最后的展平或全局池化层。

import torch import torch.nn as nn import torch.nn.functional as F class CNN1D_FeatureExtractor(nn.Module): """ 一维CNN特征提取器 输入形状: (batch_size, 1, signal_length) # 1代表通道数,对于振动信号是单通道 """ def __init__(self, input_length=1024, num_classes=4): super(CNN1D_FeatureExtractor, self).__init__() # 第一卷积块:提取低级特征(如边缘、冲击) self.conv1 = nn.Conv1d(in_channels=1, out_channels=16, kernel_size=64, stride=4, padding=32) self.bn1 = nn.BatchNorm1d(16) self.pool1 = nn.MaxPool1d(kernel_size=4, stride=4) # 第二卷积块:提取中级特征 self.conv2 = nn.Conv1d(in_channels=16, out_channels=32, kernel_size=16, stride=2, padding=8) self.bn2 = nn.BatchNorm1d(32) self.pool2 = nn.MaxPool1d(kernel_size=4, stride=4) # 第三卷积块:提取高级特征 self.conv3 = nn.Conv1d(in_channels=32, out_channels=64, kernel_size=4, stride=1, padding=2) self.bn3 = nn.BatchNorm1d(64) self.pool3 = nn.MaxPool1d(kernel_size=2, stride=2) # 计算经过所有卷积和池化层后的特征图长度 # 这是一个关键步骤,用于确定全连接层的输入维度 self._to_linear = None self._calculate_conv_output_dim(input_length) # 全局平均池化层:将每个通道的特征图池化为一个标量,形成特征向量 # 替代了展平+全连接层,参数更少,更不容易过拟合 self.gap = nn.AdaptiveAvgPool1d(1) # 最终的分类头(全连接层)—— 这个层我们后续会移除,用于SVM训练 self.fc = nn.Linear(64, num_classes) # 64是conv3的输出通道数,也是GAP后的特征维度 def _calculate_conv_output_dim(self, length): """辅助函数,计算卷积池化后的特征长度""" # 模拟数据流经各层 x = torch.zeros(1, 1, length) x = self.pool1(F.relu(self.bn1(self.conv1(x)))) x = self.pool2(F.relu(self.bn2(self.conv2(x)))) x = self.pool3(F.relu(self.bn3(self.conv3(x)))) self._to_linear = x.shape[2] # 获取最终的特征图长度 print(f"卷积层输出特征图长度: {self._to_linear}") def forward(self, x, return_features=False): """ 前向传播 Args: x: 输入张量 (batch_size, 1, signal_length) return_features: 如果为True,返回特征向量而非分类结果 """ # 卷积块1 x = F.relu(self.bn1(self.conv1(x))) x = self.pool1(x) # 卷积块2 x = F.relu(self.bn2(self.conv2(x))) x = self.pool2(x) # 卷积块3 x = F.relu(self.bn3(self.conv3(x))) x = self.pool3(x) # 全局平均池化,得到特征向量 (batch_size, channels, 1) -> (batch_size, channels) features = self.gap(x).squeeze(-1) # 形状: (batch_size, 64) if return_features: return features # 返回特征向量,用于SVM else: # 如果使用CNN直接分类,则通过全连接层 out = self.fc(features) return out # 实例化模型 input_len = 1024 num_classes = 4 # 假设有4种健康状态 model = CNN1D_FeatureExtractor(input_length=input_len, num_classes=num_classes) print(model)

网络设计要点解析

  1. 输入形状:PyTorch的Conv1d期望输入形状为(batch_size, channels, length)。我们的振动信号是单通道,所以channels=1
  2. 卷积核大小与步长:第一层使用较大的卷积核(如64),大感受野有助于捕捉信号中较宽范围的模式(可能对应故障冲击)。后续层卷积核逐渐减小,以捕捉更精细的特征。步长(stride)用于降维。
  3. 批量归一化(BatchNorm):每个卷积层后接BatchNorm层,它可以加速训练、提升模型稳定性并有一定正则化效果,对于深层网络尤其重要。
  4. 激活函数:使用ReLU,因其计算简单且能缓解梯度消失问题。
  5. 池化层:使用最大池化(MaxPooling)进行下采样,逐步减少特征图的长度,增加后续层的感受野,同时提供一定的平移不变性。
  6. 全局平均池化(GAP):这是关键一步。传统做法是将特征图展平后接全连接层,但这会引入大量参数。GAP将每个通道的特征图平均为一个值,直接输出一个(batch_size, channels)的特征向量。这大大减少了参数量,降低了过拟合风险,并且使网络对输入长度的变化更具鲁棒性。
  7. 计算特征图长度_calculate_conv_output_dim函数非常重要。它通过模拟前向传播,计算出经过所有卷积和池化层后特征图的最终长度,从而确保网络架构与输入尺寸匹配。如果输入长度改变,这个值需要重新计算。

4.2 使用CNN提取深度特征

模型定义好后,我们需要用训练数据来训练这个CNN。但我们的目标不是用它的最后一层(self.fc)直接分类,而是训练它成为一个优秀的特征提取器。

训练CNN(特征提取器模式): 我们仍然使用分类任务来训练CNN,因为分类损失(如交叉熵)会驱动网络学习到对区分不同故障类别有用的特征。训练完成后,我们“砍掉”最后的全连接层(self.fc),用forward(x, return_features=True)来提取特征向量。

import torch.optim as optim from torch.utils.data import DataLoader, TensorDataset # 1. 将NumPy数据转换为PyTorch张量,并调整维度以适应CNN输入 (batch, channel, length) X_train_tensor = torch.FloatTensor(X_train).unsqueeze(1) # 增加通道维度 y_train_tensor = torch.LongTensor(y_train) X_val_tensor = torch.FloatTensor(X_val).unsqueeze(1) y_val_tensor = torch.LongTensor(y_val) # 创建数据加载器 train_dataset = TensorDataset(X_train_tensor, y_train_tensor) train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True) val_dataset = TensorDataset(X_val_tensor, y_val_tensor) val_loader = DataLoader(val_dataset, batch_size=64, shuffle=False) # 2. 定义损失函数和优化器 device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') model.to(device) criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(model.parameters(), lr=0.001) # Adam优化器是首选 # 3. 训练循环(简化版,实际需添加验证和早停逻辑) num_epochs = 50 for epoch in range(num_epochs): model.train() running_loss = 0.0 for batch_x, batch_y in train_loader: batch_x, batch_y = batch_x.to(device), batch_y.to(device) optimizer.zero_grad() outputs = model(batch_x, return_features=False) # 训练时用分类输出 loss = criterion(outputs, batch_y) loss.backward() optimizer.step() running_loss += loss.item() # 每个epoch后在验证集上评估 model.eval() val_correct = 0 val_total = 0 with torch.no_grad(): for batch_x, batch_y in val_loader: batch_x, batch_y = batch_x.to(device), batch_y.to(device) outputs = model(batch_x, return_features=False) _, predicted = torch.max(outputs.data, 1) val_total += batch_y.size(0) val_correct += (predicted == batch_y).sum().item() val_acc = 100 * val_correct / val_total print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {running_loss/len(train_loader):.4f}, Val Acc: {val_acc:.2f}%')

提取特征向量: 训练完成后,我们使用模型提取所有数据(训练、验证、测试)的特征表示。

def extract_features(model, data_loader, device): """使用训练好的CNN模型提取特征""" model.eval() features_list = [] labels_list = [] with torch.no_grad(): for batch_x, batch_y in data_loader: batch_x = batch_x.to(device) features = model(batch_x, return_features=True) # 关键:返回特征 features_list.append(features.cpu().numpy()) labels_list.append(batch_y.numpy()) return np.vstack(features_list), np.hstack(labels_list) # 为所有数据集创建加载器(无需打乱) train_loader_full = DataLoader(train_dataset, batch_size=64, shuffle=False) val_loader_full = DataLoader(val_dataset, batch_size=64, shuffle=False) test_dataset = TensorDataset(torch.FloatTensor(X_test).unsqueeze(1), torch.LongTensor(y_test)) test_loader_full = DataLoader(test_dataset, batch_size=64, shuffle=False) # 提取特征 X_train_features, y_train_f = extract_features(model, train_loader_full, device) X_val_features, y_val_f = extract_features(model, val_loader_full, device) X_test_features, y_test_f = extract_features(model, test_loader_full, device) print(f"特征维度: {X_train_features.shape}") # 应为 (n_samples, 64)

现在,我们得到了一个维度为64(对应CNN最后一个卷积层的通道数)的深度特征向量,它比原始的1024维信号要紧凑得多,并且包含了丰富的、与故障相关的信息。

4.3 SVM分类器的训练与调优

有了高质量的特征,SVM的训练就相对直接了。我们使用scikit-learn库。

from sklearn.svm import SVC from sklearn.metrics import accuracy_score, classification_report, confusion_matrix import seaborn as sns import matplotlib.pyplot as plt # 1. 训练SVM # 首先在训练特征上训练,用验证特征调整超参数 svm_model = SVC(kernel='rbf', C=1.0, gamma='scale', random_state=42) # 初始参数 svm_model.fit(X_train_features, y_train_f) # 2. 在验证集上评估,并调优 val_pred = svm_model.predict(X_val_features) val_accuracy = accuracy_score(y_val_f, val_pred) print(f"验证集准确率 (初始): {val_accuracy:.4f}") # 3. 超参数调优(使用网格搜索) from sklearn.model_selection import GridSearchCV # 定义参数网格 param_grid = { 'C': [0.1, 1, 10, 100], 'gamma': ['scale', 'auto', 0.001, 0.01, 0.1], 'kernel': ['rbf', 'linear'] # 也可以尝试poly } # 使用验证集进行网格搜索(小规模数据可直接用,大数据建议用交叉验证) grid_search = GridSearchCV(SVC(random_state=42), param_grid, cv=3, scoring='accuracy', n_jobs=-1, verbose=1) # 注意:这里用训练+验证特征合并来搜索,更严谨的做法是使用交叉验证,但为简化示例 X_trainval_features = np.vstack([X_train_features, X_val_features]) y_trainval_f = np.hstack([y_train_f, y_val_f]) grid_search.fit(X_trainval_features, y_trainval_f) print(f"最佳参数: {grid_search.best_params_}") print(f"最佳交叉验证分数: {grid_search.best_score_:.4f}") # 4. 用最佳模型在测试集上进行最终评估 best_svm = grid_search.best_estimator_ test_pred = best_svm.predict(X_test_features) test_accuracy = accuracy_score(y_test_f, test_pred) print(f"\n=== 最终测试集性能 ===") print(f"准确率: {test_accuracy:.4f}") print("\n分类报告:") print(classification_report(y_test_f, test_pred, target_names=['正常', '内圈', '外圈', '滚动体'])) # 根据实际标签名称修改 # 5. 绘制混淆矩阵 cm = confusion_matrix(y_test_f, test_pred) plt.figure(figsize=(8,6)) sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=['正常', '内圈', '外圈', '滚动体'], yticklabels=['正常', '内圈', '外圈', '滚动体']) plt.ylabel('真实标签') plt.xlabel('预测标签') plt.title('混淆矩阵 - 测试集') plt.show()

SVM关键参数解析

  • C (正则化参数): 控制误分类的惩罚力度。C值越大,对误分类的容忍度越低,决策边界越复杂,容易过拟合;C值越小,允许更多的误分类,决策边界更平滑,可能欠拟合。
  • gamma (RBF核参数): 定义了单个训练样本的影响范围。gamma值越大,影响范围越小,决策边界越曲折,容易过拟合;gamma值越小,影响范围越大,决策边界越平滑。‘scale’‘auto’是自动计算gamma的选项。
  • kernel (核函数): 对于线性可分或近似可分的数据,线性核(‘linear’)效率高且可解释性强。对于复杂的非线性问题,径向基函数核(‘rbf’)是最常用的选择。多项式核(‘poly’)也有其应用场景。

通过网格搜索,我们可以找到最适合当前特征数据的Cgamma组合,从而最大化SVM的分类性能。

5. 模型评估、对比与优化思路

得到一个测试集准确率数字并不是终点。我们需要深入分析模型的表现,理解其优缺点,并探索可能的优化方向。

5.1 性能评估与误差分析

除了整体的准确率,我们更应关注混淆矩阵分类报告(精确率、召回率、F1-score)。

  • 混淆矩阵:直观显示每个类别被正确分类和误分类的情况。例如,你可能发现“外圈故障”容易被误判为“正常”,这可能是因为外圈故障的冲击信号在某些负载下不够明显,或者样本中该故障类型的数据质量较差。
  • 精确率 (Precision):在所有被预测为某类的样本中,真正属于该类的比例。高精确率意味着模型对该类的预测“很准”,假阳性少。
  • 召回率 (Recall):在所有真实属于某类的样本中,被模型正确预测出来的比例。高召回率意味着模型对该类的“检出率”高,假阴性少。
  • F1-Score:精确率和召回率的调和平均数,是综合衡量指标。

通过分析这些指标,我们可以定位模型的薄弱环节。例如,如果某个故障类别的召回率很低,说明模型经常漏检这种故障,这是非常危险的。我们需要回溯数据,检查是否该类样本数量过少(类别不平衡),或者其特征与其他类别过于相似。

5.2 与基线模型对比

为了体现“1D-CNN+SVM”架构的优越性,我们应该与一些基线方法进行对比:

  1. 传统特征 + SVM:使用手工提取的时域(均值、方差、峭度、峰值因子等)、频域(频谱重心、均方频率等)特征,组合成特征向量,输入相同的SVM进行分类。对比结果可以直观展示1D-CNN自动学习特征的优势。
  2. 纯1D-CNN (Softmax分类):使用我们搭建的CNN,但保留最后的全连接层,直接用交叉熵损失进行端到端的训练和分类。对比可以验证“CNN特征+SVM”是否在小样本上优于纯深度模型。
  3. 其他分类器:将CNN提取的特征输入随机森林(Random Forest)、梯度提升树(XGBoost)等分类器,比较不同分类器的性能。

通常,你会发现“1D-CNN+SVM”的组合在准确率和稳定性上具有优势,尤其是在训练样本有限的情况下。

5.3 模型优化与进阶思路

如果对现有模型性能不满意,可以从以下几个方向进行优化:

1. 数据层面:

  • 数据增强:对于振动信号,可以在时域添加轻微的高斯噪声、进行随机缩放(振幅缩放)、时间偏移(小范围的裁剪和填充)等,以增加数据的多样性,提升模型鲁棒性。但需谨慎,避免破坏故障冲击的周期性。
  • 解决类别不平衡:如果某些故障类型的数据远少于其他类型,可以使用过采样(如SMOTE)、欠采样或为损失函数添加类别权重(nn.CrossEntropyLoss(weight=class_weights))等方法。
  • 更精细的样本分割:调整滑动窗口的长度和重叠步长。窗口太短可能包含不完整的故障信息,太长则可能引入过多噪声并减少样本数量。可以尝试与轴承的旋转频率对齐。

2. 模型架构层面:

  • 更深的网络:尝试使用ResNet-1D、Inception-1D等更先进的架构,它们通过残差连接等机制缓解了深层网络的梯度消失问题,可能学习到更强大的特征。
  • 注意力机制:在CNN中引入注意力模块(如SENet, CBAM),让网络学会“关注”信号中与故障最相关的部分,抑制无关噪声。
  • 多尺度特征融合:使用不同大小的卷积核并行提取多尺度特征,然后进行融合,以同时捕捉故障的宏观和微观模式。

3. 训练策略层面:

  • 学习率调度:使用torch.optim.lr_scheduler中的ReduceLROnPlateauCosineAnnealingLR等,在训练过程中动态调整学习率,有助于跳出局部最优,提升模型精度。
  • 早停 (Early Stopping):监控验证集损失,当其在连续多个epoch不再下降时停止训练,防止过拟合。
  • 标签平滑 (Label Smoothing):在计算交叉熵损失时,对真实标签进行平滑处理,可以减轻模型过拟合和过度自信的问题。

4. 融合其他信息:

  • 多传感器数据融合:除了驱动端振动信号,还可以融合风扇端振动信号、声音信号、温度信号等,构建多通道输入(对应CNN的in_channels),让模型获得更全面的信息。
  • 时频图像输入:将一维振动信号通过连续小波变换(CWT)或短时傅里叶变换(STFT)转换为二维时频图,然后使用经典的2D-CNN(如ResNet)进行处理。这相当于将时频分析的过程也交给网络学习。

6. 部署考量与常见问题排查

一个在测试集上表现良好的模型,最终要走向实际应用,还会面临诸多挑战。

6.1 模型轻量化与部署

工业现场的计算资源可能有限。我们需要考虑模型的轻量化:

  • 模型剪枝:移除网络中不重要的连接或通道。
  • 量化:将模型权重从32位浮点数转换为8位整数,大幅减少模型体积和推理时间。
  • 知识蒸馏:用一个大模型(教师模型)训练一个小模型(学生模型),让小模型模仿大模型的行为。
  • 使用移动端推理框架:如PyTorch Mobile、TensorFlow Lite,将模型部署到边缘设备(如工控机、嵌入式系统)上。

6.2 实际应用中的挑战与对策

  1. 工况变化:训练数据可能是在特定转速、负载下采集的,而实际设备工况会变化。这会导致模型性能下降。

    • 对策:收集更多不同工况下的数据用于训练。或者采用迁移学习,先在大型公开数据集上预训练特征提取器,再用目标工况的小数据微调。也可以研究领域自适应方法。
  2. 噪声干扰:工业现场环境嘈杂,振动信号中混有大量非故障相关的噪声(如电机电磁噪声、齿轮啮合振动、背景振动)。

    • 对策:在数据预处理阶段加入有效的去噪环节,如小波阈值去噪、变分模态分解(VMD)等。也可以尝试让CNN在训练时接触带噪声的数据,增强其抗噪能力。
  3. 未知故障:模型只能识别训练集中出现过的故障类型。对于全新的、未知的故障,它可能会错误地归类为已知类别。

    • 对策:在系统中引入异常检测机制。例如,可以训练一个仅针对正常数据的自编码器(Autoencoder)或一类SVM(One-Class SVM)。当输入信号的重构误差或异常分数超过阈值时,即使分类模型给出了一个结果,也将其标记为“未知异常”,触发人工检查。

6.3 常见错误与排查清单

在项目实现过程中,你可能会遇到以下问题:

问题现象可能原因排查与解决思路
训练准确率高,验证/测试准确率极低严重的过拟合。1. 检查是否误将测试集数据用于了标准化器的fit(数据泄露)。
2. 增加Dropout层、L2正则化、或使用更强的数据增强。
3. 简化模型结构(减少层数、通道数)。
4. 收集更多训练数据。
训练损失不下降,准确率徘徊在随机猜测水平模型没有学到任何有效特征。1. 检查数据预处理是否正确,特别是标准化步骤。
2. 检查输入数据的维度和模型期望的维度是否匹配((batch, channel, length))。
3. 学习率可能太大或太小,尝试调整学习率。
4. 检查网络结构,特别是卷积后特征图尺寸计算是否正确(是否被池化到0?)。
5. 检查标签是否正确对应。
SVM训练或预测速度非常慢1. 特征维度仍然较高。
2. 使用了kernel='rbf'且数据量大。
3.Cgamma参数设置不当。
1. 考虑在CNN的GAP层之前增加一个卷积层,进一步降低特征维度(如从64降到32)。
2. 对于大数据集,考虑使用线性核(kernel='linear'),或使用SVC的近似算法(如设置cache_size)。
3. 使用LinearSVC替代SVC(kernel='linear'),通常更快。
混淆矩阵显示某一类始终分错类别不平衡或该类特征不明显。1. 查看该类样本数量是否远少于其他类。
2. 可视化该类样本的特征(如用t-SNE降维后观察),看是否与其他类严重重叠。
3. 为该类在损失函数中设置更高的权重,或对该类数据进行过采样。
模型在真实设备上表现糟糕领域分布差异。真实数据与训练数据分布不同。1. 进行领域适配:在真实设备上收集少量带标签数据,对CNN特征提取器进行微调(Fine-tuning)。
2. 重新审视数据预处理流程,确保与训练时一致(如相同的采样频率、滤波方式)。

这个基于1D-CNN和SVM的滚动轴承故障诊断项目,从理论到实践,涵盖了数据、模型、训练、评估和部署的完整链条。它不仅仅是一个算法练习,更是一个通向工业智能运维的实用桥梁。在实际操作中,最大的挑战往往不是模型本身,而是数据的质量、对业务的理解以及将模型与现有系统无缝集成。希望这份详细的拆解和记录,能为你提供扎实的参考,助你少走弯路,更快地构建出属于自己的、可靠的设备健康“听诊器”。

本文还有配套的精品资源,点击获取

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

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

立即咨询