code: def forward(self, g, feat_dict):
      funcs = {}  # message and reduce functions dict
      # for each type of edges, compute messages and reduce them all
      for srctype, etype, dsttype in g.canonical_etypes:
          if srctype == dsttype:  # for self loops
              messages = self.W1(feat_dict[srctype])
              g.nodes[srctype].data[etype] = messages  # store in ndata
              funcs[(srctype, etype, dsttype)] = (
                  fn.copy_u(etype, "m"),
                  fn.sum("m", "h"),
              )  # define message and reduce functions
          else:
              src, dst = g.edges(etype=(srctype, etype, dsttype))
              norm = self.norm_dict[(srctype, etype, dsttype)]
              messages = norm * (
                  self.W1(feat_dict[srctype][src])
                  + self.W2(
                      feat_dict[srctype][src] * feat_dict[dsttype][dst]
                  )
              )  # compute messages
              g.edges[(srctype, etype, dsttype)].data[
                  etype
              ] = messages  # store in edata
              funcs[(srctype, etype, dsttype)] = (
                  fn.copy_e(etype, "m"),
                  fn.sum("m", "h"),
              )  # define message and reduce functions
  
      g.multi_update_all(
          funcs, "sum"
      )  # update all, reduce by first type-wisely then across different types
      feature_dict = {}
      for ntype in g.ntypes:
          h = self.leaky_relu(g.nodes[ntype].data["h"])  # leaky relu
          h = self.dropout(h)  # dropout
          h = F.normalize(h, dim=1, p=2)  # l2 normalize
          feature_dict[ntype] = h
      return feature_dict
  
file_path: dgl/examples/pytorch/NGCF/NGCF/model.py
imports: import dgl.function
  import torch
  import torch.nn
  import torch.nn.functional
label_desc: Use image node_id 2 for calling the NGCFLayer obj's underlying member method code with example usage: obj.forward(g, feat_dict) and returns: feature_dict