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:
          src, dst = g.edges(etype=(srctype, etype, dsttype))
          norm = self.norm_dict[(srctype, etype, dsttype)]
          # TODO: CHECK HERE
          messages = norm * feat_dict[srctype][src]  # 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 = F.normalize(
              g.nodes[ntype].data["h"], dim=1, p=2
          )  # l2 normalize
          feature_dict[ntype] = h
      return feature_dict
  
file_path: cornac/cornac/models/lightgcn/lightgcn.py
imports: import torch
  import torch.nn
  import torch.nn.functional
  import dgl
  import dgl.function
label_desc: Use image node_id 2 for calling the GCNLayer obj's underlying member method code with example usage: obj.forward(g, feat_dict) and returns: feature_dict