AI Hints
Home›Deep Learning Tutorial›Beyond Images and Text
Deep Learning · Lesson 79 of 92

Forecasting with LSTMs

And an honest comparison.

⏱ 2 min read▶ Video at 2:27:08🎓 Free
Watch this lesson in the Deep Learning courseWatch on YouTube ↗Full Deep Learning course

Power companies need to know tomorrow's demand. Shops need next week's sales. Time series are everywhere, and deep learning can help. But it's also where people fool themselves the most, because a simple trick can look like intelligence.

Forecasting with LSTMs
From the video: Forecasting with LSTMs
  • Tomorrow's demand, next week's sales
  • Time series are everywhere
  • People fool themselves here

An LSTM against a baseline

We've got a noisy wave. Each input is the past thirty values, and the target is the next one. The LSTM reads the window, and we take its last output. We train on the first nine hundred points, and test on the rest. Critically, we also compute what you'd score by simply repeating the last value. Run it. The L S T M's error is point one two seven. The lazy baseline gets point one six four. So the model really has learned something, but it isn't dramatic. A famous trap is a forecast chart that looks perfect, where the model is just copying yesterday, one step late. Always compare with the baseline.

lstm_forecast.pypython
import numpy as np
import torch

torch.manual_seed(0)
t = np.arange(1200)
series = np.sin(t * 2 * np.pi / 50) + 0.1 * np.random.default_rng(0).normal(size=1200)
w = 30
X = torch.tensor(np.lib.stride_tricks.sliding_window_view(series[:-1], w), dtype=torch.float32)[..., None]
y = torch.tensor(series[w:], dtype=torch.float32)
tr = 900

class Model(torch.nn.Module):
    def __init__(self):
        super().__init__()
        self.lstm = torch.nn.LSTM(1, 32, batch_first=True)
        self.out = torch.nn.Linear(32, 1)
    def forward(self, x):
        return self.out(self.lstm(x)[0][:, -1]).squeeze(1)

m = Model()
opt = torch.optim.Adam(m.parameters(), lr=.01)
for epoch in range(6):
    for i in torch.randperm(tr).split(32):
        loss = torch.nn.functional.mse_loss(m(X[i]), y[i])
        opt.zero_grad(); loss.backward(); opt.step()

print("LSTM error:", round(((m(X[tr:]) - y[tr:]) ** 2).mean().sqrt().item(), 3))
print("Repeat last value:", round(((X[tr:, -1, 0] - y[tr:]) ** 2).mean().sqrt().item(), 3))
Output
LSTM error: 0.127
Repeat last value: 0.164

Time series rules

Keep test data strictly in the future. Never shuffle across time when you split. Scale using training data only. Forecast several steps ahead, as that's where the real difficulty is. And know that for many business series, simple methods and boosted trees are hard to beat. Deep models shine when you've got thousands of related series.

Future test datanever shuffle
Scale on train onlyno leaks
Many steps aheadthe real test
Thousands of serieswhere deep wins

Summary

Always beat the lazy baseline first. Next, a surprising result about the world's most common kind of data.

Key takeaways
  • Compare with repeating the last value
  • Keep the test in the future
  • Simple methods are hard to beat
Next up: Tables: A Reality Check — where boosting still wins