class_docstr: Net3D is a 3D graph neural network that expects a DGL graph input with 3D coordinates stored under the name 'd' and node features stored under the name 'feat'. It is based on the 3D Infomax architecture [1].
  
  Parameters
  ----------
  hidden_dim : int
      The dimension of the hidden layers.
  target_dim : int
      The dimension of the output layer.
  readout_aggregators : List[str]
      A list of aggregator functions for the readout layer. Options are 'sum', 'max', 'min', 'mean'.
  batch_norm : bool, optional (default=False)
      Whether to use batch normalization.
  node_wise_output_layers : int, optional (default=2)
      The number of output layers for each node.
  readout_batchnorm : bool, optional (default=True)
      Whether to use batch normalization in the readout layer.
  batch_norm_momentum : float, optional (default=0.1)
      The momentum for the batch normalization layers.
  reduce_func : str, optional (default='sum')
      The reduce function to use for aggregating messages.
  dropout : float, optional (default=0.0)
      The dropout rate for the layers.
  propagation_depth : int, optional (default=4)
      The number of propagation layers in the network.
  readout_layers : int, optional (default=2)
      The number of readout layers in the network.
  readout_hidden_dim : int, optional (default=None)
      The dimension of the hidden layers in the readout network.
  fourier_encodings : int, optional (default=0)
      The number of Fourier encodings to use.
  activation : str, optional (default='SiLU')
      The activation function to use in the network.
  update_net_layers : int, optional (default=2)
      The number of update network layers.
  message_net_layers : int, optional (default=2)
      The number of message network layers.
  use_node_features : bool, optional (default=False)
      Whether to use node features as input.
  
  Examples
  --------
  >>> from deepchem.feat.molecule_featurizers.conformer_featurizer import RDKitConformerFeaturizer
  >>> from deepchem.models.torch_models.gnn3d import Net3D
  >>> smiles = ["C[C@H](F)Cl", "C[C@@H](F)Cl"]
  >>> featurizer = RDKitConformerFeaturizer()
  >>> data = featurizer.featurize(smiles)
  >>> dgldata = [[graph.to_dgl_graph() for graph in conf] for conf in data]
  >>> net3d = Net3D(hidden_dim=3, target_dim=2, readout_aggregators=['sum', 'mean'])
  >>> output = [[net3d(graph) for graph in conf] for conf in dgldata]
  
  References
  ----------
  .. [1] Stärk, H. et al. 3D Infomax improves GNNs for Molecular Property Prediction. Preprint at https://doi.org/10.48550/arXiv.2110.04126 (2022).
code: def __init__(
      self,
      hidden_dim,
      target_dim,
      readout_aggregators: List[str],
      node_wise_output_layers=2,
      batch_norm=True,
      batch_norm_momentum=0.1,
      reduce_func="sum",
      dropout=0.0,
      propagation_depth: int = 4,
      readout_layers: int = 2,
      readout_hidden_dim=None,
      fourier_encodings=4,
      update_net_layers=2,
      message_net_layers=2,
      use_node_features=False,
  ):
      super(Net3D, self).__init__()
      self.fourier_encodings = fourier_encodings
      edge_in_dim = (
          1 if fourier_encodings == 0 else 2 * fourier_encodings + 1
      )
  
      self.edge_input = nn.Sequential(
          MultilayerPerceptron(
              d_input=edge_in_dim,
              d_output=hidden_dim,
              d_hidden=(hidden_dim,),
              batch_norm=batch_norm,
              batch_norm_momentum=batch_norm_momentum,
          ),
          torch.nn.SiLU(),
      )
  
      self.use_node_features = use_node_features
      if self.use_node_features:
          self.atom_encoder = AtomEncoder(hidden_dim)
      else:
          self.node_embedding = nn.Parameter(torch.empty((hidden_dim,)))
          nn.init.normal_(self.node_embedding)
  
      self.mp_layers = nn.ModuleList()
      for _ in range(propagation_depth):
          self.mp_layers.append(
              Net3DLayer(
                  edge_dim=hidden_dim,
                  hidden_dim=hidden_dim,
                  batch_norm=batch_norm,
                  batch_norm_momentum=batch_norm_momentum,
                  dropout=dropout,
                  reduce_func=reduce_func,
                  message_net_layers=message_net_layers,
                  update_net_layers=update_net_layers,
              )
          )
  
      self.node_wise_output_layers = node_wise_output_layers
      if self.node_wise_output_layers > 0:
          self.node_wise_output_network = MultilayerPerceptron(
              d_input=hidden_dim,
              d_output=hidden_dim,
              d_hidden=(hidden_dim,),
              batch_norm=batch_norm,
              batch_norm_momentum=batch_norm_momentum,
          )
  
      if readout_hidden_dim is None:
          readout_hidden_dim = hidden_dim
      self.readout_aggregators = readout_aggregators
  
      self.output = MultilayerPerceptron(
          d_input=hidden_dim * len(self.readout_aggregators),
          d_output=target_dim,
          d_hidden=(readout_hidden_dim,)
          * (
              readout_layers - 1
          ),  # -1 because the input layer is not considered a hidden layer
          batch_norm=False,
      )
  
imports: import itertools
  from typing import Callable, List, Union, Literal, Optional
  import dgl
  import dgl.function
  import torch
  from torch import nn
  from torch.nn import functional
  from deepchem.models.losses import NTXentMultiplePositives
  from deepchem.models.torch_models import ModularTorchModel
  from deepchem.models.torch_models.layers import MultilayerPerceptron
  from deepchem.models.torch_models.pna_gnn import PNA, AtomEncoder
  from deepchem.utils.graph_utils import fourier_encode_dist
label_desc: Use image node_id 1 to create a new Net3D object from inherited base classes: nn with example: obj = Net3D(hidden_dim, target_dim, readout_aggregators, node_wise_output_layers, batch_norm, batch_norm_momentum, reduce_func, dropout, propagation_depth, readout_layers, readout_hidden_dim, fourier_encodings, update_net_layers, message_net_layers, use_node_features)