class_docstr: A single PNA tower in PNA layers
class_docstr_tok: ["A","single","PNA","tower","in","PNA","layers"]
docstr: compute the forward pass of a single tower in PNA convolution layer
docstr_tok: ["compute","the","forward","pass","of","a","single","tower","in","PNA","convolution","layer"]
code: def forward(self, graph, node_feat, edge_feat=None):
      """compute the forward pass of a single tower in PNA convolution layer"""
      # calculate graph normalization factors
      snorm_n = torch.cat(
          [
              torch.ones(N, 1).to(node_feat) / N
              for N in graph.batch_num_nodes()
          ],
          dim=0,
      ).sqrt()
      with graph.local_scope():
          graph.ndata["h"] = node_feat
          if self.edge_feat_size > 0:
              assert (
                  edge_feat is not None
              ), "Edge features must be provided."
              graph.edata["a"] = edge_feat
  
          graph.update_all(self.message, self.reduce_func)
          h = self.U(
              torch.cat([node_feat, graph.ndata["h_neigh"]], dim=-1)
          )
          h = h * snorm_n
          return self.dropout(self.batchnorm(h))
  
imports: import numpy
  import torch
  import torch.nn
label_desc: Use image node_id 4 for calling the PNAConvTower obj's underlying member method code with example usage: obj.forward(graph, node_feat, edge_feat) and returns: self