|

A Coding Guide to Build Flexible Multi-Model Workflows in GluonTS with Synthetic Data, Evaluation, and Advanced Visualizations

🚀

On this tutorial, we discover GluonTS from a sensible perspective, the place we generate advanced artificial datasets, put together them, and apply a number of fashions in parallel. We deal with find out how to work with various estimators in the identical pipeline, deal with lacking dependencies gracefully, and nonetheless produce usable outcomes. By constructing in analysis and visualization steps, we create a workflow that highlights how fashions may be skilled, in contrast, and interpreted in a single, seamless course of. Try the FULL CODES here. Be happy to take a look at 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.cut up import cut up
from gluonts.analysis import make_evaluation_predictions, Evaluator
from gluonts.dataset.synthetic import ComplexSeasonalTimeSeries


strive:
   from gluonts.torch import DeepAREstimator
   TORCH_AVAILABLE = True
besides ImportError:
   TORCH_AVAILABLE = False


strive:
   from gluonts.mx import DeepAREstimator as MXDeepAREstimator
   from gluonts.mx import SimpleFeedForwardEstimator
   MX_AVAILABLE = True
besides ImportError:
   MX_AVAILABLE = False

We start by importing the core libraries for information dealing with, visualization, and GluonTS utilities. We additionally arrange conditional imports for PyTorch and MXNet estimators, permitting us to flexibly use whichever backend is on the market in our surroundings. Try the FULL CODES here. Be happy to take a look at our GitHub Page for Tutorials, Codes and Notebooks.

def create_synthetic_dataset(num_series=50, size=365, prediction_length=30):
   """Generate artificial multi-variate time collection with traits, seasonality, and noise"""
   np.random.seed(42)
   series_list = []
  
   for i in vary(num_series):
       pattern = np.cumsum(np.random.regular(0.1 + i*0.01, 0.1, size))
      
       daily_season = 10 * np.sin(2 * np.pi * np.arange(size) / 7) 
       yearly_season = 20 * np.sin(2 * np.pi * np.arange(size) / 365.25) 
      
       noise = np.random.regular(0, 5, size)
       values = np.most(pattern + daily_season + yearly_season + noise + 100, 1)
      
       dates = pd.date_range(begin='2020-01-01', intervals=size, freq='D')
      
       series_list.append(pd.Sequence(values, index=dates, title=f'series_{i}'))
  
   return pd.concat(series_list, axis=1)

We create an artificial dataset the place every collection combines pattern, seasonality, and noise. We design it so each run produces constant outcomes, and we return a clear multi-series DataFrame prepared for experimentation. Try the FULL CODES here. Be happy to take a look at our GitHub Page for Tutorials, Codes and Notebooks.

print("🚀 Creating artificial multi-series dataset...")
df = create_synthetic_dataset(num_series=10, size=200, prediction_length=30)


dataset = PandasDataset(df, goal=df.columns.tolist())


training_data, test_gen = cut up(dataset, offset=-60)
test_data = test_gen.generate_instances(prediction_length=30, home windows=2)


print("🔧 Initializing forecasting fashions...")


fashions = {}


if TORCH_AVAILABLE:
   strive:
       fashions['DeepAR_Torch'] = DeepAREstimator(
           freq='D',
           prediction_length=30
       )
       print("✅ PyTorch DeepAR loaded")
   besides Exception as e:
       print(f"❌ PyTorch DeepAR did not load: {e}")


if MX_AVAILABLE:
   strive:
       fashions['DeepAR_MX'] = MXDeepAREstimator(
           freq='D',
           prediction_length=30,
           coach=dict(epochs=5)
       )
       print("✅ MXNet DeepAR loaded")
   besides Exception as e:
       print(f"❌ MXNet DeepAR did not load: {e}")
  
   strive:
       fashions['FeedForward'] = SimpleFeedForwardEstimator(
           freq='D',
           prediction_length=30,
           coach=dict(epochs=5)
       )
       print("✅ FeedForward mannequin loaded")
   besides Exception as e:
       print(f"❌ FeedForward did not load: {e}")


if not fashions:
   print("🔄 Utilizing synthetic dataset with built-in fashions...")
   artificial_ds = ComplexSeasonalTimeSeries(
       num_series=10,
       prediction_length=30,
       freq='D',
       length_low=150,
       length_high=200
   ).generate()
  
   training_data, test_gen = cut up(artificial_ds, offset=-60)
   test_data = test_gen.generate_instances(prediction_length=30, home windows=2)

We generate a 10-series dataset, wrap it right into a GluonTS PandasDataset, and cut up it into coaching and take a look at home windows. We then initialize a number of estimators (PyTorch DeepAR, MXNet DeepAR, and FeedForward) when accessible, and fall again to a built-in synthetic dataset if no backends load. Try the FULL CODES here. Be happy to take a look at our GitHub Page for Tutorials, Codes and Notebooks.

trained_models = {}
all_forecasts = {}


if fashions:
   for title, estimator in fashions.objects():
       print(f"🎯 Coaching {title} mannequin...")
       strive:
           predictor = estimator.prepare(training_data)
           trained_models[name] = predictor
          
           forecasts = checklist(predictor.predict(test_data.enter))
           all_forecasts[name] = forecasts
           print(f"✅ {title} coaching accomplished!")
          
       besides Exception as e:
           print(f"❌ {title} coaching failed: {e}")
           proceed


print("📊 Evaluating mannequin efficiency...")
evaluator = Evaluator(quantiles=[0.1, 0.5, 0.9])
evaluation_results = {}


for title, forecasts in all_forecasts.objects():
   if forecasts: 
       strive:
           agg_metrics, item_metrics = evaluator(test_data.label, forecasts)
           evaluation_results[name] = agg_metrics
           print(f"n{title} Efficiency:")
           print(f"  MASE: {agg_metrics['MASE']:.4f}")
           print(f"  sMAPE: {agg_metrics['sMAPE']:.4f}")
           print(f"  Imply wQuantileLoss: {agg_metrics['mean_wQuantileLoss']:.4f}")
       besides Exception as e:
           print(f"❌ Analysis failed for {title}: {e}")

We prepare every accessible estimator, acquire probabilistic forecasts, and retailer the fitted predictors for reuse. We then consider outcomes with MASE, sMAPE, and weighted quantile loss, giving us a constant, comparative view of mannequin efficiency. Try the FULL CODES here. Be happy to take a look at our GitHub Page for Tutorials, Codes and Notebooks.

def plot_advanced_forecasts(test_data, forecasts_dict, series_idx=0):
   """Superior plotting with a number of fashions and uncertainty bands"""
   fig, axes = plt.subplots(2, 2, figsize=(15, 10))
   fig.suptitle('Superior GluonTS Forecasting Outcomes', fontsize=16, fontweight='daring')
  
   if not forecasts_dict:
       fig.textual content(0.5, 0.5, 'No profitable forecasts to show',
               ha='middle', va='middle', fontsize=20)
       return fig
  
   if series_idx < len(test_data.label):
       ts_label = test_data.label[series_idx]
       ts_input = test_data.enter[series_idx]['target']
      
       colours = ['blue', 'red', 'green', 'purple', 'orange']
      
       ax1 = axes[0, 0]
       ax1.plot(vary(len(ts_input)), ts_input, 'k-', label='Historic', alpha=0.8, linewidth=2)
       ax1.plot(vary(len(ts_input), len(ts_input) + len(ts_label)),
               ts_label, 'k--', label='True Future', alpha=0.8, linewidth=2)
      
       for i, (title, forecasts) in enumerate(forecasts_dict.objects()):
           if series_idx < len(forecasts):
               forecast = forecasts[series_idx]
               forecast_range = vary(len(ts_input), len(ts_input) + len(forecast.imply))
              
               colour = colours[i % len(colors)]
               ax1.plot(forecast_range, forecast.imply,
                       colour=colour, label=f'{title} Imply', linewidth=2)
              
               strive:
                   ax1.fill_between(forecast_range,
                                  forecast.quantile(0.1), forecast.quantile(0.9),
                                  alpha=0.2, colour=colour, label=f'{title} 80% CI')
               besides:
                   move 
      
       ax1.set_title('Multi-Mannequin Forecasts Comparability', fontsize=12, fontweight='daring')
       ax1.legend()
       ax1.grid(True, alpha=0.3)
       ax1.set_xlabel('Time Steps')
       ax1.set_ylabel('Worth')
      
       ax2 = axes[0, 1]
       if all_forecasts:
           first_model = checklist(all_forecasts.keys())[0]
           if series_idx < len(all_forecasts[first_model]):
               forecast = all_forecasts[first_model][series_idx]
               ax2.scatter(ts_label, forecast.imply, alpha=0.7, s=60)
              
               min_val = min(min(ts_label), min(forecast.imply))
               max_val = max(max(ts_label), max(forecast.imply))
               ax2.plot([min_val, max_val], [min_val, max_val], 'r--', alpha=0.8)
              
               ax2.set_title(f'Prediction vs Precise - {first_model}', fontsize=12, fontweight='daring')
               ax2.set_xlabel('Precise Values')
               ax2.set_ylabel('Predicted Values')
               ax2.grid(True, alpha=0.3)
      
       ax3 = axes[1, 0]
       if all_forecasts:
           first_model = checklist(all_forecasts.keys())[0]
           if series_idx < len(all_forecasts[first_model]):
               forecast = all_forecasts[first_model][series_idx]
               residuals = ts_label - forecast.imply
               ax3.hist(residuals, bins=15, alpha=0.7, colour='skyblue', edgecolor='black')
               ax3.axvline(x=0, colour='r', linestyle='--', linewidth=2)
               ax3.set_title(f'Residuals Distribution - {first_model}', fontsize=12, fontweight='daring')
               ax3.set_xlabel('Residuals')
               ax3.set_ylabel('Frequency')
               ax3.grid(True, alpha=0.3)
      
       ax4 = axes[1, 1]
       if evaluation_results:
           metrics = ['MASE', 'sMAPE'] 
           model_names = checklist(evaluation_results.keys())
           x = np.arange(len(metrics))
           width = 0.35
          
           for i, model_name in enumerate(model_names):
               values = [evaluation_results[model_name].get(metric, 0) for metric in metrics]
               ax4.bar(x + i*width, values, width,
                      label=model_name, colour=colours[i % len(colors)], alpha=0.8)
          
           ax4.set_title('Mannequin Efficiency Comparability', fontsize=12, fontweight='daring')
           ax4.set_xlabel('Metrics')
           ax4.set_ylabel('Worth')
           ax4.set_xticks(x + width/2 if len(model_names) > 1 else x)
           ax4.set_xticklabels(metrics)
           ax4.legend()
           ax4.grid(True, alpha=0.3)
       else:
           ax4.textual content(0.5, 0.5, 'No evaluationnresults accessible',
                   ha='middle', va='middle', rework=ax4.transAxes, fontsize=14)
  
   plt.tight_layout()
   return fig


if all_forecasts and test_data.label:
   print("📈 Creating superior visualizations...")
   fig = plot_advanced_forecasts(test_data, all_forecasts, series_idx=0)
   plt.present()
  
   print(f"n🎉 Tutorial accomplished efficiently!")
   print(f"📊 Educated {len(trained_models)} mannequin(s) on {len(df.columns) if 'df' in locals() else 10} time collection")
   print(f"🎯 Prediction size: 30 days")
  
   if evaluation_results:
       best_model = min(evaluation_results.objects(), key=lambda x: x[1]['MASE'])
       print(f"🏆 Finest performing mannequin: {best_model[0]} (MASE: {best_model[1]['MASE']:.4f})")
  
   print(f"n🔧 Setting Standing:")
   print(f"  PyTorch Assist: {'✅' if TORCH_AVAILABLE else '❌'}")
   print(f"  MXNet Assist: {'✅' if MX_AVAILABLE else '❌'}")
  
else:
   print("⚠  Creating demonstration plot with artificial information...")
  
   fig, ax = plt.subplots(1, 1, figsize=(12, 6))
  
   dates = pd.date_range('2020-01-01', intervals=100, freq='D')
   ts = 100 + np.cumsum(np.random.regular(0, 2, 100)) + 20 * np.sin(np.arange(100) * 2 * np.pi / 30)
  
   ax.plot(dates[:70], ts[:70], 'b-', label='Historic Information', linewidth=2)
   ax.plot(dates[70:], ts[70:], 'r--', label='Future (Instance)', linewidth=2)
   ax.fill_between(dates[70:], ts[70:] - 5, ts[70:] + 5, alpha=0.3, colour='crimson')
  
   ax.set_title('GluonTS Probabilistic Forecasting Instance', fontsize=14, fontweight='daring')
   ax.set_xlabel('Date')
   ax.set_ylabel('Worth')
   ax.legend()
   ax.grid(True, alpha=0.3)
  
   plt.tight_layout()
   plt.present()
  
   print("n📚 Tutorial demonstrates superior GluonTS ideas:")
   print("  • Multi-series dataset era")
   print("  • Probabilistic forecasting")
   print("  • Mannequin analysis and comparability")
   print("  • Superior visualization strategies")
   print("  • Strong error dealing with")

We prepare every accessible mannequin, generate probabilistic forecasts, and consider them with constant metrics earlier than visualizing comparisons, residuals, and uncertainty bands. If no fashions can be found, we nonetheless reveal the workflow with an artificial instance so we are able to examine plots and key ideas finish to finish.

In conclusion, we put collectively a strong setup that balances information creation, mannequin experimentation, and efficiency evaluation. As an alternative of counting on a single configuration, we see find out how to adapt flexibly, take a look at a number of choices, and visualize leads to ways in which make comparability intuitive. This provides us a stronger basis for experimenting with GluonTS and making use of the identical ideas to actual datasets, whereas preserving the method modular and simple to increase.


Try the FULL CODES here. Be happy to take a look at our GitHub Page for Tutorials, Codes and Notebooks. Additionally, be happy to observe us on Twitter and don’t neglect to hitch our 100k+ ML SubReddit and Subscribe to our Newsletter.

The put up A Coding Guide to Build Flexible Multi-Model Workflows in GluonTS with Synthetic Data, Evaluation, and Advanced Visualizations appeared first on MarkTechPost.

Similar Posts