使用LSTM预测时间序列的多个前向时间步长

问题描述 投票:13回答:3

我想预测每周可预测的某些值(低SNR)。我需要预测一年中形成的一年的整个时间序列(52个值 - 图1)

Figure 1: Year time series by week

我的第一个想法是使用Keras over TensorFlow开发多对多LSTM模型(图2)。我正在使用52输入层(前一年的给定时间序列)和52预测输出层(明年的时间序列)训练模型。 train_X的形状是(X_examples,52,1),换言之,要训练的X_examples,每个1个特征的52个时间步长。据我所知,Keras会将52个输入视为同一域的时间序列。 train_Y的形状是相同的(y_examples,52,1)。我添加了一个TimeDistributed层。我的想法是算法会将值预测为时间序列而不是孤立值(我是否正确?)

Keras的模型代码是:

y = y.reshape(y.shape[0], 52, 1)
X = X.reshape(X.shape[0], 52, 1)
# design network
model = Sequential()
model.add(LSTM(n_neurons, input_shape=(X.shape[1], X.shape[2]), return_sequences=True))
model.add(TimeDistributed(Dense(1)))
model.compile(loss='mean_squared_error', optimizer='adam')
# fit network
model.fit(X, y, epochs=n_epochs, batch_size=n_batch, verbose=2)

Figure 2: Many-to-many LSTM architecture

问题是算法没有学习这个例子。它预测的值与属性的值非常相似。我是否正确建模了问题?

第二个问题:另一个想法是用1输入和1输出训练算法,但是在测试期间如何在不看“1输入”的情况下预测整个2015时间序列?测试数据将具有与训练数据不同的形状。

time-series keras lstm prediction forward
3个回答
19
投票

分享关于数据太少的相同问题,你可以这样做。

首先,将值保持在-1和+1之间是个好主意,所以我先将它们标准化。

对于LSTM模型,您必须确保使用return_sequences=True。 您的模型没有“错误”,但可能需要更多或更少的层或单元来实现您的需求。 (虽然没有明确的答案)。

训练模型以预测下一步:

你需要的只是将Y作为移位的X传递:

entireData = arrayWithShape((samples,52,1))
X = entireData[:,:-1,:]
y = entireData[:,1:,:]

使用这些训练模型。

预测未来:

现在,为了预测未来,由于我们需要使用预测元素作为更多预测元素的输入,我们将使用循环并制作模型stateful=True

使用以下更改创建与前一个相同的模型:

  • 所有LSTM层必须具有stateful=True
  • 批输入形状必须是(batch_size,None, 1) - 这允许可变长度

复制先前训练的模型的权重:

newModel.set_weights(oldModel.get_weights())

一次仅预测一个样本,并且在开始任何序列之前永远不要忘记调用model.reset_states()

首先用您已经知道的序列进行预测(这将确保模型正确地准备其状态以预测未来)

model.reset_states()
predictions = model.predict(entireData)

按照我们训练的方式,预测的最后一步将是未来的第一个元素:

futureElement = predictions[:,-1:,:]

futureElements = []
futureElements.append(futureElement)

现在我们创建一个循环,其中此元素是输入。 (由于有状态,模型将理解它是前一个序列的新输入步骤而不是新序列)

for i in range(howManyPredictions):
    futureElement = model.predict(futureElement)
    futureElements.append(futureElement)

此链接包含一个完整示例,用于预测两个功能的未来:https://github.com/danmoller/TestRepo/blob/master/TestBookLSTM.ipynb


2
投票

我有10年的数据。如果我的训练数据集是:从4周开始预测第5个值并且我继续移动,我可以有近52个例子来训练模型,52个预测(去年)

这实际上意味着您只有9个训练样例,每个示例包含52个特征(除非您想训练高度重叠的输入数据)。无论哪种方式,我认为这几乎不足以值得训练LSTM

我建议尝试一个更简单的模型。您的输入和输出数据具有固定大小,因此您可以尝试sklearn.linear_model.LinearRegression,它可以处理每个训练示例的多个输入要素(在您的情况下为52),以及多个目标(也为52)。

更新:如果你必须使用LSTM,那么看看LSTM Neural Network for Time Series Prediction,一个Keras LSTM实现,它通过将每个预测作为输入反馈,一次或迭代地支持多个未来预测。根据您的评论,这应该是您想要的。

该实现中的网络架构是:

model = Sequential()

model.add(LSTM(
    input_shape=(layers[1], layers[0]),
    output_dim=layers[1],
    return_sequences=True))
model.add(Dropout(0.2))

model.add(LSTM(
    layers[2],
    return_sequences=False))
model.add(Dropout(0.2))

model.add(Dense(
    output_dim=layers[3]))
model.add(Activation("linear"))

但是,我仍然建议运行线性回归或者可能是一个带有一个隐藏层的简单前馈网络,并将精度与LSTM进行比较。特别是如果您一次预测一个输出并将其作为输入反馈,您的错误很容易累积,从而进一步给您带来非常糟糕的预测。


1
投票

我想补充一下这个问题

我添加了一个TimeDistributed层。我的想法是算法会将值预测为时间序列而不是孤立值(我是否正确?)

因为我自己很难理解Keras TimeDistributed层背后的功能。

我认为你的动机是正确的,不能隔离时间序列预测的计算。在预测其未来形态时,你特别想要将整个系列的特征和相互依赖性放在一起。

但是,这与TimeDistributed Layer的目的正好相反。它用于隔离每个时间步的计算。你可能会问,为什么这很有用?对于完全不同的任务,例如序列标记,你有一个顺序输入(i1, i2, i3, ..., i_n),旨在分别为每个时间步输出标签(label1, label2, label1, ..., label2)

Imho最好的解释可以在这个postKeras Documentation找到。

出于这个原因,我声称,针对所有直觉,添加TimeDistributed层对时间序列预测来说可能永远不是一个好主意。打开并很高兴听到其他意见!

© www.soinside.com 2019 - 2024. All rights reserved.