- 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
- 🍖 原作者:K同学啊
目标
复用LSTM模型实现火灾温度预测
具体实现
(一)环境
语言环境:Python 3.10
编 译 器: PyCharm
框 架: Pytorch
(二)具体步骤
1. 具体代码
import torch.nn.functional as F
import numpy as np
import pandas as pd
import torch
from torch import nn import matplotlib.pyplot as plt
import seaborn as sns device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(device) data = pd.read_csv('data/woodpine2.csv')
print(data) 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])
plt.show() from sklearn.preprocessing import MinMaxScaler
# 从原始数据中去除第一列(通常为索引列),保留所有行和其他列,并创建数据副本
dataFrame = data.iloc[:,1:].copy()
# 将数据归一化,范围是0-1
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))
print(dataFrame)
print(dataFrame.shape) width_X = 8
width_y = 1 X = []
y = [] print(f"原始数据长度: {len(dataFrame)}")
print(f"可创建的序列数量: {len(dataFrame) - width_X}") # 数据窗口划分主循环
# 功能:将时间序列数据划分为输入样本X和对应标签y
# 参数说明:
# data: 原始数据DataFrame
# dataFrame: 转换后的numpy数组
# width_X: 输入序列长度
# width_y: 输出序列长度
# 返回值:
# X: 输入样本列表
# y: 标签列表
# 窗口滑动逻辑:
# 1. 计算当前窗口结束索引
# 2. 检查窗口是否超出数据边界
# 3. 合法窗口则提取对应数据片段
# 4. 窗口起始位置逐步后移
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, 1) print(X.shape)
print(y.shape) print(np.any(np.isnan(X)))
print(np.any(np.isnan(y))) max_samples = min(5000, len(X))
X_train = torch.tensor(np.array(X[:max_samples]), dtype=torch.float32).to(device)
y_train = torch.tensor(np.array(y[:max_samples]), dtype=torch.float32).to(device)
X_test = torch.tensor(np.array(X[max_samples:]), dtype=torch.float32).to(device)
y_test = torch.tensor(np.array(y[max_samples:]), dtype=torch.float32).to(device)
print("训练集大小:", X_train.shape, y_train.shape)
print("测试集大小:", X_test.shape, y_test.shape) from torch.utils.data import TensorDataset, DataLoader
train_dl = DataLoader(TensorDataset(X_train, y_train), batch_size=64, shuffle=False)
test_dl = DataLoader(TensorDataset(X_test, y_test), batch_size=64, shuffle=False) class model_lstm(nn.Module): """ LSTM神经网络模型,包含两个LSTM层和一个全连接层。 参数: input_size (int): 输入特征的维度,默认为3(CO、烟雾、温度) hidden_size (int): 隐藏层维度,默认为320 num_layers (int): LSTM层数,默认为1 batch_first (bool): 输入数据是否以batch为第一维度,默认True 返回值: torch.Tensor: 形状为(batch_size, 1)的预测结果 """ def __init__(self): super(model_lstm, 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): """ 前向传播函数。 参数: x (torch.Tensor): 输入张量,形状为(batch_size, seq_length, input_size) 返回值: torch.Tensor: 输出张量,形状为(batch_size, 1) """ out, hidden1 = self.lstm0(x) out, _ = self.lstm1(out, hidden1) out = self.fc0(out) return out[:, -1, :] model = model_lstm()
print(model) print(model(torch.rand(30, 8, 3)).shape) import copy
def train(train_dl, model, loss_fn, opt, lr_scheduler=None): """ 训练模型单个epoch。 参数: train_dl (DataLoader): 训练数据加载器 model (nn.Module): 神经网络模型 loss_fn (nn.Module): 损失函数 opt (Optimizer): 优化器 lr_scheduler (LRScheduler): 学习率调度器(可选) 返回值: float: 当前epoch的平均训练损失 """ 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() loss.backward() opt.step() train_loss += loss.item() if lr_scheduler is not None: lr_scheduler.step() print("当前学习率:", lr_scheduler.get_last_lr()) train_loss /= num_batches return train_loss def test(dataloader, model, loss_fn): """ 测试模型性能。 参数: dataloader (DataLoader): 测试数据加载器 model (nn.Module): 训练好的神经网络模型 loss_fn (nn.Module): 损失函数 返回值: float: 测试集的平均损失 """ 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) pred = model(x) loss = loss_fn(pred, y) test_loss += loss.item() test_loss /= num_batches return test_loss # 训练
model = model_lstm().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, T_max=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:{:.3f}, Test_loss:{:.3f}' print(template.format(epoch + 1, epoch_train_loss, epoch_test_loss)) print("="*20, 'Done', "="*20) 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 Testing Loss")
plt.title("Training and Valiadation Loss")
plt.xlabel(current_time)
plt.legend()
plt.show() # 调用模型进行预测
model.eval()
with torch.no_grad(): predicted_y_lstm = sc.inverse_transform(model(X_test).cpu().detach().numpy().reshape(-1, 1))
y_test_1 = sc.inverse_transform(y_test.cpu().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=(10, 5), dpi=120)
plt.plot(y_test_one[:2000], color='red', label='read_temp')
plt.plot(predicted_y_lstm_one[:2000], color='blue', label='predict')
plt.title('Title')
plt.xlabel('X')
plt.ylabel('Y')
plt.legend()
plt.show()
2. 结果
C:\Users\feng_\anaconda3\envs\Pytorch\python.exe E:\dev\AI\Pytorch\RNN\R4-LSTM火灾温度预测\LSTM-HUOZAI.py
cudaTime 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]Tem1 CO 1 Soot 1
0 0.000000 0.000000 0.000000
1 0.000000 0.000000 0.000000
2 0.000000 0.000000 0.000000
3 0.000000 0.000000 0.000000
4 0.000000 0.000000 0.000000
... ... ... ...
5943 0.957447 0.968672 0.968750
5944 0.953901 0.963659 0.964844
5945 0.946809 0.958647 0.958984
5946 0.943262 0.954887 0.955078
5947 0.939716 0.951128 0.951172[5948 rows x 3 columns]
(5948, 3)
原始数据长度: 5948
可创建的序列数量: 5940
(5939, 8, 3)
(5939, 1)
False
False
训练集大小: torch.Size([5000, 8, 3]) torch.Size([5000, 1])
测试集大小: torch.Size([939, 8, 3]) torch.Size([939, 1])
model_lstm((lstm0): LSTM(3, 320, batch_first=True)(lstm1): LSTM(320, 320, batch_first=True)(fc0): Linear(in_features=320, out_features=1, bias=True)
)
torch.Size([30, 1])
当前学习率: [0.09990133642141358]
Epoch: 1, Train_loss:0.001, Test_loss:0.012
当前学习率: [0.0996057350657239]
Epoch: 2, Train_loss:0.014, Test_loss:0.012
当前学习率: [0.09911436253643444]
Epoch: 3, Train_loss:0.014, Test_loss:0.011
当前学习率: [0.09842915805643154]
Epoch: 4, Train_loss:0.013, Test_loss:0.011
当前学习率: [0.09755282581475767]
Epoch: 5, Train_loss:0.013, Test_loss:0.010
当前学习率: [0.09648882429441256]
Epoch: 6, Train_loss:0.012, Test_loss:0.010
当前学习率: [0.09524135262330098]
Epoch: 7, Train_loss:0.012, Test_loss:0.009
当前学习率: [0.09381533400219318]
Epoch: 8, Train_loss:0.011, Test_loss:0.009
当前学习率: [0.09221639627510075]
Epoch: 9, Train_loss:0.010, Test_loss:0.008
当前学习率: [0.09045084971874737]
Epoch:10, Train_loss:0.009, Test_loss:0.007
当前学习率: [0.08852566213878946]
Epoch:11, Train_loss:0.008, Test_loss:0.006
当前学习率: [0.08644843137107057]
Epoch:12, Train_loss:0.007, Test_loss:0.005
当前学习率: [0.08422735529643442]
Epoch:13, Train_loss:0.006, Test_loss:0.005
当前学习率: [0.08187119948743447]
Epoch:14, Train_loss:0.005, Test_loss:0.004
当前学习率: [0.07938926261462366]
Epoch:15, Train_loss:0.004, Test_loss:0.003
当前学习率: [0.07679133974894982]
Epoch:16, Train_loss:0.003, Test_loss:0.003
当前学习率: [0.07408768370508576]
Epoch:17, Train_loss:0.002, Test_loss:0.002
当前学习率: [0.07128896457825362]
Epoch:18, Train_loss:0.002, Test_loss:0.002
当前学习率: [0.06840622763423389]
Epoch:19, Train_loss:0.001, Test_loss:0.001
当前学习率: [0.06545084971874736]
Epoch:20, Train_loss:0.001, Test_loss:0.001
当前学习率: [0.06243449435824272]
Epoch:21, Train_loss:0.001, Test_loss:0.001
当前学习率: [0.05936906572928623]
Epoch:22, Train_loss:0.000, Test_loss:0.001
当前学习率: [0.056266661678215216]
Epoch:23, Train_loss:0.000, Test_loss:0.001
当前学习率: [0.053139525976465665]
Epoch:24, Train_loss:0.000, Test_loss:0.001
当前学习率: [0.049999999999999996]
Epoch:25, Train_loss:0.000, Test_loss:0.001
当前学习率: [0.046860474023534326]
Epoch:26, Train_loss:0.000, Test_loss:0.001
当前学习率: [0.04373333832178478]
Epoch:27, Train_loss:0.000, Test_loss:0.001
当前学习率: [0.040630934270713764]
Epoch:28, Train_loss:0.000, Test_loss:0.001
当前学习率: [0.03756550564175726]
Epoch:29, Train_loss:0.000, Test_loss:0.001
当前学习率: [0.03454915028125265]
Epoch:30, Train_loss:0.000, Test_loss:0.001
当前学习率: [0.03159377236576612]
Epoch:31, Train_loss:0.000, Test_loss:0.001
当前学习率: [0.028711035421746366]
Epoch:32, Train_loss:0.000, Test_loss:0.001
当前学习率: [0.025912316294914226]
Epoch:33, Train_loss:0.000, Test_loss:0.001
当前学习率: [0.023208660251050155]
Epoch:34, Train_loss:0.000, Test_loss:0.001
当前学习率: [0.020610737385376346]
Epoch:35, Train_loss:0.000, Test_loss:0.001
当前学习率: [0.01812880051256551]
Epoch:36, Train_loss:0.000, Test_loss:0.001
当前学习率: [0.015772644703565562]
Epoch:37, Train_loss:0.000, Test_loss:0.001
当前学习率: [0.013551568628929433]
Epoch:38, Train_loss:0.000, Test_loss:0.001
当前学习率: [0.011474337861210542]
Epoch:39, Train_loss:0.000, Test_loss:0.001
当前学习率: [0.009549150281252632]
Epoch:40, Train_loss:0.000, Test_loss:0.001
当前学习率: [0.007783603724899257]
Epoch:41, Train_loss:0.000, Test_loss:0.001
当前学习率: [0.0061846659978068205]
Epoch:42, Train_loss:0.000, Test_loss:0.001
当前学习率: [0.004758647376699033]
Epoch:43, Train_loss:0.000, Test_loss:0.001
当前学习率: [0.0035111757055874327]
Epoch:44, Train_loss:0.000, Test_loss:0.001
当前学习率: [0.0024471741852423235]
Epoch:45, Train_loss:0.000, Test_loss:0.001
当前学习率: [0.0015708419435684518]
Epoch:46, Train_loss:0.000, Test_loss:0.001
当前学习率: [0.000885637463565564]
Epoch:47, Train_loss:0.000, Test_loss:0.001
当前学习率: [0.00039426493427611173]
Epoch:48, Train_loss:0.000, Test_loss:0.001
当前学习率: [9.866357858642205e-05]
Epoch:49, Train_loss:0.000, Test_loss:0.001
当前学习率: [0.0]
Epoch:50, Train_loss:0.000, Test_loss:0.001
==================== Done ====================
(三)总结
- 数据处理采用了滑动窗口技术:将时间序列划分为长度为8的输入序列和长度为1的预测目标
- 多变量输入: 同时使用温度(Tem1)、CO浓度(CO 1)和烟雾浓度(Soot 1)三个特征
- 双层LSTM结构: 两个320隐藏单元的LSTM层串联,增强模型的时序建模能力;单一全连接层直接输出预测结果;