- 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
- 🍖 原作者:K同学啊
import torch.nn as nn
import torch.nn.functional as F
import torchvision,torch
import numpy as np
import pandas as pd
import seaborn as sns
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
plt.rcParams['savefig.dpi'] = 500 #图片像素
plt.rcParams['figure.dpi'] = 500 #分辨率
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
import warnings
warnings.filterwarnings("ignore")
# 设置硬件设备,如果有GPU则使用,没有则使用cpu
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
device
device(type='cuda')
数据导入
DataFrame=pd.read_excel(r'C:\Users\11054\Desktop\kLearning\R6\dia.xls')
DataFrame.head()
卡号 | 性别 | 年龄 | 高密度脂蛋白胆固醇 | 低密度脂蛋白胆固醇 | 极低密度脂蛋白胆固醇 | 甘油三酯 | 总胆固醇 | 脉搏 | 舒张压 | 高血压史 | 尿素氮 | 尿酸 | 肌酐 | 体重检查结果 | 是否糖尿病 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 18054421 | 0 | 38 | 1.25 | 2.99 | 1.07 | 0.64 | 5.31 | 83 | 83 | 0 | 4.99 | 243.3 | 50 | 1 | 0 |
1 | 18054422 | 0 | 31 | 1.15 | 1.99 | 0.84 | 0.50 | 3.98 | 85 | 63 | 0 | 4.72 | 391.0 | 47 | 1 | 0 |
2 | 18054423 | 0 | 27 | 1.29 | 2.21 | 0.69 | 0.60 | 4.19 | 73 | 61 | 0 | 5.87 | 325.7 | 51 | 1 | 0 |
3 | 18054424 | 0 | 33 | 0.93 | 2.01 | 0.66 | 0.84 | 3.60 | 83 | 60 | 0 | 2.40 | 203.2 | 40 | 2 | 0 |
4 | 18054425 | 0 | 36 | 1.17 | 2.83 | 0.83 | 0.73 | 4.83 | 85 | 67 | 0 | 4.09 | 236.8 | 43 | 0 | 0 |
# 查看数据是否有缺失值
print('数据缺失值---------------------------------')
print(DataFrame.isnull().sum())
数据缺失值---------------------------------
卡号 0
性别 0
年龄 0
高密度脂蛋白胆固醇 0
低密度脂蛋白胆固醇 0
极低密度脂蛋白胆固醇 0
甘油三酯 0
总胆固醇 0
脉搏 0
舒张压 0
高血压史 0
尿素氮 0
尿酸 0
肌酐 0
体重检查结果 0
是否糖尿病 0
dtype: int64
# 数据分布分析
feature_map = {
'年龄': '年龄',
'高密度脂蛋白胆固醇': '高密度脂蛋白胆固醇',
'低密度脂蛋白胆固醇': '低密度脂蛋白胆固醇',
'极低密度脂蛋白胆固醇': '极低密度脂蛋白胆固醇',
'甘油三酯': '甘油三酯',
'总胆固醇': '总胆固醇',
'脉搏': '脉搏',
'舒张压':'舒张压',
'高血压史':'高血压史',
'尿素氮':'尿素氮',
'尿酸':'尿酸',
'肌酐':'肌酐',
'体重检查结果':'体重检查结果'
}
plt.figure(figsize=(15, 10))
for i, (col, col_name) in enumerate(feature_map.items(), 1):
plt.subplot(3, 5, i)
sns.boxplot(x=DataFrame['是否糖尿病'], y=DataFrame[col])
plt.title(f'{col_name}的箱线图', fontsize=14)
plt.ylabel('数值', fontsize=12)
plt.grid(axis='y', linestyle='--', alpha=0.7)
plt.tight_layout()
plt.show()
# 数据集构建
from sklearn.preprocessing import StandardScaler
# '高密度脂蛋白胆固醇'字段与糖尿病负相关,故而在 X 中去掉该字段
X = DataFrame.drop(['卡号','是否糖尿病','高密度脂蛋白胆固醇'],axis=1)
y = DataFrame['是否糖尿病']
# sc_X = StandardScaler()
# X = sc_X.fit_transform(X)
X = torch.tensor(np.array(X), dtype=torch.float32)
y = torch.tensor(np.array(y), dtype=torch.int64)
train_X, test_X, train_y, test_y = train_test_split(X, y,
test_size=0.2,
random_state=1)
train_X.shape, train_y.shape
(torch.Size([804, 13]), torch.Size([804]))
from torch.utils.data import TensorDataset, DataLoader
train_dl = DataLoader(TensorDataset(train_X, train_y),
batch_size=64,
shuffle=False)
test_dl = DataLoader(TensorDataset(test_X, test_y),
batch_size=64,
shuffle=False)
#定义模型
class model_lstm(nn.Module):
def __init__(self):
super(model_lstm, self).__init__()
self.lstm0 = nn.LSTM(input_size=13 ,hidden_size=200,
num_layers=1, batch_first=True)
self.lstm1 = nn.LSTM(input_size=200 ,hidden_size=200,
num_layers=1, batch_first=True)
self.fc0 = nn.Linear(200, 2)
def forward(self, x):
out, hidden1 = self.lstm0(x)
out, _ = self.lstm1(out, hidden1)
out = self.fc0(out)
return out
初始化模型
model = model_lstm().to(device)
print(model)
loss_fn = nn.CrossEntropyLoss() # 创建损失函数
learn_rate = 1e-3 # 学习率
lambda1 = lambda epoch:(0.92**(epoch//2))
optimizer = torch.optim.Adam(model.parameters(),lr = learn_rate)
scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer,lr_lambda=lambda1) # 选定调整方法
epochs = 60
model_lstm(
(lstm0): LSTM(13, 200, batch_first=True)
(lstm1): LSTM(200, 200, batch_first=True)
(fc0): Linear(in_features=200, out_features=2, bias=True)
)
定义损失
# 训练循环
def train(dataloader, model, loss_fn, optimizer):
size = len(dataloader.dataset) # 训练集的大小
num_batches = len(dataloader) # 批次数目, (size/batch_size,向上取整)
train_loss, train_acc = 0, 0 # 初始化训练损失和正确率
for X, y in dataloader: # 获取图片及其标签
X, y = X.to(device), y.to(device)
# 计算预测误差
pred = model(X) # 网络输出
loss = loss_fn(pred, y) # 计算网络输出和真实值之间的差距,targets为真实值,计算二者差值即为损失
# 反向传播
optimizer.zero_grad() # grad属性归零
loss.backward() # 反向传播
optimizer.step() # 每一步自动更新
# 记录acc与loss
train_acc += (pred.argmax(1) == y).type(torch.float).sum().item()
train_loss += loss.item()
train_acc /= size
train_loss /= num_batches
return train_acc, train_loss
# 测试模型
def test (dataloader, model, loss_fn):
size = len(dataloader.dataset) # 测试集的大小
num_batches = len(dataloader) # 批次数目, (size/batch_size,向上取整)
test_loss, test_acc = 0, 0
# 当不进行训练时,停止梯度更新,节省计算内存消耗
with torch.no_grad():
for X, y in dataloader:
X, y = X.to(device), y.to(device)
# 计算loss
target_pred = model(X)
loss = loss_fn(target_pred, y)
test_loss += loss.item()
test_acc += (target_pred.argmax(1) == y).type(torch.float).sum().item()
test_acc /= size
test_loss /= num_batches
return test_acc, test_loss
训练模型
import copy
train_loss = []
train_acc = []
test_loss = []
test_acc = []
best_acc = 0.0
for epoch in range(epochs):
model.train()
epoch_train_acc, epoch_train_loss = train(train_dl, model, loss_fn, optimizer)
# 更新学习率
scheduler.step() # 更新学习率——调用官方动态学习率时使用
model.eval()
epoch_test_acc, epoch_test_loss = test(test_dl, model, loss_fn)
# 保存最佳模型
if epoch_test_acc > best_acc:
best_acc = epoch_test_acc
best_model = copy.deepcopy(model)
train_acc.append(epoch_train_acc)
train_loss.append(epoch_train_loss)
test_acc.append(epoch_test_acc)
test_loss.append(epoch_test_loss)
# 获取当前的学习率
lr = optimizer.state_dict()['param_groups'][0]['lr']
template = ('Epoch:{:2d}, Train_acc:{:.1f}%, Train_loss:{:.3f}, Test_acc:{:.1f}%, Test_loss:{:.3f}, Lr:{:.2E}')
print(template.format(epoch+1, epoch_train_acc*100, epoch_train_loss,
epoch_test_acc*100, epoch_test_loss, lr))
print('Done. Best test acc: ', best_acc)
Epoch: 1, Train_acc:53.2%, Train_loss:0.699, Test_acc:53.0%, Test_loss:0.722, Lr:1.00E-03
Epoch: 2, Train_acc:56.7%, Train_loss:0.680, Test_acc:53.0%, Test_loss:0.720, Lr:9.20E-04
Epoch: 3, Train_acc:56.3%, Train_loss:0.669, Test_acc:51.5%, Test_loss:0.704, Lr:9.20E-04
Epoch: 4, Train_acc:59.6%, Train_loss:0.647, Test_acc:64.4%, Test_loss:0.671, Lr:8.46E-04
Epoch: 5, Train_acc:64.6%, Train_loss:0.605, Test_acc:63.9%, Test_loss:0.638, Lr:8.46E-04
Epoch: 6, Train_acc:69.8%, Train_loss:0.553, Test_acc:63.9%, Test_loss:0.626, Lr:7.79E-04
Epoch: 7, Train_acc:72.8%, Train_loss:0.512, Test_acc:66.8%, Test_loss:0.605, Lr:7.79E-04
Epoch: 8, Train_acc:76.5%, Train_loss:0.471, Test_acc:68.3%, Test_loss:0.592, Lr:7.16E-04
Epoch: 9, Train_acc:77.0%, Train_loss:0.442, Test_acc:69.3%, Test_loss:0.573, Lr:7.16E-04
Epoch:10, Train_acc:78.7%, Train_loss:0.425, Test_acc:69.8%, Test_loss:0.583, Lr:6.59E-04
Epoch:11, Train_acc:80.8%, Train_loss:0.390, Test_acc:71.3%, Test_loss:0.579, Lr:6.59E-04
Epoch:12, Train_acc:81.7%, Train_loss:0.376, Test_acc:69.3%, Test_loss:0.604, Lr:6.06E-04
Epoch:13, Train_acc:82.0%, Train_loss:0.363, Test_acc:69.3%, Test_loss:0.654, Lr:6.06E-04
Epoch:14, Train_acc:84.6%, Train_loss:0.352, Test_acc:67.8%, Test_loss:0.651, Lr:5.58E-04
Epoch:15, Train_acc:86.7%, Train_loss:0.307, Test_acc:70.3%, Test_loss:0.665, Lr:5.58E-04
Epoch:16, Train_acc:86.8%, Train_loss:0.298, Test_acc:68.3%, Test_loss:0.681, Lr:5.13E-04
Epoch:17, Train_acc:87.9%, Train_loss:0.275, Test_acc:68.8%, Test_loss:0.718, Lr:5.13E-04
Epoch:18, Train_acc:89.4%, Train_loss:0.257, Test_acc:70.3%, Test_loss:0.696, Lr:4.72E-04
Epoch:19, Train_acc:90.4%, Train_loss:0.238, Test_acc:70.8%, Test_loss:0.693, Lr:4.72E-04
Epoch:20, Train_acc:89.9%, Train_loss:0.238, Test_acc:66.3%, Test_loss:0.874, Lr:4.34E-04
Epoch:21, Train_acc:90.0%, Train_loss:0.245, Test_acc:70.3%, Test_loss:0.774, Lr:4.34E-04
Epoch:22, Train_acc:91.7%, Train_loss:0.202, Test_acc:66.3%, Test_loss:0.829, Lr:4.00E-04
Epoch:23, Train_acc:93.5%, Train_loss:0.191, Test_acc:69.8%, Test_loss:0.806, Lr:4.00E-04
Epoch:24, Train_acc:92.4%, Train_loss:0.191, Test_acc:68.3%, Test_loss:0.858, Lr:3.68E-04
Epoch:25, Train_acc:94.0%, Train_loss:0.170, Test_acc:67.8%, Test_loss:0.868, Lr:3.68E-04
Epoch:26, Train_acc:95.0%, Train_loss:0.143, Test_acc:67.3%, Test_loss:0.958, Lr:3.38E-04
Epoch:27, Train_acc:95.0%, Train_loss:0.151, Test_acc:67.3%, Test_loss:0.900, Lr:3.38E-04
Epoch:28, Train_acc:93.9%, Train_loss:0.158, Test_acc:67.8%, Test_loss:0.931, Lr:3.11E-04
Epoch:29, Train_acc:96.0%, Train_loss:0.136, Test_acc:68.8%, Test_loss:0.878, Lr:3.11E-04
Epoch:30, Train_acc:97.6%, Train_loss:0.110, Test_acc:68.8%, Test_loss:0.993, Lr:2.86E-04
Epoch:31, Train_acc:98.3%, Train_loss:0.091, Test_acc:67.8%, Test_loss:1.012, Lr:2.86E-04
Epoch:32, Train_acc:97.6%, Train_loss:0.092, Test_acc:68.3%, Test_loss:1.023, Lr:2.63E-04
Epoch:33, Train_acc:98.3%, Train_loss:0.082, Test_acc:67.3%, Test_loss:1.064, Lr:2.63E-04
Epoch:34, Train_acc:98.3%, Train_loss:0.081, Test_acc:67.3%, Test_loss:1.081, Lr:2.42E-04
Epoch:35, Train_acc:97.9%, Train_loss:0.079, Test_acc:67.3%, Test_loss:1.112, Lr:2.42E-04
Epoch:36, Train_acc:97.8%, Train_loss:0.084, Test_acc:68.8%, Test_loss:1.100, Lr:2.23E-04
Epoch:37, Train_acc:96.4%, Train_loss:0.105, Test_acc:68.3%, Test_loss:1.030, Lr:2.23E-04
Epoch:38, Train_acc:96.9%, Train_loss:0.101, Test_acc:64.9%, Test_loss:1.269, Lr:2.05E-04
Epoch:39, Train_acc:96.3%, Train_loss:0.105, Test_acc:67.3%, Test_loss:1.091, Lr:2.05E-04
Epoch:40, Train_acc:96.8%, Train_loss:0.098, Test_acc:70.8%, Test_loss:1.121, Lr:1.89E-04
Epoch:41, Train_acc:98.6%, Train_loss:0.064, Test_acc:67.3%, Test_loss:1.141, Lr:1.89E-04
Epoch:42, Train_acc:99.4%, Train_loss:0.049, Test_acc:68.3%, Test_loss:1.174, Lr:1.74E-04
Epoch:43, Train_acc:99.6%, Train_loss:0.040, Test_acc:66.8%, Test_loss:1.171, Lr:1.74E-04
Epoch:44, Train_acc:99.9%, Train_loss:0.036, Test_acc:67.3%, Test_loss:1.189, Lr:1.60E-04
Epoch:45, Train_acc:99.9%, Train_loss:0.032, Test_acc:66.3%, Test_loss:1.218, Lr:1.60E-04
Epoch:46, Train_acc:99.9%, Train_loss:0.030, Test_acc:65.8%, Test_loss:1.215, Lr:1.47E-04
Epoch:47, Train_acc:99.9%, Train_loss:0.028, Test_acc:66.3%, Test_loss:1.240, Lr:1.47E-04
Epoch:48, Train_acc:99.9%, Train_loss:0.027, Test_acc:66.8%, Test_loss:1.238, Lr:1.35E-04
Epoch:49, Train_acc:99.9%, Train_loss:0.025, Test_acc:66.3%, Test_loss:1.261, Lr:1.35E-04
Epoch:50, Train_acc:99.9%, Train_loss:0.024, Test_acc:66.8%, Test_loss:1.257, Lr:1.24E-04
Epoch:51, Train_acc:99.9%, Train_loss:0.023, Test_acc:66.3%, Test_loss:1.280, Lr:1.24E-04
Epoch:52, Train_acc:99.9%, Train_loss:0.022, Test_acc:66.8%, Test_loss:1.272, Lr:1.14E-04
Epoch:53, Train_acc:99.9%, Train_loss:0.021, Test_acc:66.8%, Test_loss:1.297, Lr:1.14E-04
Epoch:54, Train_acc:99.9%, Train_loss:0.020, Test_acc:67.3%, Test_loss:1.287, Lr:1.05E-04
Epoch:55, Train_acc:99.9%, Train_loss:0.019, Test_acc:66.3%, Test_loss:1.312, Lr:1.05E-04
Epoch:56, Train_acc:99.9%, Train_loss:0.019, Test_acc:66.8%, Test_loss:1.304, Lr:9.68E-05
Epoch:57, Train_acc:99.9%, Train_loss:0.018, Test_acc:66.3%, Test_loss:1.325, Lr:9.68E-05
Epoch:58, Train_acc:100.0%, Train_loss:0.017, Test_acc:66.8%, Test_loss:1.320, Lr:8.91E-05
Epoch:59, Train_acc:99.9%, Train_loss:0.017, Test_acc:66.3%, Test_loss:1.336, Lr:8.91E-05
Epoch:60, Train_acc:100.0%, Train_loss:0.016, Test_acc:66.8%, Test_loss:1.335, Lr:8.20E-05
Done. Best test acc: 0.7128712871287128
模型评估
import matplotlib.pyplot as plt
#隐藏警告
import warnings
warnings.filterwarnings("ignore") #忽略警告信息
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
plt.rcParams['figure.dpi'] = 100 #分辨率
epochs_range = range(epochs)
plt.figure(figsize=(12, 3))
plt.subplot(1, 2, 1)
plt.plot(epochs_range, train_acc, label='Training Accuracy')
plt.plot(epochs_range, test_acc, label='Test Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')
plt.subplot(1, 2, 2)
plt.plot(epochs_range, train_loss, label='Training Loss')
plt.plot(epochs_range, test_loss, label='Test Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()
个人总结
学习了如何使用LSTM模型并成功运用于糖尿病预测
model_lstm 类继承自 torch.nn.Module
self.lstm0:第一个 LSTM 层,输入大小为 13,隐藏层大小为 200,层数为 1,且输入数据的维度为 (batch_size, sequence_length, input_size)。
self.lstm1:第二个 LSTM 层,输入大小为 200,隐藏层大小为 200,层数为 1,且输入数据的维度为 (batch_size, sequence_length, input_size)。
self.fc0:全连接层,输入大小为 200,输出大小为 2。
forward 方法定义了模型的前向传播过程,即输入数据如何通过模型的各个层生成输出。
输入 x 的维度为 (batch_size, sequence_length, input_size)。
out, hidden1 = self.lstm0(x):将输入 x 通过第一个 LSTM 层,返回输出 out 和隐藏状态 hidden1。
out, _ = self.lstm1(out, hidden1):将第一个 LSTM 层的输出 out 和隐藏状态 hidden1 通过第二个 LSTM 层,返回新的输出 out(第二个 LSTM 层的隐藏状态未使用,因此用 _ 表示忽略)。
out = self.fc0(out):将第二个 LSTM 层的输出 out 通过全连接层,最后返回模型的输出。
- 语法
torch.nn.LSTM(input_size, hidden_size, num_layers=1,
bias=True, batch_first=False,
dropout=0, bidirectional=False)
● input_size: 输入特征的维度。
● hidden_size: 隐藏状态的维度,也是输出特征的维度。
● num_layers(可选参数): LSTM 层的数量,默认为 1。
● bias(可选参数): 是否使用偏置,默认为 True。
● batch_first(可选参数): 如果为 True,则输入和输出张量的形状为 (batch_size, seq_len, feature_size),默认为 False,张量的形状为(seq_len, batch_size, feature_dim)。
● dropout(可选参数): 如果非零,将在 LSTM 层的输出上应用 dropout,防止过拟合。默认为 0。
● bidirectional(可选参数): 如果为 True,则使用双向 LSTM,输出维度将翻倍。默认为 False。