def __init__( self, cell_type: str = "LSTM", hidden_size: int = 10, rnn_layers: int = 2, dropout: float = 0.1, static_categoricals: List[str] = [], static_reals: List[str] = [], time_varying_categoricals_encoder: List[str] = [], time_varying_categoricals_decoder: List[str] = [], categorical_groups: Dict[str, List[str]] = {}, time_varying_reals_encoder: List[str] = [], time_varying_reals_decoder: List[str] = [], embedding_sizes: Dict[str, Tuple[int, int]] = {}, embedding_paddings: List[str] = [], embedding_labels: Dict[str, np.ndarray] = {}, x_reals: List[str] = [], x_categoricals: List[str] = [], n_validation_samples: int = None, n_plotting_samples: int = None, target: Union[str, List[str]] = None, loss: DistributionLoss = None, logging_metrics: nn.ModuleList = None, **kwargs, ): """ DeepAR Network. The code is based on the article `DeepAR: Probabilistic forecasting with autoregressive recurrent networks <https://www.sciencedirect.com/science/article/pii/S0169207019301888>`_. Args: cell_type (str, optional): Recurrent cell type ["LSTM", "GRU"]. Defaults to "LSTM". hidden_size (int, optional): hidden recurrent size - the most important hyperparameter along with ``rnn_layers``. Defaults to 10. rnn_layers (int, optional): Number of RNN layers - important hyperparameter. Defaults to 2. dropout (float, optional): Dropout in RNN layers. Defaults to 0.1. static_categoricals: integer of positions of static categorical variables static_reals: integer of positions of static continuous variables time_varying_categoricals_encoder: integer of positions of categorical variables for encoder time_varying_categoricals_decoder: integer of positions of categorical variables for decoder time_varying_reals_encoder: integer of positions of continuous variables for encoder time_varying_reals_decoder: integer of positions of continuous variables for decoder categorical_groups: dictionary where values are list of categorical variables that are forming together a new categorical variable which is the key in the dictionary x_reals: order of continuous variables in tensor passed to forward function x_categoricals: order of categorical variables in tensor passed to forward function embedding_sizes: dictionary mapping (string) indices to tuple of number of categorical classes and embedding size embedding_paddings: list of indices for embeddings which transform the zero's embedding to a zero vector embedding_labels: dictionary mapping (string) indices to list of categorical labels n_validation_samples (int, optional): Number of samples to use for calculating validation metrics. Defaults to None, i.e. no sampling at validation stage and using "mean" of distribution for logging metrics calculation. n_plotting_samples (int, optional): Number of samples to generate for plotting predictions during training. Defaults to ``n_validation_samples`` if not None or 100 otherwise. target (str, optional): Target variable or list of target variables. Defaults to None. loss (DistributionLoss, optional): Distribution loss function. Keep in mind that each distribution loss function might have specific requirements for target normalization. Defaults to :py:class:`~pytorch_forecasting.metrics.NormalDistributionLoss`. logging_metrics (nn.ModuleList, optional): Metrics to log during training. Defaults to nn.ModuleList([SMAPE(), MAE(), RMSE(), MAPE(), MASE()]). """ if loss is None: loss = NormalDistributionLoss() if logging_metrics is None: logging_metrics = nn.ModuleList( [SMAPE(), MAE(), RMSE(), MAPE(), MASE()]) if n_plotting_samples is None: if n_validation_samples is None: n_plotting_samples = n_validation_samples else: n_plotting_samples = 100 self.save_hyperparameters() # store loss function separately as it is a module super().__init__(loss=loss, logging_metrics=logging_metrics, **kwargs) self.embeddings = MultiEmbedding( embedding_sizes=embedding_sizes, embedding_paddings=embedding_paddings, categorical_groups=categorical_groups, x_categoricals=x_categoricals, ) assert set(self.encoder_variables) - set(to_list(target)) == set( self.decoder_variables ), "Encoder and decoder variables have to be the same apart from target variable" for targeti in to_list(target): assert ( targeti in time_varying_reals_encoder ), f"target {targeti} has to be real" # todo: remove this restriction assert ( isinstance(target, str) and isinstance(loss, DistributionLoss) ) or ( isinstance(target, (list, tuple)) and isinstance(loss, MultiLoss) and len(loss) == len(target) ), "number of targets should be equivalent to number of loss metrics" time_series_rnn = get_cell(cell_type) self.rnn = time_series_rnn( input_size=self.input_size, hidden_size=self.hparams.hidden_size, num_layers=self.hparams.rnn_layers, dropout=self.hparams.dropout if self.hparams.rnn_layers > 1 else 0, batch_first=True, ) # add linear layers for argument projects if isinstance(loss, MultiLoss): # multi target self.distribution_projector = nn.ModuleList([ nn.Linear(self.hparams.hidden_size, len(args)) for args in self.loss.distribution_arguments ]) else: self.distribution_projector = nn.Linear( self.hparams.hidden_size, len(self.loss.distribution_arguments))
def test_get_gru_cell(): cell = get_cell("GRU")(10, 10) assert isinstance(cell, TimeSeriesGRU) assert isinstance(cell, nn.GRU)
def test_get_cell_raises_value_error(): pytest.raises(ValueError, lambda: get_cell("ABCDEF"))
def test_get_lstm_cell(): cell = get_cell("LSTM")(10, 10) assert isinstance(cell, TimeSeriesLSTM) assert isinstance(cell, nn.LSTM)