class_docstr: Class that wraps a given `Keras` model to include graph regularization.
  
  Graph regularization is configured by an instance of
  `nsl.configs.GraphRegConfig` and the resulting loss is added as a
  regularization term to the model's training objective. The graph-regularized
  model reuses the layers and variables from the base model. So, training this
  model will also update the variables in the base model.
  
  Note: This class expects input data to include neighor features corresponding
  to the maximum number of neighbors used for graph regularization.
  
  Example usage:
  
  ```python
  # Create a base model using the sequential, functional, or subclass API.
  base_model = tf.keras.Sequential(...)
  
  # Wrap the base model to include graph regularization using up to 1 neighbor
  # per sample.
  graph_config = nsl.configs.make_graph_reg_config(max_neighbors=1)
  graph_model = nsl.keras.GraphRegularization(base_model, graph_config)
  
  # Compile, train, and evaluate the graph-regularized model as usual.
  graph_model.compile(
      optimizer='adam',
      loss=tf.keras.losses.SparseCategoricalCrossentropy(),
      metrics=['accuracy'])
  graph_model.fit(train_dataset, epochs=5)
  graph_model.evaluate(test_dataset)
  ```
docstr: Incorporates graph regularization into the loss of `base_model`.
  
  Graph regularization is done on the logits layer and only during training.
  
  Args:
    inputs: Dictionary containing sample features, neighbor features, and
      neighbor weights in the same format as described in
      `utils.unpack_neighbor_features`.
    training: Boolean tensor that indicates if we are in training mode.
    **kwargs: Additional keyword arguments to be passed to `self.base_model`.
  
  Returns:
    The output tensors for the wrapped graph-regularized model.
docstr_tok: ["Incorporates","graph","regularization","into","the","loss","of","`","base_model","`",".","Graph","regularization","is","done","on","the","logits","layer","and","only","during","training",".","Args",":","inputs",":","Dictionary","containing","sample","features",",","neighbor","features",",","and","neighbor","weights","in","the","same","format","as","described","in","`","utils.unpack_neighbor_features","`",".","training",":","Boolean","tensor","that","indicates","if","we","are","in","training","mode",".","*","*","kwargs",":","Additional","keyword","arguments","to","be","passed","to","`","self.base_model","`",".","Returns",":","The","output","tensors","for","the","wrapped","graph-regularized","model","."]
code: def call(self, inputs, training=False, **kwargs):
      """Incorporates graph regularization into the loss of `base_model`.
  
      Graph regularization is done on the logits layer and only during training.
  
      Args:
        inputs: Dictionary containing sample features, neighbor features, and
          neighbor weights in the same format as described in
          `utils.unpack_neighbor_features`.
        training: Boolean tensor that indicates if we are in training mode.
        **kwargs: Additional keyword arguments to be passed to `self.base_model`.
  
      Returns:
        The output tensors for the wrapped graph-regularized model.
      """
      # Invoke the call() function of the neighbor features layer directly instead
      # of invoking it as a callable to avoid Keras from wrapping placeholder
      # tensors with the tf.identity() op.
      (
          sample_features,
          nbr_features,
          nbr_weights,
      ) = self.nbr_features_layer.call(inputs)
      base_output = self.base_model(
          sample_features, training=training, **kwargs
      )
  
      # For evaluation and prediction, we use the base model. So, this overridden
      # call function will get invoked only for training.
      has_nbr_inputs = nbr_weights is not None and nbr_features
      if has_nbr_inputs and self.graph_reg_config.multiplier > 0:
          # Use logits for regularization.
          sample_logits = base_output
          nbr_logits = self.base_model(
              nbr_features, training=training, **kwargs
          )
          graph_loss = self.regularizer(
              sources=sample_logits,
              targets=nbr_logits,
              weights=nbr_weights,
          )
      else:
          graph_loss = tf.constant(0, dtype=tf.float32)
  
      scaled_graph_loss = self.graph_reg_config.multiplier * graph_loss
      # Note that add_metric() cannot be invoked in a control flow branch.
      self.add_metric(
          scaled_graph_loss,
          name="scaled_graph_loss",
          aggregation="mean",
      )
      self.add_loss(scaled_graph_loss)
  
      return base_output
  
file_path: neural-structured-learning/neural_structured_learning/keras/graph_regularization.py
imports: from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  import neural_structured_learning.configs
  from neural_structured_learning.keras import layers
  import tensorflow
label_desc: Use image node_id 5 for calling the GraphRegularization obj's underlying member method code with example usage: obj.call(inputs, training) and returns: base_output