LSTM因其具有记忆的功能,可以利用很长的序列信息来建立学习模型,所以用它来进行时间序列的预测会很有优势。
在实际工程中用LSTM进行时间序列的预测主要有两个难点:一是前期对数据的处理,二是初始模型的搭建。
对数据的处理无论是单步、多步、单变量还是多变量都会用到滑动窗口来处理数据,具体处理的方法后面会进行阐述;
而对模型的搭建则要根据要解决的问题,原始数据的情况等,对模型的参数做相应的设定,如果单纯的LSTM无法满足要求,一般会加入全连接层来解决。
单变量单步的预测是最简单的,比如说有一组数据为:
[1,2,3,4,5,6,7,8,9,10],然后要求利用这组数据训练一个模型,使其能对后面提供的数据做一个单步的预测。
我们先来对数据进行处理,处理的时候要根据不同框架所要求的LSTM的输入形式来处理,比如我们用Pytorch框架的时候输入要求是(seq_len, batch, input_size)。
因为是单变量的数据,我们令input_size=3,然后设seq_len=7,然后batch为1,
处理后的数据变为:
[[1,2,3], =====> [4]
[2,3,4], =====> [5]
[3,4,5], =====> [6]
[4,5,6], =====> [7]
[5,6,7], =====> [8]
[6,7,8], =====> [9]
[7,8,9]] =====> [10]
前半部分是输入,箭头指向输出。也就是说将数据分批输入LSTM,没三个数据对应一个单步的预测目标。
数据处理好之后就是模型的搭建了,我们根据输入输出的形式来反推模型的结构。
我们知道LSTM的结构是lstm = nn.LSTM(input_size, hidden_size, num_layers)。由上面给出的输入的形式可以确定input_size=3, hidden_size, num_layers这两个参数要自己设置,也就是隐藏层的大小和层数。我们的预计输出的形式为(7,1),但是LSTM的标准输出形式为:
output=(seq_len,batch,num_directionshidden_size)=(7,1,num_directionshidden_size),
当num_directionshidden_size不为1时我们需要在LSTM的后面加一个全连接层,并令全连接层的输入形式为num_directionshidden_size,输出为1 。这样我们的输出就变为了output=(7,1,1) ,然后用reshape方法(当out为numpy array时)或者view方法(当out为tensor时)将output整形为(7,1)。这样就可以用在后面的训练中了,即计算损失函数和反向传播。
比如一组数据为:
[[1,11],[2,12],[3,13],[4,14],[5,15],[6,16],[7,17],[8,18],[9,19],[10,20]]
要求对其进行两步预测,则我们对其进行处理:
[[[1,11],[2,12],[3,13]], ======>[[4,14],[5,15]]
[[2,12],[3,13],[4,14]], ======>[[5,15],[6,16]]
[[3,13],[4,14],[5,15]], ======>[[6,16],[7,17]]
[[4,14],[5,15],[6,16]], ======>[[7,17],[8,18]]
[[5,15],[6,16],[7,17]], ======>[[8,18],[9,19]]
[[6,16],[7,17],[8,18]], ======>[[9,19],[10,20]]
前半部分是输入,箭头指向输出。seq_len=6,batch=3,input_size=2
搭建模型的部分跟上面的分析是一样的,output的形状跟target一样为(6,2,2),而输入的形状为(6,3,2),所以还是需要一个全连接层使其输入为(6,3,2)输出为(6,2,2),这样才能用在后面的训练中。
最后如果要画出输出的图像的话可以取out[:3, 0, :]和out[:,1,:]在axis=0上拼接出来。
下面是模型的建立:
class LSTM(nn.Module):
def __init__(self, input_size, hidden_size, num_layers):
super(LSTM, self).__init__()
self.hidden_size = hidden_size
self.num_layers = num_layers
self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True)
self.fc = nn.Linear(hidden_size, 2) # 2 for bidirection
def forward(self, x):
# Set initial states
h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device) # 2 for bidirection
c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device)
# Forward propagate LSTM
out, _ = self.lstm(x, (h0, c0)) # out: tensor of shape (batch_size, seq_length, hidden_size*2)
# print("output_in=", out.shape)
# print("fc_in_shape=", out[:, -1, :].shape)
# Decode the hidden state of the last time step
# out = torch.cat((out[:, 0, :], out[-1, :, :]), axis=0)
# out = self.fc(out[:, -1, :]) # 取最后一列为out
out = self.fc(out)
return out
单变量多步和多变量单步的情况的处理方法跟上面两个是类似的。
基于LSTM的时间序列数据(多步)预测
如何进行多变量LSTM时间序列预测未来一周的数据?
用LSTM预测未来一个月航班数
多维多步预测