- 🍨 本文為🔗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層串聯,增強模型的時序建模能力;單一全連接層直接輸出預測結果;