def from_dataset( cls, dataset: TimeSeriesDataSet, allowed_encoder_known_variable_names: List[str] = None, **kwargs, ): """ Create model from dataset. Args: dataset: timeseries dataset allowed_encoder_known_variable_names: List of known variables that are allowed in encoder, defaults to all **kwargs: additional arguments such as hyperparameters for model (see ``__init__()``) Returns: DeepAR network """ # assert fixed encoder and decoder length for the moment new_kwargs = {} if dataset.multi_target: new_kwargs.setdefault( "loss", MultiLoss([NormalDistributionLoss()] * len(dataset.target_names))) new_kwargs.update(kwargs) assert not isinstance(dataset.target_normalizer, NaNLabelEncoder) and ( not isinstance(dataset.target_normalizer, MultiNormalizer) or all([ not isinstance(normalizer, NaNLabelEncoder) for normalizer in dataset.target_normalizer ]) ), "target(s) should be continuous - categorical targets are not supported" # todo: remove this restriction return super().from_dataset(dataset, allowed_encoder_known_variable_names= allowed_encoder_known_variable_names, **new_kwargs)
def from_dataset( cls, dataset: TimeSeriesDataSet, allowed_encoder_known_variable_names: List[str] = None, **kwargs, ): """ Create model from dataset. Args: dataset: timeseries dataset allowed_encoder_known_variable_names: List of known variables that are allowed in encoder, defaults to all **kwargs: additional arguments such as hyperparameters for model (see ``__init__()``) Returns: TemporalFusionTransformer """ # add maximum encoder length new_kwargs = dict(max_encoder_length=dataset.max_encoder_length) # infer output size def get_output_size(normalizer, loss): if isinstance(loss, QuantileLoss): return len(loss.quantiles) elif isinstance(normalizer, NaNLabelEncoder): return len(normalizer.classes_) else: return 1 loss = kwargs.get("loss", QuantileLoss()) # handle multiple targets new_kwargs["n_targets"] = len(dataset.target_names) if new_kwargs["n_targets"] > 1: # try to infer number of ouput sizes if not isinstance(loss, MultiLoss): loss = MultiLoss([deepcopy(loss)] * new_kwargs["n_targets"]) new_kwargs["loss"] = loss if isinstance(loss, MultiLoss) and "output_size" not in kwargs: new_kwargs["output_size"] = [ get_output_size(normalizer, l) for normalizer, l in zip( dataset.target_normalizer.normalizers, loss.metrics) ] elif "output_size" not in kwargs: new_kwargs["output_size"] = get_output_size( dataset.target_normalizer, loss) # update defaults new_kwargs.update(kwargs) # create class and return return super().from_dataset(dataset, allowed_encoder_known_variable_names= allowed_encoder_known_variable_names, **new_kwargs)
def test_integration(multiple_dataloaders_with_covariates, tmp_path, gpus): train_dataloader = multiple_dataloaders_with_covariates["train"] val_dataloader = multiple_dataloaders_with_covariates["val"] early_stop_callback = EarlyStopping(monitor="val_loss", min_delta=1e-4, patience=1, verbose=False, mode="min") # check training logger = TensorBoardLogger(tmp_path) checkpoint = ModelCheckpoint(filepath=tmp_path) trainer = pl.Trainer( checkpoint_callback=checkpoint, max_epochs=3, gpus=gpus, weights_summary="top", gradient_clip_val=0.1, callbacks=[early_stop_callback], fast_dev_run=True, logger=logger, ) # test monotone constraints automatically if "discount_in_percent" in train_dataloader.dataset.reals: monotone_constaints = {"discount_in_percent": +1} cuda_context = torch.backends.cudnn.flags(enabled=False) else: monotone_constaints = {} cuda_context = nullcontext() with cuda_context: if isinstance(train_dataloader.dataset.target_normalizer, NaNLabelEncoder): loss = CrossEntropy() elif isinstance(train_dataloader.dataset.target_normalizer, MultiNormalizer): loss = MultiLoss([ CrossEntropy() if isinstance(normalizer, NaNLabelEncoder) else QuantileLoss() for normalizer in train_dataloader.dataset.target_normalizer.normalizers ]) else: loss = QuantileLoss() net = TemporalFusionTransformer.from_dataset( train_dataloader.dataset, learning_rate=0.15, hidden_size=4, attention_head_size=1, dropout=0.2, hidden_continuous_size=2, loss=loss, log_interval=5, log_val_interval=1, log_gradient_flow=True, monotone_constaints=monotone_constaints, ) net.size() try: trainer.fit( net, train_dataloader=train_dataloader, val_dataloaders=val_dataloader, ) # check loading net = TemporalFusionTransformer.load_from_checkpoint( checkpoint.best_model_path) # check prediction net.predict(val_dataloader, fast_dev_run=True, return_index=True, return_decoder_lengths=True) # check prediction on gpu if not (isinstance(gpus, int) and gpus == 0): net.to("cuda") net.predict(val_dataloader, fast_dev_run=True, return_index=True, return_decoder_lengths=True) finally: shutil.rmtree(tmp_path, ignore_errors=True)
def test_integration(multiple_dataloaders_with_covariates, tmp_path, gpus): train_dataloader = multiple_dataloaders_with_covariates["train"] val_dataloader = multiple_dataloaders_with_covariates["val"] early_stop_callback = EarlyStopping(monitor="val_loss", min_delta=1e-4, patience=1, verbose=False, mode="min") # check training logger = TensorBoardLogger(tmp_path) trainer = pl.Trainer( max_epochs=2, gpus=gpus, weights_summary="top", gradient_clip_val=0.1, callbacks=[early_stop_callback], checkpoint_callback=True, default_root_dir=tmp_path, limit_train_batches=2, limit_val_batches=2, logger=logger, ) # test monotone constraints automatically if "discount_in_percent" in train_dataloader.dataset.reals: monotone_constaints = {"discount_in_percent": +1} cuda_context = torch.backends.cudnn.flags(enabled=False) else: monotone_constaints = {} cuda_context = nullcontext() with cuda_context: if isinstance(train_dataloader.dataset.target_normalizer, NaNLabelEncoder): loss = CrossEntropy() elif isinstance(train_dataloader.dataset.target_normalizer, MultiNormalizer): loss = MultiLoss( [ CrossEntropy() if isinstance(normalizer, NaNLabelEncoder) else QuantileLoss() for normalizer in train_dataloader.dataset.target_normalizer.normalizers ] ) else: loss = QuantileLoss() net = TemporalFusionTransformer.from_dataset( train_dataloader.dataset, learning_rate=0.15, hidden_size=4, attention_head_size=1, dropout=0.2, hidden_continuous_size=2, loss=loss, log_interval=5, log_val_interval=1, log_gradient_flow=True, monotone_constaints=monotone_constaints, ) net.size() try: trainer.fit( net, train_dataloader=train_dataloader, val_dataloaders=val_dataloader, ) # check loading net = TemporalFusionTransformer.load_from_checkpoint(trainer.checkpoint_callback.best_model_path) # check prediction predictions, x, index = net.predict(val_dataloader, return_index=True, return_x=True) pred_len = len(multiple_dataloaders_with_covariates["val"].dataset) # check that output is of correct shape def check(x): if isinstance(x, (tuple, list)): for xi in x: check(xi) elif isinstance(x, dict): for xi in x.values(): check(xi) else: assert pred_len == x.shape[0], "first dimension should be prediction length" check(predictions) check(x) check(index) # check prediction on gpu if not (isinstance(gpus, int) and gpus == 0): net.to("cuda") net.predict(val_dataloader, fast_dev_run=True, return_index=True, return_decoder_lengths=True) finally: shutil.rmtree(tmp_path, ignore_errors=True)
and len(dataset.time_varying_unknown_categoricals) == 0 and len(dataset.static_categoricals) == 0 and len(dataset.static_reals) == 0 and len(dataset.time_varying_unknown_reals) == len( dataset.target_names ) # Expect as as many unknown reals as targets ), "Only covariate should be in 'time_varying_unknown_reals'" return super().from_dataset(dataset, **new_kwargs) model = FullyConnectedMultiTargetModel.from_dataset( multi_target_dataset, hidden_size=10, n_hidden_layers=2, loss=MultiLoss(metrics=[MAE(), SMAPE()], weights=[2.0, 1.0]), ) model.summarize("full") model.hparams # %% [markdown] # Now, let's pass some data through our model and calculate the loss. # %% out = model(x) out # %% y_hat = model.transform_output( out ) # the model's transform_output method re-scales/de-normalizes the predictions to into the real target space
return_decoder_lengths=True) finally: shutil.rmtree(tmp_path, ignore_errors=True) net.predict(val_dataloader, fast_dev_run=True, return_index=True, return_decoder_lengths=True) @pytest.mark.parametrize( "kwargs", [ {}, dict( loss=MultiLoss([QuantileLoss(), MAE()]), data_loader_kwargs=dict( time_varying_unknown_reals=["volume", "discount"], target=["volume", "discount"], ), ), dict( loss=CrossEntropy(), data_loader_kwargs=dict(target="agency", ), ), ], ) def test_integration(data_with_covariates, tmp_path, gpus, kwargs): _integration(data_with_covariates.assign(target=lambda x: x.volume), tmp_path, gpus, **kwargs)