如何使用深度学习模型进行时间序列预测?

时间:2020-01-30 02:30:22

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

我有28天从机器(m1, m2, so on)录制的信号。 (注意:每天的每个信号的长度为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的信号,并要求预测{{1 }}等,因此当我到达day 3时,网络将所有信号都提高到28,并要求预测day 28,等的信号。

我试图按如下方法制作单变量LSTM模型。

day 29

但是,此示例非常简单,因为它没有像我这样的长序列。例如,我的# 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, ...]] 2930。在那种情况下,我不确定如何更改此示例以满足我的需求。我想特别知道我选择的方向是否正确。如果是这样,该怎么做。

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

编辑:

我已经提到了31

enter image description here

2 个答案:

答案 0 :(得分:2)

我认为您的方向不错,要增加每天的时间步长,您需要在数据中添加一个填充,此示例可以为您提供帮助:https://github.com/keras-team/keras/blob/master/examples/imdb_lstm.py#L46

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

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

答案 1 :(得分:2)

模型和形状

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

尽管您可以像(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)

还有许多其他探索数据的方式,这是一个极富创造力的领域。例如,您可以在daily_minutes之后排除inner_average lambda层之后使用K.mean方法。

时间窗口逼近

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

以上模型适用于此方法。

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

预处理数据并将其分组:

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

您将需要一个手动训练循环,在该循环中,每个阶段都要喂食这些组中的每一个(不能同时喂食不同的体重)。


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

  • inputs = original_inputs[:, :-1]#不包括上一个培训日
  • outputs = original_inputs[:, 1:]#不包括首个培训日

要使上面的模型适合这种方法,您需要在每个使用日维作为步骤的LSTM中使用return_sequences=True(而不是inner_seq)。 (inner_average方法将失败,并且您将不得不使用daily_minutes和紧随其后的另一个return_sequences=True的{​​{1}}方法。

形状为:

  • branch1:Permute((2,1,3))
  • branch2:(m, d, 360, units1)-为此需要调整(m, d, 360, few_units)
    • 不需要使用1个时间步进行重塑,Reshape尺寸将代替1。
    • 考虑到批量大小和可变天数,您可能需要使用days层进行重塑(如果需要详细信息,请告诉我)

训练和预测

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

然后,您可以按照herehere too, more complete with a few links所述的方法进行操作。 (尽管要注意输出形状,但在您的问题中,即使时间步长可能为1,我们也始终保持其大小)

要点是:

  • 如果您选择Lambda
    • 这意味着使用stateful=False可以轻松地进行训练(只要您不使用“不同长度”方法);
    • 这还意味着您将需要使用fit建立新模型,复制经过训练的模型的权重;
    • 然后您进行手动逐步预测
  • 如果您从一开始就选择stateful=True
    • 这必然意味着手动训练循环(例如,使用stateful=True);
    • 这必然意味着,当您要提交其序列不是最后一批的续集(如果您的批次包含整个序列的每一批)的序列时,将需要train_on_batch
    • 无需构建新模型即可进行人工预测,但人工预测仍保持不变