单步模型的时间序列多步泛化

数据挖掘 机器学习 时间序列 lstm
2022-02-06 18:19:27

我已经建立了一个通用的堆叠 lstm 模型:

self.model = tf.keras.Sequential([
            lstm_layer(n_neurons, return_sequences=True),
            lstm_layer(n_neurons, return_sequences=True),
            lstm_layer(n_neurons, return_sequences=True),
            lstm_layer(n_neurons),
            tf.keras.layers.Dense(n_output)
        ])

数据的形状为x_train = (total_samples,timestep, features) and y_test = (total_samples,n_output,1),然后我以 30% 的验证拆分拟合模型。

我的问题是:

为什么模型完美地预测领先一步(n_output = 1)但是当我尝试设置 n_output>1 时模型变得非常非常不精确,是否有充分的理论理由?(loss<val_loss from epoch 1) 它是模型/数据依赖的东西还是我搞砸了数据准备?

2个回答

欢迎来到社区 Fra,您可以在下面找到一个已完成的示例,该示例实现了一个多元输入特征(我认为是您的情况)时间序列预测、预测多个未来步骤(多步预测)、应用贝叶斯超参数化。

它基于从更简单到更复杂的方法,因此您可以看到架构中的层数很少,而被超参数化的是这些层中的单元。这是一个完整的示例,以防您几乎可以直接应用它并首先尝试使用单个输出节点进行建模以进行单步预测然后添加更多未来步骤预测以检查您是否仍然在同一问题上运行正如你所描述的(从 n_output = 1 开始,然后增加它,例如在我的情况下,它是 72 个未来值来预测)。

对于这种类型的数据集:

在此处输入图像描述

并尝试预测温度值的几个未来时间步长(深蓝点): 在此处输入图像描述

我们有一些代码,例如:

  • 训练验证数据集拆分器功能:

      def multivariate_data(dataset, target, start_index, end_index, history_size, target_size, step, single_step=False):
        data = []
        labels = []
    
        start_index = start_index + history_size
        if end_index is None:
          end_index = len(dataset) - target_size
    
        for i in range(start_index, end_index):
          indices = range(i-history_size, i, step)
          data.append(dataset[indices])
    
          if single_step:
            labels.append(target[i+target_size])
          else:
            labels.append(target[i:i+target_size])
    
        return np.array(data), np.array(labels)
    

这是我们通过应用该函数得到的(在您的情况下,您不需要应用 6 个时间步长的采样间隔,您可以将其设置为 1;这是为了以防您想要对可能太长的历史进行下采样):

在此处输入图像描述

  • 构建训练评估集的函数实现:

      past_history = 720 # historic values to consider for each prediction
      future_target = 72 # number of future values to predict 
      STEP = 6 # sampling frequency (it makes taking 720/6 historic points for each sample)
    
      x_train_multi, y_train_multi = multivariate_data(dataset_standardized, dataset_standardized[:, 1], 0,TRAIN_SPLIT, past_history, future_target, STEP) 
      x_val_multi, y_val_multi = multivariate_data(dataset_standardized, dataset_standardized[:, 1], TRAIN_SPLIT, None, past_history, future_target, STEP)
    

这样你就有:

  • 过去历史的单一窗口:(120, 3)
  • 要预测的目标温度:(72,)

对于训练阶段,我们定义批量大小和其他值并构建我们的训练和验证集:

BATCH_SIZE = 256
BUFFER_SIZE = 10000

train_data_multi = tf.data.Dataset.from_tensor_slices((x_train_multi, y_train_multi))
train_data_multi = train_data_multi.cache().shuffle(BUFFER_SIZE).batch(BATCH_SIZE).repeat()

val_data_multi = tf.data.Dataset.from_tensor_slices((x_val_multi, y_val_multi))
val_data_multi = val_data_multi.batch(BATCH_SIZE).repeat()

并从定义一个简单的架构开始,我们有:

multi_step_model = tf.keras.models.Sequential()
multi_step_model.add(tf.keras.layers.LSTM(32,
                                          return_sequences=True,  # "Boolean. Whether to return the last output. in the output sequence, or the full sequence"
                                          input_shape=x_train_multi.shape[-2:]))
multi_step_model.add(tf.keras.layers.LSTM(16, activation='relu'))
multi_step_model.add(tf.keras.layers.Dense(72))

multi_step_model.compile(optimizer=tf.keras.optimizers.RMSprop(clipvalue=1.0), loss='mae')

我们可以检查验证集的性能:

EVALUATION_INTERVAL = 200
EPOCHS = 10

multi_step_history = multi_step_model.fit(train_data_multi, epochs=EPOCHS,
                                          steps_per_epoch=EVALUATION_INTERVAL,
                                          validation_data=val_data_multi,
                                          validation_steps=50) 

在将值缩小到其原始比例后,下面的预测为红色:

for x, y in val_data_multi.take(3):
    x_denormalized = (x[0])*temps_std+temps_mean
    y_denormalized = (y[0])*temps_std+temps_mean
    
    multi_step_plot(x_denormalized, y_denormalized, (multi_step_model.predict(x)[0])*temps_std+temps_mean)

在此处输入图像描述

也许对您的用例来说最有趣的部分是,您可以尝试使用 keras 贝叶斯调谐器将一些参数的超参数化实现为隐藏层单元,如下所示:

from kerastuner import BayesianOptimization

def build_model_2(hp):
    model = keras.Sequential()
    model.add(keras.layers.LSTM(units=hp.Int('units',min_value=16,
                                        max_value=32,
                                        step=16), 
                                        #activation='relu', 
                                        return_sequences=True, 
                                        input_shape=x_train_multi.shape[-2:]))
    model.add(keras.layers.LSTM(units=hp.Int('units',min_value=16,
                                        max_value=32,
                                        step=16),  
                                        activation='relu'))
    model.add(keras.layers.Dense(72))

    model.compile(loss='mae', optimizer=tf.keras.optimizers.RMSprop(clipvalue=1.0),
            
                   metrics=['mae'])
    return model

# define model
bayesian_opt_tuner_2 = BayesianOptimization(
    build_model_2,
    objective='mae',
    max_trials=3,
    executions_per_trial=1,
    directory=os.path.normpath('C:/keras_tuning'),
    project_name='timeseries_temp_ts_test_from_TF_ex_multivar_multistep_2',
    overwrite=True)

EVALUATION_INTERVAL = 200
EPOCHS = 10
bayesian_opt_tuner_2.search(train_data_multi, 
             epochs=EPOCHS,
             validation_data=val_data_multi,
             validation_steps=50,  
             steps_per_epoch=EVALUATION_INTERVAL)

# and selecting the best model: 

    best_MULTIVAR_MULTISTEP_LSTM_model_2 = bayesian_opt_tuner_2.get_best_models(num_models=1)[0]

我们有我们的新模型预测:

在此处输入图像描述

这在验证集上给出了改进的 MAE。

在模型将变得严格依赖于之前的时间数据的项目中遇到了类似的问题。我想这个问题在处理时间序列时很普遍,并且预测某些事情会发生等问题T根据来自的数据提前时间T1时间落后。这样做的问题是模型总是可以预测与最近时间点相同的结果并获得“好”分数。查看本文的标题“时间延迟预测和自相关”作者写了一个后续,我也推荐看看。

尽管我的记忆力很好,但我相信通过重塑我们训练的时间区域,在那个时间点不使用测量值,而是使用相关数据的时间空间的增量,这种偏差在我的项目中得到了显着改善。例如,如果尝试提前 1 天预测并且您知道该模式是在过去 1-10 天的某个地方,则创建一个为此量身定制的训练集。(该时间区域中数据的增量或滑动增量)。