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等数据集的分类预测)