您现在的位置是:首页 > 技术教程 正文

时间序列预测模型实战案例(三)(LSTM)(Python)(深度学习)时间序列预测(包括运行代码以及代码讲解)

admin 阅读: 2024-03-25
后台-插件-广告管理-内容页头部广告(手机)

目录

引言

LSTM的预测效果图

LSTM机制

了解LSTM的结构

忘记门

输入门

输出门

LSTM的变体

只有忘记门的LSTM单元

独立循环(IndRNN)单元

双向RNN结构(LSTM)

运行代码

代码讲解


引言

LSTM(Long Short-Term Memory)是一种常用的循环神经网络(RNN)模型,用于处理序列数据,具有记忆长短期的能力。在时间序列预测中,LSTM既可以多元预测机制又可以作为单元预测机制使用。

作为多元预测机制,LSTM可以处理多个相关变量的历史数据,从而可以预测这些变量的未来值。具体地,我们可以将多个变量的历史数据作为LSTM的输入,将多个变量的未来值作为LSTM的输出。在训练过程中,我们可以使用误差反向传播算法来更新LSTM的参数,从而优化模型的预测性能。

作为单元预测机制,LSTM可以预测单一变量的未来值,例如股票价格、销售量等。在单元时间序列预测中,我们需要对历史数据进行分析,确定趋势、季节性和周期性等因素,并使用这些因素来预测未来的值。LSTM可以通过学习历史数据中的模式和规律,来预测未来的值。

LSTM作为多元预测机制和单元预测机制的优点是可以处理序列数据中的长期依赖关系,从而可以捕捉到数据中的复杂模式和规律。它可以自适应地学习和调整模型参数,从而提高模型的预测性能和泛化能力。

总的来说,LSTM作为多元预测机制和单元预测机制的应用广泛,可以用于预测股票价格、气象数据、交通流量等多个领域的数据。

(文末有复制粘贴即可运行的代码)

LSTM的预测效果图

这里先给大家展示一下LSTM的预测效果图(这里的预测指的是预测未知的数据并不是在测试集或者验证集上的预测),其中MAE误差为0.15,ME误差为-0.03。

其误差损失图为,其为MAE的误差图

LSTM机制

LSTM(长短期记忆,Long Short-Term Memory)是一种用于处理序列数据的深度学习模型属于循环神经网络(RNN)的一种变体,其使用一种类似于搭桥术结构的RNN单元。相对于普通的RNN,LSTM引入了门控机制,能够更有效地处理长期依赖和短期记忆问题,是RNN网络中最常使用的Cell之一。

了解LSTM的结构

LSTM通过刻意的设计来实现学习序列关系的同时,又能够避免长期依赖的问题。它的结构示意图如下所示。

在LSTM的结构示意图中,每一条黑线传输着一整个向量,从一个节点的输出到其他节点的输入。其中“+”号代表着运算操作(如矢量的和)而矩形代表着学习到的神经网络层。汇合在一起的线表示向量的连接,分叉的线表示内容被复制,然后分发到不同的位置。

如果上面的LSTM结构图你看着很难理解,但是其实LSTM的本质就是一个带有tanh激活函数的简单RNN,如下图所示。

LSTM这种结构的原理是引入一个称为细胞状态的连接。这个状态细胞用来存放想要的记忆的东西(对应简单LSTM结构中的h,只不过这里面不再只保存上一次状态了,而是通过网络学习存放那些有用的状态),同时在加入三个门,分别是

        忘记门:决定什么时候将以前的状态忘记。

        输入门:决定什么时候将新的状态加进来。

        输出门:决定什么时候需要把状态和输入放在一起输出。

从字面上可以看出,由于三个门的操作,LSTM在状态的更新和状态是否要作为输入,全部交给了神经网络的训练机制来选择。

下面分别来介绍一下三个门的结构和作用。

忘记门

下图所示为忘记门的操作,忘记门决定模型会从细胞状态中丢弃什么信息

忘记门会读取前一序列模型的输出h_{t-1}

在上图的LSTM的忘记门中,f_{t}

在上面输入门的结构中,I_{t}

再上图LSTM输入门的更新图中,B_{t}

在LSTM的输出门结构图中,O_{t}

双向RNN会比单项RNN多一个隐藏层,6个独特的权值在每一个时步被重复利用,6个权值分别对应:输入到向前和向后隐含层,隐含层到隐含层自身,向前和向后隐含层到输出层。

有关双向RNN(LSTM)我会在后续文章中讲到,这里只是大致介绍一下。 

(在大多数应用中,基于时间序列的分析和有关NLP中自动回答类的一些问题中,一般是以双向LSTM配合单向LSTM或RNN横向扩展来实现,效果非常好)

运行代码

下面的代码大家可以赋值到一个py文件中输入自己的文件预测文件即可运行,这只是一个简单LSTM模型搭建,其可以搭配许多其他模块进行组合例如:注意力机制(TPA)、其他的网络结构(GRU)、双向的RNN结构等。

  1. import time
  2. import numpy as np
  3. import pandas as pd
  4. import torch
  5. import torch.nn as nn
  6. from matplotlib import pyplot as plt
  7. from sklearn.preprocessing import MinMaxScaler
  8. np.random.seed(0)
  9. def calculate_mae(y_true, y_pred):
  10. # 平均绝对误差
  11. mae = np.mean(np.abs(y_true - y_pred))
  12. return mae
  13. true_data = pd.read_csv('ETTh1-Test.csv') # 填你自己的数据地址
  14. target = 'OT'
  15. # 这里加一些数据的预处理, 最后需要的格式是pd.series
  16. true_data = np.array(true_data['OT'])
  17. # 定义窗口大小
  18. test_data_size = 32
  19. # 训练集和测试集的尺寸划分
  20. test_size = 0.15
  21. train_size = 0.85
  22. # 标准化处理
  23. scaler_train = MinMaxScaler(feature_range=(0, 1))
  24. scaler_test = MinMaxScaler(feature_range=(0, 1))
  25. train_data = true_data[:int(train_size * len(true_data))]
  26. test_data = true_data[-int(test_size * len(true_data)):]
  27. print("训练集尺寸:", len(train_data))
  28. print("测试集尺寸:", len(test_data))
  29. train_data_normalized = scaler_train.fit_transform(train_data.reshape(-1, 1))
  30. test_data_normalized = scaler_test.fit_transform(test_data.reshape(-1, 1))
  31. # 转化为深度学习模型需要的类型Tensor
  32. train_data_normalized = torch.FloatTensor(train_data_normalized).view(-1)
  33. test_data_normalized = torch.FloatTensor(test_data_normalized).view(-1)
  34. def create_inout_sequences(input_data, tw, pre_len):
  35. inout_seq = []
  36. L = len(input_data)
  37. for i in range(L - tw):
  38. train_seq = input_data[i:i + tw]
  39. if (i + tw + 4) > len(input_data):
  40. break
  41. train_label = input_data[i + tw:i + tw + pre_len]
  42. inout_seq.append((train_seq, train_label))
  43. return inout_seq
  44. pre_len = 4
  45. train_window = 16
  46. # 定义训练器的的输入
  47. train_inout_seq = create_inout_sequences(train_data_normalized, train_window, pre_len)
  48. class LSTM(nn.Module):
  49. def __init__(self, input_dim=1, hidden_dim=350, output_dim=1):
  50. super(LSTM, self).__init__()
  51. self.hidden_dim = hidden_dim
  52. self.lstm = nn.LSTM(input_dim, hidden_dim, batch_first=True)
  53. self.fc = nn.Linear(hidden_dim, output_dim)
  54. def forward(self, x):
  55. x = x.unsqueeze(1)
  56. h0_lstm = torch.zeros(1, self.hidden_dim).to(x.device)
  57. c0_lstm = torch.zeros(1, self.hidden_dim).to(x.device)
  58. out, _ = self.lstm(x, (h0_lstm, c0_lstm))
  59. out = out[:, -1]
  60. out = self.fc(out)
  61. return out
  62. lstm_model = LSTM(input_dim=1, output_dim=pre_len, hidden_dim=train_window)
  63. loss_function = nn.MSELoss()
  64. optimizer = torch.optim.Adam(lstm_model.parameters(), lr=0.001)
  65. epochs = 10
  66. Train = True # 训练还是预测
  67. if Train:
  68. losss = []
  69. lstm_model.train() # 训练模式
  70. start_time = time.time() # 计算起始时间
  71. for i in range(epochs):
  72. for seq, labels in train_inout_seq:
  73. lstm_model.train()
  74. optimizer.zero_grad()
  75. y_pred = lstm_model(seq)
  76. single_loss = loss_function(y_pred, labels)
  77. single_loss.backward()
  78. optimizer.step()
  79. print(f'epoch: {i:3} loss: {single_loss.item():10.8f}')
  80. losss.append(single_loss.detach().numpy())
  81. torch.save(lstm_model.state_dict(), 'save_model.pth')
  82. print(f"模型已保存,用时:{(time.time() - start_time) / 60:.4f} min")
  83. plt.plot(losss)
  84. # 设置图表标题和坐标轴标签
  85. plt.title('Training Error')
  86. plt.xlabel('Epoch')
  87. plt.ylabel('Error')
  88. # 保存图表到本地
  89. plt.savefig('training_error.png')
  90. else:
  91. # 加载模型进行预测
  92. lstm_model.load_state_dict(torch.load('save_model.pth'))
  93. lstm_model.eval() # 评估模式
  94. results = []
  95. reals = []
  96. losss = []
  97. test_inout_seq = create_inout_sequences(test_data_normalized, train_window, pre_len)
  98. for seq, labels in train_inout_seq:
  99. pred = lstm_model(seq)[0].item()
  100. results.append(pred)
  101. mae = calculate_mae(pred, labels.detach().numpy()) # MAE误差计算绝对值(预测值 - 真实值)
  102. reals.append(labels.detach().numpy())
  103. losss.append(mae)
  104. print("模型预测结果:", results)
  105. print("预测误差MAE:", losss)
  106. plt.style.use('ggplot')
  107. # 创建折线图
  108. plt.plot(results, label='real', color='blue') # 实际值
  109. plt.plot(reals, label='forecast', color='red', linestyle='--') # 预测值
  110. # 增强视觉效果
  111. plt.grid(True)
  112. plt.title('real vs forecast')
  113. plt.xlabel('time')
  114. plt.ylabel('value')
  115. plt.legend()
  116. plt.savefig('test——results.png')

数据格式 

运行上述代码需要只需要一列数据即可,并且最后数据需要是一个pd.series类型,大家可以在读取进来文件后面加一些数据的处理操作。

(需要注意的是大家的数据不要打乱时间顺序否则预测出来的结果可能不准) 

代码讲解

在上面的运行代码中,主要填写的是在下面填上你的数据目录,

true_data = pd.read_csv('') # 填你自己的数据地址

这里是定义了test_data_size是指根据过去多少条数据来预测未来的预测值

test_size和train_size代表训练集和测试集的尺寸划分。 

  1. # 定义窗口大小
  2. test_data_size = 350
  3. # 训练集和测试集的尺寸划分
  4. test_size = 0.15
  5. train_size = 0.85

这里定义了数据加载器的操作 

  1. def create_inout_sequences(input_data, tw):
  2. inout_seq = []
  3. L = len(input_data)
  4. for i in range(L - tw):
  5. train_seq = input_data[i:i + tw]
  6. if (i + tw + 4) > len(input_data):
  7. break
  8. train_label = input_data[i + tw:i + tw + 1]
  9. inout_seq.append((train_seq, train_label))
  10. return inout_seq
  11. train_window = 350
  12. # 定义训练器的的输入
  13. train_inout_seq = create_inout_sequences(train_data_normalized, train_window)

模型的本身其中包含一个LSTM层和一个全连接层进行结果的输出 

  1. class LSTM(nn.Module):
  2. def __init__(self, input_dim=1, hidden_dim=350, output_dim=1):
  3. super(LSTM, self).__init__()
  4. self.hidden_dim = hidden_dim
  5. self.lstm = nn.LSTM(input_dim, hidden_dim, batch_first=True)
  6. self.fc = nn.Linear(hidden_dim, output_dim)
  7. def forward(self, x):
  8. x = x.unsqueeze(1)
  9. h0_lstm = torch.zeros(1, self.hidden_dim).to(x.device)
  10. c0_lstm = torch.zeros(1, self.hidden_dim).to(x.device)
  11. out, _ = self.lstm(x, (h0_lstm, c0_lstm))
  12. out = out[:, -1]
  13. out = self.fc(out)
  14. return out

这里定义了模型损失函数和优化器,其中的Train代表着是否进行训练。 

  1. lstm_model = LSTM()
  2. loss_function = nn.MSELoss()
  3. optimizer = torch.optim.Adam(lstm_model.parameters(), lr=0.001)
  4. epochs = 20
  5. Train = False # 训练还是预测

当Train为True时则开始训练并在最好将模型保存到本地,训练好模型之后我门将Train设置为False则开始评估模式。 

  1. if Train:
  2. losss = []
  3. lstm_model.train() # 训练模式
  4. for i in range(epochs):
  5. start_time = time.time() # 计算起始时间
  6. for seq, labels in train_inout_seq:
  7. lstm_model.train()
  8. optimizer.zero_grad()
  9. y_pred = lstm_model(seq)
  10. single_loss = loss_function(y_pred, labels)
  11. losss.append(single_loss.detach().numpy())
  12. single_loss.backward()
  13. optimizer.step()
  14. if i % 1 == 1:
  15. print(f'epoch: {i:3} loss: {single_loss.item():10.8f}')
  16. torch.save(lstm_model.state_dict(), 'save_model.pth')
  17. print(f"模型已保存,用时:{(time.time() - start_time) / 60:.4f} min")
  18. plt.plot(losss)
  19. # 设置图表标题和坐标轴标签
  20. plt.title('Training Error')
  21. plt.xlabel('Epoch')
  22. plt.ylabel('Error')
  23. # 保存图表到本地
  24. plt.savefig('training_error.png')
  25. else:
  26. # 加载模型进行预测
  27. lstm_model.load_state_dict(torch.load('save_model.pth'))
  28. lstm_model.eval() # 评估模式
  29. results = []
  30. losss = []
  31. test_inout_seq = create_inout_sequences(test_data_normalized, train_window)
  32. for seq, labels in test_inout_seq:
  33. # 这里的pred = lstm_model(seq)[0].item()是结果的输出这里只保存了输出的第一个值如果想拿出更多的预测值可以修改数字0用切片的方式
  34. pred = lstm_model(seq)[0].item()
  35. results.append(pred)
  36. mae = calculate_mae(pred, labels.detach().numpy()) # MAE误差计算绝对值(预测值 - 真实值)
  37. losss.append(mae)
  38. print("模型预测结果:", results)
  39. print("预测误差MAE:", losss)

后期我也会讲一些最新的预测模型包括Informer,TPA-LSTM,ARIMA,XGBOOST,Holt-winter,移动平均法等等一系列关于时间序列预测的模型,包括深度学习和机器学习方向的模型我都会讲,你可以根据需求选取适合你自己的模型进行预测,如果有需要可以+个关注,包括本次模型我自己的代码大家有需要我也会放出百度网盘下载链接!!

其它时间序列预测模型的讲解!

--------------------------------------------------------MTS-Mixers---------------------------------------------------------

【全网首发】(MTS-Mixers)(Python)(Pytorch)最新由华为发布的时间序列预测模型实战案例(一)(包括代码讲解)实现企业级预测精度包括官方代码BUG修复Transform模型

 --------------------------------------------------------Holt-Winters--------------------------------------------------------

时间序列预测模型实战案例(二)(Holt-Winter)(Python)结合K-折交叉验证进行时间序列预测实现企业级预测精度(包括运行代码以及代码讲解)

如果大家有不懂的也可以评论区留言一些报错什么的大家可以讨论讨论看到我也会给大家解答如何解决!
 

标签:
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

在线投稿:投稿 站长QQ:1888636

后台-插件-广告管理-内容页尾部广告(手机)
关注我们

扫一扫关注我们,了解最新精彩内容

搜索