class_docstr: Graph Convolutional Network
class_docstr_tok: ["Graph","Convolutional","Network"]
docstr: Construct a k-Nearest-Neighbor item-item semantic graph.
  
  Returns:
      Sparse tensor of the normalized item-item matrix.
docstr_tok: ["Construct","a","k-Nearest-Neighbor","item-item","semantic","graph",".","Returns",":","Sparse","tensor","of","the","normalized","item-item","matrix","."]
code: def build_adj(self, context, topk):
      r"""Construct a k-Nearest-Neighbor item-item semantic graph.
  
      Returns:
          Sparse tensor of the normalized item-item matrix.
      """
  
      # construct similarity adj matrix
      n_entities = context.shape[0]
      context_norm = context.div(
          torch.norm(context, p=2, dim=-1, keepdim=True)
      ).cpu()
      sim = torch.mm(context_norm, context_norm.transpose(1, 0))
      # knn_val: [n_entities, topk]  knn_index: [n_entities, topk]
      knn_val, knn_index = torch.topk(sim, topk, dim=-1)
      knn_val, knn_index = knn_val.to(self.device), knn_index.to(
          self.device
      )
  
      y = knn_index.reshape(-1)
      x = (
          torch.arange(0, n_entities).unsqueeze(dim=-1).to(self.device)
      )  # [n_entities, 1]
      x = x.expand(n_entities, topk).reshape(-1)
      indice = torch.cat(
          (x.unsqueeze(dim=0), y.unsqueeze(dim=0)), dim=0
      )  # [2, n_entities * topk]
      value = knn_val.reshape(-1)
      adj_sparsity = torch.sparse.FloatTensor(
          indice.data, value.data, torch.Size([n_entities, n_entities])
      ).to(self.device)
  
      # normalized laplacian adj
      rowsum = torch.sparse.sum(adj_sparsity, dim=1)
      d_inv_sqrt = torch.pow(rowsum, -0.5)
      d_mat_inv_sqrt_value = d_inv_sqrt._values()
      x = torch.arange(0, n_entities).unsqueeze(dim=0).to(self.device)
      x = x.expand(2, n_entities)
      d_mat_inv_sqrt_indice = x
      d_mat_inv_sqrt = torch.sparse.FloatTensor(
          d_mat_inv_sqrt_indice,
          d_mat_inv_sqrt_value,
          torch.Size([n_entities, n_entities]),
      )
      L_norm = torch.sparse.mm(
          torch.sparse.mm(d_mat_inv_sqrt, adj_sparsity), d_mat_inv_sqrt
      )
      return L_norm
  
imports: import numpy
  import scipy.sparse
  import torch
  import torch.nn
  import torch.nn.functional
  from recbole.model.abstract_recommender import KnowledgeRecommender
  from recbole.model.init import xavier_normal_initialization
  from recbole.model.layers import SparseDropout
  from recbole.model.loss import BPRLoss, EmbLoss
  from recbole.utils import InputType
label_desc: Use image node_id 4 for calling the GraphConv obj's underlying member method code with example usage: obj.build_adj(context, topk) and returns: L_norm