Transformer Forecasting for Series
A transformer reads the whole past window at once. Attention weighs every old step directly, so last winter can speak to this winter.
Why Does This Exist?
Recurrent nets read history in order, one step at a time. That chain is honest but slow, and old steps fade as gradients travel back. By step 200, last season is a whisper. You want a model that asks every past step directly, however far back it sits, and trains in parallel instead of queuing.
Attention does that. It scores every pair of steps, turns scores into weights, and blends the past in one hop. The path from any history point to the forecast stays one hop long. Long seasonal links stop fading, and the whole window trains at once.
This page teaches that swap: patching, position tags, attention, and horizon decoding. The recurrent predecessor lives in LSTM forecasting. The ordered-data base lives in time series fundamentals. Stretching one prediction into many lives in multi-step forecasting. Judging the result lives in evaluation metrics.
Basics first: means lookback length, means horizon length, and a token here means one patched chunk of steps. If ordered data is new, read fundamentals first. Everything below assumes you know why shuffling breaks time.
Think of It Like This
Reading front to back versus jumping with search
An LSTM reads like you reading a logbook front to back. By page 200 you remember the gist of page 10, not its numbers. To quote page 10 you walk back through 190 pages.
A transformer reads like you with search over the same logbook. You type one query and jump straight to page 10, compare it with page 200 side by side, and quote both exactly. Distance stops mattering.
Where it stops: search finds words for free. Attention learns its jump weights from data and pays for every pair it scores. That freedom costs memory that grows with the square of the window, which reading in order never pays.
How It Actually Works
Call the window to , meaning the past values ending now. Call the horizon , meaning how many steps ahead you must emit. Self-attention builds a query , key , and value per token, scores queries against keys, normalises with softmax, and blends values by those weights. Every token reaches every other in one hop, so the maximum path is .
Three adaptations make it work on time. Patching groups raw steps into chunks, so hours becomes 24 patches of 4 and the pair cost falls by 16 times. Position and calendar tags restore order, because attention alone cannot tell shuffled from sorted. You add absolute positions plus hour of day and day of week, so the model sees both place and season. Decoding then emits : one-shot heads write the whole horizon at once and stay stable, while recursive heads feed each prediction back and drift when early steps err.
Worked example
Window of three values: 10, 12, 8. Scores for the forecast query are 2, 1, 0.
- Exponentiate: , , . Sum .
- Weights: , , . They sum to .
- Blend: , so the forecast is about 10.3.
- Pair cost is scores for . Double to and pairs quadruple to 36.
No chain carried 10 forward through 12 and 8. The query reached back two steps in one hop because the weight 0.665 said so.
Code
This stdlib snippet runs the diagram arithmetic: softmax of 2 1 0, the blend into 10.3, and the pair count:
import math
def softmax(scores: list[float]) -> list[float]: """Normalise scores into weights that sum to 1.""" exps: list[float] = [math.exp(s) for s in scores] total: float = sum(exps) return [e / total for e in exps]
def blend(values: list[float], weights: list[float]) -> float: """Weighted average of past values by attention weights.""" return sum(v * w for v, w in zip(values, weights))
values: list[float] = [10.0, 12.0, 8.0]weights: list[float] = softmax([2.0, 1.0, 0.0])print([round(w, 3) for w in weights]) # -> [0.665, 0.245, 0.09]print(round(blend(values, weights), 2)) # -> 10.31print(3 * 3) # -> 9Weights round to 0.665, 0.245, 0.090 and blend to 10.31. Nine pairs for three steps shows the square law before you scale to hundreds.
Watch Out For
Feeding raw ticks into quadratic attention
You pass 10,000 raw ticks to a plain transformer. The symptom is instant failure: memory explodes, batches shrink to 1, then the run dies with an allocation error. Pairs grow as , so 10,000 steps means 100 million scores per head.
Fix it by shortening before attention. Patch steps into chunks, sample to a coarser grain, or pick a sparse attention variant. Prove the pair math first: squared times heads must fit your card.
Dropping the position tags
You embed values but forget order info. The symptom is a model blind to shuffling: permute the window and the forecast barely moves, while season flips go unnoticed. Attention alone is a set tool, not a sequence tool.
Fix it by always adding position plus calendar features. Absolute order plus hour of day and day of week turns the set back into a series. Test the fix by shuffling once: a correct model must change its answer.
The Quick Version
- Transformers swap the step-by-step chain for one-hop attention over the window.
- Scores 2 1 0 normalise to 0.665 0.245 0.090 and blend 10 12 8 into 10.3.
- Patching chunks steps to cut the pair cost, which grows as squared.
- Position and calendar tags restore order that attention alone cannot see.
- One-shot heads write the horizon at once, recursive heads feed back and can drift.
- Raw high-frequency windows blow memory, so shorten before you attend.