class_docstr: GCMC is a model that incorporate graph autoencoders for recommendation.
  
  Graph autoencoders are comprised of:
  
  1) a graph encoder model :math:`Z = f(X; A)`, which take as input an :math:`N \times D` feature matrix X and
  a graph adjacency matrix A, and produce an :math:`N \times E` node embedding matrix
  :math:`Z = [z_1^T,..., z_N^T ]^T`;
  
  2) a pairwise decoder model :math:`\hat A = g(Z)`, which takes pairs of node embeddings :math:`(z_i, z_j)` and
  predicts respective entries :math:`\hat A_{ij}` in the adjacency matrix.
  
  Note that :math:`N` denotes the number of nodes, :math:`D` the number of input features,
  and :math:`E` the embedding size.
  
  We implement the model following the original author with a pairwise training mode.
class_docstr_tok: ["GCMC","is","a","model","that","incorporate","graph","autoencoders","for","recommendation",".","Graph","autoencoders","are","comprised","of",":","1",")","a","graph","encoder","model",":","math",":","`","Z","=","f","(","X",";","A",")","`",",","which","take","as","input","an",":","math",":","`","N","\\times","D","`","feature","matrix","X","and","a","graph","adjacency","matrix","A",",","and","produce","an",":","math",":","`","N","\\times","E","`","node","embedding","matrix",":","math",":","`","Z","=","[","z_1^T",",","...",",","z_N^T","]","^T","`",";","2",")","a","pairwise","decoder","model",":","math",":","`","\\hat","A","=","g","(","Z",")","`",",","which","takes","pairs","of","node","embeddings",":","math",":","`","(","z_i",",","z_j",")","`","and","predicts","respective","entries",":","math",":","`","\\hat","A_","{","ij","}","`","in","the","adjacency","matrix",".","Note","that",":","math",":","`","N","`","denotes","the","number","of","nodes",",",":","math",":","`","D","`","the","number","of","input","features",",","and",":","math",":","`","E","`","the","embedding","size",".","We","implement","the","model","following","the","original","author","with","a","pairwise","training","mode","."]
code: def __init__(self, config, dataset):
      super(GCMC, self).__init__(config, dataset)
  
      # load dataset info
      self.num_all = self.n_users + self.n_items
      self.interaction_matrix = dataset.inter_matrix(form="coo").astype(
          np.float32
      )  # csr
  
      # load parameters info
      self.dropout_prob = config["dropout_prob"]
      self.sparse_feature = config["sparse_feature"]
      self.gcn_output_dim = config["gcn_output_dim"]
      self.dense_output_dim = config["embedding_size"]
      self.n_class = config["class_num"]
      self.num_basis_functions = config["num_basis_functions"]
  
      # generate node feature
      if self.sparse_feature:
          features = self.get_sparse_eye_mat(self.num_all)
          i = features._indices()
          v = features._values()
          self.user_features = torch.sparse.FloatTensor(
              i[:, : self.n_users],
              v[: self.n_users],
              torch.Size([self.n_users, self.num_all]),
          ).to(self.device)
          item_i = i[:, self.n_users :]
          item_i[0, :] = item_i[0, :] - self.n_users
          self.item_features = torch.sparse.FloatTensor(
              item_i,
              v[self.n_users :],
              torch.Size([self.n_items, self.num_all]),
          ).to(self.device)
      else:
          features = torch.eye(self.num_all).to(self.device)
          self.user_features, self.item_features = torch.split(
              features, [self.n_users, self.n_items]
          )
      self.input_dim = self.user_features.shape[1]
  
      # adj matrices for each relation are stored in self.support
      self.Graph = self.get_norm_adj_mat().to(self.device)
      self.support = [self.Graph]
  
      # accumulation operation
      self.accum = config["accum"]
      if self.accum == "stack":
          div = self.gcn_output_dim // len(self.support)
          if self.gcn_output_dim % len(self.support) != 0:
              self.logger.warning(
                  "HIDDEN[0] (=%d) of stack layer is adjusted to %d (in %d splits)."
                  % (
                      self.gcn_output_dim,
                      len(self.support) * div,
                      len(self.support),
                  )
              )
          self.gcn_output_dim = len(self.support) * div
  
      # define layers and loss
      self.GcEncoder = GcEncoder(
          accum=self.accum,
          num_user=self.n_users,
          num_item=self.n_items,
          support=self.support,
          input_dim=self.input_dim,
          gcn_output_dim=self.gcn_output_dim,
          dense_output_dim=self.dense_output_dim,
          drop_prob=self.dropout_prob,
          device=self.device,
          sparse_feature=self.sparse_feature,
      ).to(self.device)
      self.BiDecoder = BiDecoder(
          input_dim=self.dense_output_dim,
          output_dim=self.n_class,
          drop_prob=0.0,
          device=self.device,
          num_weights=self.num_basis_functions,
      ).to(self.device)
      self.loss_function = nn.CrossEntropyLoss()
  
imports: import math
  import numpy
  import scipy.sparse
  import torch
  import torch.nn
  from recbole.model.abstract_recommender import GeneralRecommender
  from recbole.model.layers import SparseDropout
  from recbole.utils import InputType
label_desc: Use image node_id 1 to create a new GCMC object from inherited base classes: GeneralRecommender with example: obj = GCMC(config, dataset)