Coding Guide for Building Flexible Multi-Model Workflows with Synthesized Data, Evaluation and Advanced Visualization GLUONTS
In this tutorial, we explore Gluonts From a practical point of view, we are generating complex synthetic datasets, preparing them and applying multiple models in parallel. We focus on how to work with different estimators in the same pipeline, gracefully dealing with missing dependencies and still yielding available 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 The complete code is here. Check out ours anytime Tutorials, codes and notebooks for github pages.
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 first need to import the core library for data processing, visualization and Gluonts utilities. We also set up conditional imports for Pytorch and MXNET estimators, giving us the flexibility to use the backends available in our environment. Check The complete code is here. Check out ours anytime Tutorials, codes and notebooks for github pages.
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, each series combining trends, seasonality, and noise. We designed it so that each run produces consistent results and return a clean multi-series data framework for experimentation. Check The complete code is here. Check out ours anytime Tutorials, codes and notebooks for github pages.
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 of datasets, wrap it into Gluonts Pandasdataset, and then divide it into training and testing windows. Then, without the backend load, we initialize multiple estimators (Pytorch Deepar, Mxnet Deepar, and FeedForward) and lag behind the built-in manual dataset. Check The complete code is here. Check out ours anytime Tutorials, codes and notebooks for github pages.
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 probability predictions, and store appropriate predictors for reuse. We then evaluate the results with MASE, SMAPE, and weighted quantile losses, thus giving us a consistent comparative view of model performance. Check The complete code is here. Check out ours anytime Tutorials, codes and notebooks for github pages.
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 evaluationnresults 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 predictions, and evaluate them with consistent metrics before visualizing comparisons, residuals, and uncertainty bands. If there is no model available, we can still demonstrate the workflow with synthesis examples, so we can check the graphs and key concepts end-to-end.
In short, we put together a powerful setup to balance data creation, model experimentation, and performance analysis. Instead of relying on a single configuration, we see how to flexibly adjust, test multiple options and visualize the results in a more intuitive way. This provides us with a stronger foundation for experimenting with Gluonts and applying the same principles to real-world dataset applications while making the process modular and easy to scale.
Check The complete code is here. Check out ours anytime Tutorials, codes and notebooks for github pages. Also, please stay tuned for us twitter And don’t forget to join us 100K+ ml reddit And subscribe Our newsletter.
Asif Razzaq is CEO of Marktechpost Media Inc. As a visionary entrepreneur and engineer, ASIF is committed to harnessing the potential of artificial intelligence to achieve social benefits. His recent effort is to launch Marktechpost, an artificial intelligence media platform that has an in-depth coverage of machine learning and deep learning news that can sound both technically, both through technical voices and be understood by a wide audience. The platform has over 2 million views per month, demonstrating its popularity among its audience.