class_docstr: Base class implementing a simple feed-forward neural network that takes
  in static and dynamic features and produces `num_hidden_nodes` independent
  outputs. These outputs are then used by derived classes to construct the
  forecast distribution for a single time step.
  
  Note that the dynamic features are just treated as independent features
  without considering their temporal nature.
class_docstr_tok: ["Base","class","implementing","a","simple","feed-forward","neural","network","that","takes","in","static","and","dynamic","features","and","produces","`","num_hidden_nodes","`","independent","outputs",".","These","outputs","are","then","used","by","derived","classes","to","construct","the","forecast","distribution","for","a","single","time","step",".","Note","that","the","dynamic","features","are","just","treated","as","independent","features","without","considering","their","temporal","nature","."]
code: def __init__(
      self,
      context_length: int,
      num_hidden_nodes: List[int],
      cardinality: List[int],
      embedding_dimension: List[int],
      num_time_features: int,
      batch_norm: bool = False,
      input_scaling: Optional[Union[Callable, str]] = None,
      dropout_rate: float = 0.0,
  ):
      super().__init__()
  
      self.context_length = context_length
      self.num_hidden_nodes = num_hidden_nodes
      self.batch_norm = batch_norm
      self.input_scaling = (
          INPUT_SCALING_MAP[input_scaling]
          if isinstance(input_scaling, str)
          else input_scaling
      )
      self.dropout_rate = dropout_rate
  
      # Embedding for categorical features
      self.embedder = FeatureEmbedder(
          cardinalities=cardinality,
          embedding_dimensions=embedding_dimension,
      )
      total_embedding_dim = sum(embedding_dimension)
  
      # We have two target related features: past_target and observed value
      # indicator each of length `context_length`.
      # Also, +1 for the static real feature.
      dimensions = [
          context_length * (num_time_features + 2)
          + total_embedding_dim
          + 1
      ] + num_hidden_nodes
      modules: List[nn.Module] = []
      for in_features, out_features in zip(
          dimensions[:-1], dimensions[1:]
      ):
          modules += [nn.Linear(in_features, out_features), nn.ReLU()]
          if self.batch_norm:
              modules.append(nn.BatchNorm1d(out_features))
          if self.dropout_rate > 0:
              modules.append(nn.Dropout(self.dropout_rate))
  
      self.model = nn.Sequential(*modules)
      self.model.apply(partial(init_weights, scale=0.07))
  
imports: from functools import partial
  from typing import Optional, Callable, List, Union
  import torch
  from torch import nn
  from torch.distributions import Categorical, MixtureSameFamily, Normal
  from gluonts.core.component import validated
  from gluonts.torch.distributions import DiscreteDistribution
  from .scaling import min_max_scaling, standard_normal_scaling
label_desc: Use image node_id 1 to create a new DeepNPTSNetwork object from inherited base classes: nn with example: obj = DeepNPTSNetwork(context_length, num_hidden_nodes, cardinality, embedding_dimension, num_time_features, batch_norm, input_scaling, dropout_rate)