故障诊断方向而言,无论是信号处理、特征提取、故障分类还是寿命预测,所有的方法实现基本都依靠于Python代码,很多小白遇到的第一个拦路虎便是代码环境的配置。
Pytorch是Python第三方库的一种,里面包含很多深度学习机器学习的函数,Pytorch本身有两个版本,一个是简便的CPU版本,一个是高速高效的GPU版本。另外代码编辑器可以直接用于编写、编辑和运行代码。它们提供了代码高亮、自动补全、代码调试、版本控制集成等功能,以提高开发效率和代码质量,也是故障诊断相关代码的必备工具之一。
本期给大家带来Pytorch环境(Anaconda)安装教程,并附带代码编辑器配置过程。每一部分内容都附带推荐的视频教程以及教程链接,保证每一位故障诊断学习者都能搭建自己的代码平台。此外,后续文章还手把手带大家跑通第一个故障诊断案例,代码包含数据处理,1DCNN模型搭建,模型训练,以及模型评估等故障诊断完整过程,特别适合研一、研二小白入门。
本期涉及代码非常详细,所占篇幅也非常多,所以分三次呈现给大家,第1篇文章主要介绍主要介绍了Python环境以及各个软件环境安装【初学者必看教程 | 手把手教你安装GPU版Pytorch环境及手把手带大家跑通第一个故障诊断案例!!!(上)】。第2篇文章主要介绍西储大学数据集以及一些所需深度学习基础知识,文章后半部分讲解了本期代码的数据预处理以及数据切割等部分【初学者必看教程| 手把手教你安装GPU版Pytorch环境及手把手带大家跑通第一个故障诊断案例!!!(中)】。本篇为第3篇文章主要构建1DCNN模型框架以及模型训练模型检测等内容。
1 引言
2 安装Anaconda
2.1 Anaconda介绍
2.2 Anaconda安装
3 配置Pytorch环境(CPU版)
3.1 Pytorch介绍
3.2 Pytorch配置教程(CPU版)
4 配置Pytorch环境(GPU版)
4.1 两种Pytorch区别(看是否支持GPU)
4.2 CUDA安装
4.3 Pytorch配置教程(GPU版)
5 配置代码编辑器
5.1 代码编辑器区别
5.2 VScode编辑器
5.3 Pycharm编辑器
5.4 JupyterNotebook编辑器
6 故障诊断代码示例 (重中之重)
6.1 代码介绍
6.2 检验Pytorch
6.3 故障诊断实战代码(模型构建及训练测试部分)
注:小编能力有限,如有不恰之处,请多多指正~
在学习故障诊断相关代码时,拥有一个强大且灵活的开发环境是至关重要的。Anaconda和Pytorch正是这样的工具,它们为我们提供了一个完整的生态系统,用于进行数据分析、模型训练和部署,是目前常用的工具软件资源。
import torch
from joblib import dump, load
import torch.utils.data as Data
import numpy as np
import pandas as pd
import torch
import torch.nn as nn
# 定义VGG-1D模型
class VGG1DModel(nn.Module):
#类定义和初始化
def __init__(self, batch_size, input_channels, conv_archs, num_classes):
super(VGG1DModel, self).__init__()
self.batch_size = batch_size
# CNN参数
self.conv_arch = conv_archs # 网络结构
self.input_channels = input_channels # 输入通道数
self.features = self.make_layers()
# 自适应平局池化 在这里做了改进,摒弃了 大参数量的三层全连接层,改为自适应平均池化来替代
self.avgpool = nn.AdaptiveAvgPool1d(1)#
# 定义全连接层
self.classifier = nn.Linear(conv_archs[-1][-1], num_classes)
# CNN卷积池化结构构建
def make_layers(self):
layers = []
for (num_convs, out_channels) in self.conv_arch:
for _ in range(num_convs):
layers.append(nn.Conv1d(self.input_channels, out_channels, kernel_size=3, padding=1))
layers.append(nn.ReLU(inplace=True))
self.input_channels = out_channels
layers.append(nn.MaxPool1d(kernel_size=2, stride=2))
return nn.Sequential(*layers)
#前向传播
def forward(self,input_seq): # torch.Size([32, 1024])
#改变输入形状,适应网络输入[batch,dim, seq_length]
input_seq = input_seq.view(self.batch_size, 1, 1024)
# 送入CNN网络模型
features = self.features(input_seq) # 调用,torch.Size([32, 128, 128])
# 自适应平均池化
x = self.avgpool(features) # ttorch.Size([32, 128, 1])
# 平铺
flat_tensor = x.view(self.batch_size, -1) # torch.Size([32, 128])
output = self.classifier(flat_tensor) # torch.Size([32, 10])
return output
(1) 类定义和初始化 __init__
batch_size:批次大小,表示每次训练时同时处理的数据样本数量。
input_channels:输入数据的通道数。对于一维数据,通常为 1。
conv_archs:CNN 网络结构的配置,是一个列表,其中每个元素是一个元组,指定了每个卷积块中卷积层的数量和输出通道数。
num_classes:输出的维度,即分类任务中的类别数。
self.batch_size:存储传入的参数batch_size,即每批次样本数量。
self.conv_arch :存储传入的参数conv_archs,即每个卷积块中卷积层的数量和输出通道数。
self.input_channels :存储传入的参数input_channels,即输入数据的通道数。
self.features:通过调用 self.make_layers() 方法构建 CNN 的卷积和池化层。
self.avgpool:定义一个自适应平均池化层,用于将特征图的空间维度压缩为1。
self.classifier:定义一个全连接层,用于将特征映射到输出类别。
(2) CNN 卷积池化结构构建 make_layers
作用:根据 conv_archs 和 input_channels 构建 CNN 的卷积和池化层。
遍历 conv_archs 中的每个元组,每个元组表示一个卷积块。对于每个卷积块,根据指定的卷积层数量和输出通道数,添加相应数量的卷积层 和 ReLU 激活层。在每个卷积块的末尾添加一个最大池化层,用于降低特征图的空间维度。
返回值:将构建的层组合成一个 nn.Sequential 模块并返回。
(3) 前向传播forward
(4) 模型实例化
#模型实例化
batch_size = 32
conv_archs = conv_archs = ((2, 32), (1, 64), (1, 128)) # vgg11
input_channels = 1 # 做 1 D卷积, 输入维度为1
num_classes = 10
model = VGG1DModel(batch_size, input_channels, conv_archs, num_classes)
batch_size = 32:批次大小为 32。
conv_archs = ((2, 32), (1, 64), (1, 128)):CNN 网络结构配置,表示有三个卷积块,第一个卷积块包含两个卷积层,输出通道数为 32;第二个卷积块包含一个卷积层,输出通道数为 64;第三个卷积块包含一个卷积层,输出通道数为 128。
input_channels = 1:输入通道数为 1,表示一维卷积。
num_classes = 10:输出类别数为 10。
print(model)#检查模型框架
图1 1DCNN模型结构
根据输出结果可以看出这个VGG1DModel是一个为一维数据设计的卷积神经网络模型,它由一系列卷积层、激活层、池化层以及最后的全连接层组成。模型的输入层接受单通道的一维数据,随后通过两个具有32个输出通道的卷积层,每个卷积层后面紧跟一个ReLU激活函数,用于增加非线性。接着是一个最大池化层,用于降低特征图的维度。然后,模型通过一个具有64个输出通道的卷积层,再次应用ReLU激活,随后是第二个最大池化层。接下来,模型通过一个具有128个输出通道的卷积层和第三个最大池化层,这之后是一个自适应平均池化层,将特征图的每个维度缩减到1。最后,一个全连接层将128个输入特征映射到10个输出类别,通常用于分类任务。整个网络结构旨在通过层层抽象提取一维数据的特征,并最终实现有效的分类。
6.3.3模型训练
# 训练模型
import time
import torch.nn.functional as F
import matplotlib
import matplotlib.pyplot as plt
matplotlib.rc("font", family='Microsoft YaHei')
def model_train(batch_size, epochs, train_loader, val_loader, model, optimizer, loss_function):
model = model.to(device)
# 定义损失函数和优化函数
loss_function = nn.CrossEntropyLoss(reduction='sum') # loss
learn_rate = 0.0003
optimizer = torch.optim.Adam(model.parameters(), learn_rate) # 优化器
# 样本长度
train_size = len(train_loader) * batch_size
val_size = len(val_loader) * batch_size
# 最高准确率 最佳模型
best_accuracy = 0.0
best_model = model
train_loss = [] # 记录在训练集上每个epoch的loss的变化情况
train_acc = [] # 记录在训练集上每个epoch的准确率的变化情况
validate_acc = []
validate_loss = []
# 计算模型运行时间
start_time = time.time()
for epoch in range(epochs):
# 训练
model.train()
loss_epoch = 0. #保存当前epoch的loss和
correct_epoch = 0 #保存当前epoch的正确个数和
for seq, labels in train_loader:
seq, labels = seq.to(device), labels.to(device)
# print(seq.size(), labels.size()) torch.Size([32, 7, 1024]) torch.Size([32])
# 每次更新参数前都梯度归零和初始化
optimizer.zero_grad()
# 前向传播
y_pred = model(seq) # torch.Size([16, 10])
# 对模型输出进行softmax操作,得到概率分布
probabilities = F.softmax(y_pred, dim=1)
# 得到预测的类别(最大概率的标签)
predicted_labels = torch.argmax(probabilities, dim=1)
# 与真实标签进行比较,计算预测正确的样本数量 # 计算当前batch预测正确个数
correct_epoch += (predicted_labels == labels).sum().item()
# 损失计算
loss = loss_function(y_pred, labels)
loss_epoch += loss.item()
# 反向传播和参数更新
loss.backward()
optimizer.step()
# break
# break
# 计算准确率
train_Accuracy = correct_epoch/train_size
train_loss.append(loss_epoch/train_size)
train_acc.append(train_Accuracy)
print(f'Epoch: {epoch+1:2} train_Loss: {loss_epoch/train_size:10.8f} train_Accuracy:{train_Accuracy:4.4f}')
# 每一个epoch结束后,在验证集上验证实验结果。
with torch.no_grad():
loss_validate = 0.
correct_validate = 0
for data, label in val_loader:
data, label = data.to(device), label.to(device)
pre = model(data)
# 对模型输出进行softmax操作,得到概率分布
probabilities = F.softmax(pre, dim=1)
# 得到预测的类别
predicted_labels = torch.argmax(probabilities, dim=1)
# 与真实标签进行比较,计算预测正确的样本数量 # 计算当前batch预测正确个数
correct_validate += (predicted_labels == label).sum().item()
loss = loss_function(pre, label)
loss_validate += loss.item()
# print(f'validate_sum:{loss_validate}, validate_Acc:{correct_validate}')
val_accuracy = correct_validate/val_size ''
print(f'Epoch: {epoch+1:2} val_Loss:{loss_validate/val_size:10.8f}, validate_Acc:{val_accuracy:4.4f}')
validate_loss.append(loss_validate/val_size)
validate_acc.append(val_accuracy)
# 如果当前模型的准确率优于之前的最佳准确率,则更新最佳模型
#保存当前最优模型参数
if val_accuracy > best_accuracy:
best_accuracy = val_accuracy
best_model = model# 更新最佳模型的参数
# 保存最后的参数
# torch.save(model, 'final_model_1dvgg.pt')
# 保存最好的参数
torch.save(best_model, 'best_model_1dvgg.pt')
print(f'\nDuration: {time.time() - start_time:.0f} seconds')
# 保存结果 方便 后续画图处理
dump(train_loss, 'train_loss')
dump(train_acc, 'train_acc')
dump(validate_loss, 'validate_loss')
dump(validate_acc, 'validate_acc')
print("best_accuracy :", best_accuracy)
# batch_size = 32
epochs = 50
# 模型训练
model_train(batch_size, epochs, train_loader, val_loader, model, optimizer, loss_function)
这段代码定义了一个 ’model_train‘的函数,用于训练一个深度学习模型。首先将模型移动到指定的设备上,计算训练集和验证集的样本总数,并初始化用于记录训练和验证过程中损失和准确率的列表以及存储最佳模型和最高准确率的变量。然后,在指定的训练轮数内,通过遍历训练数据加载器中的每个批次,进行前向传播、损失计算、反向传播和参数更新,同时记录每个 epoch 的训练损失和准确率。在每个 epoch 结束后,使用验证数据加载器评估模型性能,计算验证集的损失和准确率,并根据验证准确率更新最佳模型。最后,保存训练过程中最佳的模型参数到文件'best_model_1dvgg.pt'中,并计算模型训练的总运行时间。整个过程包含模型的训练、验证和性能评估等多个环节。
图2 训练过程及结果(GPU版)
根据代码结果可知,训练50次的情况下用时71s,其中验证集上最好的准确率是0.96,接着我们可以用曲线具体描述模型训练过程。
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
from joblib import dump, load
matplotlib.rc("font", family='Microsoft YaHei')
# 加载数据
train_loss = load('train_loss')
train_acc = load('train_acc')
validate_loss = load('validate_loss')
validate_acc = load('validate_acc')
# 创建训练损失图
# 创建左侧图:损失
plt.figure(figsize=(14, 7), dpi=300)
plt.subplot(1, 2, 1)
plt.plot(train_loss, label='Train-loss', marker='^', color='blue') # o ^ * s + x , marker='o'
plt.plot(validate_loss, label='Validate-loss', marker='+', color='red') # 颜色 曲线类型 可灵活替换
plt.xlabel('Epochs', fontsize=12)
plt.ylabel('Loss', fontsize=12)
plt.xticks(fontsize=10)
plt.yticks(fontsize=10)
plt.legend(fontsize=12)
plt.title('training visualization : Training and Validation Loss', fontsize=16)
# 创建右侧图:准确率
plt.subplot(1, 2, 2)
plt.plot(train_acc,color = 'orange', marker='o',label = 'Train-accuracy')
plt.plot(validate_acc, color = 'green', marker='*',label = 'Validate_accuracy')
plt.xlabel('Epochs', fontsize=12)
plt.ylabel('Accuracy', fontsize=12)
plt.xticks(fontsize=10)
plt.yticks(fontsize=10)
plt.legend(fontsize=12)
plt.title(' training visualization : Training and Validation Accuracy', fontsize=16)
plt.tight_layout() # 用于确保子图之间的距离适当
plt.show()
这段代码加载训练过程中的各个结果,其中train_loss代表训练集损失值、train_acc代表训练集准确率、validate_loss代表验证集损失值、validate_acc代表验证集准确率,并通过曲线图绘制训练过程,包含每次训练的准确率以及损失函数变化。
图3 训练过程曲线
结果如图所示,其中左图蓝色曲线是训练集损失函数变化,红色是验证集损失函数,右图中黄色是验证集准确率变化曲线,绿色是验证集准确率变化曲线。随着训练次数增加,损失函数逐渐减少,准确率逐渐增加趋近于1。
6.3.4 模型验证
模型验证部分代码首先用测试集输入最佳模型,并通过折线图以及准确率、召回率等指标检验模型效果,最后通过混淆矩阵进一步分析实验结果。
# 模型 测试集 验证
from sklearn.metrics import confusion_matrix
import torch.nn.functional as F
device = torch.device("cuda" if torch.cuda.is_available() else "cpu") # 有GPU先用GPU训练
print(device)
# 得出每一类的分类准确率
model = torch.load('best_model_1dvgg.pt')
model = model.to(device)
# 使用测试集数据进行推断并计算每一类的分类准确率
true_labels = [] # 存储类别标签
predicted_labels = [] # 存储预测的标签
with torch.no_grad():
for test_data, test_label in test_loader:
# 将模型设置为评估模式
model.eval()
test_data = test_data.to(device)
test_output = model(test_data)
probabilities = F.softmax(test_output, dim=1)
predicted = torch.argmax(probabilities, dim=1)
true_labels.extend(test_label.tolist())
predicted_labels.extend(predicted.tolist())
# 混淆矩阵
confusion_mat = confusion_matrix(true_labels, predicted_labels)
from sklearn.metrics import classification_report
# 计算每一类的分类准确率
report = classification_report(true_labels, predicted_labels, digits=4)
print(report)
首先,代码设置了一个设备变量 'device',用于确定模型将在 CPU 还是 GPU 上运行。如果系统中有可用的 CUDA(GPU)设备,'device'将被设置为 "cuda",否则将使用 "cpu"。然后,打印出当前选择的设备,以确认模型将在哪个设备上运行。接下来,代码加载了预训练的最佳模型参数文件 'best_model_1dvgg.pt',并将模型移动到之前设置的设备上。
true_labels用于存储测试集的真实标签、predicted_labels用于存储测试集预测标签。然后,代码进入一个 'with torch.no_grad()' 块,这个上下文管理器用于禁用梯度计算,因为在推断过程中不需要计算梯度,这样可以减少内存消耗和加快计算速度。在该块内,代码遍历测试数据加载器'test_loader'中的每个批次数据 'test_data' 和对应的标签 'test_label'。
对于每个批次的数据,将模型设置为评估模式 'model.eval()',这会关闭模型中的一些特定于训练的行为,如 'Dropout' 层。接着,将测试数据移动到指定的设备上,并进行前向传播 'est_output = model(test_data)',得到模型对测试数据的输出。然后,对模型输出进行 'softmax' 操作 'F.softmax(test_output, dim=1)',得到每个类别的概率分布。使用 'torch.argmax(probabilities, dim=1)'获取预测的类别标签,并将真实标签和预测标签分别添加到'true_labels'和 'predicted_labels'列表中。
在完成所有测试数据的推断后,代码使用 'confusion_matrix`'函数计算混淆矩阵。混淆矩阵的行表示真实标签,列表示预测标签,矩阵中的每个元素表示对应类别对的样本数量。最后,代码使用 'classification_report'函数生成一个文本报告,显示主要的分类指标,包括精确率、召回率、F1 分数和支持度。'digits=4'参数表示结果保留四位小数。打印出分类报告,以查看每一类的分类准确率和其他指标,从而评估模型在测试集上的整体性能。
图4 测试集文本报告
根据生成文本报告,我们可以初步判断在调用训练得到的最佳模型对测试集检验时,标签0、标签1、标签3、标签7、标签9的F1得分达到了百分百,总体准确率为0.93。
准确率(Accuracy):正确预测的样本数占总样本数的比例。
精确率(Precision):预测为正类的样本中实际为正类的比例。
召回率(Recall):所有实际为正类的样本中,被正确预测为正类的比例。
F1-score:精确率和召回率的调和平均数。
AUC-ROC曲线:接收者操作特征曲线下的面积,用于衡量模型区分正负类的能力。
混淆矩阵(Confusion Matrix):显示真实类别与预测类别之间的关系。
宏平均(Macro Average):这种方法计算每个类别的指标(如精确度、召回率、F1分数等),然后取这些指标的算术平均值。它对所有类别给予相同的权重,不考虑类别之间的样本数量差异。这意味着每个类别对最终的宏平均指标的贡献是相同的。
加权平均(Weighted Average):与宏平均不同,加权平均在计算指标时会考虑每个类别的样本数量。它为每个类别的指标赋予权重,这个权重通常是该类别样本数量占总样本数量的比例。因此,样本数量较多的类别对最终的加权平均指标的贡献更大 。
均方误差(Mean Squared Error, MSE):预测值与真实值差的平方的平均值。
均方根误差(Root Mean Squared Error, RMSE):MSE的平方根。
平均绝对误差(Mean Absolute Error, MAE):预测值与真实值差的绝对值的平均值
例如,我们通过加载上述混淆矩阵并画出具体矩阵图分析模型效果。
# 绘制混淆矩阵
import matplotlib.pyplot as plt
import seaborn as sns
# 原始标签和自定义标签的映射
label_mapping = {
0: "C1",1: "C2",2: "C3",3: "C4",4: "C5",
5: "C6",6: "C7",7: "C8",8: "C9",9: "C10",
}
# 绘制混淆矩阵
plt.figure(figsize=(10, 8), dpi=300)
sns.heatmap(confusion_mat, xticklabels=label_mapping.values(), yticklabels=label_mapping.values(),annot=True, fmt='d', cmap='summer')
plt.xlabel('Predicted Labels')
plt.ylabel('True Labels')
plt.title('Confusion Matrix')
plt.show()
图5 测试集混淆矩阵
6.3.5 对比CPU版Pytorch
图6 训练过程及结果(CPU版)
通过对比可得,在简单的基础模型条件下,使用GPU计算可比CPU计算节省一半时间,在更复杂的数据及模型中GPU的运算速度及优势将更为明显。
编辑:赵栓栓
校核:李正平、陈凯歌、曹希铭、赵学功、白亮、王金、陈莹洁、陈宇航、任超、海洋、Tina、赵诚
该文资料搜集自网络,仅用作学术分享,不做商业用途,若侵权,后台联系小编进行删除
点击左下角阅读原文,即可在线阅读论文。