code: def NDCG(pos_mask, pred, excl_mask, at=[100]):
      def _map_fn(tups):
          user_pos_mask, user_pred, user_excl_mask = tups
          user_pred = tf.math.exp(user_pred) * tf.cast(
              tf.math.logical_not(user_excl_mask), tf.float32
          )
          pos_pred = user_pred[user_pos_mask]
          rank_above = tf.math.count_nonzero(
              user_pred > tf.reshape(pos_pred, (-1, 1)),
              axis=1,
              dtype=tf.float32,
          )
          rank_above = tf.tile(
              tf.expand_dims(rank_above, 0), [len(at), 1]
          )
          tf_at = tf.reshape(tf.constant(at, dtype=tf.float32), [-1, 1])
          log_recipr = tf.math.reciprocal(_log2(rank_above + 2))
  
          user_ndcg = tf.reduce_sum(
              log_recipr * tf.cast(rank_above < tf_at, tf.float32),
              axis=1,
          )
  
          return user_ndcg
  
      ndcg = tf.map_fn(
          _map_fn,
          (pos_mask, pred, excl_mask),
          parallel_iterations=10,
          dtype=tf.float32,
      )
  
      return ndcg
  
imports: import tensorflow
  import numpy
label_desc: Use image node_id 3 for calling a global function with example usage: NDCG(pos_mask, pred, excl_mask, at) and returns: ndcg, user_ndcg