code: def graph_log_likelihood(batch_adj, wys_output):
      """
      Computes the graph log likelihood loss function as in https://arxiv.org/abs/1710.09599.
  
      This is different to most Keras loss functions in that it doesn't directly compare predicted values to expected
      values. It uses `wys_output` which contains the dot products of embeddings and expected random walks,
      and part of the adjacency matrix `batch_adj` to calculate how well the node embeddings capture the graph
      structure in some sense.
  
      .. seealso: The :class:`.WatchYourStep` model, for which this loss function is designed.
  
      Args:
          batch_adj: tensor with shape ``batch_rows x 1 x num_nodes`` containing rows of the adjacency matrix
          wys_output: tensor with shape ``batch_rows x 2 x num_nodes`` containing the embedding outer product
              scores with shape ``batch_rows x 1 x num_nodes`` and attentive expected random walk
              with shape ``batch_rows x 1, num_nodes`` concatenated.
      Returns:
          the graph log likelihood loss for the batch
      """
  
      expected_walks = tf.gather(wys_output, [0], axis=1)
      scores = tf.gather(wys_output, [1], axis=1)
  
      adj_mask = tf.cast((batch_adj == 0), "float32")
  
      log_sigmoid = tf.math.log_sigmoid(scores)
      log1m_sigmoid = (
          log_sigmoid - scores
      )  # log(1 - σ(scores)), simplified
      matrix = -expected_walks * log_sigmoid - adj_mask * log1m_sigmoid
      loss = tf.math.reduce_sum(tf.abs(matrix))
  
      return tf.expand_dims(loss, 0)
  
imports: import tensorflow
  from .core.experimental import experimental
label_desc: Use image node_id 1 for calling a global function with example usage: graph_log_likelihood(batch_adj, wys_output) and returns: tf