mirror of
https://github.com/wassname/pytorch-ts.git
synced 2026-08-02 13:03:05 +08:00
32 KiB
32 KiB
In [1]:
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import torchIn [2]:
from gluonts.dataset.multivariate_grouper import MultivariateGrouper
from gluonts.dataset.repository.datasets import dataset_recipes, get_dataset
from gluonts.evaluation.backtest import make_evaluation_predictions
from gluonts.evaluation import MultivariateEvaluatorIn [3]:
from pts.model.tempflow import TempFlowEstimator
from pts.model.time_grad import TimeGradEstimator
from pts.model.transformer_tempflow import TransformerTempFlowEstimator
from pts import TrainerIn [4]:
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")In [5]:
def plot(target, forecast, prediction_length, prediction_intervals=(50.0, 90.0), color='g', fname=None):
label_prefix = ""
rows = 4
cols = 4
fig, axs = plt.subplots(rows, cols, figsize=(24, 24))
axx = axs.ravel()
seq_len, target_dim = target.shape
ps = [50.0] + [
50.0 + f * c / 2.0 for c in prediction_intervals for f in [-1.0, +1.0]
]
percentiles_sorted = sorted(set(ps))
def alpha_for_percentile(p):
return (p / 100.0) ** 0.3
for dim in range(0, min(rows * cols, target_dim)):
ax = axx[dim]
target[-2 * prediction_length :][dim].plot(ax=ax)
ps_data = [forecast.quantile(p / 100.0)[:,dim] for p in percentiles_sorted]
i_p50 = len(percentiles_sorted) // 2
p50_data = ps_data[i_p50]
p50_series = pd.Series(data=p50_data, index=forecast.index)
p50_series.plot(color=color, ls="-", label=f"{label_prefix}median", ax=ax)
for i in range(len(percentiles_sorted) // 2):
ptile = percentiles_sorted[i]
alpha = alpha_for_percentile(ptile)
ax.fill_between(
forecast.index,
ps_data[i],
ps_data[-i - 1],
facecolor=color,
alpha=alpha,
interpolate=True,
)
# Hack to create labels for the error intervals.
# Doesn't actually plot anything, because we only pass a single data point
pd.Series(data=p50_data[:1], index=forecast.index[:1]).plot(
color=color,
alpha=alpha,
linewidth=10,
label=f"{label_prefix}{100 - ptile * 2}%",
ax=ax,
)
legend = ["observations", "median prediction"] + [f"{k}% prediction interval" for k in prediction_intervals][::-1]
axx[0].legend(legend, loc="upper left")
if fname is not None:
plt.savefig(fname, bbox_inches='tight', pad_inches=0.05)In [6]:
print(f"Available datasets: {list(dataset_recipes.keys())}")Available datasets: ['constant', 'exchange_rate', 'solar-energy', 'electricity', 'traffic', 'exchange_rate_nips', 'electricity_nips', 'traffic_nips', 'solar_nips', 'wiki-rolling_nips', 'taxi_30min', 'kaggle_web_traffic_with_missing', 'kaggle_web_traffic_without_missing', 'kaggle_web_traffic_weekly', 'm1_yearly', 'm1_quarterly', 'm1_monthly', 'nn5_daily_with_missing', 'nn5_daily_without_missing', 'nn5_weekly', 'tourism_monthly', 'tourism_quarterly', 'tourism_yearly', 'cif_2016', 'london_smart_meters_without_missing', 'wind_farms_without_missing', 'car_parts_without_missing', 'dominick', 'fred_md', 'pedestrian_counts', 'hospital', 'covid_deaths', 'kdd_cup_2018_without_missing', 'weather', 'm3_monthly', 'm3_quarterly', 'm3_yearly', 'm3_other', 'm4_hourly', 'm4_daily', 'm4_weekly', 'm4_monthly', 'm4_quarterly', 'm4_yearly', 'm5', 'uber_tlc_daily', 'uber_tlc_hourly', 'airpassengers']
In [7]:
# exchange_rate_nips, electricity_nips, traffic_nips, solar_nips, wiki-rolling_nips, ## taxi_30min is buggy still
dataset = get_dataset("electricity_nips", regenerate=False)In [8]:
dataset.metadataOut [8]:
MetaData(freq='H', target=None, feat_static_cat=[CategoricalFeatureInfo(name='feat_static_cat_0', cardinality='370')], feat_static_real=[], feat_dynamic_real=[], feat_dynamic_cat=[], prediction_length=24)
In [9]:
train_grouper = MultivariateGrouper(max_target_dim=min(2000, int(dataset.metadata.feat_static_cat[0].cardinality)))
test_grouper = MultivariateGrouper(num_test_dates=int(len(dataset.test)/len(dataset.train)*2),
max_target_dim=min(2000, int(dataset.metadata.feat_static_cat[0].cardinality)))In [10]:
dataset_train = train_grouper(dataset.train)
dataset_test = test_grouper(dataset.test)/home/wassname/miniforge3/envs/glounts/lib/python3.9/site-packages/gluonts/dataset/multivariate_grouper.py:191: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.
return {FieldName.TARGET: np.array([funcs(data) for data in dataset])}
In [11]:
estimator = TimeGradEstimator(
target_dim=int(dataset.metadata.feat_static_cat[0].cardinality),
prediction_length=dataset.metadata.prediction_length,
context_length=dataset.metadata.prediction_length,
cell_type='GRU',
input_size=1484,
freq=dataset.metadata.freq,
loss_type='l2',
scaling=True,
diff_steps=100,
beta_end=0.1,
beta_schedule="linear",
trainer=Trainer(device=device,
epochs=20,
learning_rate=1e-3,
num_batches_per_epoch=100,
batch_size=64,)
)In [12]:
predictor = estimator.train(dataset_train, num_workers=0)0%| | 0/99 [00:00<?, ?it/s]
0%| | 0/99 [00:00<?, ?it/s]
0%| | 0/99 [00:00<?, ?it/s]
0%| | 0/99 [00:00<?, ?it/s]
0%| | 0/99 [00:00<?, ?it/s]
0%| | 0/99 [00:00<?, ?it/s]
0%| | 0/99 [00:00<?, ?it/s]
0%| | 0/99 [00:00<?, ?it/s]
0%| | 0/99 [00:00<?, ?it/s]
0%| | 0/99 [00:00<?, ?it/s]
0%| | 0/99 [00:00<?, ?it/s]
0%| | 0/99 [00:00<?, ?it/s]
0%| | 0/99 [00:00<?, ?it/s]
0%| | 0/99 [00:00<?, ?it/s]
0%| | 0/99 [00:00<?, ?it/s]
0%| | 0/99 [00:00<?, ?it/s]
0%| | 0/99 [00:00<?, ?it/s]
[0;31m---------------------------------------------------------------------------[0m [0;31mException[0m Traceback (most recent call last) [1;32m/media/wassname/SGIronWolf/projects5/timeseries/pytorch-ts/examples/Time-Grad-Electricity.ipynb Cell 12[0m in [0;36m<cell line: 1>[0;34m()[0m [0;32m----> <a href='vscode-notebook-cell:/media/wassname/SGIronWolf/projects5/timeseries/pytorch-ts/examples/Time-Grad-Electricity.ipynb#X14sZmlsZQ%3D%3D?line=0'>1</a>[0m predictor [39m=[39m estimator[39m.[39;49mtrain(dataset_train, num_workers[39m=[39;49m[39m0[39;49m) File [0;32m/media/wassname/SGIronWolf/projects5/timeseries/pytorch-ts/pts/model/estimator.py:179[0m, in [0;36mPyTorchEstimator.train[0;34m(self, training_data, validation_data, num_workers, prefetch_factor, shuffle_buffer_length, cache_data, **kwargs)[0m [1;32m 169[0m [39mdef[39;00m [39mtrain[39m( [1;32m 170[0m [39mself[39m, [1;32m 171[0m training_data: Dataset, [0;32m (...)[0m [1;32m 177[0m [39m*[39m[39m*[39mkwargs, [1;32m 178[0m ) [39m-[39m[39m>[39m PyTorchPredictor: [0;32m--> 179[0m [39mreturn[39;00m [39mself[39;49m[39m.[39;49mtrain_model( [1;32m 180[0m training_data, [1;32m 181[0m validation_data, [1;32m 182[0m num_workers[39m=[39;49mnum_workers, [1;32m 183[0m prefetch_factor[39m=[39;49mprefetch_factor, [1;32m 184[0m shuffle_buffer_length[39m=[39;49mshuffle_buffer_length, [1;32m 185[0m cache_data[39m=[39;49mcache_data, [1;32m 186[0m [39m*[39;49m[39m*[39;49mkwargs, [1;32m 187[0m )[39m.[39mpredictor File [0;32m/media/wassname/SGIronWolf/projects5/timeseries/pytorch-ts/pts/model/estimator.py:151[0m, in [0;36mPyTorchEstimator.train_model[0;34m(self, training_data, validation_data, num_workers, prefetch_factor, shuffle_buffer_length, cache_data, **kwargs)[0m [1;32m 133[0m validation_iter_dataset [39m=[39m TransformedIterableDataset( [1;32m 134[0m dataset[39m=[39mvalidation_data, [1;32m 135[0m transform[39m=[39mtransformation [0;32m (...)[0m [1;32m 139[0m cache_data[39m=[39mcache_data, [1;32m 140[0m ) [1;32m 141[0m validation_data_loader [39m=[39m DataLoader( [1;32m 142[0m validation_iter_dataset, [1;32m 143[0m batch_size[39m=[39m[39mself[39m[39m.[39mtrainer[39m.[39mbatch_size, [0;32m (...)[0m [1;32m 148[0m [39m*[39m[39m*[39mkwargs, [1;32m 149[0m ) [0;32m--> 151[0m [39mself[39;49m[39m.[39;49mtrainer( [1;32m 152[0m net[39m=[39;49mtrained_net, [1;32m 153[0m train_iter[39m=[39;49mtraining_data_loader, [1;32m 154[0m validation_iter[39m=[39;49mvalidation_data_loader, [1;32m 155[0m ) [1;32m 157[0m [39mreturn[39;00m TrainOutput( [1;32m 158[0m transformation[39m=[39mtransformation, [1;32m 159[0m trained_net[39m=[39mtrained_net, [0;32m (...)[0m [1;32m 162[0m ), [1;32m 163[0m ) File [0;32m/media/wassname/SGIronWolf/projects5/timeseries/pytorch-ts/pts/trainer.py:63[0m, in [0;36mTrainer.__call__[0;34m(self, net, train_iter, validation_iter)[0m [1;32m 61[0m [39m# training loop[39;00m [1;32m 62[0m [39mwith[39;00m tqdm(train_iter, total[39m=[39mtotal) [39mas[39;00m it: [0;32m---> 63[0m [39mfor[39;00m batch_no, data_entry [39min[39;00m [39menumerate[39m(it, start[39m=[39m[39m1[39m): [1;32m 64[0m optimizer[39m.[39mzero_grad() [1;32m 66[0m inputs [39m=[39m [v[39m.[39mto([39mself[39m[39m.[39mdevice) [39mfor[39;00m v [39min[39;00m data_entry[39m.[39mvalues()] File [0;32m~/miniforge3/envs/glounts/lib/python3.9/site-packages/tqdm/notebook.py:259[0m, in [0;36mtqdm_notebook.__iter__[0;34m(self)[0m [1;32m 257[0m [39mtry[39;00m: [1;32m 258[0m it [39m=[39m [39msuper[39m(tqdm_notebook, [39mself[39m)[39m.[39m[39m__iter__[39m() [0;32m--> 259[0m [39mfor[39;00m obj [39min[39;00m it: [1;32m 260[0m [39m# return super(tqdm...) will not catch exception[39;00m [1;32m 261[0m [39myield[39;00m obj [1;32m 262[0m [39m# NB: except ... [ as ...] breaks IPython async KeyboardInterrupt[39;00m File [0;32m~/miniforge3/envs/glounts/lib/python3.9/site-packages/tqdm/std.py:1195[0m, in [0;36mtqdm.__iter__[0;34m(self)[0m [1;32m 1192[0m time [39m=[39m [39mself[39m[39m.[39m_time [1;32m 1194[0m [39mtry[39;00m: [0;32m-> 1195[0m [39mfor[39;00m obj [39min[39;00m iterable: [1;32m 1196[0m [39myield[39;00m obj [1;32m 1197[0m [39m# Update and possibly print the progressbar.[39;00m [1;32m 1198[0m [39m# Note: does not call self.update(1) for speed optimisation.[39;00m File [0;32m~/miniforge3/envs/glounts/lib/python3.9/site-packages/torch/utils/data/dataloader.py:628[0m, in [0;36m_BaseDataLoaderIter.__next__[0;34m(self)[0m [1;32m 625[0m [39mif[39;00m [39mself[39m[39m.[39m_sampler_iter [39mis[39;00m [39mNone[39;00m: [1;32m 626[0m [39m# TODO(https://github.com/pytorch/pytorch/issues/76750)[39;00m [1;32m 627[0m [39mself[39m[39m.[39m_reset() [39m# type: ignore[call-arg][39;00m [0;32m--> 628[0m data [39m=[39m [39mself[39;49m[39m.[39;49m_next_data() [1;32m 629[0m [39mself[39m[39m.[39m_num_yielded [39m+[39m[39m=[39m [39m1[39m [1;32m 630[0m [39mif[39;00m [39mself[39m[39m.[39m_dataset_kind [39m==[39m _DatasetKind[39m.[39mIterable [39mand[39;00m \ [1;32m 631[0m [39mself[39m[39m.[39m_IterableDataset_len_called [39mis[39;00m [39mnot[39;00m [39mNone[39;00m [39mand[39;00m \ [1;32m 632[0m [39mself[39m[39m.[39m_num_yielded [39m>[39m [39mself[39m[39m.[39m_IterableDataset_len_called: File [0;32m~/miniforge3/envs/glounts/lib/python3.9/site-packages/torch/utils/data/dataloader.py:671[0m, in [0;36m_SingleProcessDataLoaderIter._next_data[0;34m(self)[0m [1;32m 669[0m [39mdef[39;00m [39m_next_data[39m([39mself[39m): [1;32m 670[0m index [39m=[39m [39mself[39m[39m.[39m_next_index() [39m# may raise StopIteration[39;00m [0;32m--> 671[0m data [39m=[39m [39mself[39;49m[39m.[39;49m_dataset_fetcher[39m.[39;49mfetch(index) [39m# may raise StopIteration[39;00m [1;32m 672[0m [39mif[39;00m [39mself[39m[39m.[39m_pin_memory: [1;32m 673[0m data [39m=[39m _utils[39m.[39mpin_memory[39m.[39mpin_memory(data, [39mself[39m[39m.[39m_pin_memory_device) File [0;32m~/miniforge3/envs/glounts/lib/python3.9/site-packages/torch/utils/data/_utils/fetch.py:34[0m, in [0;36m_IterableDatasetFetcher.fetch[0;34m(self, possibly_batched_index)[0m [1;32m 32[0m [39mfor[39;00m _ [39min[39;00m possibly_batched_index: [1;32m 33[0m [39mtry[39;00m: [0;32m---> 34[0m data[39m.[39mappend([39mnext[39;49m([39mself[39;49m[39m.[39;49mdataset_iter)) [1;32m 35[0m [39mexcept[39;00m [39mStopIteration[39;00m: [1;32m 36[0m [39mself[39m[39m.[39mended [39m=[39m [39mTrue[39;00m File [0;32m~/miniforge3/envs/glounts/lib/python3.9/site-packages/gluonts/transform/_base.py:103[0m, in [0;36mTransformedDataset.__iter__[0;34m(self)[0m [1;32m 102[0m [39mdef[39;00m [39m__iter__[39m([39mself[39m) [39m-[39m[39m>[39m Iterator[DataEntry]: [0;32m--> 103[0m [39myield from[39;00m [39mself[39m[39m.[39mtransformation( [1;32m 104[0m [39mself[39m[39m.[39mbase_dataset, is_train[39m=[39m[39mself[39m[39m.[39mis_train [1;32m 105[0m ) File [0;32m~/miniforge3/envs/glounts/lib/python3.9/site-packages/gluonts/transform/_base.py:124[0m, in [0;36mMapTransformation.__call__[0;34m(self, data_it, is_train)[0m [1;32m 121[0m [39mdef[39;00m [39m__call__[39m( [1;32m 122[0m [39mself[39m, data_it: Iterable[DataEntry], is_train: [39mbool[39m [1;32m 123[0m ) [39m-[39m[39m>[39m Iterator: [0;32m--> 124[0m [39mfor[39;00m data_entry [39min[39;00m data_it: [1;32m 125[0m [39mtry[39;00m: [1;32m 126[0m [39myield[39;00m [39mself[39m[39m.[39mmap_transform(data_entry[39m.[39mcopy(), is_train) File [0;32m~/miniforge3/envs/glounts/lib/python3.9/site-packages/gluonts/transform/_base.py:124[0m, in [0;36mMapTransformation.__call__[0;34m(self, data_it, is_train)[0m [1;32m 121[0m [39mdef[39;00m [39m__call__[39m( [1;32m 122[0m [39mself[39m, data_it: Iterable[DataEntry], is_train: [39mbool[39m [1;32m 123[0m ) [39m-[39m[39m>[39m Iterator: [0;32m--> 124[0m [39mfor[39;00m data_entry [39min[39;00m data_it: [1;32m 125[0m [39mtry[39;00m: [1;32m 126[0m [39myield[39;00m [39mself[39m[39m.[39mmap_transform(data_entry[39m.[39mcopy(), is_train) File [0;32m~/miniforge3/envs/glounts/lib/python3.9/site-packages/gluonts/transform/_base.py:189[0m, in [0;36mFlatMapTransformation.__call__[0;34m(self, data_it, is_train)[0m [1;32m 182[0m [39myield[39;00m result [1;32m 184[0m [39mif[39;00m ( [1;32m 185[0m [39m# negative values disable the check[39;00m [1;32m 186[0m [39mself[39m[39m.[39mmax_idle_transforms [39m>[39m [39m0[39m [1;32m 187[0m [39mand[39;00m num_idle_transforms [39m>[39m [39mself[39m[39m.[39mmax_idle_transforms [1;32m 188[0m ): [0;32m--> 189[0m [39mraise[39;00m [39mException[39;00m( [1;32m 190[0m [39m"[39m[39mReached maximum number of idle transformation[39m[39m"[39m [1;32m 191[0m [39m"[39m[39m calls.[39m[39m\n[39;00m[39mThis means the transformation looped over[39m[39m"[39m [1;32m 192[0m [39mf[39m[39m"[39m[39m [39m[39m{[39;00m[39mself[39m[39m.[39mmax_idle_transforms[39m}[39;00m[39m inputs without returning any[39m[39m"[39m [1;32m 193[0m [39m"[39m[39m output.[39m[39m\n[39;00m[39mThis occurred in the following[39m[39m"[39m [1;32m 194[0m [39mf[39m[39m"[39m[39m transformation:[39m[39m\n[39;00m[39m{[39;00m[39mself[39m[39m}[39;00m[39m"[39m [1;32m 195[0m ) [0;31mException[0m: Reached maximum number of idle transformation calls. This means the transformation looped over 10 inputs without returning any output. This occurred in the following transformation: gluonts.transform.split.InstanceSplitter(dummy_value=0.0, forecast_start_field="forecast_start", future_length=24, instance_sampler=gluonts.transform.sampler.ExpectedNumInstanceSampler(axis=-1, min_past=192, min_future=24, num_instances=1.0, total_length=585345038, n=104191), is_pad_field="is_pad", lead_time=0, output_NTC=True, past_length=192, start_field="start", target_field="target", time_series_fields=["time_feat", "observed_values"])
In [ ]:
forecast_it, ts_it = make_evaluation_predictions(dataset=dataset_test,
predictor=predictor,
num_samples=100)In [ ]:
forecasts = list(forecast_it)
targets = list(ts_it)In [ ]:
plot(
target=targets[0],
forecast=forecasts[0],
prediction_length=dataset.metadata.prediction_length,
)
plt.show()In [ ]:
evaluator = MultivariateEvaluator(quantiles=(np.arange(20)/20.0)[1:],
target_agg_funcs={'sum': np.sum})In [ ]:
agg_metric, item_metrics = evaluator(targets, forecasts, num_series=len(dataset_test))In [ ]:
print("CRPS:", agg_metric["mean_wQuantileLoss"])
print("ND:", agg_metric["ND"])
print("NRMSE:", agg_metric["NRMSE"])
print("")
print("CRPS-Sum:", agg_metric["m_sum_mean_wQuantileLoss"])
print("ND-Sum:", agg_metric["m_sum_ND"])
print("NRMSE-Sum:", agg_metric["m_sum_NRMSE"])In [ ]: