text: # AUTOGENERATED! DO NOT EDIT! File to edit: nbs/models/models.deepcrossing.ipynb (unless otherwise specified).
  
  __all__ = ['DeepCrossing']
  
  # Cell
  import torch
  from torch import nn
  
  from .layers.embedding import EmbeddingLayer
  
  from .bases.ctr import CTRModel
  
  # Internal Cell
  def get_activation(activation):
      if isinstance(activation, str):
          if activation.lower() == "relu":
              return nn.ReLU()
          elif activation.lower() == "sigmoid":
              return nn.Sigmoid()
          elif activation.lower() == "tanh":
              return nn.Tanh()
          else:
              return getattr(nn, activation)()
      else:
          return activation
  
  # Internal Cell
  class ResidualBlock(nn.Module):
      def __init__(self,
                   input_dim,
                   hidden_dim,
                   hidden_activation="ReLU",
                   dropout_rate=0,
                   use_residual=True,
                   batch_norm=False):
          super(ResidualBlock, self).__init__()
          self.activation_layer = get_activation(hidden_activation)
          self.layer = nn.Sequential(nn.Linear(input_dim, hidden_dim),
                                     self.activation_layer,
                                     nn.Linear(hidden_dim, input_dim))
          self.use_residual = use_residual
          self.batch_norm = nn.BatchNorm1d(input_dim) if batch_norm else None
          self.dropout = nn.Dropout(dropout_rate) if dropout_rate > 0 else None
  
      def forward(self, X):
          X_out = self.layer(X)
          if self.use_residual:
              X_out = X_out + X
          if self.batch_norm is not None:
              X_out = self.batch_norm(X_out)
          output = self.activation_layer(X_out)
          if self.dropout is not None:
              output = self.dropout(output)
          return output
  
  # Cell
  class DeepCrossing(CTRModel):
      def __init__(self,
                   feature_map,
                   model_id="DeepCrossing",
                   task="binary_classification",
                   learning_rate=1e-3,
                   embedding_initializer="torch.nn.init.normal_(std=1e-4)",
                   embedding_dim=10,
                   residual_blocks=[64, 64, 64],
                   hidden_activations="ReLU",
                   net_dropout=0,
                   batch_norm=False,
                   use_residual=True,
                   **kwargs):
          super(DeepCrossing, self).__init__(feature_map,
                                             model_id=model_id,
                                             **kwargs)
          self.embedding_layer = EmbeddingLayer(feature_map, embedding_dim)
          if not isinstance(hidden_activations, list):
              hidden_activations = [hidden_activations] * len(residual_blocks)
          layers = []
          input_dim = feature_map.num_fields * embedding_dim
          for hidden_dim, hidden_activation in zip(residual_blocks, hidden_activations):
              layers.append(ResidualBlock(input_dim,
                                          hidden_dim,
                                          hidden_activation,
                                          net_dropout,
                                          use_residual,
                                          batch_norm))
          layers.append(nn.Linear(input_dim, 1))
          self.crossing_layer = nn.Sequential(*layers) # * used to unpack list
          self.output_activation = self.get_final_activation(task)
          self.init_weights(embedding_initializer=embedding_initializer)
  
      def forward(self, inputs):
          feature_emb = self.embedding_layer(inputs)
          y_pred = self.crossing_layer(feature_emb.flatten(start_dim=1))
          if self.output_activation is not None:
              y_pred = self.output_activation(y_pred)
          return y_pred