In this tutorial, we explore GluonTS from a practical perspective, where we generate complex synthetic datasets, prepare them, and apply multiple models in parallel. We focus on how to work with diverse estimators in the same pipeline, handle missing dependencies gracefully, and still produce usable results. By building in evaluation and visualization steps, we create a workflow that highlights how models can be trained, compared, and interpreted in a single, seamless process. Check out the FULL CODES here. Feel free to check out our GitHub Page for Tutorials, Codes and Notebooks.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime, timedelta
import warnings
warnings.filterwarnings('ignore')
from gluonts.dataset.pandas import PandasDataset
from gluonts.dataset.split import split
from gluonts.evaluation import make_evaluation_predictions, Evaluator
from gluonts.dataset.artificial import ComplexSeasonalTimeSeries
try:
from gluonts.torch import DeepAREstimator
TORCH_AVAILABLE = True
except ImportError:
TORCH_AVAILABLE = False
try:
from gluonts.mx import DeepAREstimator as MXDeepAREstimator
from gluonts.mx import SimpleFeedForwardEstimator
MX_AVAILABLE = True
except ImportError:
MX_AVAILABLE = False
We begin by importing the core libraries for data handling, visualization, and GluonTS utilities. We also set up conditional imports for PyTorch and MXNet estimators, allowing us to flexibly use whichever backend is available in our environment. Check out the FULL CODES here. Feel free to check out our GitHub Page for Tutorials, Codes and Notebooks.
def create_synthetic_dataset(num_series=50, length=365, prediction_length=30):
"""Generate synthetic multi-variate time series with trends, seasonality, and noise"""
np.random.seed(42)
series_list = []
for i in range(num_series):
trend = np.cumsum(np.random.normal(0.1 + i*0.01, 0.1, length))
daily_season = 10 * np.sin(2 * np.pi * np.arange(length) / 7)
yearly_season = 20 * np.sin(2 * np.pi * np.arange(length) / 365.25)
noise = np.random.normal(0, 5, length)
values = np.maximum(trend + daily_season + yearly_season + noise + 100, 1)
dates = pd.date_range(start="2020-01-01", periods=length, freq='D')
series_list.append(pd.Series(values, index=dates, name=f'series_{i}'))
return pd.concat(series_list, axis=1)
We create a synthetic dataset where each series combines trend, seasonality, and noise. We design it so every run produces consistent results, and we return a clean multi-series DataFrame ready for experimentation. Check out the FULL CODES here. Feel free to check out our GitHub Page for Tutorials, Codes and Notebooks.
print("🚀 Creating synthetic multi-series dataset...")
df = create_synthetic_dataset(num_series=10, length=200, prediction_length=30)
dataset = PandasDataset(df, target=df.columns.tolist())
training_data, test_gen = split(dataset, offset=-60)
test_data = test_gen.generate_instances(prediction_length=30, windows=2)
print("🔧 Initializing forecasting models...")
models = {}
if TORCH_AVAILABLE:
try:
models['DeepAR_Torch'] = DeepAREstimator(
freq='D',
prediction_length=30
)
print("✅ PyTorch DeepAR loaded")
except Exception as e:
print(f"❌ PyTorch DeepAR failed to load: {e}")
if MX_AVAILABLE:
try:
models['DeepAR_MX'] = MXDeepAREstimator(
freq='D',
prediction_length=30,
trainer=dict(epochs=5)
)
print("✅ MXNet DeepAR loaded")
except Exception as e:
print(f"❌ MXNet DeepAR failed to load: {e}")
try:
models['FeedForward'] = SimpleFeedForwardEstimator(
freq='D',
prediction_length=30,
trainer=dict(epochs=5)
)
print("✅ FeedForward model loaded")
except Exception as e:
print(f"❌ FeedForward failed to load: {e}")
if not models:
print("🔄 Using artificial dataset with built-in models...")
artificial_ds = ComplexSeasonalTimeSeries(
num_series=10,
prediction_length=30,
freq='D',
length_low=150,
length_high=200
).generate()
training_data, test_gen = split(artificial_ds, offset=-60)
test_data = test_gen.generate_instances(prediction_length=30, windows=2)
We generate a 10-series dataset, wrap it into a GluonTS PandasDataset, and split it into training and test windows. We then initialize multiple estimators (PyTorch DeepAR, MXNet DeepAR, and FeedForward) when available, and fall back to a built-in artificial dataset if no backends load. Check out the FULL CODES here. Feel free to check out our GitHub Page for Tutorials, Codes and Notebooks.
trained_models = {}
all_forecasts = {}
if models:
for name, estimator in models.items():
print(f"🎯 Training {name} model...")
try:
predictor = estimator.train(training_data)
trained_models[name] = predictor
forecasts = list(predictor.predict(test_data.input))
all_forecasts[name] = forecasts
print(f"✅ {name} training completed!")
except Exception as e:
print(f"❌ {name} training failed: {e}")
continue
print("📊 Evaluating model performance...")
evaluator = Evaluator(quantiles=[0.1, 0.5, 0.9])
evaluation_results = {}
for name, forecasts in all_forecasts.items():
if forecasts:
try:
agg_metrics, item_metrics = evaluator(test_data.label, forecasts)
evaluation_results[name] = agg_metrics
print(f"\n{name} Performance:")
print(f" MASE: {agg_metrics['MASE']:.4f}")
print(f" sMAPE: {agg_metrics['sMAPE']:.4f}")
print(f" Mean wQuantileLoss: {agg_metrics['mean_wQuantileLoss']:.4f}")
except Exception as e:
print(f"❌ Evaluation failed for {name}: {e}")
We train each available estimator, collect probabilistic forecasts, and store the fitted predictors for reuse. We then evaluate results with MASE, sMAPE, and weighted quantile loss, giving us a consistent, comparative view of model performance. Check out the FULL CODES here. Feel free to check out our GitHub Page for Tutorials, Codes and Notebooks.
def plot_advanced_forecasts(test_data, forecasts_dict, series_idx=0):
"""Advanced plotting with multiple models and uncertainty bands"""
fig, axes = plt.subplots(2, 2, figsize=(15, 10))
fig.suptitle('Advanced GluonTS Forecasting Results', fontsize=16, fontweight="bold")
if not forecasts_dict:
fig.text(0.5, 0.5, 'No successful forecasts to display',
ha="center", va="center", fontsize=20)
return fig
if series_idx 1 else x)
ax4.set_xticklabels(metrics)
ax4.legend()
ax4.grid(True, alpha=0.3)
else:
ax4.text(0.5, 0.5, 'No evaluation\nresults available',
ha="center", va="center", transform=ax4.transAxes, fontsize=14)
plt.tight_layout()
return fig
if all_forecasts and test_data.label:
print("📈 Creating advanced visualizations...")
fig = plot_advanced_forecasts(test_data, all_forecasts, series_idx=0)
plt.show()
print(f"\n🎉 Tutorial completed successfully!")
print(f"📊 Trained {len(trained_models)} model(s) on {len(df.columns) if 'df' in locals() else 10} time series")
print(f"🎯 Prediction length: 30 days")
if evaluation_results:
best_model = min(evaluation_results.items(), key=lambda x: x[1]['MASE'])
print(f"🏆 Best performing model: {best_model[0]} (MASE: {best_model[1]['MASE']:.4f})")
print(f"\n🔧 Environment Status:")
print(f" PyTorch Support: {'✅' if TORCH_AVAILABLE else '❌'}")
print(f" MXNet Support: {'✅' if MX_AVAILABLE else '❌'}")
else:
print("⚠️ Creating demonstration plot with synthetic data...")
fig, ax = plt.subplots(1, 1, figsize=(12, 6))
dates = pd.date_range('2020-01-01', periods=100, freq='D')
ts = 100 + np.cumsum(np.random.normal(0, 2, 100)) + 20 * np.sin(np.arange(100) * 2 * np.pi / 30)
ax.plot(dates[:70], ts[:70], 'b-', label="Historical Data", linewidth=2)
ax.plot(dates[70:], ts[70:], 'r--', label="Future (Example)", linewidth=2)
ax.fill_between(dates[70:], ts[70:] - 5, ts[70:] + 5, alpha=0.3, color="red")
ax.set_title('GluonTS Probabilistic Forecasting Example', fontsize=14, fontweight="bold")
ax.set_xlabel('Date')
ax.set_ylabel('Value')
ax.legend()
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
print("\n📚 Tutorial demonstrates advanced GluonTS concepts:")
print(" • Multi-series dataset generation")
print(" • Probabilistic forecasting")
print(" • Model evaluation and comparison")
print(" • Advanced visualization techniques")
print(" • Robust error handling")
We train each available model, generate probabilistic forecasts, and evaluate them with consistent metrics before visualizing comparisons, residuals, and uncertainty bands. If no models are available, we still demonstrate the workflow with a synthetic example so we can inspect plots and key concepts end to end.
In conclusion, we put together a robust setup that balances data creation, model experimentation, and performance analysis. Instead of relying on a single configuration, we see how to adapt flexibly, test multiple options, and visualize results in ways that make comparison intuitive. This gives us a stronger foundation for experimenting with GluonTS and applying the same principles to real datasets, while keeping the process modular and easy to extend.
Check out the FULL CODES here. Feel free to check out our GitHub Page for Tutorials, Codes and Notebooks. Also, feel free to follow us on Twitter and don’t forget to join our 100k+ ML SubReddit and Subscribe to our Newsletter.
Asif Razzaq is the CEO of Marktechpost Media Inc.. As a visionary entrepreneur and engineer, Asif is committed to harnessing the potential of Artificial Intelligence for social good. His most recent endeavor is the launch of an Artificial Intelligence Media Platform, Marktechpost, which stands out for its in-depth coverage of machine learning and deep learning news that is both technically sound and easily understandable by a wide audience. The platform boasts of over 2 million monthly views, illustrating its popularity among audiences.