如何使用深度学习模型进行时间序列预测?
How to use deep learning models for time-series forecasting?
我从机器 (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 天每台机器的信号序列。即 day29
、day30
、day31
。
但是,我没有 29
、30
和 31
天的值。因此,我的计划如下使用 LSTM
模型。
第一步是获取 day 1
的信号并要求预测 day 2
的信号,然后在下一步中获取 days 1, 2
的信号并要求预测 days 1, 2
的信号=24=],等等,所以当我到达 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, ...]]
此外,我需要29
、30
、31
天的预测。在那种情况下,我不确定如何更改此示例以满足我的需要。我想具体地知道我选择的方向是否正确。如果可以,怎么做。
如果需要,我很乐意提供更多详细信息。
编辑:
我已经提到了model.summary()
。
我认为你的方向很好,要增加每天的时间步长,你需要在你的数据中添加一个填充,这个例子可以帮助你:https://github.com/keras-team/keras/blob/master/examples/imdb_lstm.py#L46.
不过,我也会尝试另一种方法,比如固定时间步数,例如3天、4天、5天...然后,评估你的火车,你可以选择多少时间步是最适合您的模型。
也许您最初增加天数的方法会更好,但在此类问题中,在 LSTM 中找到最佳时间步数非常重要。
模型和形状
由于这些是序列中的序列,您需要使用不同格式的数据。
虽然您可以像 (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 层....您明白了。
时间windows接近
你的方法听起来不错。一步预测下一步,两步预测第三步,三步预测第四步。
上述模型适用于这种方法。
请记住,非常短的输入可能毫无用处,并且可能会使您的模型变得更糟。 (试着想象有多少步足以让您开始预测下一个步骤)
预处理您的数据并将其分组:
- 长度为 4 的组(例如)
- 长度为 5 的组
- ...
- 组长度 = 28
您将需要一个手动训练循环,在每个时期中,您为这些组中的每一个提供食物(您不能同时提供不同长度的食物)。
另一种方法是,给出所有步骤,使模型预测一个移位序列,如:
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
层来重塑(如果需要详细信息,请告诉我)
训练和预测
(很抱歉现在没时间细说)
然后您可以按照提到的方法进行操作 and 。 (注意输出形状,尽管在你的问题中,我们始终保持时间步长维度,即使它可能是 1)
重点是:
- 如果您选择
stateful=False
:
- 这意味着使用
fit
进行轻松训练(只要您没有使用 "different lengths" 方法);
- 这也意味着你需要用
stateful=True
建立一个新模型,复制训练模型的权重;
- 然后你一步一步地进行手动预测
- 如果您从一开始就选择
stateful=True
:
- 这必然意味着手动训练循环(例如使用
train_on_batch
);
- 这必然意味着您将需要
model.reset_states()
每当您要展示其序列不是上一批次的续集(如果您的批次包含完整序列,则每批次)。
- 不需要建立新的模型来手动预测,但手动预测保持不变
我从机器 (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 天每台机器的信号序列。即 day29
、day30
、day31
。
但是,我没有 29
、30
和 31
天的值。因此,我的计划如下使用 LSTM
模型。
第一步是获取 day 1
的信号并要求预测 day 2
的信号,然后在下一步中获取 days 1, 2
的信号并要求预测 days 1, 2
的信号=24=],等等,所以当我到达 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, ...]]
此外,我需要29
、30
、31
天的预测。在那种情况下,我不确定如何更改此示例以满足我的需要。我想具体地知道我选择的方向是否正确。如果可以,怎么做。
如果需要,我很乐意提供更多详细信息。
编辑:
我已经提到了model.summary()
。
我认为你的方向很好,要增加每天的时间步长,你需要在你的数据中添加一个填充,这个例子可以帮助你:https://github.com/keras-team/keras/blob/master/examples/imdb_lstm.py#L46.
不过,我也会尝试另一种方法,比如固定时间步数,例如3天、4天、5天...然后,评估你的火车,你可以选择多少时间步是最适合您的模型。
也许您最初增加天数的方法会更好,但在此类问题中,在 LSTM 中找到最佳时间步数非常重要。
模型和形状
由于这些是序列中的序列,您需要使用不同格式的数据。
虽然您可以像 (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 层....您明白了。
时间windows接近
你的方法听起来不错。一步预测下一步,两步预测第三步,三步预测第四步。
上述模型适用于这种方法。
请记住,非常短的输入可能毫无用处,并且可能会使您的模型变得更糟。 (试着想象有多少步足以让您开始预测下一个步骤)
预处理您的数据并将其分组:
- 长度为 4 的组(例如)
- 长度为 5 的组
- ...
- 组长度 = 28
您将需要一个手动训练循环,在每个时期中,您为这些组中的每一个提供食物(您不能同时提供不同长度的食物)。
另一种方法是,给出所有步骤,使模型预测一个移位序列,如:
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
层来重塑(如果需要详细信息,请告诉我)
- 不需要使用 1 个时间步的整形,
训练和预测
(很抱歉现在没时间细说)
然后您可以按照提到的方法进行操作
重点是:
- 如果您选择
stateful=False
:- 这意味着使用
fit
进行轻松训练(只要您没有使用 "different lengths" 方法); - 这也意味着你需要用
stateful=True
建立一个新模型,复制训练模型的权重; - 然后你一步一步地进行手动预测
- 这意味着使用
- 如果您从一开始就选择
stateful=True
:- 这必然意味着手动训练循环(例如使用
train_on_batch
); - 这必然意味着您将需要
model.reset_states()
每当您要展示其序列不是上一批次的续集(如果您的批次包含完整序列,则每批次)。 - 不需要建立新的模型来手动预测,但手动预测保持不变
- 这必然意味着手动训练循环(例如使用