1D卷积预测方法
另一种预测时间序列的方法是使用一维卷积模型。1D卷积使用一个过滤窗口并在数据上循环该窗口以产生新的输出。根据所学的卷积窗参数,它们可以像移动平均线、方向指示器或模式探测器一样随时间变化。
step 1
这里有一个包含8个元素的数据集,过滤器大小为4。过滤器中的四个数字是Conv1D层学习的参数。在第一步中,我们将过滤器的元素乘以输入数据,并将结果相加以产生卷积输出。
step 2
在卷积的第二步中,窗口向前移动一个,重复相同的过程以产生第二个输出。
Last step
这个过程一直持续到窗口到达输入数据的末尾。在我们的例子中,一个输入数据序列是我们之前设置的72小时的数据。如果我们添加padding=“same”选项,我们的输入数据将在开始和结束处用零进行填充,以保持输出长度等于输入长度。上面的演示使用线性激活,这意味着最后一个多色数组是我们的输出。但是,我们可以在这里使用一整套激活函数,这些函数将通过一个额外的步骤来运行这个数字。因此,在下面的例子中,将有一个ReLU激活函数应用于最后的输出,以产生最终的输出。
下面展示了建立1D卷积模型的相关代码:
defbasic_conv1D(n_filters=10, fsize=5, window_size=5, n_features=2): new_model=keras.Sequential() new_model.add(tf.keras.layers.Conv1D(n_filters, fsize, padding=”same”, activation=”relu”, input_shape=(window_size, n_features))) #Flattenwilltakeourconvolutionfiltersandlaythemoutendtoendsoourdenselayercanpredictbasedontheoutcomesofeachnew_model.add(tf.keras.layers.Flatten()) new_model.add(tf.keras.layers.Dense(1800, activation=’relu’)) new_model.add(tf.keras.layers.Dense(100)) new_model.add(tf.keras.layers.Dense(1)) new_model.compile(optimizer=”adam”, loss=”mean_squared_error”) returnnew_model
模型情况如下:
univar_model=basic_conv1D(n_filters=24, fsize=8, window_size=window_size, n_features=X_train.shape[2]) univar_model.summary() Model: "sequential_1"_________________________________________________________________Layer (type) OutputShapeParam#=================================================================conv1d (Conv1D) (None, 72, 24) 216_________________________________________________________________flatten_1 (Flatten) (None, 1728) 0_________________________________________________________________dense_3 (Dense) (None, 1800) 3112200_________________________________________________________________dense_4 (Dense) (None, 100) 180100_________________________________________________________________dense_5 (Dense) (None, 1) 101=================================================================Totalparams: 3,292,617Trainableparams: 3,292,617Non-trainableparams: 0
注意,这里有24个卷积窗口,过滤器大小是8。因此,在我们的例子中,输入数据将是72小时,这将创建一个大小为8的窗口,其中将有24个过滤器。因为我使用padding=“same”,每个过滤器的输出宽度将是72,就像我们的输入数据一样,并且输出的数量将是24个卷积数组。最后通过Flatten生成72*24=1728
长度的数组。Flatten的工作过程如下图所示:
Flatten工作示意图
对比1D卷积模型、LSTM、基线模型的预测损失如下:
显然1D卷积方法比LSTM更好一些,但是它仍然没有达到最初的基准模型更好的效果。当我们看预测效果曲线时,我们可以看到这个模型有明显的偏差:
1D卷积预测效果
添加数据维度
在上面的例子中,我们只使用我们想要预测的特性作为我们的输入变量。然而,我们的数据集有12个可能的输入变量。我们可以将所有的输入变量叠加起来,然后一起使用它们来进行预测。由于许多输入变量与我们的输出变量具有中等/较强的相关性,因此使用更多的数据进行更好的预测应该是可能的。
多输入1D卷积
如果我想把一个不同的数据序列叠加到模型中,首先要通过相同的窗口处理过程来生成一组观测值,每个观测值都包含变量的最后72个读数。例如,如果我想在第1列中添加变量DADemand(日前需求,当前前一天的需求),将对其执行以下操作:
(DADemand, _) =window_data(gc_df, window_size, 1, 1) scaler=StandardScaler() DADemand=scaler.fit_transform(DADemand) split=int(0.8*len(X)) DADemand_train=DADemand[: split—1] DADemand_test=DADemand[split:] DADemand_test.shape(61875, 72, 1)
然后,可以对所有的12个变量重复这个过程,并将它们堆积成一个单独的集合,如下所示:
data_train=np.concatenate((X_train, db_train, dew_train, DADemand_train, DALMP_train, DAEC_train, DACC_train, DAMLC_train, RTLMP_train, RTEC_train, RTCC_train, RTMLC_train), axis=2) data_test=np.concatenate((X_test, db_test, dew_test, DADemand_test, DALMP_test, DAEC_test, DACC_test, DAMLC_test, RTLMP_test, RTEC_test, RTCC_test, RTMLC_test), axis=2) data_train.shape(61875, 72, 12)
至此生成了包含61875个样本、每一个都包含12个不同时间序列的72小时单独读数的数据集。我们现在通过一个Conv1D网络来运行它,看看我们得到了什么结果。如果回顾一下我们用于创建这些模型的函数,会注意到其中一个变量是特征feature的数量,因此运行这个新模型的代码同样十分简单。预测误差结果如下:
模型的性能实际上随着其他变量的增加而降低。分析其原因,可能是“模糊”效应(添加更多的数据集往往会“模糊”任何一个特定输入变化的影响,反而会产生一个不太精确的模型。)。
2D卷积
我们实际需要的是一个卷积窗口,它可以查看我们的模型特征并找出哪些特征是有益的。2D卷积可以实现我们想要的效果。
在做了一些尝试之后,本文将使用(1,filter_size)大小的2D卷积窗口,在上图中,filter_size=3。回到我们的能源预测问题,我们有12个特点。为了让它进入二维卷积窗口,我们实际上需要它有4个维度。我们可以通过以下方法得到另一个维度:
data_train_wide=data_train.reshape((data_train.shape[0], data_train.shape[1], data_train.shape[2], 1)) data_test_wide=data_test.reshape((data_test.shape[0], data_test.shape[1], data_test.shape[2], 1)) data_train_wide.shape(61875, 72, 12, 1)
测试了不同的窗口尺寸过后,我们发现一次考虑两个特征效果最好:
defbasic_conv2D(n_filters=10, fsize=5, window_size=5, n_features=2): new_model=keras.Sequential() new_model.add(tf.keras.layers.Conv2D(n_filters, (1,fsize), padding=”same”, activation=”relu”, input_shape=(window_size, n_features, 1))) new_model.add(tf.keras.layers.Flatten()) new_model.add(tf.keras.layers.Dense(1000, activation=’relu’)) new_model.add(tf.keras.layers.Dense(100)) new_model.add(tf.keras.layers.Dense(1)) new_model.compile(optimizer=”adam”, loss=”mean_squared_error”) returnnew_modelm2=basic_conv2D(n_filters=24, fsize=2, window_size=window_size, n_features=data_train_wide.shape[2]) m2.summary() Model: "sequential_4"_________________________________________________________________Layer (type) OutputShapeParam#=================================================================conv2d (Conv2D) (None, 72, 12, 24) 72_________________________________________________________________flatten_4 (Flatten) (None, 20736) 0_________________________________________________________________dense_12 (Dense) (None, 1000) 20737000_________________________________________________________________dense_13 (Dense) (None, 100) 100100_________________________________________________________________dense_14 (Dense) (None, 1) 101=================================================================Totalparams: 20,837,273Trainableparams: 20,837,273Non-trainableparams: 0
这个模型相当大。在普通CPU上训练每一个epoch大约需要4分钟。不过,当它完成后,预测效果如下图:
与其他模型对比预测误差:
可以看到,2D卷积的效果优于其它所有的预测模型。
补充
如果我们使用类似的想法,但同时用尺寸为(8,1)的滤波器进行卷积运算呢?相关代码如下:
defdeeper_conv2D(n_filters=10, fsize=5, window_size=5, n_features=2, hour_filter=8): new_model=keras.Sequential() new_model.add(tf.keras.layers.Conv2D(n_filters, (1,fsize), padding=”same”, activation=”linear”, input_shape=(window_size, n_features, 1))) new_model.add(tf.keras.layers.Conv2D(n_filters, (hour_filter, 1), padding=”same”, activation=”relu”)) new_model.add(tf.keras.layers.Flatten()) new_model.add(tf.keras.layers.Dense(1000, activation=’relu’)) new_model.add(tf.keras.layers.Dense(100)) new_model.add(tf.keras.layers.Dense(1)) new_model.compile(optimizer=”adam”, loss=”mean_squared_error”) returnnew_model
模型预测性能表现很好:
模型预测误差也进一步降低:
本文所有代码和数据可以在这里直接下载:
https://github.com/walesdata/2Dconv_pub
作者:Johnny Wales