【问题标题】:How to use deep learning models for time-series forecasting?如何使用深度学习模型进行时间序列预测?
【发布时间】:2020-01-30 02:30:22
【问题描述】:

我从机器 (m1, m2, so on) 记录了 28 天的信号。 (注意:每天的每个信号都是 360 长度)。

machine_num, day1, day2, ..., day28
m1, [12, 10, 5, 6, ...], [78, 85, 32, 12, ...], ..., [12, 12, 12, 12, ...]
m2, [2, 0, 5, 6, ...], [8, 5, 32, 12, ...], ..., [1, 1, 12, 12, ...]
...
m2000, [1, 1, 5, 6, ...], [79, 86, 3, 1, ...], ..., [1, 1, 12, 12, ...]

我想预测每台机器未来 3 天的信号序列。即在day29day30day31。 但是,我没有 293031 天的值。所以,我的计划如下使用LSTM 模型。

第一步是获取day 1的信号并要求预测day 2的信号,然后在下一步获取days 1, 2的信号并要求预测day 3的信号等,所以当我到达day 28, 网络有多达28个信号,并被要求预测day 29等的信号。

我尝试如下做一个单变量 LSTM 模型。

# univariate lstm example
from numpy import array
from keras.models import Sequential
from keras.layers import LSTM
from keras.layers import Dense
# define dataset
X = array([[10, 20, 30], [20, 30, 40], [30, 40, 50], [40, 50, 60]])
y = array([40, 50, 60, 70])
# reshape from [samples, timesteps] into [samples, timesteps, features]
X = X.reshape((X.shape[0], X.shape[1], 1))
# define model
model = Sequential()
model.add(LSTM(50, activation='relu', input_shape=(3, 1)))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')
# fit model
model.fit(X, y, epochs=1000, verbose=0)
# demonstrate prediction
x_input = array([50, 60, 70])
x_input = x_input.reshape((1, 3, 1))
yhat = model.predict(x_input, verbose=0)
print(yhat)

但是,这个例子非常简单,因为它没有像我这样的长序列。例如,m1 的数据如下所示。

m1 = [[12, 10, 5, 6, ...], [78, 85, 32, 12, ...], ..., [12, 12, 12, 12, ...]]

此外,我需要293031 的日期预测。在这种情况下,我不确定如何更改此示例以满足我的需要。我想具体知道我选择的方向是否正确。如果有,该怎么做。

如果需要,我很乐意提供更多详细信息。

编辑:

我已经提到了model.summary()

【问题讨论】:

  • 也许这个答案有它? stackoverflow.com/questions/46901371/… --- 稍后我可能会为您的问题写一个具体的答案,随着时间的推移。
  • 发表评论,因为我现在无法保存此链接,并且对该主题非常感兴趣。
  • 感谢您的提醒。为了确保我正确理解维度,我们有 2000 台机器每天记录 360 个值的数组。所以所有数组都是相同的维度,我们可以说矩阵是 2000*28*360 对吗?
  • @CeliusStingher 非常感谢您的评论。是的,你是对的。我有 28 天的 2000 台机器的数据。对于每一天,我都有一个 360 的数组。因此矩阵是 2000*28*360。如果您需要更多详细信息,请告诉我。期待您的建议。谢谢你:)
  • 测试前的最后一个问题,360 观察和每天的关系是什么。我们可以说每个观察都独立于另一个(每天)吗?那么第 1 天的观察 1 和第 2 天的观察 1 呢?我们能找到这些值之间的关系吗?有点像 MANOVA... TL;DR:值之间是否有任何关系需要考虑?

标签: python deep-learning time-series lstm forecasting


【解决方案1】:

模型和形状

由于这些是序列中的序列,因此您需要以不同的格式使用数据。

虽然您可以像 (machines, days, 360) 那样简单地将 360 视为功能(在某些情况下可以工作),但对于一个健壮的模型(那么可能存在速度问题),您需要同时处理这两个问题作为序列。

然后我会使用像 (machines, days, 360, 1) 这样的数据和两个级别的重复。

我们的模型 input_shape 然后将是 (None, 360, 1)

示范案例 1 - 仅日复现

数据形状:(machines, days, 360)
对数据应用一些规范化。

这里是一个例子,但模型可以很灵活,因为您可以添加更多层、尝试卷积等:

inputs = Input((None, 360)) #(m, d, 360)
outs = LSTM(some_units, return_sequences=False, 
            stateful=depends_on_training_approach)(inputs)  #(m, some_units)
outs = Dense(360, activation=depends_on_your_normalization)(outs) #(m, 360)
outs = Reshape((1,360)) #(m, 1, 360) 
    #this reshape is not necessary if using the "shifted" approach - see time windows below
    #it would then be (m, d, 360)

model = Model(inputs, outs)

根据日内序列的复杂性,可以很好地预测它们,但如果它们以复杂的方式进化,那么下一个模​​型会更好一些。

永远记住,您可以创建更多层并探索事物以增加此模型的能力,这只是一个很小的示例

模型案例 2 - 两级递归

数据形状:(machines, days, 360, 1)
对数据应用一些标准化。

有很多方法可以试验如何做到这一点,但这里有一个简单的方法。

inputs = Input((None, 360, 1)) #(m, d, 360, 1)

#branch 1
inner_average = TimeDistributed(
                    Bidirectional(
                        LSTM(units1, return_sequences=True, stateful=False),
                        merge_mode='ave'
                    )
                )(inputs) #(m, d, 360, units1)
inner_average = Lambda(lambda x: K.mean(x, axis=1))(inner_average) #(m, 360, units1)


#branch 2
inner_seq = TimeDistributed(
                LSTM(some_units, return_sequences=False, stateful=False)
            )(inputs) #may be Bidirectional too
            #shape (m, d, some_units)

outer_seq = LSTM(other_units, return_sequences = False, 
                 stateful=depends_on_training_approach)(inner_seq) #(m, other_units)

outer_seq = Dense(few_units * 360, activation = 'tanh')(outer_seq) #(m, few_units * 360)
    #activation = same as inner_average 


outer_seq = Reshape((360,few_units))(outer_seq) #(m, 360, few_units)


#join branches

outputs = Concatenate()([inner_average, outer_seq]) #(m, 360, units1+few_units)
outputs = LSTM(units, return_sequences=True, stateful= False)(outputs) #(m, 360,units)
outputs = Dense(1, activation=depends_on_your_normalization)(outputs) #(m, 360, 1)
outputs = Reshape((1,360))(outputs) #(m, 1, 360) for training purposes

model = Model(inputs, outputs)

这是一次尝试,我做了平均天数,但我本可以做,而不是 inner_average,类似:

#branch 1
daily_minutes = Permute((2,1,3))(inputs) #(m, 360, d, 1)
daily_minutes = TimeDistributed(
                    LSTM(units1, return_sequences=False, 
                         stateful=depends_on_training_approach)
                )(daily_minutes) #(m, 360, units1)

探索数据的许多其他方式都是可能的,这是一个极具创意的领域。例如,您可以在inner_average 之后使用daily_minutes 方法,不包括K.mean lambda 层......你明白了。

时间窗方法

你的方法听起来不错。给一个步骤来预测下一个步骤,给两个步骤来预测第三个步骤,给三个步骤来预测第四个步骤。

上述模型适合这种方法。

请记住,很短的输入可能没有用,并且可能会使您的模型变得更糟。 (试着想象多少步足以让你开始预测下一步)

预处理您的数据并将其分组:

  • 长度为 4 的组(例如)
  • 长度为 5 的组
  • ...
  • 长度为 28 的组

您将需要一个手动训练循环,在每个 epoch 中,您需要为这些组中的每一个提供数据(您不能同时提供不同长度的数据)。


另一种方法是,给出所有步骤,让模型预测一个移位的序列,例如:

  • inputs = original_inputs[:, :-1]#排除最后一天的培训
  • outputs = original_inputs[:, 1:]#排除第一天培训

为了使上述模型适合这种方法,您需要在每个使用天维度作为步骤的 LSTM 中使用 return_sequences=True(而不是 inner_seq)。 (inner_average 方法将失败,您将不得不使用daily_minutes 方法,然后使用return_sequences=True 和另一个Permute((2,1,3))

形状是:

  • 分支1:(m, d, 360, units1)
  • branch2 : (m, d, 360, few_units) - 为此需要调整 Reshape
    • 无需使用 1 个时间步进行重塑,days 维度将替换 1。
    • 考虑到批量大小和可变天数,您可能需要使用Lambda 层来重塑(如果需要详细信息,请告诉我)

训练和预测

(抱歉现在没有时间详细介绍)

​​>

然后您可以按照提到的方法herehere too, more complete with a few links。 (注意输出形状,不过,在您的问题中,我们始终保持时间步长维度,即使它可能是 1)

重点是:

  • 如果您选择stateful=False
    • 这意味着使用fit 进行轻松训练(只要您不使用“不同长度”方法);
    • 这也意味着你需要用stateful=True建立一个新模型,复制训练模型的权重;
    • 然后你手动进行逐步预测
  • 如果您从一开始就选择stateful=True
    • 这必然意味着手动训练循环(例如使用train_on_batch);
    • 这必然意味着,当您要呈现一个批次的序列不是最后一批的后续序列时(如果您的批次包含整个序列,则每个批次)都需要model.reset_states()
    • 不需要建立新模型手动预测,但手动预测保持不变

【讨论】:

  • 哇,这令人印象深刻。非常感谢您的详细回答。我仍在阅读并试图理解您提到的内容。请给我两天的时间来完全理解你提到的事情。如果有任何不清楚的地方,我会在 cmets 中询问。再次感谢你。这非常有帮助老实说,我在这个问题上停留了大约一个月。所以,非常感谢你帮助我:)
  • 您选择了什么时间窗口?我的答案中的第二个链接显示了如何训练。
  • 只有在我在家的时候,对不起。 :(
  • 如果你最后使用“线性”激活,损失可能是“mse”,我喜欢“adam”优化器,它通常很好。除了“mae”,我不确定我们是否有好的指标。您可能使用过 sigmoid(从 0 到 1 并尝试“binary_crossentropy”)。
  • 模型的输出形状必须与“目标”(batch_y)的形状相匹配。您的模型当前正在输出 2D 数据(None, something),您制作的模型在某处丢失了时间维度。查看模型摘要
【解决方案2】:

我认为你的方向是好的,为了增加每天的时间步长,你需要在你的数据中添加一个 pad,这个例子可以帮助你:https://github.com/keras-team/keras/blob/master/examples/imdb_lstm.py#L46

但是,我也会尝试其他方法,例如固定时间步数,例如 3 天、4、5...然后,评估您的火车,您可以选择最适合的时间步数你的模型。

也许你增加天数的初始方法会更好,但在这类问题中,找到 LSTM 中的最佳时间步数非常重要。

【讨论】:

    猜你喜欢
    • 2018-11-03
    • 2016-09-07
    • 1970-01-01
    • 2014-06-25
    • 2020-05-07
    • 2018-09-16
    • 2020-05-27
    • 1970-01-01
    • 2021-07-29
    相关资源
    最近更新 更多