class_docstr: The GNNExplainer model from the paper:
  
  > [GNNExplainer: Generating Explanations for Graph Neural Networks](https://arxiv.org/abs/1903.03894)<br>
  > Rex Ying, Dylan Bourgeois, Jiaxuan You, Marinka Zitnik and Jure Leskovec.
  
  The model can be used to explain the predictions for a single node or for an entire
  graph. In both cases, it returns the subgraph that mostly contributes to the
  prediction.
  
  **Arguments**
  
  - `model`: tf.keras.Model to explain;
  - `n_hops`: number of hops from which the GNN aggregates info. If `None`, then the
  number is inferred from the Conv and MessagePassing layers in the model.
  - `preprocess`: a preprocessing function to transform the adjacency matrix before
  giving it as input to the GNN; this is usually the same `preprocess` function of the
  Conv or MessagePassing layers used in the GNN (e.g., `GCNConv.preprocess`).
  - `graph_level`: if True, the GNN is assumed to be for graph-level prediction and
  the explanation is computed for the whole graph (and not just a node).
  - `verbose`: if True, print info during training;
  - `learning_rate`: learning rate when training the model;
  - `a_size_coef`: coefficient to control the number of edges of the subgraph that
  contributes to the prediction;
  - `x_size_coef`: coefficient to control the number of features of the subgraph
  that contributes to the prediction;
  - `a_entropy_coef`: coefficient to control the discretization of the adjacency
  mask;
  - `x_entropy_coef`: coefficient to control the discretization of the features
  mask;
  - `laplacian_coef`: coefficient to control the graph Laplacian loss;
class_docstr_tok: ["The","GNNExplainer","model","from","the","paper",":",">","[","GNNExplainer",":","Generating","Explanations","for","Graph","Neural","Networks","]","(","https",":","\/\/arxiv.org\/abs\/1903.03894",")","<","br",">",">","Rex","Ying",",","Dylan","Bourgeois",",","Jiaxuan","You",",","Marinka","Zitnik","and","Jure","Leskovec",".","The","model","can","be","used","to","explain","the","predictions","for","a","single","node","or","for","an","entire","graph",".","In","both","cases",",","it","returns","the","subgraph","that","mostly","contributes","to","the","prediction",".","*","*","Arguments","*","*","-","`","model","`",":","tf.keras.Model","to","explain",";","-","`","n_hops","`",":","number","of","hops","from","which","the","GNN","aggregates","info",".","If","`","None","`",",","then","the","number","is","inferred","from","the","Conv","and","MessagePassing","layers","in","the","model",".","-","`","preprocess","`",":","a","preprocessing","function","to","transform","the","adjacency","matrix","before","giving","it","as","input","to","the","GNN",";","this","is","usually","the","same","`","preprocess","`","function","of","the","Conv","or","MessagePassing","layers","used","in","the","GNN","(","e.g.",",","`","GCNConv.preprocess","`",")",".","-","`","graph_level","`",":","if","True",",","the","GNN","is","assumed","to","be","for","graph-level","prediction","and","the","explanation","is","computed","for","the","whole","graph","(","and","not","just","a","node",")",".","-","`","verbose","`",":","if","True",",","print","info","during","training",";","-","`","learning_rate","`",":","learning","rate","when","training","the","model",";","-","`","a_size_coef","`",":","coefficient","to","control","the","number","of","edges","of","the","subgraph","that","contributes","to","the","prediction",";","-","`","x_size_coef","`",":","coefficient","to","control","the","number","of","features","of","the","subgraph","that","contributes","to","the","prediction",";","-","`","a_entropy_coef","`",":","coefficient","to","control","the","discretization","of","the","adjacency","mask",";","-","`","x_entropy_coef","`",":","coefficient","to","control","the","discretization","of","the","features","mask",";","-","`","laplacian_coef","`",":","coefficient","to","control","the","graph","Laplacian","loss",";"]
code: def _explainer_cleaning(self, a_mask, x_mask, node_idx, a_thresh):
      # Get the masks
      selected_adj_mask = tf.nn.sigmoid(a_mask)
      selected_feat_mask = tf.nn.sigmoid(x_mask)
  
      # convert into a binary matrix
      if self.preprocess is not None:
          comp_graph_values = tf.ones_like(self.comp_graph.values)
          self.comp_graph = tf.sparse.SparseTensor(
              self.comp_graph.indices,
              comp_graph_values,
              self.comp_graph.shape,
          )
  
      # remove the edges which value is < a_thresh
      selected_adj_mask = tf.where(
          selected_adj_mask >= a_thresh, selected_adj_mask, 0
      )
  
      selected_subgraph = tf.sparse.map_values(
          tf.multiply, self.comp_graph, selected_adj_mask
      )
  
      is_nonzero = tf.not_equal(selected_subgraph.values, 0)
      selected_subgraph = tf.sparse.retain(
          selected_subgraph, is_nonzero
      )
  
      # impose the symmetry of the adj matrix
      selected_subgraph = (
          tf.sparse.add(
              selected_subgraph, tf.sparse.transpose(selected_subgraph)
          )
          / 2
      )
  
      if not self.graph_level:
          # get the final denoised subgraph centerd in the interested node
          selected_subgraph = k_hop_sparse_subgraph(
              selected_subgraph, node_idx, self.n_hops
          )
  
      # the the top_feat relevant feature ids
      selected_features = tf.argsort(
          tf.nn.sigmoid(selected_feat_mask), direction="DESCENDING"
      )[0]
  
      return selected_subgraph, selected_features
  
file_path: spektral/spektral/models/gnn_explainer.py
imports: import networkx
  import numpy
  import tensorflow
  from scipy.sparse import csr_matrix
  from spektral.layers import MessagePassing
  from spektral.layers.convolutional.conv import Conv
  from spektral.layers.ops import dot
  from spektral.utils.sparse import sp_matrix_to_sp_tensor
label_desc: Use image node_id 5 for calling the GNNExplainer obj's underlying member method code with example usage: obj._explainer_cleaning(a_mask, x_mask, node_idx, a_thresh) and returns: selected_subgraph,  selected_features