PyTorch:用LSTM预测未来价值



我目前正在构建一个LSTM模型,以使用PyTorch预测时间序列数据。我使用滞后特性通过前面的n个步骤作为训练网络的输入。我将数据拆分为三组,即训练验证测试拆分,并使用前两组来训练模型。我的验证函数从验证数据集中获取数据,并通过使用DataLoaders和TensorDataset类将其传递给LSTM模型来计算预测值。最初,我得到了非常好的结果,R2值在0.85-0.95之间。

然而,对于这个验证函数是否也适合测试我的模型的性能,我有一种不安的感觉。因为函数现在从DataLoader中获取实际的X值,即时滞特征,以预测y^值,即预测的目标值,而不是在下一次预测中使用预测的y^值作为特征。这种情况似乎与现实相去甚远,因为模型对之前时间步长的真实值一无所知,尤其是如果你预测更长时间段的时间序列数据,比如3-6个月。

我目前有点困惑于解决这个问题,并定义一个函数来预测未来的值,该函数依赖于模型的值,而不是测试集中的实际值。我有下面的函数predict,它可以进行一步预测,但我还没有真正弄清楚如何使用DataLoader预测整个测试数据集。

def predict(self, x):
# convert row to data
x = x.to(device)
# make prediction
yhat = self.model(x)
# retrieve numpy array
yhat = yhat.to(device).detach().numpy()
return yhat

您可以在下面找到我如何拆分和加载数据集、LSTM模型的构造函数以及验证函数。如果您需要更多信息,请随时联系我。

拆分和加载数据集

def create_tensor_datasets(X_train_arr, X_val_arr, X_test_arr, y_train_arr, y_val_arr, y_test_arr):
train_features = torch.Tensor(X_train_arr)
train_targets = torch.Tensor(y_train_arr)
val_features = torch.Tensor(X_val_arr)
val_targets = torch.Tensor(y_val_arr)
test_features = torch.Tensor(X_test_arr)
test_targets = torch.Tensor(y_test_arr)
train = TensorDataset(train_features, train_targets)
val = TensorDataset(val_features, val_targets)
test = TensorDataset(test_features, test_targets)
return train, val, test
def load_tensor_datasets(train, val, test, batch_size=64, shuffle=False, drop_last=True):
train_loader = DataLoader(train, batch_size=batch_size, shuffle=shuffle, drop_last=drop_last)
val_loader = DataLoader(val, batch_size=batch_size, shuffle=shuffle, drop_last=drop_last)
test_loader = DataLoader(test, batch_size=batch_size, shuffle=shuffle, drop_last=drop_last)
return train_loader, val_loader, test_loader

LSTM类

class LSTMModel(nn.Module):
def __init__(self, input_dim, hidden_dim, layer_dim, output_dim, dropout_prob):
super(LSTMModel, self).__init__()
self.hidden_dim = hidden_dim
self.layer_dim = layer_dim
self.lstm = nn.LSTM(
input_dim, hidden_dim, layer_dim, batch_first=True, dropout=dropout_prob
)
self.fc = nn.Linear(hidden_dim, output_dim)
def forward(self, x, future=False):
h0 = torch.zeros(self.layer_dim, x.size(0), self.hidden_dim).requires_grad_()
c0 = torch.zeros(self.layer_dim, x.size(0), self.hidden_dim).requires_grad_()
out, (hn, cn) = self.lstm(x, (h0.detach(), c0.detach()))
out = out[:, -1, :]
out = self.fc(out)
return out

验证(在培训师课程中定义)

def validation(self, val_loader, batch_size, n_features):
with torch.no_grad():
predictions = []
values = []
for x_val, y_val in val_loader:
x_val = x_val.view([batch_size, -1, n_features]).to(device)
y_val = y_val.to(device)
self.model.eval()
yhat = self.model(x_val)
predictions.append(yhat.cpu().detach().numpy())
values.append(y_val.cpu().detach().numpy())
return predictions, values

我终于找到了一种基于早期观测值预测值的方法。正如预期的那样,这些预测在短期内相当准确,在长期内略有恶化。随着时间的推移,未来的预测偏离主题并不奇怪,因为它们不再依赖于实际值。回顾我的研究结果和我对这个话题的讨论,以下是我的收获:

  • 在现实生活中,可以在预测的每一步(无论是每周、每天还是每小时)检索真实值并将其输入到模型中,以便可以使用上一步的实际值预测下一步。因此,基于测试集的实际值来测试性能可能会在一定程度上反映定期维护的模型的真实性能。

  • 然而,为了长期预测未来的价值,如果你愿意,你需要进行多个一步预测或跨你希望预测的时间段的多步预测。

  • 基于模型预测的值进行多个一步预测在短期内产生合理的结果。随着预测周期的增加,预测变得不那么准确,因此不太适合预测目的。

  • 要进行多个一步预测并在每次预测后更新输入,我们必须一个接一个地遍历数据集,就像我们在测试集上进行for循环一样。毫不奇怪,这让我们失去了矩阵运算和小批量训练所提供的所有计算优势

  • 一种替代方案可以是预测值的序列,而不是只预测下一个值,比如使用具有多对多或序列到序列结构的多维输出的RNN。他们可能更难训练,对不同时间段的预测也不那么灵活。编码器-解码器结构可能对解决这个问题很有用,尽管我自己还没有实现它。

您可以找到我的函数的代码,该函数基于数据集的最后一行X(时滞特征)和y(目标值)预测下一个n_steps。为了迭代数据集中的每一行,我将batch_size设置为1,n_features设置为滞后观测的数量。

def forecast(self, X, y, batch_size=1, n_features=1, n_steps=100):
predictions = []
X = torch.roll(X, shifts=1, dims=2)
X[..., -1, 0] = y.item(0)
with torch.no_grad():
self.model.eval()
for _ in range(n_steps):
X = X.view([batch_size, -1, n_features]).to(device)
yhat = self.model(X)
yhat = yhat.to(device).detach().numpy()
X = torch.roll(X, shifts=1, dims=2)
X[..., -1, 0] = yhat.item(0)
predictions.append(yhat)
return predictions

下面的线将张量的第二维度中的值偏移一,使得张量[[[x1, x2, x3, ... , xn ]]]变为[[[xn, x1, x2, ... , x(n-1)]]]

X = torch.roll(X, shifts=1, dims=2)

并且,下面的行从三维张量的最后一个维度中选择第一个元素,并将该项设置为存储在NumPy ndarray(yhat)[[xn+1]]中的预测值。然后,新的输入张量变为[[[x(n+1), x1, x2, ... , x(n-1)]]]

X[..., -1, 0] = yhat.item(0)

最近,我决定把我学到的东西和我想早点知道的东西放在一起。如果你想看一看,你可以在下面找到链接。我希望你会觉得它有用。如果你同意或不同意我上面的任何言论,请随时评论或联系我。

  • 使用PyTorch为时间序列构建RNN、LSTM和GRU
  • 使用PyTorch预测RNN、LSTM和GRU的未来值

最新更新