长短期记忆网络(简称LSTM)可应用于时间序列预测。
有许多类型的 LSTM 模型可用于每种特定类型的时间序列预测问题。
在本教程中,您将了解如何为一系列标准时间序列预测问题开发一套 LSTM 模型。
本教程的目标是为每种时间序列问题的每个模型提供独立示例,作为您可以复制和调整的模板,以适应您的特定时间序列预测问题。
完成本教程后,您将了解:
如何开发用于单变量时间序列预测的 LSTM 模型。
如何开发用于多元时间序列预测的 LSTM 模型。
如何开发用于多步时间序列预测的 LSTM 模型。
所有示例的Python 源代码文件。
教程概述
在本教程中,我们将探讨如何开发一套用于时间序列预测的不同类型的 LSTM 模型。
这些模型是在小型人为的时间序列问题上进行演示的,旨在展示所要解决的时间序列问题的类型。所选的模型配置是任意的,并未针对每个问题进行优化;这不是我们的目标。
本教程分为四个部分:
- 单变量 LSTM 模型
- 数据准备
- 标准LSTM
- 堆叠式 LSTM
- 双向 LSTM
- CNN 长短期记忆
- 卷积LSTM
- 多元 LSTM 模型
- 多输入系列。
- 多个并行系列。
- 多步骤 LSTM 模型
- 数据准备
- 矢量输出模型
- 编码器-解码器模型
- 多元多步骤 LSTM 模型
- 多输入多步骤输出。
-
多个并行输入和多步输出
一. 单变量 LSTM 模型
LSTM 可用于建模单变量时间序列预测问题。
这些问题由一系列观察组成,需要一个模型从一系列过去的观察中学习来预测序列中的下一个值。
我们将展示用于单变量时间序列预测的 LSTM 模型的多种变体。
本节分为六个部分,分别是:
- 数据准备
- 标准LSTM
- 堆叠式 LSTM
- 双向 LSTM
- CNN 长短期记忆
- 卷积LSTM
这些模型中的每一个都适用于单步单变量时间序列预测,但可以轻松地进行调整并用作其他类型的时间序列预测问题模型的输入部分。
1. 数据准备
在对单变量序列进行建模之前,必须做好准备工作。
LSTM 模型将学习一个函数,该函数将过去观察序列作为输入映射到输出观察。因此,观察序列必须转换为 LSTM 可以学习的多个示例。
考虑给定的单变量序列:
[10, 20, 30, 40, 50, 60, 70, 80, 90]
我们可以将序列划分为多个输入/输出模式(称为样本),其中三个时间步骤用作输入,一个时间步骤用作正在学习的一步预测的输出。
10, 20, 30 40
20, 30, 40 50
30, 40, 50 60
...
下面的split_sequence()函数实现了这一行为,并将给定的单变量序列分成多个样本,其中每个样本具有指定数量的时间步骤,并且输出是单个时间步骤。
# split a univariate sequence into samples
def split_sequence(sequence, n_steps):
X, y = list(), list()
for i in range(len(sequence)):
# find the end of this pattern
end_ix = i + n_steps
# check if we are beyond the sequence
if end_ix > len(sequence)-1:
break
# gather input and output parts of the pattern
seq_x, seq_y = sequence[i:end_ix], sequence[end_ix]
X.append(seq_x)
y.append(seq_y)
return array(X), array(y)
我们可以在上面我们设计的小型数据集上演示此功能。
完整的示例如下。
# univariate data preparation
from numpy import array
# split a univariate sequence into samples
def split_sequence(sequence, n_steps):
X, y = list(), list()
for i in range(len(sequence)):
# find the end of this pattern
end_ix = i + n_steps
# check if we are beyond the sequence
if end_ix > len(sequence)-1:
break
# gather input and output parts of the pattern
seq_x, seq_y = sequence[i:end_ix], sequence[end_ix]
X.append(seq_x)
y.append(seq_y)
return array(X), array(y)
# define input sequence
raw_seq = [10, 20, 30, 40, 50, 60, 70, 80, 90]
# choose a number of time steps
n_steps = 3
# split into samples
X, y = split_sequence(raw_seq, n_steps)
# summarize the data
for i in range(len(X)):
print(X[i], y[i])
运行该示例将单变量序列分成六个样本,每个样本有三个输入时间步骤和一个输出时间步骤。
[10 20 30] 40
[20 30 40] 50
[30 40 50] 60
[40 50 60] 70
[50 60 70] 80
[60 70 80] 90
现在我们知道如何准备一个单变量序列进行建模,让我们看看如何开发可以学习输入到输出映射的 LSTM 模型,从 Vanilla LSTM 开始。
2. 标准LSTM
标准LSTM(Vanilla LSTM) 是一种 LSTM 模型,它具有一个由 LSTM 单元组成的隐藏层和一个用于进行预测的输出层。
我们可以定义一个用于单变量时间序列预测的 Vanilla LSTM,如下所示。
...
# define model
model = Sequential()
model.add(LSTM(50, activation='relu', input_shape=(n_steps, n_features)))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')
定义中的关键是输入的形状;即模型在时间步数和特征数量方面对每个样本的输入期望。
我们正在处理单变量系列,因此对于一个变量,特征数量为 1。
作为输入的时间步数是我们在准备数据集作为split_sequence()函数的参数时选择的数字。
每个样本的输入形状在第一个隐藏层的定义中的input_shape参数中指定。
我们几乎总是有多个样本,因此,模型将期望训练数据的输入部分具有以下维度或形状:
[samples, timesteps, features]
上一节中的split_sequence()函数输出形状为 [ samples, timesteps ] 的 X,因此我们可以轻松地将其重塑,为一个特征增加一个维度。
...
# reshape from [samples, timesteps] into [samples, timesteps, features]
n_features = 1
X = X.reshape((X.shape[0], X.shape[1], n_features))
在本例中,我们定义一个模型,其隐藏层有 50 个 LSTM 单元,输出层可以预测单个数值。
该模型使用高效的Adam 版本随机梯度下降进行拟合,并使用均方误差或“ mse ”损失函数进行优化。
一旦定义了模型,我们就可以将其适合训练数据集。
...
# fit model
model.fit(X, y, epochs=200, verbose=0)
模型拟合好之后,我们就可以用它来进行预测。
我们可以通过提供输入来预测序列中的下一个值:
[70, 80, 90]
并期望模型预测如下:
[100]
该模型期望输入形状是三维的,具有 [样本、时间步长、特征],因此,我们必须在进行预测之前重塑单个输入样本。
...
# demonstrate prediction
x_input = array([70, 80, 90])
x_input = x_input.reshape((1, n_steps, n_features))
yhat = model.predict(x_input, verbose=0)
我们可以将所有这些结合在一起,并演示如何开发用于单变量时间序列预测的 Vanilla LSTM 并做出单一预测。
# univariate lstm example
from numpy import array
from keras.models import Sequential
from keras.layers import LSTM
from keras.layers import Dense
# split a univariate sequence into samples
def split_sequence(sequence, n_steps):
X, y = list(), list()
for i in range(len(sequence)):
# find the end of this pattern
end_ix = i + n_steps
# check if we are beyond the sequence
if end_ix > len(sequence)-1:
break
# gather input and output parts of the pattern
seq_x, seq_y = sequence[i:end_ix], sequence[end_ix]
X.append(seq_x)
y.append(seq_y)
return array(X), array(y)
# define input sequence
raw_seq = [10, 20, 30, 40, 50, 60, 70, 80, 90]
# choose a number of time steps
n_steps = 3
# split into samples
X, y = split_sequence(raw_seq, n_steps)
# reshape from [samples, timesteps] into [samples, timesteps, features]
n_features = 1
X = X.reshape((X.shape[0], X.shape[1], n_features))
# define model
model = Sequential()
model.add(LSTM(50, activation='relu', input_shape=(n_steps, n_features)))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')
# fit model
model.fit(X, y, epochs=200, verbose=0)
# demonstrate prediction
x_input = array([70, 80, 90])
x_input = x_input.reshape((1, n_steps, n_features))
yhat = model.predict(x_input, verbose=0)
print(yhat)
运行示例来准备数据、拟合模型并做出预测。
注意:由于算法或评估程序的随机性,或数值精度的差异,您的结果可能会有所不同。考虑运行示例几次并比较平均结果。
我们可以看到模型预测了序列中的下一个值。
[[102.09213]]
3. 堆叠式 LSTM
多个隐藏的 LSTM 层可以堆叠在一起,这就是所谓的 Stacked LSTM 模型。
LSTM 层需要三维输入,并且 LSTM 默认会产生二维输出作为序列末尾的解释。
通过在层上设置return_sequences=True参数,我们可以让 LSTM 为输入数据中的每个时间步骤输出一个值,从而解决这个问题。这使我们能够将隐藏 LSTM 层的 3D 输出作为下一层的输入。
因此,我们可以按如下方式定义 Stacked LSTM。
...
# define model
model = Sequential()
model.add(LSTM(50, activation='relu', return_sequences=True, input_shape=(n_steps, n_features)))
model.add(LSTM(50, activation='relu'))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')
我们可以将它们联系在一起;完整的代码示例如下所示。
# univariate stacked lstm example
from numpy import array
from keras.models import Sequential
from keras.layers import LSTM
from keras.layers import Dense
# split a univariate sequence
def split_sequence(sequence, n_steps):
X, y = list(), list()
for i in range(len(sequence)):
# find the end of this pattern
end_ix = i + n_steps
# check if we are beyond the sequence
if end_ix > len(sequence)-1:
break
# gather input and output parts of the pattern
seq_x, seq_y = sequence[i:end_ix], sequence[end_ix]
X.append(seq_x)
y.append(seq_y)
return array(X), array(y)
# define input sequence
raw_seq = [10, 20, 30, 40, 50, 60, 70, 80, 90]
# choose a number of time steps
n_steps = 3
# split into samples
X, y = split_sequence(raw_seq, n_steps)
# reshape from [samples, timesteps] into [samples, timesteps, features]
n_features = 1
X = X.reshape((X.shape[0], X.shape[1], n_features))
# define model
model = Sequential()
model.add(LSTM(50, activation='relu', return_sequences=True, input_shape=(n_steps, n_features)))
model.add(LSTM(50, activation='relu'))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')
# fit model
model.fit(X, y, epochs=200, verbose=0)
# demonstrate prediction
x_input = array([70, 80, 90])
x_input = x_input.reshape((1, n_steps, n_features))
yhat = model.predict(x_input, verbose=0)
print(yhat)
注意:由于算法或评估程序的随机性,或数值精度的差异,您的结果可能会有所不同。考虑运行示例几次并比较平均结果。
运行该示例将预测序列中的下一个值,我们预计该值是 100。
[[102.47341]]
4. 双向 LSTM
在某些序列预测问题中,允许 LSTM 模型正向和反向学习输入序列并连接两种解释会很有帮助。
这被称为双向 LSTM。
我们可以通过将第一个隐藏层包装在名为双向的包装层中来实现用于单变量时间序列预测的双向 LSTM。
定义双向 LSTM 来读取前向和后向输入的示例如下。
...
# define model
model = Sequential()
model.add(Bidirectional(LSTM(50, activation='relu'), input_shape=(n_steps, n_features)))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')
下面列出了用于单变量时间序列预测的双向 LSTM 的完整示例。
# univariate bidirectional lstm example
from numpy import array
from keras.models import Sequential
from keras.layers import LSTM
from keras.layers import Dense
from keras.layers import Bidirectional
# split a univariate sequence
def split_sequence(sequence, n_steps):
X, y = list(), list()
for i in range(len(sequence)):
# find the end of this pattern
end_ix = i + n_steps
# check if we are beyond the sequence
if end_ix > len(sequence)-1:
break
# gather input and output parts of the pattern
seq_x, seq_y = sequence[i:end_ix], sequence[end_ix]
X.append(seq_x)
y.append(seq_y)
retur