前面已经写了很多关于时间序列预测的文章:
上面所有文章都是“单变量输出”,虽然某些文章中提到了“多变量”,但这个多变量只是输入多变量,而不是输出多变量。比如我们利用前24个时刻的[负荷、温度、湿度、压强]预测接下来12个时刻的负荷,此时输入为多变量,虽然有多个输出(多步长),但输出的都是同一变量。
那么有没有办法一次性输出多个变量呢?当然是可以的,在前几篇文章的评论中也有人提到了这个问题,当时我给出的回答是:“这样做效果很不好,不建议这么做”。
多变量输入自不必说,不了解的可以去看一下前面几篇文章。
多变量输出是指:我们一次性输出多个变量的预测值。比如我们利用前24小时的[负荷、温度、湿度、压强]预测接下来12个时刻的[负荷、温度、湿度、压强]。实际上,我们可以将多个变量的输出分解开来,看成多个任务,也就是多任务学习,其中每一个任务都是前面提到的多变量输入单变量输出。
具体来讲,假设需要预测四个变量,输出在经过LSTM后得到output,我们将output分别通过四个全连接层,就能得到四个输出。得到四个输出后,我们就可以计算出四个损失函数,对这四个损失函数,本文将其简单求平均以得到最终的损失函数。关于如何组合多任务学习中的损失,已经有很多文献探讨过,感兴趣的可以自行了解。
本次实验的数据集中包含三个地区的负荷值。
数据集:
依旧使用前24个时刻的三个变量预测后12个时刻的三个变量,数据处理同前面文章一致。
多输入多输出LSTM模型搭建如下:
class MTL_LSTM(keras.Model):
def __init__(self, args):
super().__init__()
self.args = args
self.lstm = layers.LSTM(units=args.hidden_size, input_shape=(args.seq_len, args.input_size),
activation='tanh', return_sequences=True)
self.fc = layers.Dense(64, activation='relu')
self.fc1 = layers.Dense(args.output_size)
self.fc2 = layers.Dense(args.output_size)
self.fc3 = layers.Dense(args.output_size)
def call(self, input_seq):
output = self.lstm(input_seq)
output = self.fc(output)
pred1, pred2, pred3 = self.fc1(output), self.fc2(output), self.fc3(output)
pred1, pred2, pred3 = pred1[:, -1, :], pred2[:, -1, :], pred3[:, -1, :]
return [pred1, pred2, pred3]
可以看到,由于需要预测三个变量,所以我们在模型中定义了三个全连接层。在得到LSTM的输出后,分别利用三个全连接层得到三个变量的输出,再将三个输出进行拼接,得到最后的pred,pred的shape为:
predict(n_outputs, batch_size, output_size)
其中n_outputs=3,表示一次性预测三个变量,output_size=12表示这里采用了PyTorch搭建LSTM实现多变量多步长时间序列预测(一):直接多输出中的策略,一次性输出接下来12个时刻的预测值,因为是直接多输出,所以这里pred_step_size=output_size。
模型训练中,经过预测后,我们得到的label和pred的shape分别为:
label(batch_size, n_outputs, pred_step_size)
pred((n_outputs, batch_size, pred_step_size))
由于需要对每一个output计算损失然后相加求平均,所以我们的损失函数求解如下:
total_loss = 0
for k in range(args.n_outputs):
total_loss = total_loss + loss_function(labels[:, k, :], preds[k])
total_loss /= 3
即每次都取出一个output进行计算求和再平均。
简单训练100轮,三个地区的负荷值预测结果如下所示:
变量 | 负荷1 | 负荷2 | 负荷3 |
---|---|---|---|
MAPE | 4.44% | 7.61% | 6.60% |
后面将陆续公开~