NNForecaster Training and Tuning
This tutorial shows how to utilize the built-in forecaster training and tuning functionalities of CommonPower.
[1]:
%load_ext autoreload
%autoreload 2
[2]:
from datetime import timedelta
import pathlib
from ray import tune as ray_tune, train as ray_train
from ray.tune.schedulers import AsyncHyperBandScheduler
from ray.tune.stopper import TrialPlateauStopper, CombinedStopper, MaximumIterationStopper
from ray.tune.search.hyperopt import HyperOptSearch
from ray.air.integrations.wandb import WandbLoggerCallback
from sklearn.preprocessing import MinMaxScaler
from commonpower.data_forecasting.nn_forecasting.config import ParameterSpace, TrainConfig
from commonpower.data_forecasting.nn_forecasting.eval_metrics import RootMeanSquaredError, MeanAbsolutePercentageError, MeanAbsoluteError
from commonpower.data_forecasting.nn_forecasting.nn_forecasting import NNForecaster
from commonpower.data_forecasting.data_sources import CSVDataSource
from commonpower.data_forecasting.nn_forecasting.data_splitting import SimpleFractionalSplit, DatePeriodFractionalSplit
from commonpower.data_forecasting.nn_forecasting.dataset_wrappers import NStepAhead
from commonpower.data_forecasting.nn_forecasting.models import *
from commonpower.data_forecasting.nn_forecasting.transform import SklearnScalerTransform
from commonpower.data_forecasting.nn_forecasting.nn_tuner import tune
[3]:
experiments_dir = pathlib.Path().absolute()
data_path = (experiments_dir / 'data').resolve()
results_dir = (experiments_dir / 'results').resolve()
tuner_dir = (experiments_dir / 'tuner').resolve()
[4]:
horizon = timedelta(hours=24)
frequency = timedelta(minutes=60)
look_back = timedelta(hours=24)
[5]:
data_source = CSVDataSource(
data_path / '1-LV-rural2--1-sw' / 'LoadProfile.csv',
delimiter=";",
datetime_format="%d.%m.%Y %H:%M",
rename_dict={"time": "t", "H0-A_pload": "p"},
auto_drop=True,
resample=frequency)
Configure and Tune
[ ]:
train_config = TrainConfig(
forecaster=NNForecaster(
targets=["p"],
model_class=SimpleMLP,
frequency=frequency,
feature_transform=SklearnScalerTransform(MinMaxScaler()),
target_transform=SklearnScalerTransform(MinMaxScaler()),
),
data_source=data_source,
dataset_wrapper_class=NStepAhead,
dataset_split_class=DatePeriodFractionalSplit,
parameter_space=ParameterSpace(
model={
"hidden_dims": ray_tune.choice([[64, 256, 512, 512, 256, 64]]),
"n_features": 1,
"n_targets": 1,
"n_lookback": ray_tune.choice([24]),
"n_ahead": ray_tune.choice([6]),
"dropout_p": ray_tune.choice([0.5]),
},
optimizer={
"lr": 1e-3
},
data_loader={
"batch_size": ray_tune.choice([128]),
},
dataset_wrapper={},
dataset_split={
"train_fraction": 0.8,
"val_fraction": 0.2
},
),
eval_metrics=[RootMeanSquaredError(), MeanAbsoluteError(), MeanAbsolutePercentageError()],
device='cpu'
)
[7]:
run_config = ray_train.RunConfig(
stop=CombinedStopper(
MaximumIterationStopper(max_iter=1000),
#TrialPlateauStopper(metric=RootMeanSquaredError().name, std=0.0001, num_results=5, grace_period=5),
),
callbacks=[WandbLoggerCallback(project="commonpower_forecaster_tuning", mode="online", config=train_config.model_dump())],
checkpoint_config=ray_train.CheckpointConfig(
num_to_keep=10,
checkpoint_score_attribute=RootMeanSquaredError().name,
checkpoint_score_order="min"
),
storage_path=tuner_dir,
)
tune_config = ray_tune.TuneConfig(
metric=RootMeanSquaredError().name,
mode='min',
scheduler=None, #AsyncHyperBandScheduler(grace_period=500),
num_samples=4,
max_concurrent_trials=16,
trial_dirname_creator=lambda trial: f"{trial.trial_id}",
)
[ ]:
tuned_forecaster, result_checkpoint = tune(
train_config,
tune_config,
run_config,
results_dir
)
Load from checkpoint and use
[9]:
from commonpower.data_forecasting.base import DataProvider
forecaster = NNForecaster(
targets=["p"],
model_class=SimpleMLP,
frequency=frequency,
horizon=horizon,
feature_transform=SklearnScalerTransform.from_checkpoint(result_checkpoint, "feature", scaler=MinMaxScaler()),
target_transform=SklearnScalerTransform.from_checkpoint(result_checkpoint, "target", scaler=MinMaxScaler()),
).with_model(SimpleMLP.from_checkpoint(result_checkpoint))
data_provider = DataProvider(
data_source=data_source,
forecaster=forecaster,
)
[ ]:
import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime
timestamps = pd.date_range(start=datetime(2016, 6, 29, 6), periods=int(horizon / frequency) + 1, freq=frequency)
true_data = data_source(timestamps[0], timestamps[-1])
forecast = data_provider.observe(timestamps[0])["p"]
plt.plot(true_data, label="true data")
plt.plot(forecast, label="forecast")
plt.xticks(range(len(true_data)), timestamps.strftime('%H:%M'), rotation=90)
plt.xlabel("time step")
plt.ylabel("active power [kW]")
plt.legend()
plt.show()
[ ]: