卷积神经网络(CNN)是一种利用卷积运算的深度学习结构。这允许神经网络减少特征空间,有效地过滤输入,防止过度拟合。并且由于其可以通过卷积运算有效地滤除时间序列中的噪声,使得能够产生一系列不包括异常值的稳健特性。同时CNN通常比LSTM训练更快,因为它们的操作可以并行。
卷积是通过一个内核来实现的,这个内核在模型拟合过程中也经过了训练。内核的步长决定了它在卷积的每一步移动的步数。在时序数据中,由于内核只能在时间维度中移动,导致内核只在一个方向(向右)移动,因此是一维卷积。另外为了防止卷积过程中丢失太多信息,通常会在原始数据的前后进行0值填充,然后不断移动内核,取其在不同位置与特征向量的点积,由于填充的关系,最终的得到的结果长度与原始特征向量的长度相同。
输入、输出与内核长度关系:output length = input length – kernel length + 1
CNN模型除了单独使用外,还可以与LSTM进行组合,形成一个单一的模型。
由于CNN卷积操作的存在,因此为了保证预测输出达到所要求的长度,需要对输入数据进行处理,处理办法有两种,一种是加大输入长度,假如内核长度为3,那么当需要预测24个步长的数据时,根据input length=output length+kernel length-1可得应输入长度为24+3-1=26;另外一种办法是使用填充,在输入的前后进行0填充,下文中使用第一种方法。
KERNEL_WIDTH = 3
LABEL_WIDTH = 24
INPUT_WIDTH = LABEL_WIDTH + KERNEL_WIDTH - 1
conv_window = DataWindow(input_width=KERNEL_WIDTH, label_width=1, shift=1, label_columns=['traffic_volume'])
wide_conv_window = DataWindow(input_width=INPUT_WIDTH, label_width=LABEL_WIDTH, shift=1, label_columns=['traffic_volume'])
cnn_model = Sequential([
Conv1D(filters=32,
kernel_size=(KERNEL_WIDTH,),
activation='relu'),
Dense(units=32, activation='relu'),
Dense(units=1)
])
history = compile_and_fit(cnn_model, conv_window)
val_performance['CNN'] = cnn_model.evaluate(conv_window.val)
performance['CNN'] = cnn_model.evaluate(conv_window.test, verbose=0)
cnn_lstm_model = Sequential([
Conv1D(filters=32,
kernel_size=(KERNEL_WIDTH,),
activation='relu'),
LSTM(32, return_sequences=True),
LSTM(32, return_sequences=True),
Dense(1)
])
history = compile_and_fit(cnn_lstm_model, conv_window)
val_performance['CNN + LSTM'] = cnn_lstm_model.evaluate(conv_window.val)
performance['CNN + LSTM'] = cnn_lstm_model.evaluate(conv_window.test, verbose=0)
通过对基线、线性、DNN、LSTM、CNN以及CNN+LSTM模型的预测结果比较,发现LSTM的效果仍然是最佳的,CNN次之,而CNN+LSTM反而更低,此处很大可能是由于数据量导致,使模型未得到充分学习而导致。
与单步模式类似,只是将偏移参数shift从1修改为24,以达到预测未来24个数据点。
KERNEL_WIDTH = 3
LABEL_WIDTH = 24
INPUT_WIDTH = LABEL_WIDTH + KERNEL_WIDTH - 1
wide_conv_window = DataWindow(input_width=INPUT_WIDTH, label_width=LABEL_WIDTH, shift=24, label_columns=['traffic_volume'])
cnn_model = Sequential([
Conv1D(filters=32,
kernel_size=(KERNEL_WIDTH,),
activation='relu'),
Dense(units=32, activation='relu'),
Dense(units=1)
])
history = compile_and_fit(cnn_model, wide_conv_window)
ms_val_performance['CNN'] = cnn_model.evaluate(wide_conv_window.val)
ms_performance['CNN'] = cnn_model.evaluate(wide_conv_window.test, verbose=0)
cnn_lstm_model = Sequential([
Conv1D(filters=32,
kernel_size=(KERNEL_WIDTH,),
activation='relu'),
LSTM(32, return_sequences=True),
LSTM(32, return_sequences=True),
Dense(1)
])
history = compile_and_fit(cnn_lstm_model, wide_conv_window)
ms_val_performance['CNN + LSTM'] = cnn_lstm_model.evaluate(wide_conv_window.val)
ms_performance['CNN + LSTM'] = cnn_lstm_model.evaluate(wide_conv_window.test, verbose=0)
通过对基线、线性、DNN、LSTM、CNN以及CNN+LSTM模型的预测结果比较,发现在多步模式下CNN与LSTM组合后效果最佳。
相比单步模式,仅修改标签参数,修改为预测temp,traffic_volume两个参数。
KERNEL_WIDTH = 3
LABEL_WIDTH = 24
INPUT_WIDTH = LABEL_WIDTH + KERNEL_WIDTH - 1
wide_conv_window = DataWindow(input_width=INPUT_WIDTH, label_width=24, shift=1, label_columns=['temp','traffic_volume'])
cnn_model = Sequential([
Conv1D(filters=32,
kernel_size=(KERNEL_WIDTH,),
activation='relu'),
Dense(units=32, activation='relu'),
Dense(units=2)
])
history = compile_and_fit(cnn_model, wide_conv_window)
mo_val_performance['CNN'] = cnn_model.evaluate(wide_conv_window.val)
mo_performance['CNN'] = cnn_model.evaluate(wide_conv_window.test, verbose=0)
3.2 CNN+LSTM
cnn_lstm_model = Sequential([
Conv1D(filters=32,
kernel_size=(KERNEL_WIDTH,),
activation='relu'),
LSTM(32, return_sequences=True),
LSTM(32, return_sequences=True),
Dense(units=2)
])
history = compile_and_fit(cnn_lstm_model, wide_conv_window)
mo_val_performance['CNN + LSTM'] = cnn_lstm_model.evaluate(wide_conv_window.val)
mo_performance['CNN + LSTM'] = cnn_lstm_model.evaluate(wide_conv_window.test, verbose=0)
通过对基线、线性、DNN、LSTM、CNN以及CNN+LSTM模型的预测结果比较,发现在多输出模式下,CNN+LSTM组合模型的效果仍是最佳的。