class_docstr: Performs Message Passing to generate encodings for the molecule.
  
  Parameters
  ----------
  atom_messages: bool
      True if encoding atom-messages else False.
  init_message_dim: int
      Dimension of embedding message.
  attach_feats: bool
      Set to `True` if additional features are passed along with node/edge embeddings.
  attached_feat_fdim: int
      Dimension of additional features when `attach_feats` is `True`
  undirected: bool
      If set to `True`, the graph is considered as an undirected graph.
  depth: int
      number of hops in a message passing iteration
  dynamic_depth: str, default: none
      If set to `uniform` for randomly sampling dynamic depth from an uniform distribution else if set to `truncnorm`, dynamic depth is sampled from a truncated normal distribution.
  input_layer: str
      If set to `fc`, adds an initial feed-forward layer. If set to `none`, does not add an initial feed forward layer.
class_docstr_tok: ["Performs","Message","Passing","to","generate","encodings","for","the","molecule",".","Parameters","--","--","--","--","--","atom_messages",":","bool","True","if","encoding","atom-messages","else","False",".","init_message_dim",":","int","Dimension","of","embedding","message",".","attach_feats",":","bool","Set","to","`","True","`","if","additional","features","are","passed","along","with","node\/edge","embeddings",".","attached_feat_fdim",":","int","Dimension","of","additional","features","when","`","attach_feats","`","is","`","True","`","undirected",":","bool","If","set","to","`","True","`",",","the","graph","is","considered","as","an","undirected","graph",".","depth",":","int","number","of","hops","in","a","message","passing","iteration","dynamic_depth",":","str",",","default",":","none","If","set","to","`","uniform","`","for","randomly","sampling","dynamic","depth","from","an","uniform","distribution","else","if","set","to","`","truncnorm","`",",","dynamic","depth","is","sampled","from","a","truncated","normal","distribution",".","input_layer",":","str","If","set","to","`","fc","`",",","adds","an","initial","feed-forward","layer",".","If","set","to","`","none","`",",","does","not","add","an","initial","feed","forward","layer","."]
code: def forward(
      self,
      init_messages,
      init_attached_features,
      a2nei,
      a2attached,
      b2a=None,
      b2revb=None,
      adjs=None,
  ) -> torch.FloatTensor:
      if self.input_layer == "fc":
          message = self.act_func(self.W_i(init_messages))
      elif self.input_layer == "none":
          message = init_messages
  
      attached_feats = init_attached_features
  
      if self.training and self.dynamic_depth != "none":
          if self.dynamic_depth == "uniform":
              ndepth = abs(
                  int(np.random.uniform(self.depth - 3, self.depth + 3))
              )
          elif self.dynamic_depth == "truncnorm":
              mu, sigma = self.depth, 1
              lower, upper = mu - 3 * sigma, mu + 3 * sigma
              X = stats.truncnorm(
                  (lower - mu) / sigma,
                  (upper - mu) / sigma,
                  loc=mu,
                  scale=sigma,
              )
              ndepth = int(X.rvs(1)[0])
      else:
          ndepth = self.depth
  
      for _ in range(ndepth - 1):
          if self.undirected:
              message = (message + message[b2revb]) / 2
  
          nei_message = _select_neighbor_and_aggregate(message, a2nei)
          a_message = nei_message
          if self.attached_feat:
              attached_nei_feats = _select_neighbor_and_aggregate(
                  attached_feats, a2attached
              )
              a_message = torch.cat(
                  (nei_message, attached_nei_feats), dim=1
              )
  
          if not self.atom_messages:
              rev_message = message[b2revb]
              if self.attached_feat:
                  atom_rev_message = attached_feats[b2a[b2revb]]
                  rev_message = torch.cat(
                      (rev_message, atom_rev_message), dim=1
                  )
              # Except reverse bond its-self(w) ! \sum_{k\in N(u) \ w}
              message = (
                  a_message[b2a] - rev_message
              )  # num_bonds x hidden
          else:
              message = a_message
  
          # FIXME When input_layer is none, for the first iteration of message passing, we should ideally
          # be using different weight matrix since message will be of shape num_bonds x f_bonds_dim
          # in the first iteration and in the subsequent iterations, it will be num_bonds x hidden_size
          message = self.W_h(message)
  
          message = self.dropout_layer(self.act_func(message))
  
      return message
  
imports: from typing import List, Dict
  import numpy
  from scipy import stats
  from deepchem.models.torch_models.readout import GroverReadout
  from deepchem.models.torch_models.layers import SublayerConnection, PositionwiseFeedForward
label_desc: Use image node_id 2 for calling the GroverMPNEncoder obj's underlying member method code with example usage: obj.forward(init_messages, init_attached_features, a2nei, a2attached, b2a, b2revb, adjs) and returns: message