def test_prediction_with_dataloder_raw(data_with_covariates, tmp_path):
    # tests correct concatenation of raw output
    test_data = data_with_covariates.copy()
    np.random.seed(2)
    test_data = test_data.sample(frac=0.5)

    dataset = TimeSeriesDataSet(
        test_data,
        time_idx="time_idx",
        max_encoder_length=8,
        max_prediction_length=10,
        min_prediction_length=1,
        min_encoder_length=1,
        target="volume",
        group_ids=["agency", "sku"],
        constant_fill_strategy=dict(volume=0.0),
        allow_missing_timesteps=True,
        time_varying_unknown_reals=["volume"],
        time_varying_known_reals=["time_idx"],
        target_normalizer=GroupNormalizer(groups=["agency", "sku"]),
    )

    net = TemporalFusionTransformer.from_dataset(
        dataset,
        learning_rate=1e-6,
        hidden_size=4,
        attention_head_size=1,
        dropout=0.2,
        hidden_continuous_size=2,
        log_interval=1,
        log_val_interval=1,
        log_gradient_flow=True,
    )
    logger = TensorBoardLogger(tmp_path)
    trainer = pl.Trainer(max_epochs=1, gradient_clip_val=1e-6, logger=logger)
    trainer.fit(net,
                train_dataloaders=dataset.to_dataloader(batch_size=4,
                                                        num_workers=0))

    # choose small batch size to provoke issue
    res = net.predict(dataset.to_dataloader(batch_size=2, num_workers=0),
                      mode="raw")
    # check that interpretation works
    net.interpret_output(res)["attention"]
    assert net.interpret_output(res.iget(
        slice(1)))["attention"].size() == torch.Size(
            (1, net.hparams.max_encoder_length))
def test_distribution_loss(data_with_covariates, tmp_path, gpus):
    data_with_covariates = data_with_covariates.assign(
        volume=lambda x: x.volume.round())
    dataloaders_with_covariates = make_dataloaders(
        data_with_covariates,
        target="volume",
        time_varying_known_reals=["price_actual"],
        time_varying_unknown_reals=["volume"],
        static_categoricals=["agency"],
        add_relative_time_idx=True,
        target_normalizer=GroupNormalizer(groups=["agency", "sku"],
                                          center=False),
    )
    _integration(dataloaders_with_covariates,
                 tmp_path,
                 gpus,
                 loss=NegativeBinomialDistributionLoss())
    def _create_dataset(self, df, valid_p=0.2):
        df = df_utils.check_dataframe(df)
        df = self._handle_missing_data(df)
        df = df[["ds", "y"]]
        df["time_idx"] = range(df.shape[0])
        df["series"] = 0
        self.n_data = df.shape[0]
        self.set_auto_batch_epoch(self.n_data)

        training_cutoff = df.shape[0] - int(valid_p * df.shape[0])

        training = TimeSeriesDataSet(
            df.iloc[:training_cutoff],
            time_idx="time_idx",
            target="y",
            categorical_encoders={"series": NaNLabelEncoder().fit(df.series)},
            group_ids=["series"],
            min_encoder_length=self.context_length,
            max_encoder_length=self.context_length,
            max_prediction_length=self.prediction_length,
            min_prediction_length=self.prediction_length,
            time_varying_unknown_reals=["y"],
            target_normalizer=GroupNormalizer(groups=["series"]),
            randomize_length=None,
            add_relative_time_idx=False,
            add_target_scales=False,
        )

        validation = TimeSeriesDataSet.from_dataset(
            training, df, min_prediction_idx=training_cutoff)
        train_dataloader = training.to_dataloader(train=True,
                                                  batch_size=self.batch_size,
                                                  num_workers=self.num_workers)
        val_dataloader = validation.to_dataloader(train=False,
                                                  batch_size=self.batch_size,
                                                  num_workers=self.num_workers)

        return training, train_dataloader, val_dataloader
def test_mqf2_loss(data_with_covariates, tmp_path, gpus):
    data_with_covariates = data_with_covariates.assign(
        volume=lambda x: x.volume.round())
    dataloaders_with_covariates = make_dataloaders(
        data_with_covariates,
        target="volume",
        time_varying_known_reals=["price_actual"],
        time_varying_unknown_reals=["volume"],
        static_categoricals=["agency"],
        add_relative_time_idx=True,
        target_normalizer=GroupNormalizer(groups=["agency", "sku"],
                                          center=False,
                                          transformation="softplus"),
    )

    prediction_length = dataloaders_with_covariates[
        "train"].dataset.min_prediction_length

    _integration(
        dataloaders_with_covariates,
        tmp_path,
        gpus,
        loss=MQF2DistributionLoss(prediction_length=prediction_length))
        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",
    [
        {},
        {
            "cell_type": "GRU"
        },
        dict(data_loader_kwargs=dict(target_normalizer=GroupNormalizer(
            groups=["agency", "sku"], center=False)), ),
        dict(data_loader_kwargs=dict(lags={"volume": [2, 5]},
                                     target="volume",
                                     time_varying_unknown_reals=["volume"],
                                     min_encoder_length=2)),
        dict(data_loader_kwargs=dict(
            time_varying_unknown_reals=["volume", "discount"],
            target=["volume", "discount"],
            lags={
                "volume": [2],
                "discount": [2]
            },
        )),
    ],
)
def test_integration(data_with_covariates, tmp_path, gpus, kwargs):
    def predict(self, future_dataframe):
        """
        Predicts based on the future_dataframe. Should be called only after make_future_dataframe is called
        Args:
            future_dataframe: DataFrame form make_future_dataframe function
        Returns:
            forecast dataframe
        """

        if self.fitted is False:
            log.warning("Model has not been fitted. Predictions will be random.")

        future_dataframe = future_dataframe.copy(deep=True)

        testing = TimeSeriesDataSet(
            future_dataframe,
            time_idx="time_idx",
            target="y",
            categorical_encoders={"series": NaNLabelEncoder().fit(future_dataframe.series)},
            group_ids=["series"],
            min_encoder_length=self.context_length,
            max_encoder_length=self.context_length,
            max_prediction_length=self.prediction_length,
            min_prediction_length=self.prediction_length,
            time_varying_known_reals=["time_idx"],
            time_varying_unknown_reals=["y"],
            target_normalizer=GroupNormalizer(groups=["series"], transformation="softplus", center=False),
            add_relative_time_idx=True,
            add_target_scales=True,
            add_encoder_length=True,
        )

        new_raw_predictions, new_x = self.model.predict(testing, mode="raw", return_x=True)

        y_predicted = self.model.to_prediction(new_raw_predictions).detach().cpu()  # [0, : new_x["decoder_lengths"][0]]

        y_predicted = y_predicted.detach().numpy()

        def pad_with(vector, pad_width, iaxis, kwargs):
            pad_value = kwargs.get("padder", np.nan)
            vector[: pad_width[0]] = pad_value
            vector[-pad_width[1] :] = pad_value

        y_pred_padded = np.pad(y_predicted, self.prediction_length, pad_with)[
            self.prediction_length : -1, self.prediction_length : -self.prediction_length
        ]
        y_pred_padded = np.vstack([np.roll(y_pred_padded[:, i], i, axis=0) for i in range(y_pred_padded.shape[1])]).T

        result = pd.DataFrame(
            np.ones(shape=(len(future_dataframe), (2 + self.prediction_length))) * np.nan,
            columns=["ds", "y"] + [f"yhat{i}" for i in range(1, self.prediction_length + 1)],
        )
        result["ds"] = future_dataframe["ds"]

        result.loc[: len(future_dataframe) - (self.periods + 1), "y"] = (
            future_dataframe["y"].iloc[: len(future_dataframe) - (self.periods)].values
        )

        first_part = result.iloc[: self.context_length]
        second_part = result.iloc[self.context_length :]

        second_part.loc[:, [col for col in second_part.columns[2:]]] = y_pred_padded
        result = pd.concat([first_part, second_part])
        for i in range(1, self.prediction_length + 1):
            result[f"residual{i}"] = result[f"yhat{i}"] - result["y"]

        return result
Esempio n. 7
0
        net.predict(val_dataloader, fast_dev_run=True, return_index=True, 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",
    [
        {},
        {"cell_type": "GRU"},
        dict(
            loss=LogNormalDistributionLoss(),
            clip_target=True,
            data_loader_kwargs=dict(target_normalizer=GroupNormalizer(groups=["agency", "sku"], transformation="log")),
        ),
        dict(
            loss=NegativeBinomialDistributionLoss(),
            clip_target=False,
            data_loader_kwargs=dict(target_normalizer=GroupNormalizer(groups=["agency", "sku"], center=False)),
        ),
        dict(
            loss=BetaDistributionLoss(),
            clip_target=True,
            data_loader_kwargs=dict(
                target_normalizer=GroupNormalizer(groups=["agency", "sku"], transformation="logit")
            ),
        ),
        dict(
            data_loader_kwargs=dict(