构建全连接神经网络(下)

236 阅读6分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

利用全连接网络实现病例AD,heart,WDBC等数据集的分类预测

1.网络搭建:

 """
 作者:lds
 网络搭建
 """
 import torch.nn as nn
 from torchvision import transforms as T
 ​
 class Net(nn.Module):
     # 搭建6层网络
     def __init__(self, input, hidden_1, hidden_2, hidden_3, hidden_4, hidden_5,output):##在用到Net时,可以自己手动根据不同的数据集进行改动各层的大小。
         # nn.Module子类的函数必须在构造函数中执行父类的构造函数
         super(Net, self).__init__()
 ##充分利用Sequential函数,将线性层Linear、BatchNormalization和激活函数层Tanh()连接起来,从而构造一层全连接。
         self.hidden_layer1 = nn.Sequential(
             nn.Linear(input, hidden_1), nn.BatchNorm1d(hidden_1),
             nn.Tanh()
         )
         self.hidden_layer2 = nn.Sequential(
             nn.Linear(hidden_1, hidden_2), nn.BatchNorm1d(hidden_2),
             nn.Tanh()
         )
         self.hidden_layer3 = nn.Sequential(
             nn.Linear(hidden_2, hidden_3), nn.BatchNorm1d(hidden_3),
             nn.Tanh()
         )
         self.hidden_layer4 = nn.Sequential(
             nn.Linear(hidden_3, hidden_4), nn.BatchNorm1d(hidden_4),
             nn.Tanh()
         )
         self.hidden_layer5 = nn.Sequential(
             nn.Linear(hidden_4, hidden_5), nn.BatchNorm1d(hidden_5),
             nn.Tanh()
         )
         self.output_layer = nn.Sequential(
             nn.Linear(hidden_5, output),
             nn.Sigmoid()
         )
 ​
     def forward(self, x):
         x = self.hidden_layer1(x)
         x = self.hidden_layer2(x)
         x = self.hidden_layer3(x)
         x = self.hidden_layer4(x)
         x = self.hidden_layer5(x)
         x = self.output_layer(x)
 ​
         return x
 ​
 ​

2.网络参数配置:

 """
 作者:lds
 整个实验运行时涉及的一些自定义方法
 包括数据获取、网络初始化、网络训练、网络测试以及交叉验证
 """
 import pandas as pd
 import numpy as np
 import Visualization as v
 import time
 import torch as t
 import torch.nn as nn
 import scipy.io
 import net as classifier
 import torch.optim as opt
 ​
 ​
 def init(model):
     """
     训练前对模型权重进行初始化
     :param model: 训练模型
     """
     for m in model.modules():
         if isinstance(m, nn.Linear):
             nn.init.xavier_uniform_(m.weight)  ##这里调用xavier_uniform初始化函数
 ​
 ​
 def train(train_ds, train_ls, model, criterion, optimizer, epochs=20):
     """
     训练模型
     :param train_ds: 训练数据
     :param train_ls: 训练标签
     :param model: 训练模型
     :param criterion: 损失函数
     :param optimizer: 优化算法
     :param epochs: 迭代次数
     :return: 训练损失值
     """
     t_loss_list = []
     train_correct = 0
     # 将训练集迁移到GPU上
     train_ds = train_ds.cuda()
     train_ls = train_ls.cuda()
     model = model.cuda()
     init(model)
     for epoch in range(epochs-1):
         model.train()
         # 每次训练前梯度置零
         optimizer.zero_grad()
         # 正向传播
         output = model(train_ds)
         # 计算损失值
         train_loss = criterion(output, train_ls.squeeze())
         # 反向传播,计算梯度
         train_loss.backward()
         # 更新参数
         optimizer.step()
         t_loss_list.append(train_loss.item())
     # 获取预测值
     predict = output.max(1, keepdim=True)[1]
     # 统计预测正确个数
     train_correct += predict.eq(train_ls.view_as(predict)).sum().item()
 ​
     # 计算准确率
     train_accuracy = train_correct / train_ds.shape[0]
 ​
 ​
     print("Train loss: {:.3f}".format(train_loss.item()))
     print("Train Accuracy:{:.2f}%".format(train_accuracy*100))
 ​
     return train_loss.item(), train_accuracy, t_loss_list
 ​
 ​
 def for_test(test_ds, test_ls, model, criterion):
     """
     测试模型
     :param test_ds: 测试数据
     :param test_ls: 测试标签
     :param model: 测试模型
     :param criterion: 损失函数
     :return: 测试损失值,测试准确度
     """
     # 将测试数据迁移到GPU上
     test_ds = test_ds.cuda()
     test_ls = test_ls.cuda()
     model = model.eval()
     correct = 0
 ​
     with t.no_grad():
         # 使用训练好的模型测试
         output = model(test_ds)
         # 计算测试集损失函数
         test_loss = criterion(output, test_ls.squeeze())
         # 获取预测值
         predict = output.max(1, keepdim=True)[1]
         # 统计预测正确个数
         correct += predict.eq(test_ls.view_as(predict)).sum().item()
 ​
         # 计算准确率
         accuracy = correct / test_ds.shape[0]
 ​
     print("Test loss: {:.3f}".format(test_loss.item()))
     print("Test Accuracy:{:.2f}%".format(accuracy*100))
 ​
     return test_loss.item(), accuracy
 ​
 ​
 def train_va(dataname, c_model, c_epochs, c_criterion, c_opt, result_name):   ###k, c_datas, c_labels,
     """
     对模型进行训练和可视化
     :param dataname: 数据集的名字
     :param c_datas: 数据集
     :param c_labels: 标签集
     :param c_model: 用于分类的模型
     :param c_epochs: 迭代次数
     :param c_criterion: 损失函数
     :param c_opt: 优化算法
     :param result_name: 实验结果文件名字符串
     """
     # 获取样本总数
     # examples = c_datas.shape[0]
     # # 每一份有几个样本
     # batch_examples = examples // k
 ​
     # 存储每次验证结果
     performs = []
 ​
     # 存储训练损失值、准确率,测试损失值、准确率,用于可视化和计算最终结果
     t_loss_list = []
     t_acc_list = []
     v_loss_list = []
     v_acc_list = []
 ​
     # 记录整个训练起始时间
     start_time = time.perf_counter()
     #划分相应的数据集
     data = scipy.io.loadmat('%s.mat'%(dataname))
     # data=data.to_numpy()
     train_datas = data['xtrain']
     train_labels = data['ytrain']
     test_datas = data['xtest']
     test_labels = data['ytest']
     # 固定随机种子,确保每次运行结果一致
     np.random.seed(5)
     # 判断标签是否符合标准,即是否从0开始标注
     if 0 not in train_labels:
         # 标签从1开始,就将每个标签值-1
         train_labels = train_labels - 1
     if 0 not in test_labels:
         # 标签从1开始,就将每个标签值-1
         test_labels = test_labels - 1
     train_datas = train_datas / 1.0
     train_datas =t.from_numpy(train_datas).float()
     train_labels = t.from_numpy(train_labels).long()
     test_datas = test_datas / 1.0
     test_datas = t.from_numpy(test_datas).float()
     test_labels = t.from_numpy(test_labels).long()
 ​
     # for i in range(c_epochs):
     t_loss, t_acc , t_loss_list= train(train_datas, train_labels, c_model, c_criterion, c_opt, epochs=c_epochs)    # 测试
     v_loss, v_acc = for_test(test_datas, test_labels, c_model, c_criterion)
     # 清空cuda缓存
     t.cuda.empty_cache()
     # 将该次训练损失值和测试准确度存放到列表中
     performs.append((v_acc, v_loss))
 ​
     t_loss_list.append(t_loss)
     v_loss_list.append(v_loss)
     print(v_loss_list)
 ​
     # 记录整个训练结束时间
     end_time = time.perf_counter()
 ​
     #根据准确度从小到大排序
     performs = sorted(performs)
     # 打印最高准确度
     print("loss: {:.3f}, accuracy: {:.2f}%".format(performs[-1][1], performs[-1][0] * 100))
     v_acc_list.append(performs[-1][0] * 100)
     # 打印耗时
     print("共耗时:{:.3f} s".format(end_time - start_time))
     # 可视化模型性能
     v.visualization(dataname, t_loss_list, result_name, v_acc_list)
 ​
 ###test结果
 # if __name__ == '__main__':
 #     DATAFILE1 = "data\heart.mat"
 #     classifer2 = classifier.Net(13, 104, 52, 26, 13, 8, 2)   ##对应于AD数据集的模型
 #     optimizer = opt.Adam(classifer2.parameters(), lr=0.01, betas=(0.9, 0.99))
 #     criterion = nn.CrossEntropyLoss()
 #     picture_name = DATAFILE1.split("\")[-1].split(".")[0] + "_result"
 #     dataname = DATAFILE1.split("\")[-1].split(".")[0]
 #     cross_validation(dataname, classifer2, 200, criterion, optimizer, picture_name)
 ​

3.可视化:

 """
 对实验的结果可视化
 作者:lds
 """
 import matplotlib.pyplot as plt
 plt.rc("font", family='KaiTi')
 EPOCHS = 600
 ​
 import matplotlib.pyplot as plt
 ​
 ​
 def visualization(dataname, t_loss_list, result_name, v_acc_list):
     # plt.ion()
     plt.figure()
     f, axes = plt.subplots(1, 1)
     # ax0 = axes[0, 0]
 ​
 ​
     if dataname=='AD':
         axes.clear()
         axes.plot([x for x in range(EPOCHS)], t_loss_list)  ###range(1,11)
         axes.set_xlabel("训练轮次")
         axes.set_ylabel("损失值")
         axes.set_title("AD")
         axes.set_ylim((0.5, max(t_loss_list)))  ###1
         axes.set_xlim((1, EPOCHS))
 ​
         row_labels = ['准确率:']
         col_labels = ['数值']
         value = v_acc_list[0]
         table_vals = [['{:.2f}%'.format(value)]]
         row_colors = ['gold']
         my_table = plt.table(cellText=table_vals, colWidths=[0.1] * 5,
                              rowLabels=row_labels, rowColours=row_colors, loc='best')
         plt.savefig(result_name + ".png")
         plt.show()
 ​
     if dataname == 'heart':
         axes.clear()
         axes.plot([x for x in range(EPOCHS)], t_loss_list)  ###range(1,11)
         axes.set_xlabel("训练轮次")
         axes.set_ylabel("损失值")
         axes.set_title("heart")
         axes.set_ylim((0.35, max(t_loss_list)))  ###1
         axes.set_xlim((1, EPOCHS))
         row_labels = ['准确率:']
         col_labels = ['数值']
         value = v_acc_list[0]
         table_vals = [['{:.2f}%'.format(value)]]
         row_colors = ['gold']
         my_table = plt.table(cellText=table_vals, colWidths=[0.1] * 5,
                              rowLabels=row_labels, rowColours=row_colors, loc='best')
         plt.savefig(result_name + ".png")
         plt.show()
     if dataname == 'maxLittle':
         axes.clear()
         axes.plot([x for x in range(EPOCHS)], t_loss_list)  ###range(1,11)
         axes.set_xlabel("训练轮次")
         axes.set_ylabel("损失值")
         axes.set_title("maxLittle")
         axes.set_ylim((0.35, max(t_loss_list)))  ###1
         axes.set_xlim((1, EPOCHS))
         row_labels = ['准确率:']
         col_labels = ['数值']
         value = v_acc_list[0]
         table_vals = [['{:.2f}%'.format(value)]]
         row_colors = ['gold']
         my_table = plt.table(cellText=table_vals, colWidths=[0.1] * 5,
                              rowLabels=row_labels, rowColours=row_colors, loc='best')
         plt.savefig(result_name + ".png")
         plt.show()
     if dataname == 'PD':
         axes.clear()
         axes.plot([x for x in range(EPOCHS)], t_loss_list)  ###range(1,11)
         axes.set_xlabel("训练轮次")
         axes.set_ylabel("损失值")
         axes.set_title("PD")
         axes.set_ylim((0.3, max(t_loss_list)))  ###1
         axes.set_xlim((1, EPOCHS))
         row_labels = ['准确率:']
         col_labels = ['数值']
         value = v_acc_list[0]
         table_vals = [['{:.2f}%'.format(value)]]
         row_colors = ['gold']
         my_table = plt.table(cellText=table_vals, colWidths=[0.1] * 5,
                              rowLabels=row_labels, rowColours=row_colors, loc='best')
         plt.savefig(result_name + ".png")
         plt.show()
     if dataname == 'pima-indians-diabetes':
         axes.clear()
         axes.plot([x for x in range(EPOCHS)], t_loss_list)  ###range(1,11)
         axes.set_xlabel("训练轮次")
         axes.set_ylabel("损失值")
         axes.set_title("pima-indians-diabetes")
         axes.set_ylim((0.6, max(t_loss_list)))  ###1
         axes.set_xlim((1, EPOCHS))
         row_labels = ['准确率:']
         col_labels = ['数值']
         value = v_acc_list[0]
         table_vals = [['{:.2f}%'.format(value)]]
         row_colors = ['gold']
         my_table = plt.table(cellText=table_vals, colWidths=[0.1] * 5,
                              rowLabels=row_labels, rowColours=row_colors, loc='best')
         plt.savefig(result_name + ".png")
         plt.show()
     if dataname == 'vehicle':
         axes.clear()
         axes.plot([x for x in range(EPOCHS)], t_loss_list)  ###range(1,11)
         axes.set_xlabel("训练轮次")
         axes.set_ylabel("损失值")
         axes.set_title("vehicle")
         axes.set_ylim((0.7, max(t_loss_list)))  ###1
         axes.set_xlim((1, EPOCHS))
         row_labels = ['准确率:']
         col_labels = ['数值']
         value = v_acc_list[0]
         table_vals = [['{:.2f}%'.format(value)]]
         row_colors = ['gold']
         my_table = plt.table(cellText=table_vals, colWidths=[0.1] * 5,
                              rowLabels=row_labels, rowColours=row_colors, loc='best')
         plt.savefig(result_name + ".png")
         plt.show()
     if dataname == 'WDBC':
         axes.clear()
         axes.plot([x for x in range(EPOCHS)], t_loss_list)  ###range(1,11)
         axes.set_xlabel("训练轮次")
         axes.set_ylabel("损失值")
         axes.set_title("WDBC")
         axes.set_ylim((0.1, max(t_loss_list)))  ###1
         axes.set_xlim((1, EPOCHS))
         row_labels = ['准确率:']
         col_labels = ['数值']
         value = v_acc_list[0]
         table_vals = [['{:.2f}%'.format(value)]]
         row_colors = ['gold']
         my_table = plt.table(cellText=table_vals, colWidths=[0.1] * 5,
                              rowLabels=row_labels, rowColours=row_colors, loc='best')
         plt.savefig(result_name + ".png")
         plt.show()
     if dataname == 'Wisconsin':
         axes.clear()
         axes.plot([x for x in range(EPOCHS)], t_loss_list)  ###range(1,11)
         axes.set_xlabel("训练轮次")
         axes.set_ylabel("损失值")
         axes.set_title("Wisconsin")
         axes.set_ylim((1, max(t_loss_list)))  ###1
         axes.set_xlim((1, EPOCHS))
         row_labels = ['准确率:']
         col_labels = ['数值']
         value = v_acc_list[0]
         table_vals = [['{:.2f}%'.format(value)]]
         row_colors = ['gold']
         my_table = plt.table(cellText=table_vals, colWidths=[0.1] * 5,
                              rowLabels=row_labels, rowColours=row_colors, loc='best')
         plt.savefig(result_name + ".png")
         plt.show()
 ​
 ​
     plt.tight_layout()  # 自动布局子图
 ​

4.主函数:

 ''''
 作者:lds
 ''''
 import utils as f
 import net as classifier
 import torch.nn as nn
 import torch.optim as opt
 ​
 DATAFILE1 = "data\AD.mat"                    # 各个数据集的路径
 DATAFILE2 = "data\heart.mat"
 DATAFILE3 = "data\maxLittle.mat"
 DATAFILE4 = "data\PD.mat"
 DATAFILE5 = "data\pima-indians-diabetes.mat"
 DATAFILE6 = "data\vehicle.mat"
 DATAFILE7 = "data\WDBC.mat"
 DATAFILE8 = "data\Wisconsin.mat"
 EPOCHS = 600                             # 迭代次数
 ​
 ​
 def start(datafile, model, lr):
     print("Starting")
     print("Loading datas...")
     # 获取数据集和标签集
     # datas, labels = f.get_datas(datafile)
     print("Datas Loaded!")
 # 定义损失函数,使用交叉熵损失函数
     criterion = nn.CrossEntropyLoss()
     # 定义优化算法,使用Adam算法,学习率lr为0.005,β1=0.9,β2=0.99
     optimizer = opt.Adam(model.parameters(), lr=lr, betas=(0.9, 0.99))
     print("Training and Validating...")
     # 根据数据集路径生成结果图的文件名
     picture_name = datafile.split("\")[-1].split(".")[0] + "_result"
     dataname = datafile.split("\")[-1].split(".")[0]
     f.train_va(dataname, model, EPOCHS, criterion, optimizer, picture_name)
 ​
 ​
 if __name__ == '__main__':
     # 创建分类器
     classifer1 = classifier.Net(32, 256, 128, 64, 32, 12, 3)  ##对应于AD数据集的模型
     classifer2 = classifier.Net(13, 208, 104, 52, 26, 13, 2)   ##对应于heart数据集的模型
     classifer3 = classifier.Net(22, 176, 88, 44, 11, 8, 2)   ##对应于maxLittle数据集的模型
     classifer4 = classifier.Net(26, 208, 104, 52, 26, 13, 2)   ##对应于PD数据集的模型
     classifer5 = classifier.Net(8, 64, 32, 16, 8, 4, 2)      ##对应于pima-indians-diabetes数据集的模型
     classifer6 = classifier.Net(18, 144, 72, 36, 18, 8, 4)   ##对应于vehicle数据集的模型
     classifer7 = classifier.Net(30, 240, 120, 60, 30, 10, 2)  ##对应于WDBC数据集的模型
     classifer8 = classifier.Net(9, 72, 36, 18, 9, 6, 4)      ##对应于Wisconsin数据集的模型
 ​
 ​
     print("------ 对AD数据集进行训练 -----")
     start(DATAFILE1, classifer1, 0.00005)
 ​
     print("\n------ 对heart数据集进行训练 -----")
     start(DATAFILE2, classifer2, 0.0001)
 ​
     print("\n------ 对maxLittle数据集进行训练 -----")
     start(DATAFILE3, classifer3, 0.0005)
 ​
     print("\n------ 对PD数据集进行训练 -----")
     start(DATAFILE4, classifer4, 0.0005)
 ​
     print("\n------ 对pima-inidians-diabetes数据集进行训练 -----")
     start(DATAFILE5, classifer5, 0.0005)
 ​
     print("\n------ 对vehicle数据集进行训练 -----")
     start(DATAFILE6, classifer6, 0.0005)
 ​
     print("\n------ 对WDBC数据集进行训练 -----")
     start(DATAFILE7, classifer7, 0.0005)
 ​
     print("\n------ 对Wisconsin数据集进行训练 -----")
     start(DATAFILE8, classifer8, 0.0005)
 ​
 ​
 ​
 ​

5.结果展示:(以下是对AD,heart,WDBC等数据集的分类预测)

AD_result

heart_result

maxLittle_result

PD_result

pima-indians-diabetes_result

WDBC_result