前言
前面已经写过不少时间序列预测的文章:
- 深入理解PyTorch中LSTM的输入和输出(从input输入到Linear输出)
- PyTorch搭建LSTM实现时间序列预测(负荷预测)
- PyTorch中利用LSTMCell搭建多层LSTM实现时间序列预测
- PyTorch搭建LSTM实现多变量时间序列预测(负荷预测)
- PyTorch搭建双向LSTM实现时间序列预测(负荷预测)
- PyTorch搭建LSTM实现多变量多步长时间序列预测(一):直接多输出
- PyTorch搭建LSTM实现多变量多步长时间序列预测(二):单步滚动预测
- PyTorch搭建LSTM实现多变量多步长时间序列预测(三):多模型单步预测
- PyTorch搭建LSTM实现多变量多步长时间序列预测(四):多模型滚动预测
- PyTorch搭建LSTM实现多变量多步长时间序列预测(五):seq2seq
- PyTorch中实现LSTM多步长时间序列预测的几种方法总结(负荷预测)
- PyTorch-LSTM时间序列预测中如何预测真正的未来值
- PyTorch搭建LSTM实现多变量输入多变量输出时间序列预测(多任务学习)
- PyTorch搭建ANN实现时间序列预测(风速预测)
- PyTorch搭建CNN实现时间序列预测(风速预测)
- PyTorch搭建CNN-LSTM混合模型实现多变量多步长时间序列预测(负荷预测)
- PyTorch搭建Transformer实现多变量多步长时间序列预测(负荷预测)
- PyTorch时间序列预测系列文章总结(代码使用方法)
- TensorFlow搭建LSTM实现时间序列预测(负荷预测)
- TensorFlow搭建LSTM实现多变量时间序列预测(负荷预测)
- TensorFlow搭建双向LSTM实现时间序列预测(负荷预测)
- TensorFlow搭建LSTM实现多变量多步长时间序列预测(一):直接多输出
- TensorFlow搭建LSTM实现多变量多步长时间序列预测(二):单步滚动预测
- TensorFlow搭建LSTM实现多变量多步长时间序列预测(三):多模型单步预测
- TensorFlow搭建LSTM实现多变量多步长时间序列预测(四):多模型滚动预测
- TensorFlow搭建LSTM实现多变量多步长时间序列预测(五):seq2seq
- TensorFlow搭建LSTM实现多变量输入多变量输出时间序列预测(多任务学习)
- TensorFlow搭建ANN实现时间序列预测(风速预测)
- TensorFlow搭建CNN实现时间序列预测(风速预测)
- TensorFlow搭建CNN-LSTM混合模型实现多变量多步长时间序列预测(负荷预测)
这些文章中LSTM的模型都采用以下方法搭建:
class LSTM(nn.Module):
def __init__(self, input_size, hidden_size, num_layers, output_size, batch_size):
super().__init__()
self.input_size = input_size
self.hidden_size = hidden_size
self.num_layers = num_layers
self.output_size = output_size
self.num_directions = 1 # 单向LSTM
self.batch_size = batch_size
self.lstm = nn.LSTM(self.input_size, self.hidden_size, self.num_layers, batch_first=True)
self.linear = nn.Linear(self.hidden_size, self.output_size)
def forward(self, input_seq):
batch_size, seq_len = input_seq.shape[0], input_seq.shape[1]
h_0 = torch.randn(self.num_directions * self.num_layers, self.batch_size, self.hidden_size).to(device)
c_0 = torch.randn(self.num_directions * self.num_layers, self.batch_size, self.hidden_size).to(device)
# output(batch_size, seq_len, num_directions * hidden_size)
output, _ = self.lstm(input_seq, (h_0, c_0)) # output(5, 30, 64)
pred = self.linear(output) # (5, 30, 1)
pred = pred[:, -1, :] # (5, 1)
return pred
其中LSTM模型的定义语句为:
self.lstm = nn.LSTM(self.input_size, self.hidden_size, self.num_layers, batch_first=True, dropout=0.5)
如果num_layers=2, hidden_size=64
,那么两层LSTM的hidden_size
都为64,并且最后一层也就是第二层结束后不会执行dropout策略。
如果我们需要让两层LSTM的hidden_size
不一样,并且每一层后都执行dropout,就可以采用LSTMCell来实现多层的LSTM。
LSTMCell
关于nn.LSTMCell的参数,官方文档给出的解释为:
参数一共三个,意义和之前文章讲的一样,不再重复。
利用LSTMCell搭建一个两层的LSTM如下所示:
class LSTM(nn.Module):
def __init__(self, args):
super().__init__()
self.args = args
self.input_size = args.input_size
self.output_size = args.output_size
self.num_directions = 1
self.batch_size = args.batch_size
self.lstm0 = nn.LSTMCell(args.input_size, hidden_size=128)
self.lstm1 = nn.LSTMCell(input_size=128, hidden_size=32)
self.dropout = nn.Dropout(p=0.4)
self.linear = nn.Linear(32, self.output_size)
def forward(self, input_seq):
batch_size, seq_len = input_seq.shape[0], input_seq.shape[1]
# batch_size, hidden_size
h_l0 = torch.zeros(batch_size, 128).to(device)
c_l0 = torch.zeros(batch_size, 128).to(device)
h_l1 = torch.zeros(batch_size, 32).to(device)
c_l1 = torch.zeros(batch_size, 32).to(device)
output = []
for t in range(seq_len):
h_l0, c_l0 = self.lstm0(input_seq[:, t, :], (h_l0, c_l0))
h_l0, c_l0 = self.dropout(h_l0), self.dropout(c_l0)
h_l1, c_l1 = self.lstm1(h_l0, (h_l1, c_l1))
h_l1, c_l1 = self.dropout(h_l1), self.dropout(c_l1)
output.append(h_l1)
pred = self.linear(output[-1])
return pred
可以发现,我们定义了两个LSTMCell,分别对应两层:
self.lstm0 = nn.LSTMCell(args.input_size, hidden_size=128)
self.lstm1 = nn.LSTMCell(input_size=128, hidden_size=32)
第一层的input_size
就为初始数据的input_size
,第二层的input_size
应当为第一层的hidden_size
,这样才能实现数据传递。
使用LSTMCell时我们需要手动对每个时间步进行计算与传递:
for t in range(seq_len):
h_l0, c_l0 = self.lstm0(input_seq[:, t, :], (h_l0, c_l0))
h_l0, c_l0 = self.dropout(h_l0), self.dropout(c_l0)
h_l1, c_l1 = self.lstm1(h_l0, (h_l1, c_l1))
h_l1, c_l1 = self.dropout(h_l1), self.dropout(c_l1)
output.append(h_l1)
input_seq
的维度为:
input_seq(batch_size, seq_len, input_size)
每次取出其中一个步长参与运算:
h_l0, c_l0 = self.lstm0(input_seq[:, t, :], (h_l0, c_l0))
第一个LSTMCell的结果将被送入第二个LSTMCell:
h_l1, c_l1 = self.lstm1(h_l0, (h_l1, c_l1))
此时得到的是一个时间步的输出,维度大小为(batch_size, hidden_size)
。重复执行多次,就可以得到所有步长的输出。最后,我们再取最后一个时间步(这里不懂请看第一篇文章)的输出进行映射以得到最终的输出:
pred = self.linear(output[-1])
可以发现,在每一个LSTMCell执行结束后,我们都可以手动添加dropout层:
h_l0, c_l0 = self.dropout(h_l0), self.dropout(c_l0)
反观LSTM的执行过程:
output, _ = self.lstm(input_seq, (h_0, c_0))
此时output的shape为:
output(batch_size, seq_len, hidden_size)
实际上就是一步到位,直接得到所有seq_len
个(batch_size, hidden_size)
。
训练/测试
这里没啥可说的,与前面一模一样。