docstr: Principal Neighbourhood Aggregation
  
  Parameters
  ----------
  data_info : dict
      The information about the input dataset.
  embed_size : int
      Embedding size.
  aggregators : str
      Aggregation function names separated by space, can include mean, max, min, std, sum
  scalers : str
      Scaler function names separated by space, can include identity, amplification, and attenuation
  dropout : float
      Dropout rate.
  batch_norm : bool
      Whether to use batch normalization.
  residual : bool
      Whether to use residual connection.
  num_mlp_layers : int
      Number of MLP layers to use after message aggregation in each PNA layer.
  num_layers : int
      Number of PNA layers.
  readout : str
      Readout for computing graph-level representations, can be 'sum' or 'mean'.
docstr_tok: ["Principal","Neighbourhood","Aggregation","Parameters","--","--","--","--","--","data_info",":","dict","The","information","about","the","input","dataset",".","embed_size",":","int","Embedding","size",".","aggregators",":","str","Aggregation","function","names","separated","by","space",",","can","include","mean",",","max",",","min",",","std",",","sum","scalers",":","str","Scaler","function","names","separated","by","space",",","can","include","identity",",","amplification",",","and","attenuation","dropout",":","float","Dropout","rate",".","batch_norm",":","bool","Whether","to","use","batch","normalization",".","residual",":","bool","Whether","to","use","residual","connection",".","num_mlp_layers",":","int","Number","of","MLP","layers","to","use","after","message","aggregation","in","each","PNA","layer",".","num_layers",":","int","Number","of","PNA","layers",".","readout",":","str","Readout","for","computing","graph-level","representations",",","can","be","'sum","'","or","'mean","'","."]
code: def __init__(
      self,
      data_info: dict,
      embed_size: int = 80,
      aggregators: str = "mean max min std",
      scalers: str = "identity amplification attenuation",
      dropout: float = 0.3,
      batch_norm: bool = True,
      residual: bool = True,
      num_mlp_layers: int = 1,
      num_layers: int = 4,
      readout: str = "mean",
  ):
      """Principal Neighbourhood Aggregation
  
      Parameters
      ----------
      data_info : dict
          The information about the input dataset.
      embed_size : int
          Embedding size.
      aggregators : str
          Aggregation function names separated by space, can include mean, max, min, std, sum
      scalers : str
          Scaler function names separated by space, can include identity, amplification, and attenuation
      dropout : float
          Dropout rate.
      batch_norm : bool
          Whether to use batch normalization.
      residual : bool
          Whether to use residual connection.
      num_mlp_layers : int
          Number of MLP layers to use after message aggregation in each PNA layer.
      num_layers : int
          Number of PNA layers.
      readout : str
          Readout for computing graph-level representations, can be 'sum' or 'mean'.
      """
      super(PNA, self).__init__()
      self.data_info = data_info
      self.embed_size = embed_size
      self.dropout = dropout
      self.batch_norm = batch_norm
      self.residual = residual
      self.num_mlp_layers = num_mlp_layers
      self.num_layers = num_layers
      self.readout = readout
  
      if aggregators is None:
          aggregators = ["mean", "max", "min", "std"]
      else:
          aggregators = [agg.strip() for agg in aggregators.split(" ")]
          assert set(aggregators).issubset(
              {"mean", "max", "min", "std", "sum"}
          ), "Expect aggregators to be a subset of ['mean', 'max', 'min', 'std', 'sum'], \
                      got {}".format(
              aggregators
          )
      if scalers is None:
          scalers = ["identity", "amplification", "attenuation"]
      else:
          scalers = [scl.strip() for scl in scalers.split(" ")]
          assert set(scalers).issubset(
              {"identity", "amplification", "attenuation"}
          ), "Expect scalers to be a subset of ['identity', 'amplification', 'attenuation'], \
                      got {}".format(
              scalers
          )
      self.aggregators = aggregators
      self.scalers = scalers
  
      if data_info["name"] in ["ogbg-molhiv", "ogbg-molpcba"]:
          self.node_encoder = AtomEncoder(embed_size)
      else:
          # Handle other datasets
          self.node_encoder = nn.Linear(
              data_info["node_feat_size"], embed_size
          )
      self.conv_layers = nn.ModuleList(
          [
              SimplePNAConv(
                  feat_size=embed_size,
                  aggregators=aggregators,
                  scalers=scalers,
                  delta=data_info["delta"],
                  dropout=dropout,
                  batch_norm=batch_norm,
                  residual=residual,
                  num_mlp_layers=num_mlp_layers,
              )
              for _ in range(num_layers)
          ]
      )
  
      if readout == "sum":
          self.pool = SumPooling()
      elif readout == "mean":
          self.pool = AvgPooling()
      else:
          raise ValueError(
              "Expect readout to be 'sum' or 'mean', got {}".format(
                  readout
              )
          )
      self.pred = MLP(
          embed_size, data_info["out_size"], decreasing_hidden_size=True
      )
  
imports: from typing import List
  import dgl.function
  import numpy
  import torch
  import torch.nn
  import torch.nn.functional
  from dgl.nn import AvgPooling, SumPooling
  from ogb.graphproppred.mol_encoder import AtomEncoder
label_desc: Use image node_id 1 to create a new PNA object from inherited base classes: nn with example: obj = PNA(data_info, embed_size, aggregators, scalers, dropout, batch_norm, residual, num_mlp_layers, num_layers, readout)