class_docstr: A generic module for computing convolution on heterogeneous graphs.
  
  The heterograph convolution applies sub-modules on their associating
  relation graphs, which reads the features from source nodes and writes the
  updated ones to destination nodes. If multiple relations have the same
  destination node types, their results are aggregated by the specified method.
  If the relation graph has no edge, the corresponding module will not be called.
  
  Pseudo-code:
  
  .. code::
  
      outputs = {nty : [] for nty in g.dsttypes}
      # Apply sub-modules on their associating relation graphs in parallel
      for relation in g.canonical_etypes:
          stype, etype, dtype = relation
          dstdata = relation_submodule(g[relation], ...)
          outputs[dtype].append(dstdata)
  
      # Aggregate the results for each destination node type
      rsts = {}
      for ntype, ntype_outputs in outputs.items():
          if len(ntype_outputs) != 0:
              rsts[ntype] = aggregate(ntype_outputs)
      return rsts
  
  Examples
  --------
  
  Create a heterograph with three types of relations and nodes.
  
  >>> import dgl
  >>> g = dgl.heterograph({
  ...     ('user', 'follows', 'user') : edges1,
  ...     ('user', 'plays', 'game') : edges2,
  ...     ('store', 'sells', 'game')  : edges3})
  
  Create a ``HeteroGraphConv`` that applies different convolution modules to
  different relations. Note that the modules for ``'follows'`` and ``'plays'``
  do not share weights.
  
  >>> import dgl.nn.pytorch as dglnn
  >>> conv = dglnn.HeteroGraphConv({
  ...     'follows' : dglnn.GraphConv(...),
  ...     'plays' : dglnn.GraphConv(...),
  ...     'sells' : dglnn.SAGEConv(...)},
  ...     aggregate='sum')
  
  Call forward with some ``'user'`` features. This computes new features for both
  ``'user'`` and ``'game'`` nodes.
  
  >>> import torch as th
  >>> h1 = {'user' : th.randn((g.num_nodes('user'), 5))}
  >>> h2 = conv(g, h1)
  >>> print(h2.keys())
  dict_keys(['user', 'game'])
  
  Call forward with both ``'user'`` and ``'store'`` features. Because both the
  ``'plays'`` and ``'sells'`` relations will update the ``'game'`` features,
  their results are aggregated by the specified method (i.e., summation here).
  
  >>> f1 = {'user' : ..., 'store' : ...}
  >>> f2 = conv(g, f1)
  >>> print(f2.keys())
  dict_keys(['user', 'game'])
  
  Call forward with some ``'store'`` features. This only computes new features
  for ``'game'`` nodes.
  
  >>> g1 = {'store' : ...}
  >>> g2 = conv(g, g1)
  >>> print(g2.keys())
  dict_keys(['game'])
  
  Call forward with a pair of inputs is allowed and each submodule will also
  be invoked with a pair of inputs.
  
  >>> x_src = {'user' : ..., 'store' : ...}
  >>> x_dst = {'user' : ..., 'game' : ...}
  >>> y_dst = conv(g, (x_src, x_dst))
  >>> print(y_dst.keys())
  dict_keys(['user', 'game'])
  
  Parameters
  ----------
  mods : dict[str, nn.Module]
      Modules associated with every edge types. The forward function of each
      module must have a `DGLGraph` object as the first argument, and
      its second argument is either a tensor object representing the node
      features or a pair of tensor object representing the source and destination
      node features.
  aggregate : str, callable, optional
      Method for aggregating node features generated by different relations.
      Allowed string values are 'sum', 'max', 'min', 'mean', 'stack'.
      The 'stack' aggregation is performed along the second dimension, whose order
      is deterministic.
      User can also customize the aggregator by providing a callable instance.
      For example, aggregation by summation is equivalent to the follows:
  
      .. code::
  
          def my_agg_func(tensors, dsttype):
              # tensors: is a list of tensors to aggregate
              # dsttype: string name of the destination node type for which the
              #          aggregation is performed
              stacked = torch.stack(tensors, dim=0)
              return torch.sum(stacked, dim=0)
  
  Attributes
  ----------
  mods : dict[str, nn.Module]
      Modules associated with every edge types.
class_docstr_tok: ["A","generic","module","for","computing","convolution","on","heterogeneous","graphs",".","The","heterograph","convolution","applies","sub-modules","on","their","associating","relation","graphs",",","which","reads","the","features","from","source","nodes","and","writes","the","updated","ones","to","destination","nodes",".","If","multiple","relations","have","the","same","destination","node","types",",","their","results","are","aggregated","by","the","specified","method",".","If","the","relation","graph","has","no","edge",",","the","corresponding","module","will","not","be","called",".","Pseudo-code",":","..","code",":",":","outputs","=","{","nty",":","[","]","for","nty","in","g.dsttypes","}","#","Apply","sub-modules","on","their","associating","relation","graphs","in","parallel","for","relation","in","g.canonical_etypes",":","stype",",","etype",",","dtype","=","relation","dstdata","=","relation_submodule","(","g","[","relation","]",",","...",")","outputs","[","dtype","]",".append","(","dstdata",")","#","Aggregate","the","results","for","each","destination","node","type","rsts","=","{","}","for","ntype",",","ntype_outputs","in","outputs.items","(",")",":","if","len","(","ntype_outputs",")","!","=","0",":","rsts","[","ntype","]","=","aggregate","(","ntype_outputs",")","return","rsts","Examples","--","--","--","--","Create","a","heterograph","with","three","types","of","relations","and","nodes",".",">",">",">","import","dgl",">",">",">","g","=","dgl.heterograph","(","{","...","(","'user","'",",","'follows","'",",","'user","'",")",":","edges1",",","...","(","'user","'",",","'plays","'",",","'game","'",")",":","edges2",",","...","(","'store","'",",","'sells","'",",","'game","'",")",":","edges3","}",")","Create","a","``","HeteroGraphConv","``","that","applies","different","convolution","modules","to","different","relations",".","Note","that","the","modules","for","``","'follows","'","``","and","``","'plays","'","``","do","not","share","weights",".",">",">",">","import","dgl.nn.pytorch","as","dglnn",">",">",">","conv","=","dglnn.HeteroGraphConv","(","{","...","'follows","'",":","dglnn.GraphConv","(","...",")",",","...","'plays","'",":","dglnn.GraphConv","(","...",")",",","...","'sells","'",":","dglnn.SAGEConv","(","...",")","}",",","...","aggregate='sum","'",")","Call","forward","with","some","``","'user","'","``","features",".","This","computes","new","features","for","both","``","'user","'","``","and","``","'game","'","``","nodes",".",">",">",">","import","torch","as","th",">",">",">","h1","=","{","'user","'",":","th.randn","(","(","g.num_nodes","(","'user","'",")",",","5",")",")","}",">",">",">","h2","=","conv","(","g",",","h1",")",">",">",">","print","(","h2.keys","(",")",")","dict_keys","(","[","'user","'",",","'game","'","]",")","Call","forward","with","both","``","'user","'","``","and","``","'store","'","``","features",".","Because","both","the","``","'plays","'","``","and","``","'sells","'","``","relations","will","update","the","``","'game","'","``","features",",","their","results","are","aggregated","by","the","specified","method","(","i.e.",",","summation","here",")",".",">",">",">","f1","=","{","'user","'",":","...",",","'store","'",":","...","}",">",">",">","f2","=","conv","(","g",",","f1",")",">",">",">","print","(","f2.keys","(",")",")","dict_keys","(","[","'user","'",",","'game","'","]",")","Call","forward","with","some","``","'store","'","``","features",".","This","only","computes","new","features","for","``","'game","'","``","nodes",".",">",">",">","g1","=","{","'store","'",":","...","}",">",">",">","g2","=","conv","(","g",",","g1",")",">",">",">","print","(","g2.keys","(",")",")","dict_keys","(","[","'game","'","]",")","Call","forward","with","a","pair","of","inputs","is","allowed","and","each","submodule","will","also","be","invoked","with","a","pair","of","inputs",".",">",">",">","x_src","=","{","'user","'",":","...",",","'store","'",":","...","}",">",">",">","x_dst","=","{","'user","'",":","...",",","'game","'",":","...","}",">",">",">","y_dst","=","conv","(","g",",","(","x_src",",","x_dst",")",")",">",">",">","print","(","y_dst.keys","(",")",")","dict_keys","(","[","'user","'",",","'game","'","]",")","Parameters","--","--","--","--","--","mods",":","dict","[","str",",","nn.Module","]","Modules","associated","with","every","edge","types",".","The","forward","function","of","each","module","must","have","a","`","DGLGraph","`","object","as","the","first","argument",",","and","its","second","argument","is","either","a","tensor","object","representing","the","node","features","or","a","pair","of","tensor","object","representing","the","source","and","destination","node","features",".","aggregate",":","str",",","callable",",","optional","Method","for","aggregating","node","features","generated","by","different","relations",".","Allowed","string","values","are","'sum","'",",","'max","'",",","'min","'",",","'mean","'",",","'stack","'",".","The","'stack","'","aggregation","is","performed","along","the","second","dimension",",","whose","order","is","deterministic",".","User","can","also","customize","the","aggregator","by","providing","a","callable","instance",".","For","example",",","aggregation","by","summation","is","equivalent","to","the","follows",":","..","code",":",":","def","my_agg_func","(","tensors",",","dsttype",")",":","#","tensors",":","is","a","list","of","tensors","to","aggregate","#","dsttype",":","string","name","of","the","destination","node","type","for","which","the","#","aggregation","is","performed","stacked","=","torch.stack","(","tensors",",","dim=0",")","return","torch.sum","(","stacked",",","dim=0",")","Attributes","--","--","--","--","--","mods",":","dict","[","str",",","nn.Module","]","Modules","associated","with","every","edge","types","."]
code: def __init__(self, mods, aggregate="sum"):
      super(HeteroGraphConv, self).__init__()
      self.mod_dict = mods
      mods = {str(k): v for k, v in mods.items()}
      # Register as child modules
      self.mods = nn.ModuleDict(mods)
      # PyTorch ModuleDict doesn't have get() method, so I have to store two
      # dictionaries so that I can index with both canonical edge type and
      # edge type with the get() method.
      # Do not break if graph has 0-in-degree nodes.
      # Because there is no general rule to add self-loop for heterograph.
      for _, v in self.mods.items():
          set_allow_zero_in_degree_fn = getattr(
              v, "set_allow_zero_in_degree", None
          )
          if callable(set_allow_zero_in_degree_fn):
              set_allow_zero_in_degree_fn(True)
      if isinstance(aggregate, str):
          self.agg_fn = get_aggregate_fn(aggregate)
      else:
          self.agg_fn = aggregate
  
imports: from functools import partial
  import torch
  import torch.nn
  from ...base import DGLError
label_desc: Use image node_id 1 to create a new HeteroGraphConv object from inherited base classes: nn with example: obj = HeteroGraphConv(mods, aggregate)