基于卷积神经网络(CNN)的轴承剩余寿命预测
前言
本文主要介绍了一种基于卷积神经网络(CNN)的轴承剩余使用寿命预测模型,模型使用轴承运行所产生的振动数据作为研究对象,通过学习其与轴承剩余使用寿命(RUL)的对应关系,构建端到端预测模型,进行轴承RUL预测。在PHM2012的数据集上进行的实验。
提示:模型基于python语言编写,运行整体程序需要pandas、numpy、Matplotlib等第三方库
一、模型介绍
考虑到轴承振动信号为一维时序特性,因此选择一维卷积神经网络(1D-CNN)作为特征提取模块,提取振动信号所包含的退化信息。在完成特征提取后,使用全连接计算对卷积神经网络提取的特征信息进行学习,输出对应时间的轴承剩余使用寿命。
1.1 1D-CNN
1D-CNN主要包括卷积层、激活成、池化层等;
卷积层:接收一维序列数据作为模型的输入。使用一维卷积核对输入序列进行卷积操作,以提取局部特征。
激活层:对提取特征进行非线性变换,增强模型的表达能力。
池化层:用于对卷积层的输出进行下采样,以减少数据的维度和冗余信息,减少计算量,同时提高模型的鲁棒性和泛化能力。
1D-CNN结构图
1D-CNN代码
class 1D_CNN(nn.Module):
# 定义卷积层
def __init__(self,in_channels,out_channels,kernel_size):
super(1D_CNN, self).__init__()
self.padding = kernel_size//2
self.conv1 = nn.Conv1d(in_channels,out_channels,kernel_size,padding=self.padding)
self.pool = nn.MaxPool1d(kernel_size=4, stride=4)
self.relu = nn.ReLU()
def forward(self, x):
x = self.conv1(x)
x = self.relu(x)
x = self.pool(x)
return x
1.2 全连接神经网络
全连接网络位于卷积网络的最后部分,用于对卷积层和池化层提取的特征进行全局分析。它使用卷积神经网络提取的特征生成对应的剩余使用寿命,实现轴承剩余使用寿命的预测。全连接神经网络主要包括:全连接层、激活层、dropout层等。
全连接层:对输入特征进行全连接计算;
激活层:对特征进行激活操作;
dropout层:对神经元进行灭活。
全连接神经网络
MLP代码
# 定义全连接层
class FC(nn.Module):
def __init__(self,in_features,out_features):
super(FC, self).__init__()
self.in_features = in_features
self.out_features = out_features
self.fc1 = nn.Linear(in_features,out_features)
self.relu = nn.ReLU()
self.dropout = nn.Dropout(p=0.5)
def forward(self, x):
x = self.fc1(x)
x = self.relu(x)
x = self.dropout(x)
return x
二、实验分析
2.1 数据处理
实验采用PHM2012数据集,选择水平振动信号作为研究对象,进行实验。数据处理包括:2.1.1数据读取;2.1.2时间步划分;2.1.3 时序样本构建
2.1.1 数据读取
为了方便了解数据,首先对实验周轴承的全生命周期振动数据进行读取,绘制时域图观察。
可以看出,不同轴承的振动退化数据数据具有比较大差异。
2.1.2 时间步划分,
为了方便模型对轴承退化信息进行学习,同时推进实际工程应用价值,对轴承全生命周期正东数据进行时间步划分,并构建对应时间步的RUL。并对单个时间步的振动数据进行归一化处理。
2.1.3 时序样本构建
为了使得输入样本具有时序性,本文在时间维度将相邻时间不的样本进行拼接,并将最后一个时间步的RUL作为该时序样本的剩余使用寿命,方便模型对轴承退化时序信息的挖掘。
2.2 实验部分
为了充分验证所提模型的有效性,采用PHM数据集轴承1~1至轴承1-7作为实验对象,采用交叉验证的方法进行实验。
训练代码如下:
# 主训练函数
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
from matplotlib import pyplot as plt
from dataprocess import load_data,data_preprocess,Sequential_Dataset
from help import Predictor,train_epoch,test_epoch,model_of_predict,sort_results
device = torch.device("cuda:0")
# 数据读取、处理
data_name = "PHM2012"
data_direction = "horiz"
SEQ_LEN = 8
train_bearing = ["Bearing1_2.pkl", "Bearing1_3.pkl", "Bearing1_4.pkl", "Bearing1_5.pkl", "Bearing1_6.pkl", "Bearing1_7.pkl"]
train_data = []
train_bearings = []
for sub_bearing in train_bearing:
bearing_name = sub_bearing
data_h, data_v = load_data(data_name, bearing_name)
step_data = data_preprocess(data_h, data_v, data_name=data_name, data_direction=data_direction, normalize=False)
train_data.append(step_data)
train_bearings.append(bearing_name)
print("训练轴承:", train_bearings)
# 将数据拼接为时序样本
train_samples = []
the_number_of_train_samples = 0
for sub_train_data in train_data:
num_steps = sub_train_data["x"].shape[0]
num_samples = num_steps - SEQ_LEN + 1
train_indices = np.random.permutation(num_samples)
train_indices = train_indices[0:]
train_sample = Sequential_Dataset(sub_train_data, train_indices, SEQ_LEN)
train_samples.append(train_sample)
the_number_of_train_samples += num_samples
# print(f"训练轴承{i+1}:,样本数量{num_samples}")
print(f"训练样本总数:{the_number_of_train_samples}")
from torch.utils.data import ConcatDataset
from torch.utils.data import DataLoader
from torch.utils.data import random_split
train_batch_size = 16
val_batch_size = 16
train_combined_dataset = ConcatDataset(train_samples) # 将子数据集拼接为一个数据集 让样本混合的更加彻底
train_ratio = 0.8
train_size = int(train_ratio * len(train_combined_dataset))
val_size = len(train_combined_dataset) - train_size
train_dataset, val_dataset = random_split(train_combined_dataset, [train_size, val_size])
train_dataloader = DataLoader(train_dataset, batch_size=train_batch_size, shuffle=True)
print(len(train_dataloader))
val_dataloader = DataLoader(val_dataset, batch_size=val_batch_size, shuffle=True)
print(len(val_dataloader))
# 实例化模型
in_channels = 1*SEQ_LEN # if data_direction == "horiz" or "vert" else 2
out_channels = [16,32,64]
kernel_size = [3,3,3,3]
in_features = int(out_channels[-1]*2560/(4**len(out_channels)))
out_features = [640,320,64,1]
model = Predictor(in_channels=in_channels, out_channels=out_channels, kernel_size=kernel_size,
in_features=in_features,out_features=out_features).to(device)
# 定义损失函数和优化器
criterion = nn.MSELoss(reduction='sum')
optimizer = optim.Adam(model.parameters(), lr=0.001, betas=(0.9, 0.999), eps=1e-08, amsgrad=False)
multistep_lr_sch = optim.lr_scheduler.MultiStepLR(optimizer, milestones=[20, 40, 50], gamma=0.1, last_epoch=-1,verbose = False)
num_epochs = 100
losses = []
best_val_loss = 1
for epoch in range(num_epochs):
train_loss = train_epoch(model, train_dataloader, criterion, optimizer, device)
val_loss = test_epoch(model, val_dataloader, criterion, device)
print(f'{epoch + 1}/{num_epochs}: train_loss = {train_loss:.4f}, val_loss = {val_loss:.4f})
losses.append([train_loss, val_loss])
plt.plot(range(len(losses)), [l[0] for l in losses], 'b.-', label='train loss')
plt.plot(range(len(losses)), [l[1] for l in losses], 'r.-', label='val loss')
plt.legend()
plt.show()
损失下降曲线
2.3 训练后模型预测效果
提示:上图为轴承1-1预测效果,考虑篇幅,其余轴承预测效果不在此处进行展示。
总结
上述即为基于1DCNN通过轴承运行过程产生振动数据对其轴承剩余使用寿命预测的主体流程。以后还会更新其他PHM领域的相关问题。