class_docstr: Multi-layer Graph Convolutional Networks (GCN).
  Support both `Unidirectional GCN
  <https://arxiv.org/pdf/1609.02907>`__ and bidirectional versions
  including `GCN-BiSep` and `GCN-BiFuse`.
  
  For the Unidirectional GCN,
  
  .. math::
    h_i^{(l+1)} = \sigma(b^{(l)} + \sum_{j\in\mathcal{N}(i)}\frac{1}{c_{ij}}h_j^{(l)}W^{(l)})
  
  where :math:`\mathcal{N}(i)` is the set of neighbors of node :math:`i`,
  :math:`c_{ij}` is the product of the square root of node degrees
  (i.e.,  :math:`c_{ij} = \sqrt{|\mathcal{N}(i)|}\sqrt{|\mathcal{N}(j)|}`),
  and :math:`\sigma` is an activation function.
  
  Parameters
  ----------
  num_layers: int
      Number of GCN layers.
  
  input_size: int
      Input feature size of the first GCN layer.
  
  hidden_size: int
      Hidden size per GCN layer.
  
  output_size: int
      Output feature size of the final GCN layer.
  
  direction_option: str
      Whether to use unidirectional (i.e., regular) or bidirectional
      (i.e., "bi_sep" and "bi_fuse") versions.
      Default : ``'bi_sep'``.
  
  gcn_norm: str, optional
      How to apply the normalizer. If is `'right'`, divide the aggregated messages
      by each node's in-degrees, which is equivalent to averaging the received messages.
      If is `'none'`, no normalization is applied. Default is `'both'`,
      where the :math:`c_{ij}` in the paper is applied.
  
  weight: bool, optional
      If True, apply a linear layer. Otherwise, aggregating the messages
      without a weight matrix.
  
  bias: bool, optional
      If True, adds a learnable bias to the output. Default: ``True``.
  
  activation: callable activation function/layer or None, optional
      If not None, applies an activation function to the updated node features.
      Default: ``None``.
  
  allow_zero_in_degree: bool, optional
  
  use_edge_weight: bool, optional
class_docstr_tok: ["Multi-layer","Graph","Convolutional","Networks","(","GCN",")",".","Support","both","`","Unidirectional","GCN","<","https",":","\/\/arxiv.org\/pdf\/1609.02907",">","`","__","and","bidirectional","versions","including","`","GCN-BiSep","`","and","`","GCN-BiFuse","`",".","For","the","Unidirectional","GCN",",","..","math",":",":","h_i^","{","(","l+1",")","}","=","\\sigma","(","b^","{","(","l",")","}","+","\\sum_","{","j\\in\\mathcal","{","N","}","(","i",")","}","\\frac","{","1","}","{","c_","{","ij","}","}","h_j^","{","(","l",")","}","W^","{","(","l",")","}",")","where",":","math",":","`","\\mathcal","{","N","}","(","i",")","`","is","the","set","of","neighbors","of","node",":","math",":","`","i","`",",",":","math",":","`","c_","{","ij","}","`","is","the","product","of","the","square","root","of","node","degrees","(","i.e.",",",":","math",":","`","c_","{","ij","}","=","\\sqrt","{","|\\mathcal","{","N","}","(","i",")","|","}","\\sqrt","{","|\\mathcal","{","N","}","(","j",")","|","}","`",")",",","and",":","math",":","`","\\sigma","`","is","an","activation","function",".","Parameters","--","--","--","--","--","num_layers",":","int","Number","of","GCN","layers",".","input_size",":","int","Input","feature","size","of","the","first","GCN","layer",".","hidden_size",":","int","Hidden","size","per","GCN","layer",".","output_size",":","int","Output","feature","size","of","the","final","GCN","layer",".","direction_option",":","str","Whether","to","use","unidirectional","(","i.e.",",","regular",")","or","bidirectional","(","i.e.",",","``","bi_sep","''","and","``","bi_fuse","''",")","versions",".","Default",":","``","'bi_sep","'","``",".","gcn_norm",":","str",",","optional","How","to","apply","the","normalizer",".","If","is","`","'right","'","`",",","divide","the","aggregated","messages","by","each","node","'s","in-degrees",",","which","is","equivalent","to","averaging","the","received","messages",".","If","is","`","'none","'","`",",","no","normalization","is","applied",".","Default","is","`","'both","'","`",",","where","the",":","math",":","`","c_","{","ij","}","`","in","the","paper","is","applied",".","weight",":","bool",",","optional","If","True",",","apply","a","linear","layer",".","Otherwise",",","aggregating","the","messages","without","a","weight","matrix",".","bias",":","bool",",","optional","If","True",",","adds","a","learnable","bias","to","the","output",".","Default",":","``","True","``",".","activation",":","callable","activation","function\/layer","or","None",",","optional","If","not","None",",","applies","an","activation","function","to","the","updated","node","features",".","Default",":","``","None","``",".","allow_zero_in_degree",":","bool",",","optional","use_edge_weight",":","bool",",","optional"]
docstr: Compute multi-layer graph convolutional networks.
  
  Parameters
  ----------
  graph : GraphData
      The graph data containing topology and features.
  
  Returns
  -------
  GraphData
      The output graph data containing updated embeddings.
docstr_tok: ["Compute","multi-layer","graph","convolutional","networks",".","Parameters","--","--","--","--","--","graph",":","GraphData","The","graph","data","containing","topology","and","features",".","Returns","--","--","--","-","GraphData","The","output","graph","data","containing","updated","embeddings","."]
code: def forward(self, graph):
      r"""Compute multi-layer graph convolutional networks.
  
      Parameters
      ----------
      graph : GraphData
          The graph data containing topology and features.
  
      Returns
      -------
      GraphData
          The output graph data containing updated embeddings.
      """
      feat = graph.node_features["node_feat"]
      dgl_graph = graph.to_dgl()
  
      if self.direction_option == "bi_sep":
          h = [feat, feat]
      else:
          h = feat
  
      if self.use_edge_weight:
          edge_weight = graph.edge_features["edge_weight"]
          if self.direction_option != "undirected":
              reverse_edge_weight = graph.edge_features[
                  "reverse_edge_weight"
              ]
          else:
              reverse_edge_weight = None
      else:
          edge_weight = None
          reverse_edge_weight = None
  
      for l in range(self.num_layers - 1):
          h = self.gcn_layers[l](
              dgl_graph,
              h,
              edge_weight=edge_weight,
              reverse_edge_weight=reverse_edge_weight,
          )
          if self.direction_option == "bi_sep":
              h = [each.flatten(1) for each in h]
          else:
              h = h.flatten(1)
  
      # output projection
      logits = self.gcn_layers[-1](dgl_graph, h)
  
      if self.direction_option == "bi_sep":
          # logits = [each.mean(1) for each in logits]
          logits = torch.cat(logits, -1)
      else:
          pass
  
      graph.node_features["node_emb"] = logits
  
      return graph
  
imports: import dgl.function
  import torch
  import torch.nn
  from torch.nn import init
  from .base import GNNBase, GNNLayerBase
label_desc: Use image node_id 2 for calling the GCN obj's underlying member method code with example usage: obj.forward(graph) and returns: graph