class_docstr: Bi-linear decoder.
  
  Given a bipartite graph G, for each edge (i, j) ~ G, compute the likelihood
  of it being class r by:
  
  .. math::
      p(M_{ij}=r) = \text{softmax}(u_i^TQ_rv_j)
  
  The trainable parameter :math:`Q_r` is further decomposed to a linear
  combination of basis weight matrices :math:`P_s`:
  
  .. math::
      Q_r = \sum_{s=1}^{b} a_{rs}P_s
  
  Parameters
  ----------
  in_units : int
      Size of input user and movie features
  num_classes : int
      Number of classes.
  num_basis : int, optional
      Number of basis. (Default: 2)
  dropout_rate : float, optional
      Dropout raite (Default: 0.0)
class_docstr_tok: ["Bi-linear","decoder",".","Given","a","bipartite","graph","G",",","for","each","edge","(","i",",","j",")","~","G",",","compute","the","likelihood","of","it","being","class","r","by",":","..","math",":",":","p","(","M_","{","ij","}","=r",")","=","\\text","{","softmax","}","(","u_i^TQ_rv_j",")","The","trainable","parameter",":","math",":","`","Q_r","`","is","further","decomposed","to","a","linear","combination","of","basis","weight","matrices",":","math",":","`","P_s","`",":","..","math",":",":","Q_r","=","\\sum_","{","s=1","}","^","{","b","}","a_","{","rs","}","P_s","Parameters","--","--","--","--","--","in_units",":","int","Size","of","input","user","and","movie","features","num_classes",":","int","Number","of","classes",".","num_basis",":","int",",","optional","Number","of","basis",".","(","Default",":","2",")","dropout_rate",":","float",",","optional","Dropout","raite","(","Default",":","0.0",")"]
docstr: Forward function.
  
  Parameters
  ----------
  graph : DGLGraph
      "Flattened" user-movie graph with only one edge type.
  ufeat : th.Tensor
      User embeddings. Shape: (|V_u|, D)
  ifeat : th.Tensor
      Movie embeddings. Shape: (|V_m|, D)
  
  Returns
  -------
  th.Tensor
      Predicting scores for each user-movie edge.
docstr_tok: ["Forward","function",".","Parameters","--","--","--","--","--","graph",":","DGLGraph","``","Flattened","''","user-movie","graph","with","only","one","edge","type",".","ufeat",":","th.Tensor","User","embeddings",".","Shape",":","(","|V_u|",",","D",")","ifeat",":","th.Tensor","Movie","embeddings",".","Shape",":","(","|V_m|",",","D",")","Returns","--","--","--","-","th.Tensor","Predicting","scores","for","each","user-movie","edge","."]
code: def forward(self, graph, ufeat, ifeat):
      """Forward function.
  
      Parameters
      ----------
      graph : DGLGraph
          "Flattened" user-movie graph with only one edge type.
      ufeat : th.Tensor
          User embeddings. Shape: (|V_u|, D)
      ifeat : th.Tensor
          Movie embeddings. Shape: (|V_m|, D)
  
      Returns
      -------
      th.Tensor
          Predicting scores for each user-movie edge.
      """
      with graph.local_scope():
          ufeat = self.dropout(ufeat)
          ifeat = self.dropout(ifeat)
          graph.nodes["movie"].data["h"] = ifeat
          basis_out = []
          for i in range(self._num_basis):
              graph.nodes["user"].data["h"] = ufeat @ self.Ps[i]
              graph.apply_edges(fn.u_dot_v("h", "h", "sr"))
              basis_out.append(graph.edata["sr"])
          out = th.cat(basis_out, dim=1)
          out = self.combine_basis(out)
      return out
  
imports: import dgl.function
  import dgl.nn.pytorch
  import torch
  import torch.nn
  from torch.nn import init
  from utils import get_activation, to_etype_name
label_desc: Use image node_id 3 for calling the BiDecoder obj's underlying member method code with example usage: obj.forward(graph, ufeat, ifeat) and returns: out