使用RNN进行非线性多变量时间序列响应预测

时间:2018-02-22 13:59:16

标签: machine-learning time-series lstm prediction recurrent-neural-network

考虑到内部和外部气候,我试图预测墙壁的湿热响应。根据文献研究,我相信RNN应该可行,但我无法获得良好的准确性。

该数据集具有12个输入特征(外部和内部气候数据的时间序列)和10个输出特征(湿热响应的时间序列),两者均包含10年的小时值。该数据是用湿热模拟软件创建的,没有遗漏数据。

数据集功能: Input feature time-series

数据集目标: Output target time-series

与大多数时间序列预测问题不同,我想预测每个时间步长的输入要素时间序列全长的响应,而不是时间序列的后续值(例如金融时间序列)预测)。我无法找到类似的预测问题(在类似或其他领域),所以如果你知道一个,非常欢迎参考。

我认为这应该可以用RNN,所以我目前正在使用Keras的LSTM。在训练之前,我按以下方式预处理我的数据:

  1. 丢弃第一年的数据,因为墙壁的湿热响应首次受到初始温度和相对湿度的影响。
  2. 分成训练和测试集。训练集包含前8年的数据,测试集包含剩余的2年。
  3. 使用Sklearn的StandardScaler标准化训练集(零均值,单位方差)。使用训练集的均值方差,类似地标准化测试集。
  4. 这导致:X_train(1 x 61320 x 12),y_train(1 x 61320 x 10),X_test(1 x 17520 x 12),y_test(1 x 17520 x 10)

    由于这些是很长的时间序列,我使用statefull LSTM并使用stateful_cut函数按照here解释时间序列。我只有1个样本,所以batch_size是1.对于T_after_cut,我尝试了24和120(24 * 5); 24似乎给出了更好的结果。这导致X_train(2555 x 24 x 12),y_train(2555 x 24 x 10),X_test(730 x 24 x 12),y_test(730 x 24 x 10)。

    接下来,我按如下方式构建和训练LSTM模型:

    model = Sequential()
    model.add(LSTM(128, 
                   batch_input_shape=(batch_size,T_after_cut,features), 
                   return_sequences=True,
                   stateful=True,
                   ))
    model.addTimeDistributed(Dense(targets)))
    model.compile(loss='mean_squared_error', optimizer=Adam())
    
    model.fit(X_train, y_train, epochs=100, batch_size=batch=batch_size, verbose=2, shuffle=False)
    

    不幸的是,我没有得到准确的预测结果;甚至没有训练集,因此该模型具有高偏差。

    The prediction results of the LSTM model for all targets

    如何改进模型?我已经尝试了以下内容:

    1. 不丢弃数据集的第一年 - >没有显着差异
    2. 区分输入要素时间序列(从当前值中减去先前值) - >结果稍差
    3. 最多四个堆叠的LSTM层,都具有相同的超参数 - >结果没有显着差异,但训练时间较长
    4. LSTM层之后的辍学层(虽然这通常用于减少方差,而我的模型具有高偏差) - >结果略好,但差异可能没有统计学意义
    5. 我是否对有状态的LSTM做错了什么?我需要尝试不同的RNN型号吗?我应该以不同方式预处理数据吗?

      此外,训练非常缓慢:上述模型大约需要4个小时。因此,我不愿意进行广泛的超参数网格搜索...

1 个答案:

答案 0 :(得分:4)

最后,我设法通过以下方式解决了这个问题:

  • 使用更多样本训练而不是仅训练1(我使用18个样本进行训练,6个进行测试)
  • 保留第一年的数据,因为所有样本的输出时间序列都具有相同的“起点”,模型需要此信息才能学习
  • 标准化输入和输出要素(零均值,单位方差)。我发现这种改进的预测准确性和训练速度
  • 按照here所述使用有状态LSTM,但在epoch之后添加重置状态(请参阅下面的代码)。我使用了batch_size = 6和T_after_cut = 1460.如果T_after_cut更长,训练更慢;如果T_after_cut较短,则精度会略有下降。如果有更多样本可用,我认为使用更大的batch_size会更快。
  • 使用CuDNNLSTM代替LSTM,这加快了训练时间x4!
  • 我发现更多的单位导致更高的准确性和更快的收敛(更短的训练时间)。此外,我发现GRU与LSTM一样准确,对于相同数量的单位而言更快收敛。
  • 在培训期间监控验证丢失并尽早停止使用

LSTM模型的构建和培训如下:

def define_reset_states_batch(nb_cuts):
    class ResetStatesCallback(Callback):
        def __init__(self):
            self.counter = 0

        def on_batch_begin(self, batch, logs={}):
            # reset states when nb_cuts batches are completed
            if self.counter % nb_cuts == 0:
                self.model.reset_states()
            self.counter += 1

        def on_epoch_end(self, epoch, logs={}):
            # reset states after each epoch
            self.model.reset_states()
    return(ResetStatesCallback)    

model = Sequential()
model.add(layers.CuDNNLSTM(256, batch_input_shape=(batch_size,T_after_cut ,features), 
                          return_sequences=True,
                          stateful=True))
model.add(layers.TimeDistributed(layers.Dense(targets, activation='linear')))
optimizer = RMSprop(lr=0.002)
model.compile(loss='mean_squared_error', optimizer=optimizer)

earlyStopping = EarlyStopping(monitor='val_loss', min_delta=0.005, patience=15, verbose=1, mode='auto')
ResetStatesCallback = define_reset_states_batch(nb_cuts)
model.fit(X_dev, y_dev, epochs=n_epochs, batch_size=n_batch, verbose=1, shuffle=False, validation_data=(X_eval,y_eval), callbacks=[ResetStatesCallback(), earlyStopping])

这给了我非常满意的准确度(R2超过0.98): Prediction 该图显示了2年内墙上的温度(左)和相对湿度(右)(未在训练中使用的数据),红色预测和黑色真实输出。残差表明误差非常小,LSTM学会捕捉长期依赖性来预测相对湿度。