Time series forecasting requires transforming sequential observations into a supervised learning format. A sliding window approach maps historical values to future targets. Given a continuous sequence, a fixed window size creates input-output pairs where past observations serve as features and subsequent values act as labels.
Data Transformation for Sequential Prediction
import numpy as np
import pandas as pd
def generate_temporal_features(series_data, window_size, forecast_horizon=1):
input_sequences, target_values = [], []
raw_values = series_data.values if isinstance(series_data, pd.Series) else np.asarray(series_data)
for start_idx in range(len(raw_values) - window_size - forecast_horizon + 1):
input_sequences.append(raw_values[start_idx : start_idx + window_size])
target_values.append(raw_values[start_idx + window_size : start_idx + window_size + forecast_horizon])
return np.array(input_sequences), np.array(target_values).reshape(-1, forecast_horizon)
Network Architecture Design
A standard backpropagation network for regression tasks consists of fully connected layers with non-linear activations. The architecture must balance representational capacity and generalization to avoid overfitting sequential noise. Dropout layers and weight initialization strategies stabilize gradient flow during training.
import torch
import torch.nn as nn
class TemporalMLP(nn.Module):
def __init__(self, feature_count, hidden_layers, dropout_prob=0.2):
super().__init__()
architecture = []
current_dim = feature_count
for layer_dim in hidden_layers:
architecture.append(nn.Linear(current_dim, layer_dim))
architecture.append(nn.GELU())
architecture.append(nn.Dropout(dropout_prob))
current_dim = layer_dim
architecture.append(nn.Linear(current_dim, 1))
self.processor = nn.Sequential(*architecture)
def forward(self, inputs):
return self.processor(inputs)
Training Loop and Optimization Strategies
Model optimization relies on gradient descent via backpropagation. Key hyperparameters include the learning rate, batch size, and weight decay. Implementing a dynamic learning rate scheduler and gradient clipping stabilizes convergence on volatile time series data. Shufflnig is disabled for validation splits to preserve temporla order during evaluation.
from torch.utils.data import TensorDataset, DataLoader
from sklearn.model_selection import train_test_split
def optimize_network(net, features, labels, num_epochs=100, batch_size=64, initial_lr=0.001):
X_train, X_val, y_train, y_val = train_test_split(features, labels, test_size=0.2, shuffle=False)
train_dataset = TensorDataset(torch.tensor(X_train, dtype=torch.float32),
torch.tensor(y_train, dtype=torch.float32))
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
loss_fn = nn.MSELoss()
optimizer = torch.optim.AdamW(net.parameters(), lr=initial_lr, weight_decay=1e-4)
lr_scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', patience=5, factor=0.5)
net.train()
for epoch in range(num_epochs):
cumulative_loss = 0.0
for batch_x, batch_y in train_loader:
optimizer.zero_grad()
predictions = net(batch_x)
loss = loss_fn(predictions, batch_y)
loss.backward()
torch.nn.utils.clip_grad_norm_(net.parameters(), max_norm=1.0)
optimizer.step()
cumulative_loss += loss.item()
val_tensor = torch.tensor(X_val, dtype=torch.float32)
val_loss = loss_fn(net(val_tensor), torch.tensor(y_val, dtype=torch.float32)).item()
lr_scheduler.step(val_loss)
Performance Evaluation and Metric Calculation
Predictive accuracy is quantified using error metrics that penalize deviations between forecasted and actual values. Root Mean Square Error (RMSE) emphaiszes larger deviations, while Mean Absolute Error (MAE) provides a linear penalty scale. Evaluating on a held-out test set ensures the network captures underlying temporal patterns rather than memorizing training noise.
from sklearn.metrics import mean_absolute_error, mean_squared_error
def compute_forecast_metrics(trained_model, test_features, test_labels):
trained_model.eval()
with torch.no_grad():
raw_predictions = trained_model(torch.tensor(test_features, dtype=torch.float32)).numpy()
rmse_score = np.sqrt(mean_squared_error(test_labels, raw_predictions))
mae_score = mean_absolute_error(test_labels, raw_predictions)
return rmse_score, mae_score, raw_predictions