R4Pytorch实现:LSTM-火灾温度预测

张开发
2026/4/4 5:33:30 15 分钟阅读
R4Pytorch实现:LSTM-火灾温度预测
本文为365天深度学习训练营 中的学习记录博客 原作者K同学啊LSTM (Long Short-Term Memory长短期记忆网络) 是一种专为处理序列数据如时间、文本、语音而设计的循环神经网络 (RNN)。它最大的突破是解决了传统 RNN 无法处理长序列时的梯度消失问题能够有效记住序列中相隔很远的关键信息。一、为什么需要 LSTM传统 RNN 的痛点标准 RNN 的结构像一条链每一时刻的信息只传给下一时刻。但在处理长序列如长句子、长时间序列时梯度消失早期信息的梯度经过多次乘法后变得极小网络无法学习到早期的重要信息“记不住很久以前的事”。梯度爆炸梯度变得极大导致参数更新失控训练崩溃。举例在句子 “我小时候在北京长大那里的秋天很美我很喜欢____。” 中传统 RNN 可能早已忘记 “北京”而 LSTM 可以保留这个关键信息来预测空格内容。二、LSTM 的核心结构LSTM 的核心是细胞状态 (Cell State, Cₜ) 和三个门控 (Gate)。你可以把它想象成一个智能传送带和三个开关细胞状态 (Cell State, Cₜ) —— 记忆传送带贯穿整个网络的 “信息高速公路”信息在上面流动时只有少量线性操作几乎无损。负责长期记忆像一条传送带让重要信息可以一直传递下去。三个门控 (Gates) —— 信息管理员门控本质是一个 Sigmoid 层 点乘运算Sigmoid 输出 0~1 之间的值0 代表完全丢弃1 代表完全保留。三个门协同工作控制信息的遗忘、存储、输出。1遗忘门 (Forget Gate, fₜ) —— 决定忘记什么作用决定从上一时刻的细胞状态 Cₜ₋₁ 中丢弃哪些无用信息。输入上一时刻的隐藏状态 hₜ₋₁ 当前时刻输入 xₜ。公式fₜ σ(Wf · [hₜ₋₁, xₜ] bf)2输入门 (Input Gate, iₜ) —— 决定记住什么新信息作用决定将当前时刻的哪些新信息存入细胞状态。两步输入门 iₜ决定哪些值需要更新。候选细胞状态 C̃ₜ通过 tanh 生成待加入的新信息。公式iₜ σ(Wi · [hₜ₋₁, xₜ] bi)C̃ₜ tanh(Wc · [hₜ₋₁, xₜ] bc)3更新细胞状态 (最核心步骤)作用结合遗忘门和输入门更新长期记忆。公式Cₜ fₜ ⊙ Cₜ₋₁ iₜ ⊙ C̃ₜfₜ ⊙ Cₜ₋₁保留一部分旧记忆。iₜ ⊙ C̃ₜ添加一部分新记忆。4输出门 (Output Gate, oₜ) —— 决定输出什么作用决定从当前细胞状态 Cₜ 中输出哪些信息作为当前隐藏状态 hₜ。公式oₜ σ(Wo · [hₜ₋₁, xₜ] bo)hₜ oₜ ⊙ tanh(Cₜ)三、LSTM 工作流程一句话总结遗忘忘记不重要的旧记忆。输入筛选并记住重要的新信息。更新合并新旧记忆更新细胞状态。输出基于最新记忆生成当前输出并传给下一时刻。四、LSTM 的主要变体GRU (Gated Recurrent Unit)简化版 LSTM合并遗忘门和输入门为更新门去掉细胞状态只有隐藏状态速度更快效果接近 LSTM。Bidirectional LSTM (Bi-LSTM)双向 LSTM同时从前往后和从后往前处理序列能同时利用过去和未来的信息常用于 NLP。Stacked LSTM多层 LSTM 堆叠深层网络学习更抽象的特征。五、典型应用场景时间序列预测代码场景 ——火灾温度预测、股价、天气、能耗预测。自然语言处理 (NLP)文本生成、机器翻译、情感分析、命名实体识别。语音处理语音识别、语音合成。其他手写识别、视频行为分析。六、回到代码训练火灾温度预测的代码中输入 X前 8 个时间步的 [Tem1, CO1, Soot1] 三维序列。LSTM 层网络自动学习这 8 步数据中的规律记住与温度相关的关键特征如 CO 浓度突增预示温度上升。输出 y基于学到的规律预测第 9 步的温度值。总结LSTM 就是一个拥有 “长期记忆力” 的神经网络。 它通过细胞状态和三重门控像人一样选择性地忘记无关信息、记住关键信息从而完美解决了长序列依赖问题是深度学习处理时序数据的基石。# 1. 环境配置与库导入 # 解决matplotlib在部分电脑上可能出现的多线程冲突问题importos os.environ.setdefault(KMP_DUPLICATE_LIB_OK,TRUE)# 导入PyTorch核心库神经网络函数、张量运算、网络层模块importtorch.nn.functionalasFimportnumpyasnp# 数值计算库处理数组importpandasaspd# 数据处理库读取csv、表格数据importtorch# 深度学习框架PyTorchfromtorchimportnn# PyTorch神经网络模块# 2. 读取火灾数据集 # 定义csv数据文件路径你本地的火灾实验数据file_pathD:\\my_project\\python\\365\\data\\woodpine2\\woodpine2.csv# 读取csv文件到DataFrame表格包含温度、CO浓度、烟密度等火灾特征datapd.read_csv(file_path)# 3. 原始数据可视化画图 importmatplotlib.pyplotasplt# 绘图库importseabornassns# 基于matplotlib的高级绘图库# 设置图片清晰度保存分辨率500dpi显示分辨率500dpiplt.rcParams[savefig.dpi]500plt.rcParams[figure.dpi]500# 创建1行3列的子图总尺寸14x3自动布局防重叠fig,axplt.subplots(1,3,constrained_layoutTrue,figsize(14,3))# 分别绘制三个特征的原始时序曲线sns.lineplot(datadata[Tem1],axax[0])# 子图1温度Tem1sns.lineplot(datadata[CO 1],axax[1])# 子图2一氧化碳浓度CO 1sns.lineplot(datadata[Soot 1],axax[2],colorr)# 子图3烟密度Soot 1红色fromdatetimeimportdatetime current_timedatetime.now()# 获取当前系统时间plt.xlabel(current_time)# 横坐标标注当前时间plt.show()# 显示原始数据图# 4. 数据预处理 # 去掉第0列索引/时间列只保留特征Tem1、CO 1、Soot 1dataFramedata.iloc[:,1:]fromsklearn.preprocessingimportMinMaxScaler# 数据归一化工具# 归一化把所有数据缩放到 0~1 之间让神经网络训练更稳定scMinMaxScaler(feature_range(0,1))# 对三个特征分别做归一化foriin[CO 1,Soot 1,Tem1]:# reshape(-1,1)把一维数据转成二维满足sklearn输入格式dataFrame[i]sc.fit_transform(dataFrame[i].values.reshape(-1,1))# 5. 构造时序样本核心 width_X8# 输入序列长度用前8个时间点的数据width_y1# 预测长度预测第9个时间点的温度# 定义空列表存放输入X和标签yX[]y[]in_start0# 滑动窗口起始位置从0开始# 遍历每一行数据滑动构造样本for_,_indata.iterrows():in_endin_startwidth_X# 输入窗口结束0~7共8个out_endin_endwidth_y# 输出位置第8号索引第9个点# 防止越界确保窗口不超出数据长度ifout_endlen(dataFrame):# 取 前8个时间步 的所有特征Tem1、CO、Soot作为输入X_np.array(dataFrame.iloc[in_start:in_end,])# 取 第9个时间步 的温度第0列作为预测目标yy_np.array(dataFrame.iloc[in_end:out_end,0])X.append(X_)# 加入输入列表y.append(y_)# 加入标签列表in_start1# 窗口向后滑动1步# 把列表转成numpy数组方便送入模型Xnp.array(X)ynp.array(y).reshape(-1,width_y,1)# 调整形状适配LSTM输入# 检查数据是否有缺失值NaN确保数据干净print(np.any(np.isnan(X)))print(np.any(np.isnan(y)))# 6. 划分训练集/测试集并转为张量 # 前5000个样本做训练集转为float32张量PyTorch默认类型X_traintorch.tensor(np.array(X[:5000]),dtypetorch.float32)y_traintorch.tensor(np.array(y[:5000]),dtypetorch.float32)# 剩余样本做测试集X_testtorch.tensor(np.array(X[5000:]),dtypetorch.float32)y_testtorch.tensor(np.array(y[5000:]),dtypetorch.float32)# 封装成数据集加载器自动分批、打乱fromtorch.utils.dataimportTensorDataset,DataLoader train_dlDataLoader(TensorDataset(X_train,y_train),batch_size64,# 每批64个样本shuffleTrue)# 训练集打乱提高泛化能力test_dlDataLoader(TensorDataset(X_test,y_test),batch_size64,shuffleTrue)# 7. 定义第一个LSTM模型预测单输出温度 classmodel_lstm1(nn.Module):def__init__(self):super(model_lstm1,self).__init__()# 第一层LSTM输入3个特征Tem1、CO、Soot隐藏层320维1层batch优先self.lstm0nn.LSTM(input_size3,hidden_size320,num_layers1,batch_firstTrue)# 第二层LSTM接收上一层320维输出继续提取时序特征self.lstm1nn.LSTM(input_size320,hidden_size320,num_layers1,batch_firstTrue)# 全连接层把320维特征映射为1个输出预测温度self.fc0nn.Linear(320,1)defforward(self,x):# 前向传播数据流过网络out,hidden1self.lstm0(x)# 第一层LSTMout,_self.lstm1(out,hidden1)# 第二层LSTMoutself.fc0(out)# 全连接输出returnout[:,-1:,:]# 只取最后1个时间步的预测值我们只需要预测第9步温度model1model_lstm1()# 实例化模型# 8. 定义训练函数 importcopydeftrain(train_dl,model,loss_fn,opt,lr_schedulerNone):sizelen(train_dl.dataset)# 训练集总样本数num_batcheslen(train_dl)# 总批次数train_loss0# 累计训练损失forx,yintrain_dl:# 遍历每一批数据x,yx.to(device),y.to(device)# 数据移到GPU/CPUpredmodel(x)# 模型前向预测lossloss_fn(pred,y)# 计算预测值与真实值误差MSEopt.zero_grad()# 清空上一轮梯度loss.backward()# 反向传播计算梯度opt.step()# 更新模型参数train_lossloss.item()# 累加损失iflr_schedulerisnotNone:lr_scheduler.step()# 更新学习率余弦退火print(learning rate {:.5f}.format(opt.param_groups[0][lr]),end )train_loss/num_batches# 平均每批次损失returntrain_loss# 9. 定义测试函数 deftest(dataloader,model,loss_fn):sizelen(dataloader.dataset)num_batcheslen(dataloader)test_loss0withtorch.no_grad():# 测试时不计算梯度节省显存forx,yindataloader:x,yx.to(device),y.to(device)y_predmodel(x)lossloss_fn(y_pred,y)test_lossloss.item()test_loss/num_batchesreturntest_loss# 10. 设置训练设备GPU优先 devicetorch.device(cudaiftorch.cuda.is_available()elsecpu)# 11. 开始训练模型 modelmodel_lstm1()modelmodel.to(device)# 模型移到设备loss_fnnn.MSELoss()# 损失函数均方误差回归任务标配learn_rate1e-1# 学习率0.1opttorch.optim.SGD(model.parameters(),lrlearn_rate,weight_decay1e-4)# 优化器epochs50# 训练50轮train_loss[]# 记录每轮训练损失test_loss[]# 记录每轮测试损失lr_schedulertorch.optim.lr_scheduler.CosineAnnealingLR(opt,epochs,last_epoch-1)# 学习率余弦衰减# 循环训练forepochinrange(epochs):model.train()# 训练模式epoch_train_losstrain(train_dl,model,loss_fn,opt,lr_scheduler)model.eval()# 评估模式epoch_test_losstest(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(epoch1,epoch_train_loss,epoch_test_loss))print(*20,训练完成,*20)# 12. 绘制损失曲线 importmatplotlib.pyplotaspltfromdatetimeimportdatetime current_timedatetime.now()plt.figure(figsize(5,3),dpi120)plt.plot(train_loss,labelLSTM Training Loss)# 训练损失plt.plot(test_loss,labelLSTM Validation Loss)# 验证损失plt.title(Training and Validation Loss)plt.xlabel(current_time)# 横坐标时间戳plt.legend()plt.show()# 13. 模型预测 反归一化 modelmodel.to(device)X_testX_test.to(device)# 模型预测 → 从GPU转到CPU → 转为numpy → 反归一化还原成真实温度predicted_y_lstmsc.inverse_transform(model(X_test).detach().cpu().numpy().reshape(-1,1))y_test_1sc.inverse_transform(y_test.reshape(-1,1))# 真实值也反归一化# 转成一维列表方便画图y_test_one[i[0]foriiny_test_1]predicted_y_lstm_one[i[0]foriinpredicted_y_lstm]# 14. 绘制真实值 vs 预测值曲线 plt.figure(figsize(5,3),dpi120)plt.plot(y_test_one[:2000],colorred,labelreal_temp)# 前2000点真实温度plt.plot(predicted_y_lstm_one[:2000],colorblue,labelprediction)# 预测温度plt.title(火灾温度预测结果)plt.xlabel(current_time)plt.ylabel(温度)plt.legend()plt.show()# 15. 模型评估指标 fromsklearnimportmetrics# RMSE均方根误差越小越好RMSE_lstmmetrics.mean_squared_error(predicted_y_lstm_one,y_test_1)**0.5# R²决定系数越接近1拟合越好R2_lstmmetrics.r2_score(predicted_y_lstm_one,y_test_1)print(均方根误差: %.5f%RMSE_lstm)print(R2: %.5f%R2_lstm)# 16. 第二个LSTM模型输出2个预测值扩展用 classmodel_lstm2(nn.Module):def__init__(self):super(model_lstm2,self).__init__()self.lstm0nn.LSTM(input_size3,hidden_size320,num_layers1,batch_firstTrue)self.lstm1nn.LSTM(input_size320,hidden_size320,num_layers1,batch_firstTrue)self.fc0nn.Linear(320,2)# 输出2个值可同时预测温度CO等defforward(self,x):out,hidden1self.lstm0(x)out,_self.lstm1(out,hidden1)outself.fc0(out[:,-1,:])returnout.unsqueeze(2)# 形状调整为 (batch, 2, 1)model2model_lstm2()

更多文章