深度学习训练camp:第R4周: Pytorch实现:LSTM-火灾温度预测
- 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
- 🍖 原作者:K同学啊
任务说明
数据集中提供了火灾温度(Tem1)、一氧化碳浓度(CO 1)、烟雾浓度(Soot 1)随着时间变化数据,我们需要根据这些数据对未来某一时刻的火灾温度做出预测(本次任务仅供学习)。
🍺要求:
- 了解LSTM是什么,并使用其构建一个完整的程序。
- R²达到0.83。
🍻拔高:
- 使用第1-8个时刻的数据预测第9~10个时刻的温度数据。
🏡 我的环境:
● 语言环境:Python3.12.4
● 编译器:Jupyter Lab
● 深度学习框架:pyTorch
● 数据地址:🔗百度网盘
一、前期准备以及数据预处理
1、导入数据
和之前一样我们先将数据导入并使用pandas查看数据的构造。
import torch.nn.functional as F
import numpy as np
import pandas as pd
import torch
from torch import nn
file_path = 'D:/OneDrive/code learning(python and matlab and latex)/365camp/data/woodpine2.csv'
data = pd.read_csv(file_path)
data
代码输出:
Time Tem1 CO 1 Soot 1
0 0.000 25.0 0.000000 0.000000
1 0.228 25.0 0.000000 0.000000
2 0.456 25.0 0.000000 0.000000
3 0.685 25.0 0.000000 0.000000
4 0.913 25.0 0.000000 0.000000
... ... ... ... ...
5943 366.000 295.0 0.000077 0.000496
5944 366.000 294.0 0.000077 0.000494
5945 367.000 292.0 0.000077 0.000491
5946 367.000 291.0 0.000076 0.000489
5947 367.000 290.0 0.000076 0.000487
[5948 rows x 4 columns]
2、数据集可视化
import matplotlib.pyplot as plt
import seaborn as sns
plt.rcParams['savefig.dpi'] = 500
plt.rcParams['figure.dpi'] = 500
fig, ax = plt.subplots(1, 3, constrained_layout=True, figsize=(14, 3))
sns.lineplot(data = data['Tem1'], ax = ax[0])
sns.lineplot(data = data['CO 1'], ax = ax[1])
sns.lineplot(data = data['Soot 1'], ax = ax[2], color='r')
plt.show()
代码输出:
dataFrame = data.iloc[:, 1:]
dataFrame
代码输出:
Tem1 CO 1 Soot 1
0 25.0 0.000000 0.000000
1 25.0 0.000000 0.000000
2 25.0 0.000000 0.000000
3 25.0 0.000000 0.000000
4 25.0 0.000000 0.000000
... ... ... ...
5943 295.0 0.000077 0.000496
5944 294.0 0.000077 0.000494
5945 292.0 0.000077 0.000491
5946 291.0 0.000076 0.000489
5947 290.0 0.000076 0.000487
[5948 rows x 3 columns]
二、构建数据集
1、数据集预处理
from sklearn.preprocessing import MinMaxScaler
dataFrame = data.iloc[:, 1:].copy()
sc = MinMaxScaler(feature_range=(0, 1))
for i in ['CO 1', 'Soot 1', 'Tem1']:
dataFrame[i] = sc.fit_transform(dataFrame[i].values.reshape(-1, 1))
dataFrame.shape
这段代码受限从sklearn
库中导入了MinMaxScaler
类,从data
数据框中选择所有的行和第二列开始的所有的列进行创建一个新的数据框架dataFrame
。copy()
方法用于确保dataFrame
是data
的一个独立副本,随后创建了一个 MinMaxScaler
实例,设置归一化的范围为 0 到 1。MinMaxScaler
会将数据缩放到指定的范围内,通常用于将特征值标准化,以便于模型训练。然后这段代码对 dataFrame
中的三列(‘CO 1’、‘Soot 1’ 和 ‘Tem1’)进行归一化处理。fit_transform
方法会计算每列的最小值和最大值,并将其缩放到 0 到 1 的范围。reshape(-1, 1)
是为了将数据转换为二维数组的形式,因为 MinMaxScaler
需要这样的输入格式。
代码输出:
(5948, 3)
2、设置x和y
width_X = 8
width_y = 1
##取前8个时间段的Tem1、CO 1、Soot 1为X,第9个时间段的Tem1为y。
X = []
y = []
in_start = 0
for _, _ in data.iterrows():
in_end = in_start + width_X
out_end = in_end + width_y
if out_end < len(dataFrame):
X_ = np.array(dataFrame.iloc[in_start:in_end , ])
y_ = np.array(dataFrame.iloc[in_end :out_end, 0])
X.append(X_)
y.append(y_)
in_start += 1
X = np.array(X)
y = np.array(y).reshape(-1,width_y,1)
X.shape, y.shape
代码输出:
((5938, 8, 3), (5938, 2, 1))
检查数据集中是否有空值:
print(np.any(np.isnan(X)))
print(np.any(np.isnan(y)))
代码输出:
False
False
X_train = torch.tensor(np.array(X[:5000]), dtype=torch.float32)
y_train = torch.tensor(np.array(y[:5000]), dtype=torch.float32)
X_test = torch.tensor(np.array(X[5000:]), dtype=torch.float32)
y_test = torch.tensor(np.array(y[5000:]), dtype=torch.float32)
X_train.shape, y_train.shape
代码输出:
(torch.Size([5000, 8, 3]), torch.Size([5000, 2, 1]))
from torch.utils.data import TensorDataset, DataLoader
train_dl = DataLoader(TensorDataset(X_train, y_train),
batch_size=64,
shuffle=True)
test_dl = DataLoader(TensorDataset(X_test, y_test),
batch_size=64,
shuffle=True)
三、模型训练
1、构建模型
class model_lstm1(nn.Module):
def __init__(self):
super(model_lstm1, self).__init__()
self.lstm0 = nn.LSTM(input_size=3 ,hidden_size=320,
num_layers=1, batch_first=True)
self.lstm1 = nn.LSTM(input_size=320 ,hidden_size=320,
num_layers=1, batch_first=True)
self.fc0 = nn.Linear(320, 1)
def forward(self, x):
out, hidden1 = self.lstm0(x)
out, _ = self.lstm1(out, hidden1)
out = self.fc0(out)
return out[:, -1:, :]#取1个预测值,否则经过lstm会得到8*1个预测
model1 = model_lstm1()
model1
代码输出:
model_lstm1(
(lstm0): LSTM(3, 320, batch_first=True)
(lstm1): LSTM(320, 320, batch_first=True)
(fc0): Linear(in_features=320, out_features=1, bias=True)
)
2、定义训练和测试函数
# 训练循环
import copy
def train(train_dl, model, loss_fn, opt, lr_scheduler=None):
size = len(train_dl.dataset)
num_batches = len(train_dl)
train_loss = 0 # 初始化训练损失和正确率
for x, y in train_dl:
x, y = x.to(device), y.to(device)
# 计算预测误差
pred = model(x) # 网络输出
loss = loss_fn(pred, y) # 计算网络输出和真实值之间的差距
# 反向传播
opt.zero_grad() # grad属性归零
loss.backward() # 反向传播
opt.step() # 每一步自动更新
# 记录loss
train_loss += loss.item()
if lr_scheduler is not None:
lr_scheduler.step()
print("learning rate = {:.5f}".format(opt.param_groups[0]['lr']), end=" ")
train_loss /= num_batches
return train_loss
def test (dataloader, model, loss_fn):
size = len(dataloader.dataset) # 测试集的大小
num_batches = len(dataloader) # 批次数目
test_loss = 0
# 当不进行训练时,停止梯度更新,节省计算内存消耗
with torch.no_grad():
for x, y in dataloader:
x, y = x.to(device), y.to(device)
# 计算loss
y_pred = model(x)
loss = loss_fn(y_pred, y)
test_loss += loss.item()
test_loss /= num_batches
return test_loss
3、训练函数
#%%
#设置GPU训练
device=torch.device("cuda" if torch.cuda.is_available() else "cpu")
device
#训练模型
model = model_lstm1()
model = model.to(device)
loss_fn = nn.MSELoss() # 创建损失函数
learn_rate = 1e-1 # 学习率
opt = torch.optim.SGD(model.parameters(),lr=learn_rate,weight_decay=1e-4)
epochs = 50
train_loss = []
test_loss = []
lr_scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(opt,epochs, last_epoch=-1)
for epoch in range(epochs):
model.train()
epoch_train_loss = train(train_dl, model, loss_fn, opt, lr_scheduler)
model.eval()
epoch_test_loss = test(test_dl, model, loss_fn)
train_loss.append(epoch_train_loss)
test_loss.append(epoch_test_loss)
template = ('Epoch:{:2d}, Train_loss:{:.5f}, Test_loss:{:.5f}')
print(template.format(epoch+1, epoch_train_loss, epoch_test_loss))
print("="*20, 'Done', "="*20)
代码输出:
learning rate = 0.09990 Epoch: 1, Train_loss:0.05296, Test_loss:0.20052
learning rate = 0.09961 Epoch: 2, Train_loss:0.04132, Test_loss:0.14725
learning rate = 0.09911 Epoch: 3, Train_loss:0.02477, Test_loss:0.06766
learning rate = 0.09843 Epoch: 4, Train_loss:0.00568, Test_loss:0.00505
learning rate = 0.09755 Epoch: 5, Train_loss:0.00037, Test_loss:0.00088
learning rate = 0.09649 Epoch: 6, Train_loss:0.00016, Test_loss:0.00079
learning rate = 0.09524 Epoch: 7, Train_loss:0.00015, Test_loss:0.00069
learning rate = 0.09382 Epoch: 8, Train_loss:0.00015, Test_loss:0.00060
learning rate = 0.09222 Epoch: 9, Train_loss:0.00015, Test_loss:0.00072
learning rate = 0.09045 Epoch:10, Train_loss:0.00015, Test_loss:0.00062
learning rate = 0.08853 Epoch:11, Train_loss:0.00015, Test_loss:0.00083
learning rate = 0.08645 Epoch:12, Train_loss:0.00016, Test_loss:0.00065
learning rate = 0.08423 Epoch:13, Train_loss:0.00015, Test_loss:0.00059
learning rate = 0.08187 Epoch:14, Train_loss:0.00015, Test_loss:0.00060
learning rate = 0.07939 Epoch:15, Train_loss:0.00015, Test_loss:0.00064
learning rate = 0.07679 Epoch:16, Train_loss:0.00015, Test_loss:0.00068
learning rate = 0.07409 Epoch:17, Train_loss:0.00015, Test_loss:0.00067
learning rate = 0.07129 Epoch:18, Train_loss:0.00015, Test_loss:0.00075
learning rate = 0.06841 Epoch:19, Train_loss:0.00015, Test_loss:0.00066
learning rate = 0.06545 Epoch:20, Train_loss:0.00015, Test_loss:0.00062
learning rate = 0.06243 Epoch:21, Train_loss:0.00015, Test_loss:0.00069
learning rate = 0.05937 Epoch:22, Train_loss:0.00015, Test_loss:0.00072
learning rate = 0.05627 Epoch:23, Train_loss:0.00015, Test_loss:0.00064
learning rate = 0.05314 Epoch:24, Train_loss:0.00015, Test_loss:0.00070
learning rate = 0.05000 Epoch:25, Train_loss:0.00015, Test_loss:0.00067
learning rate = 0.04686 Epoch:26, Train_loss:0.00015, Test_loss:0.00078
learning rate = 0.04373 Epoch:27, Train_loss:0.00015, Test_loss:0.00067
learning rate = 0.04063 Epoch:28, Train_loss:0.00015, Test_loss:0.00065
learning rate = 0.03757 Epoch:29, Train_loss:0.00015, Test_loss:0.00074
learning rate = 0.03455 Epoch:30, Train_loss:0.00015, Test_loss:0.00068
learning rate = 0.03159 Epoch:31, Train_loss:0.00015, Test_loss:0.00065
learning rate = 0.02871 Epoch:32, Train_loss:0.00015, Test_loss:0.00064
learning rate = 0.02591 Epoch:33, Train_loss:0.00015, Test_loss:0.00066
learning rate = 0.02321 Epoch:34, Train_loss:0.00015, Test_loss:0.00063
learning rate = 0.02061 Epoch:35, Train_loss:0.00015, Test_loss:0.00066
learning rate = 0.01813 Epoch:36, Train_loss:0.00015, Test_loss:0.00065
learning rate = 0.01577 Epoch:37, Train_loss:0.00015, Test_loss:0.00068
learning rate = 0.01355 Epoch:38, Train_loss:0.00015, Test_loss:0.00067
learning rate = 0.01147 Epoch:39, Train_loss:0.00015, Test_loss:0.00067
learning rate = 0.00955 Epoch:40, Train_loss:0.00015, Test_loss:0.00064
learning rate = 0.00778 Epoch:41, Train_loss:0.00014, Test_loss:0.00065
learning rate = 0.00618 Epoch:42, Train_loss:0.00015, Test_loss:0.00064
learning rate = 0.00476 Epoch:43, Train_loss:0.00015, Test_loss:0.00065
learning rate = 0.00351 Epoch:44, Train_loss:0.00015, Test_loss:0.00065
learning rate = 0.00245 Epoch:45, Train_loss:0.00015, Test_loss:0.00066
learning rate = 0.00157 Epoch:46, Train_loss:0.00015, Test_loss:0.00065
learning rate = 0.00089 Epoch:47, Train_loss:0.00015, Test_loss:0.00066
learning rate = 0.00039 Epoch:48, Train_loss:0.00015, Test_loss:0.00066
learning rate = 0.00010 Epoch:49, Train_loss:0.00015, Test_loss:0.00066
learning rate = 0.00000 Epoch:50, Train_loss:0.00015, Test_loss:0.00066
==================== Done ====================
四、模型评估
1、Loss图
import matplotlib.pyplot as plt
from datetime import datetime
current_time = datetime.now() # 获取当前时间
plt.figure(figsize=(5, 3),dpi=120)
plt.plot(train_loss , label='LSTM Training Loss')
plt.plot(test_loss, label='LSTM Validation Loss')
plt.title('Training and Validation Loss')
plt.xlabel(current_time) # 打卡请带上时间戳,否则代码截图无效
plt.legend()
plt.show()
代码输出:
2、调用模型预测:
model = model.to(device) # 将模型移动到 GPU
X_test = X_test.to(device) # 将测试数据移动到 GPU
# 测试集输入模型进行预测,然后转换回 CPU 进行反归一化
predicted_y_lstm = sc.inverse_transform(model(X_test).detach().cpu().numpy().reshape(-1, 1))
y_test_1 = sc.inverse_transform(y_test.reshape(-1, 1))
y_test_one = [i[0] for i in y_test_1]
predicted_y_lstm_one = [i[0] for i in predicted_y_lstm]
plt.figure(figsize=(5, 3), dpi=120)
# 画出真实数据和预测数据的对比曲线
plt.plot(y_test_one[:2000], color='red', label='real_temp')
plt.plot(predicted_y_lstm_one[:2000], color='blue', label='prediction')
plt.title('Title')
plt.xlabel('X')
plt.ylabel('Y')
plt.legend()
plt.show()
代码输出:
3、R²评估
from sklearn import metrics
"""
RMSE :均方根误差 -----> 对均方误差开方
R2 :决定系数,可以简单理解为反映模型拟合优度的重要的统计量
"""
RMSE_lstm = metrics.mean_squared_error(predicted_y_lstm_one, y_test_1)**0.5
R2_lstm = metrics.r2_score(predicted_y_lstm_one, y_test_1)
print('均方根误差: %.5f' % RMSE_lstm)
print('R2: %.5f' % R2_lstm)
``
代码输出:
```python
均方根误差: 7.21383
R2: 0.81756
五、提升:使用第1-8个时刻的数据预测第9~10个时刻的温度数据
模型改造:
class model_lstm2(nn.Module):
def __init__(self):
super(model_lstm2, self).__init__()
self.lstm0 = nn.LSTM(input_size=3, hidden_size=320,
num_layers=1, batch_first=True)
self.lstm1 = nn.LSTM(input_size=320, hidden_size=320,
num_layers=1, batch_first=True)
# 修改 fc0,输出 2 个值
self.fc0 = nn.Linear(320, 2)
def forward(self, x):
out, hidden1 = self.lstm0(x)
out, _ = self.lstm1(out, hidden1)
# 取最后一个时间步的隐藏状态,经过 fc0 得到 (batch, 2)
out = self.fc0(out[:, -1, :])
# 重新调整形状为 (batch, 2, 1)
return out.unsqueeze(2)
model2 = model_lstm2()
model2
使输出后两个温度,重新训练模型:
learning rate = 0.09990 Epoch: 1, Train_loss:0.05822, Test_loss:0.19761
learning rate = 0.09961 Epoch: 2, Train_loss:0.04638, Test_loss:0.17118
learning rate = 0.09911 Epoch: 3, Train_loss:0.03971, Test_loss:0.13120
learning rate = 0.09843 Epoch: 4, Train_loss:0.02665, Test_loss:0.07101
learning rate = 0.09755 Epoch: 5, Train_loss:0.00976, Test_loss:0.01794
learning rate = 0.09649 Epoch: 6, Train_loss:0.00118, Test_loss:0.00188
learning rate = 0.09524 Epoch: 7, Train_loss:0.00019, Test_loss:0.00082
learning rate = 0.09382 Epoch: 8, Train_loss:0.00015, Test_loss:0.00079
learning rate = 0.09222 Epoch: 9, Train_loss:0.00015, Test_loss:0.00073
learning rate = 0.09045 Epoch:10, Train_loss:0.00015, Test_loss:0.00093
learning rate = 0.08853 Epoch:11, Train_loss:0.00015, Test_loss:0.00075
learning rate = 0.08645 Epoch:12, Train_loss:0.00015, Test_loss:0.00077
learning rate = 0.08423 Epoch:13, Train_loss:0.00015, Test_loss:0.00078
learning rate = 0.08187 Epoch:14, Train_loss:0.00015, Test_loss:0.00079
learning rate = 0.07939 Epoch:15, Train_loss:0.00014, Test_loss:0.00074
learning rate = 0.07679 Epoch:16, Train_loss:0.00014, Test_loss:0.00077
learning rate = 0.07409 Epoch:17, Train_loss:0.00014, Test_loss:0.00074
learning rate = 0.07129 Epoch:18, Train_loss:0.00014, Test_loss:0.00080
learning rate = 0.06841 Epoch:19, Train_loss:0.00014, Test_loss:0.00080
learning rate = 0.06545 Epoch:20, Train_loss:0.00014, Test_loss:0.00080
learning rate = 0.06243 Epoch:21, Train_loss:0.00014, Test_loss:0.00071
learning rate = 0.05937 Epoch:22, Train_loss:0.00015, Test_loss:0.00073
learning rate = 0.05627 Epoch:23, Train_loss:0.00014, Test_loss:0.00075
learning rate = 0.05314 Epoch:24, Train_loss:0.00014, Test_loss:0.00069
learning rate = 0.05000 Epoch:25, Train_loss:0.00014, Test_loss:0.00071
learning rate = 0.04686 Epoch:26, Train_loss:0.00014, Test_loss:0.00074
learning rate = 0.04373 Epoch:27, Train_loss:0.00014, Test_loss:0.00079
learning rate = 0.04063 Epoch:28, Train_loss:0.00014, Test_loss:0.00076
learning rate = 0.03757 Epoch:29, Train_loss:0.00014, Test_loss:0.00079
learning rate = 0.03455 Epoch:30, Train_loss:0.00014, Test_loss:0.00072
learning rate = 0.03159 Epoch:31, Train_loss:0.00014, Test_loss:0.00080
learning rate = 0.02871 Epoch:32, Train_loss:0.00014, Test_loss:0.00075
learning rate = 0.02591 Epoch:33, Train_loss:0.00014, Test_loss:0.00074
learning rate = 0.02321 Epoch:34, Train_loss:0.00015, Test_loss:0.00076
learning rate = 0.02061 Epoch:35, Train_loss:0.00014, Test_loss:0.00075
learning rate = 0.01813 Epoch:36, Train_loss:0.00014, Test_loss:0.00076
learning rate = 0.01577 Epoch:37, Train_loss:0.00014, Test_loss:0.00075
learning rate = 0.01355 Epoch:38, Train_loss:0.00014, Test_loss:0.00077
learning rate = 0.01147 Epoch:39, Train_loss:0.00014, Test_loss:0.00073
learning rate = 0.00955 Epoch:40, Train_loss:0.00014, Test_loss:0.00077
learning rate = 0.00778 Epoch:41, Train_loss:0.00014, Test_loss:0.00075
learning rate = 0.00618 Epoch:42, Train_loss:0.00014, Test_loss:0.00077
learning rate = 0.00476 Epoch:43, Train_loss:0.00014, Test_loss:0.00077
learning rate = 0.00351 Epoch:44, Train_loss:0.00014, Test_loss:0.00076
learning rate = 0.00245 Epoch:45, Train_loss:0.00014, Test_loss:0.00076
learning rate = 0.00157 Epoch:46, Train_loss:0.00014, Test_loss:0.00076
learning rate = 0.00089 Epoch:47, Train_loss:0.00014, Test_loss:0.00076
learning rate = 0.00039 Epoch:48, Train_loss:0.00014, Test_loss:0.00077
learning rate = 0.00010 Epoch:49, Train_loss:0.00014, Test_loss:0.00076
learning rate = 0.00000 Epoch:50, Train_loss:0.00014, Test_loss:0.00076
==================== Done ====================
后续一样我们看Loss图:
预测图:
均方根:
均方根误差: 7.78845
R2: 0.77220