基于融合CNN(2D-CNN与1D-CNN融合)与SVM的滚动轴承故障诊断

本博客来源于优快云机器鱼,未同意任何人转载。

更多内容,欢迎点击本专栏,查看更多内容。

目录

0 引言

1 模型结构

2 数据准备

3 特征可视化

4 SVM故障诊断

5 结语


0 引言

这个博客的目的不是为了验证模型的优越性,而是为了灌水。如果非要给个理由,可以假把意思说我们将1*1024的时域振动信号reshape成32*32的数据矩阵,再采用两个CNN分支分别提取特征并进行特征融合,模型不仅能学习到时间上,还能学习到空间上的特征。

实际上是受多模态与双流CNN的启发,利用不同分支输入表征同一事物的不同数据源,可以更好的提高精度。但我这轴承数据也没有其他数据源,所以简单粗暴的将1*1024的reshape成32*32输入2DCNN分支,1*1024输入1DCNN分支。

1 模型结构

本博客将2D-CNN与1D-CNN融合,同时对轴承数据集进行特征提取,然后在汇聚层将两者池化层的输出concat连接成一个向量,送进全连接层。模型训练结束之后,取FC层的输出作为提取到的故障特征信号。为什么不直接采用最终的分类层做十分类,主要是我以前做过测试,针对样本比较少的情况下,采用CNN的倒数第某个全连接层的输出来做SVM分类建模,比直接CNN分类层的分类效果好,如果样本多就直接用CNN的分类层做分类效果更好。

融合CNN的结构图如图所示:

2 数据准备

采用凯斯西储轴承数据集,OHP下48k采样频率驱动端的数据,我用的数据集可以在【博客】里找到,对于10类故障(1正常,9故障),分别采集200组样本,共2000组,采样点为1024。然后按7:2:1划分训练集、验证集与测试集。

#coding:utf-8
from scipy.io import loadmat,savemat
import numpy as np
import os
from sklearn import preprocessing  # 0-1编码

def capture(original_path):
    """读取mat文件,返回字典
    :param original_path: 读取路径
    :return: 数据字典
    """
    # 获得该文件夹下所有.mat文件名
    filenames = os.listdir(d_path)
    files = {}
    n=0
    for i in filenames:
        # 文件路径
        file_path = os.path.join(d_path, i)
        print(file_path,'为第',n,'类')
        n += 1
        file = loadmat(file_path)
        file_keys = file.keys()
        for key in file_keys:
            if 'DE' in key:
                files[i] = file[key].ravel()
    return files

def slice_enc(data,number=200,length=1024):
    """
    每个样本的长度为length 每类各number个样本
    """
    keys = data.keys()
    labels,samples=[],[]
    n=0
    for i in keys:
        slice_data = data[i]
        for j in range(number):
            random_start = np.random.randint(low=0, high=(len(slice_data) - length))
            sample = slice_data[random_start:random_start + length]
            labels.append(n)    
            samples.append(sample)
        n += 1
    samples,lables=np.array(samples),np.array(labels)
    return samples,lables 


# 按rate中的比例划分训练集 验证集与测试集,比例相加为1
def train_valid_test_slice(data, labels,rate):
    
    nsamples=data.shape[0]
    index=np.arange(nsamples)
    np.random.shuffle(index)
    m1=int(nsamples*rate[0])
    m2=int(nsamples*(rate[0]+rate[1]))
    train_X=data[index[:m1],:]
    train_Y=labels[index[:m1],]
    
    valid_X=data[index[m1:m2],:]
    valid_Y=labels[index[m1:m2],]
    
    test_X=data[index[m2:],:]
    test_Y=labels[index[m2:],]    
    return train_X,train_Y,valid_X, valid_Y, test_X, test_Y
if __name__ == "__main__":
    d_path='0HP/'
    # 从所有.mat文件中读取出数据的字典
    data = capture(original_path=d_path)
    # 将数据切分为需要的样本
    data, labels = slice_enc(data,number=500,length=1024)

    
    # 将数据划分训练,验证集,测试集
    train_X,train_Y,valid_X, valid_Y, test_X, test_Y =\
        train_valid_test_slice(data, labels,rate=[0.7, 0.2, 0.1])
    
    savemat("result/data_process.mat", {'train_X': train_X,'train_Y': train_Y,
                                   'valid_X': valid_X,'valid_Y': valid_Y,
                                   'test_X': test_X,'test_Y': test_Y}) 

2 融合模型训练

基于tensorflow2.6.1深度学习框架搭建上图所示模型,模型参数有点出入,不想改visio的图,将就着看吧,代码如下:

# 融合CNN的tensorflow2实现
# coding: utf-8
# In[1]: 导入必要的库函数
import numpy as np
from scipy.io import loadmat,savemat
from sklearn.preprocessing import MinMaxScaler,StandardScaler
import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrix 
import seaborn as sns
from model import CNN_1D ,CNN_2D, CNN_fusion
from tensorflow.keras import Model
import tensorflow as tf
from tensorflow.keras.losses import SparseCategoricalCrossentropy
from tensorflow.keras.optimizers import Adam,SGD
tf.random.set_seed(0)
# In[] 加载数据
data=loadmat('result/data_process.mat')#这个是保存下来的原始数据
train_X=data['train_X']
train_Y=data['train_Y'].reshape(-1,)
valid_X=data['valid_X']
valid_Y=data['valid_Y'].reshape(-1,)
test_X=data['test_X']
test_Y=data['test_Y'].reshape(-1,)
ss=StandardScaler().fit(train_X)
train_X=ss.transform(train_X)
valid_X=ss.transform(valid_X)
test_X=ss.transform(test_X)
# In[] 搭建模型
mode='2d' # 选择 1d 2d 还是 fusion 对应1dcnn 2dcnn 与融合cnn
if mode=='1d':
    model= CNN_1D()
elif mode=='2d':
    model= CNN_2D()
elif mode=='fusion':
    model= CNN_fusion()


model.compile(optimizer=Adam(learning_rate=0.001),
              loss=SparseCategoricalCrossentropy(),
              metrics=['accuracy'])

# In[] 训练
train_again = True  # 为 False 的时候就直接加载训练好的模型进行测试
# 训练模型
if train_again:
    history = model.fit(train_X, train_Y, epochs=100,
                        validation_data=(valid_X, valid_Y),
                        batch_size=64, verbose=1)
    model.save('model/'+mode+'_model.h5')
    # 画loss曲线
    plt.figure()
    plt.ylabel('MSE')
    plt.xlabel('Epoch')
    plt.plot(history.history['loss'], label='training')
    plt.plot(history.history['val_loss'], label='validation')
    plt.title('loss curve')
    plt.legend()
    plt.savefig('result/'+mode+'_loss_curve.jpg')
else:  # 加载模型
    model = tf.keras.models.load_model('model/'+mode+'_model.h5')

test_pred = model.predict(test_X)
pred_labels = np.argmax(test_pred,1)
acc=np.sum(pred_labels==test_Y)/len(test_Y)
print('分类精度为:%f '%(acc*100),'%')
C1= confusion_matrix(test_Y, pred_labels)
print('混淆矩阵:')
print(C1)
xtick=[str(i) for i in range(10)]
ytick=[str(i) for i in range(10)]

plt.figure()
C2=C1/C1.sum(axis=1)
sns.heatmap(C2,fmt='g', cmap='Blues',annot=True,cbar=False,xticklabels=xtick, yticklabels=ytick)
plt.xlabel('Predict label')
plt.ylabel('True label')
plt.title('Confusion_matrix')
plt.savefig('result/'+mode+'_cm.jpg')


# In[] 特征提取
feature_model = Model(inputs=model.input,outputs=model.get_layer('feature').output)
train_feature = feature_model.predict(train_X)
valid_feature = feature_model.predict(valid_X)
test_feature = feature_model.predict(test_X)
savemat('result/'+mode+'data_feature.mat', {'train_X': train_feature,'train_Y': train_Y,
                                  'valid_X': valid_feature,'valid_Y': valid_Y,
                                  'test_X': test_feature,'test_Y': test_Y}) 

plt.show()  

其中model.py定义了网络结构,代码如下

# -*- coding: utf-8 -*-
from tensorflow.keras.layers import Conv1D,Conv2D, Dense, \
    MaxPool1D,MaxPool2D, concatenate, Flatten,Reshape
from tensorflow.keras import Input, Model


def CNN_fusion():
    inp= Input(shape=(1024), name='input1')
    input1_=Reshape((32, 32,1))(inp)
    input2_=Reshape((1024,1))(inp)
    #  2DCNN
    x1 = Conv2D(4, kernel_size=3, strides=1, activation='relu', padding='same')(input1_)
    x1 = MaxPool2D(pool_size=2, strides=2)(x1)
    x1 = Conv2D(8, kernel_size=3, strides=1, activation='relu', padding='same')(x1)
    x1 = MaxPool2D(pool_size=2, strides=2)(x1)
    x1 = Flatten()(x1)
    
    #    1DCNN
    x2 = Conv1D(4, kernel_size=16, strides=1, activation='relu', padding='same')(input2_)
    x2 = MaxPool1D(pool_size=2, strides=2)(x2)
    x2 = Conv1D(8, kernel_size=3, strides=1, activation='relu', padding='same')(x2)
    x2 = MaxPool1D(pool_size=2, strides=2)(x2)
    x2 = Flatten()(x2)
    
    # 合并两个通道的CNN结果
    x = concatenate([x1, x2])
    x = Dense(128, activation='sigmoid', name='feature')(x)
    output_ = Dense(10, activation='softmax', name='output')(x)
    model = Model(inputs=inp, outputs=output_)
    model.summary()
 
    return model

def CNN_1D():
    inp = Input(shape=(1024), name='input2')
    x=Reshape((1024,1))(inp)
    x = Conv1D(4, kernel_size=16, strides=1, activation='relu', padding='same')(x)
    x = MaxPool1D(pool_size=2, strides=2)(x)
    x = Conv1D(8, kernel_size=3, strides=1, activation='relu', padding='same')(x)
    x = MaxPool1D(pool_size=2, strides=2)(x)
    x = Flatten()(x)
    
    
    x = Dense(128,activation='sigmoid', name='feature')(x)
    output_ = Dense(10, activation='softmax', name='output')(x)
    model = Model(inputs=inp, outputs=output_)
    model.summary()
    return model
def CNN_2D():
    
    inp = Input(shape=(1024), name='input3')
    x=Reshape((32,32,1))(inp)
    x = Conv2D(4, kernel_size=3, strides=1, activation='relu', padding='same')(x)
    x = MaxPool2D(pool_size=2, strides=2)(x)
    x = Conv2D(8, kernel_size=3, strides=1, activation='relu', padding='same')(x)
    x = MaxPool2D(pool_size=2, strides=2)(x)
    x = Flatten()(x)
    
    x = Dense(128, activation='sigmoid',name='feature')(x)
    output_ = Dense(10, activation='softmax', name='output')(x)
    model = Model(inputs=inp, outputs=output_)
    model.summary()
 
    return model

训练结束之后,分别输入训练集、验证集、与测试集。采集FC层的输出作为最终的提取到的特征保存到mat文件中。

3 特征可视化

将提取的特征进行二维可视化,从图像上可以看出,经CNN学习之后,不同类数据的类间区分度明显增加

# -*- coding: utf-8 -*-
from scipy.io import loadmat
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler,MinMaxScaler
from sklearn.manifold import TSNE
from sklearn.decomposition import PCA
from mpl_toolkits.mplot3d import Axes3D

# In[] 加载数据
data=loadmat('result/data_process.mat')#这个是保存下来的原始数据
input_data=data['test_X']
label=data['test_Y'].reshape(-1,)

# In[] #原始数据可视化
#method=TSNE(n_components=3)
method=PCA(n_components=3)
feature0=method.fit_transform(input_data) 
colors = ['black', 'blue', 'purple', 'yellow', 'cadetblue', 'red', 'lime', 'cyan', 'orange', 'gray']

plt.figure()
ax = plt.axes(projection='3d')  # 设置三维轴
for i in range(len(colors)):
    ax.scatter3D(feature0[:, 0][label==i], feature0[:, 1][label==i],feature0[:, 2][label==i], c=colors[i],label=str(i))
#    ax.text(np.mean(feature0[:, 0][label==i]), np.mean(feature0[:, 1][label==i]),np.mean(feature0[:, 2][label==i]), str(i))
plt.legend()
plt.title('original data')
plt.savefig('result/original data可视化.jpg')

# In[] 特征数据可视化
mode='fusion' # 选择 1d 2d 还是 fusion 对应尽1dcnn 2dcnn 与融合cnn
data=loadmat('result/'+mode+'data_feature.mat')#这个是保存下来的原始数据
input_data=data['test_X']
label=data['test_Y'].reshape(-1,)

feature1=method.fit_transform(input_data) 

plt.figure()
ax = plt.axes(projection='3d')  # 设置三维轴
for i in range(len(colors)):
    ax.scatter3D(feature1[:, 0][label==i], feature1[:, 1][label==i],feature1[:, 2][label==i], c=colors[i],label=str(i))
    
plt.legend()
plt.title('feature data')
plt.savefig('result/'+mode+'可视化.jpg')
plt.show()

4 SVM故障诊断

将3提取的特征采用SVM进行分类,本文采用SVM对2中采集到的特征进行最后的分类,核函数RBF,惩罚参数1,核参数0.01。

# -*- coding: utf-8 -*-
import numpy as np    
import matplotlib.pyplot as plt 
from sklearn import svm 
from scipy.io import loadmat
from sklearn.metrics import confusion_matrix
from sklearn.preprocessing import StandardScaler,MinMaxScaler

def plot_confusion_matrix(cm, labels_name, title):
    cm = cm.astype('float') / cm.sum(axis=1)# 归一化
    plt.figure()
    plt.imshow(cm, interpolation='nearest')    # 在特定的窗口上显示图像
    plt.colorbar()
    num_local = np.array(range(len(labels_name)))    
    plt.xticks(num_local, labels_name)    # 将标签印在x轴坐标上
    plt.yticks(num_local, labels_name)    # 将标签印在y轴坐标上
    plt.ylabel('True label')    
    plt.xlabel('Predicted label')
    plt.savefig('result/'+title+'confusion_matrinx_svm.jpg')
    plt.show()

# In[] 执行svm
# 加载数据
mode='fusion' # 选择 1d 2d 还是 fusion 对应尽1dcnn 2dcnn 与融合cnn
dataFile = 'result/'+mode+'data_feature.mat'
data = loadmat(dataFile)
train_X=data['train_X']
train_Y=data['train_Y'].reshape(-1,)
valid_X=data['valid_X']
valid_Y=data['valid_Y'].reshape(-1,)
test_X=data['test_X']
test_Y=data['test_Y'].reshape(-1,)


ss=MinMaxScaler().fit(train_X)
train_X=ss.transform(train_X)
valid_X=ss.transform(valid_X)
test_X=ss.transform(test_X)

clf = svm.SVC(C=1,gamma=0.01,kernel='rbf') 

clf.fit(train_X,train_Y)
y_predict1 = clf.predict(train_X)

# 训练分类正确率计算
acc=np.sum(y_predict1==train_Y)/len(train_Y)
print('训练集分类精度为:',acc*100,'%')


y_predict2 = clf.predict(valid_X)

# 验证分类正确率计算
acc=np.sum(y_predict2==valid_Y)/len(valid_Y)
print('验证集分类精度为:',acc*100,'%')

# 测试集分类正确率计算
y_predict = clf.predict(test_X)
acc=np.sum(y_predict==test_Y)/len(test_Y)
print('测试集分类精度为:',acc*100,'%')


print('混淆矩阵')
cm=confusion_matrix(test_Y,y_predict)
# print(cm)
for i in range(10):
    # 计算每一类的精确率,召回率,F1
    precise=cm[i,i]/sum(cm[:,i])
    recall=cm[i,i]/sum(cm[i,:])
    f1=2*precise*recall/(precise+recall)
    print('测试集中,第',i,
          '类样本的精确率:',precise,
          ' 召回率为:',recall,
          ' F1分数为:',f1)

#混淆矩阵
labels_name=['0','1','2','3','4','5','6','7','8','9']
plot_confusion_matrix(cm, labels_name, mode)

对比实验

在上面的程序中可以通过修改mode,分别采用1d-cnn、2d-cnn与融合CNN进行特征提取SVM分类,模型对比极其方便,结果就不放了。

    mode='fusion' # 选择 1d 2d 还是 fusion 对应尽1dcnn 2dcnn 与融合cnn
    dataFile = 'result/'+mode+'data_feature.mat'

结果当然融合cnn++svm最好啦。就算其他方法效果好,也要调低【手动滑稽】。

5 结语

球球不要问完整代码了,完整代码和数据上面都有,稍微有点动手能力就能成功运行,非要我打包压缩好的,可以见评论区。

更多内容请点击【专栏】获取,您的点赞与收藏是我更新Python神经网络1000案例分析的动力。

### 关于1D CNN架构图 一维卷积神经网络(Convolutional Neural Network, 1D CNN)是一种专门用于处理序列数据(如时间序列、语音信号等)的模型。其核心思想在于通过滑动窗口的方式提取局部特征,类似于二维卷积神经网络在图像上的操作[^2]。 #### 架构概述 1D CNN 的基本结构通常由以下几个部分组成: - **输入层**:接收一维向量作为输入。 - **卷积层**:利用多个滤波器扫描输入数据,生成特征映射。这些滤波器通常是小型的一维核函数(例如大小为3或5),并应用激活函数(如ReLU)来引入非线性特性。 - **池化层**(可选):减少空间维度,降低计算复杂度的同时保留重要特征。 - **全连接层**:将前面提取到的空间子结构转化为最终预测输出。 - **输出层**:提供分类标签或其他形式的结果。 尽管具体的实现细节可能因应用场景而异,但总体设计原则保持一致——即逐级抽象原始信号中的模式直至能够有效区分不同类别为止[^4]。 下面给出了一种典型的1D CNN架构示意代码: ```python from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Conv1D, MaxPooling1D, Flatten, Dense model = Sequential() # 添加第一个卷积层最大池化层 model.add(Conv1D(filters=64, kernel_size=3, activation='relu', input_shape=(n_timesteps,n_features))) model.add(MaxPooling1D(pool_size=2)) # 可以堆叠更多卷积+池化组合... # 展平三维张量至二维以便接入后续密集层 model.add(Flatten()) # 定义最后几层用来做回归或者多类别的softmax概率估计 model.add(Dense(50,activation="relu")) model.add(Dense(n_outputs,activation="sigmoid")) # 或者 softmax 如果是多分类问题的话 ``` 上述脚本展示了如何构建简单的单分支1DCNN模型;当然实际项目里还可以加入正则项防止过拟合现象发生以及调整超参数优化性能表现等等额外措施。 值得注意的是,在某些情况下单独使用CNN已经可以达到相当不错的效果,甚至媲美融合RNN/LSTM单元的方法。 ### 图形表示建议 虽然无法直接展示图片文件,但是可以根据以上描述自行绘制框图表达各组成部分之间的关系链路。另外也可以查阅公开资料获取现成的标准拓扑视图参考资料[^3]。
评论 41
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

机器鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值