N-BEATS › Example
Machine Learning from ScratchAll chapters N-BEATS › ExampleOne section · Sections in this chapter4 / 8 ↓
Reading tools Definitions & inline links
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
Now that we understand the mathematical framework, let's see N-BEATS in action. We'll work through a concrete example that demonstrates how the formulas we've discussed translate into a working forecasting model.
The scenario: Suppose we have monthly sales data for a retail store over 24 months, and we want to forecast the next 6 months. This is a realistic forecasting problem where we need to separate the underlying growth trend from seasonal patterns.
What we'll learn: Through this example, you'll see:
- How the decomposition formula is applied in practice
- How the neural network learns the coefficients , , and from data
- How the basis functions combine to produce interpretable forecasts
Let's begin by creating synthetic data that mimics a real-world scenario with both trend and seasonality.
Step 1: Prepare the Input Data
First, we need to format our time series data for N-BEATS. The model typically takes a window of historical values as input. This is the in our formula. We'll create data that has both a linear growth trend and yearly seasonality, which will allow us to see how N-BEATS separates these components:
import numpy as np
import pandas as pd
# Generate sample monthly sales data
np.random.seed(42)
months = 24
t = np.arange(months)
# Create trend + seasonality + noise
trend = 100 + 2 * t # Linear growth
seasonal = 20 * np.sin(2 * np.pi * t / 12) + 10 * np.cos(2 * np.pi * t / 12)
noise = np.random.normal(0, 5, months)
sales = trend + seasonal + noise
# Create DataFrame
df = pd.DataFrame({"month": t + 1, "sales": sales})Sample sales data: month sales 0 1 112.483571 1 2 119.968933 2 3 129.558951 3 4 133.615149 4 5 119.149741 5 6 110.169061 6 7 109.896064 7 8 99.176920 8 9 91.332120 9 10 100.712800
The sales data shows monthly values with both trend and seasonal components. Notice how the values combine a steady upward trend (the linear growth) with periodic fluctuations (the seasonal pattern). The first 10 months demonstrate the underlying pattern that N-BEATS will learn to decompose and forecast.
What's happening mathematically: This data follows the decomposition formula we discussed: . The trend component is (linear growth), the seasonal component is (yearly cycle), and we've added noise to make it realistic. N-BEATS will learn to separate these components automatically.
Step 2: Define the N-BEATS Architecture
Now let's implement a simplified version of N-BEATS to understand how it works. This implementation will demonstrate the key components we discussed in the Formula section:
- The neural network that learns coefficients ()
- The trend basis functions ( with polynomial terms)
- The seasonal basis functions ( with trigonometric terms)
- The additive combination to produce forecasts
import torch
import torch.nn as nn
class SimpleNBEATS(nn.Module):
def __init__(self, input_size=12, hidden_size=64, output_size=6):
super(SimpleNBEATS, self).__init__()
# Neural network to learn coefficients
self.network = nn.Sequential(
nn.Linear(input_size, hidden_size),
nn.ReLU(),
nn.Linear(hidden_size, hidden_size),
nn.ReLU(),
nn.Linear(
hidden_size, output_size * 4
), # 4 coefficients per horizon
)
self.output_size = output_size
def forward(self, x):
# Get coefficients from neural network
coeffs = self.network(x)
# Reshape coefficients
coeffs = coeffs.view(-1, self.output_size, 4)
# Extract trend and seasonal coefficients
trend_coeffs = coeffs[:, :, :2] # Linear and quadratic
seasonal_coeffs = coeffs[:, :, 2:] # Sine and cosine
# Generate forecasts
forecasts = []
for h in range(self.output_size):
# Trend component
trend_h = trend_coeffs[:, h, 0] * (h + 1) + trend_coeffs[
:, h, 1
] * ((h + 1) ** 2)
# Seasonal component
seasonal_h = seasonal_coeffs[:, h, 0] * np.sin(
2 * np.pi * (h + 1) / 12
) + seasonal_coeffs[:, h, 1] * np.cos(2 * np.pi * (h + 1) / 12)
forecast_h = trend_h + seasonal_h
forecasts.append(forecast_h)
return torch.stack(forecasts, dim=1)
# Initialize model
model = SimpleNBEATS(input_size=12, hidden_size=64, output_size=6)
total_params = sum(p.numel() for p in model.parameters())Model parameters: 6552
The model architecture has a moderate number of parameters, making it suitable for learning the trend and seasonal patterns in the sales data.
Step 3: Prepare Training Data
We need to create input-output pairs for training:
def create_sequences(data, input_size=12, output_size=6):
"""Create input-output sequences for training"""
X, y = [], []
for i in range(len(data) - input_size - output_size + 1):
X.append(data[i : i + input_size])
y.append(data[i + input_size : i + input_size + output_size])
return np.array(X), np.array(y)
# Create training sequences
X, y = create_sequences(sales, input_size=12, output_size=6)Input shape: (7, 12) Output shape: (7, 6) Number of training samples: 7
The sliding window approach creates multiple training samples from the 24 months of data. Each sample uses 12 months as input (this is our ) to predict the next 6 months (this is our forecast horizon ). This approach allows the model to learn from different segments of the time series, seeing how historical patterns relate to future values.
Why this matters: By creating multiple training samples, we give the neural network many examples of how historical patterns (the input window) should translate into coefficient values (the learned , , ) that produce accurate forecasts.
Step 4: Train the Model
Now let's train our N-BEATS model. This is where the loss function we discussed comes into play. The model will learn the optimal coefficients by minimizing the mean squared error:
During training, the network will:
- Make predictions using current coefficients
- Calculate the loss (how far predictions are from actual values)
- Adjust its weights to reduce the loss
- Repeat until the coefficients produce accurate forecasts
import torch.optim as optim
# Convert to PyTorch tensors
X_tensor = torch.FloatTensor(X)
y_tensor = torch.FloatTensor(y)
# Training setup
optimizer = optim.Adam(model.parameters(), lr=0.001)
criterion = nn.MSELoss()
# Training loop
epochs = 1000
model.train()
training_losses = []
for epoch in range(epochs):
optimizer.zero_grad()
# Forward pass
predictions = model(X_tensor)
# Calculate loss
loss = criterion(predictions, y_tensor)
# Backward pass
loss.backward()
optimizer.step()
training_losses.append(loss.item())Epoch 0, Loss: 44180.6016 Epoch 200, Loss: 26.6763 Epoch 400, Loss: 17.0943 Epoch 600, Loss: 12.7652 Epoch 800, Loss: 10.0619 Final training loss: 8.4439
The training loss decreases over epochs, indicating that the model is learning to capture the underlying patterns in the sales data. The final loss value shows how well the model fits the training data, with lower values indicating better fit.
What's happening mathematically: As the loss decreases, the neural network is learning the optimal coefficients , , and that minimize prediction error. The network is simultaneously learning:
- How to separate trend from seasonality
- Which polynomial degrees are needed for the trend
- Which harmonics are needed for the seasonality
- The appropriate coefficients for each basis function
Step 5: Make Predictions
Finally, let's use our trained model to make forecasts. This is where all the pieces come together:
- The neural network takes the last 12 months as input ()
- It outputs the learned coefficients ()
- These coefficients are applied to the basis functions ( and )
- The trend and seasonal components are combined additively to produce the forecast
This is the decomposition formula in action. For each forecast horizon , we compute:
# Prepare last 12 months for prediction
last_window = sales[-12:].reshape(1, -1)
last_window_tensor = torch.FloatTensor(last_window)
# Make prediction
model.eval()
with torch.no_grad():
forecast = model(last_window_tensor)
forecast_np = forecast.numpy().flatten()N-BEATS Forecast for next 6 months: Month 1: 157.85 Month 2: 155.43 Month 3: 167.36 Month 4: 161.56 Month 5: 172.31 Month 6: 162.45

The forecast shows the predicted sales values for the next 6 months. These values combine the learned trend and seasonal patterns from the historical data. The model extrapolates the linear growth trend and applies the seasonal pattern learned from the 24 months of training data.
What we've accomplished: This example demonstrates the complete N-BEATS workflow:
-
Decomposition: The model learned to separate the time series into trend and seasonal components, following the formula
-
Coefficient learning: The neural network automatically learned the coefficients , , and that best fit the data, without us having to specify them manually
-
Basis function application: The learned coefficients were applied to polynomial trend functions and trigonometric seasonal functions, creating interpretable components
-
Additive combination: The trend and seasonal components were combined additively to produce forecasts that we can understand and trust
This is the power of N-BEATS: it combines mathematical rigor (the basis expansion framework) with practical learning (the neural network) to create forecasts that are both accurate and interpretable.