Beispiel #1
0
    def compute_unreduced_loss(self, labels, logits):
        """See `_RankingLoss`."""
        alpha = self._params.get('alpha', 10.0)
        is_valid = utils.is_label_valid(labels)
        labels = tf.compat.v1.where(is_valid, labels, tf.zeros_like(labels))
        logits = tf.compat.v1.where(
            is_valid, logits, -1e3 * tf.ones_like(logits) +
            tf.math.reduce_min(input_tensor=logits, axis=-1, keepdims=True))

        label_sum = tf.math.reduce_sum(input_tensor=labels,
                                       axis=1,
                                       keepdims=True)

        nonzero_mask = tf.math.greater(tf.reshape(label_sum, [-1]), 0.0)
        labels = tf.compat.v1.where(nonzero_mask, labels,
                                    _EPSILON * tf.ones_like(labels))

        rr = 1. / utils.approx_ranks(logits, alpha=alpha)
        rr = tf.math.reduce_sum(input_tensor=rr * labels,
                                axis=-1,
                                keepdims=True)
        mrr = rr / tf.math.reduce_sum(
            input_tensor=labels, axis=-1, keepdims=True)
        return -mrr, tf.reshape(tf.cast(nonzero_mask, dtype=tf.float32),
                                [-1, 1])
    def compute_unreduced_loss(self, labels, logits, weights):
        """See `_RankingLoss`."""
        alpha = self._params.get('alpha')
        is_label_valid = utils.is_label_valid(labels)
        labels = tf.where(is_label_valid, labels, tf.zeros_like(labels))
        logits = tf.where(
            is_label_valid, logits, -1e3 * tf.ones_like(logits) +
            tf.reduce_min(input_tensor=logits, axis=-1, keepdims=True))

        label_sum = tf.reduce_sum(input_tensor=labels, axis=1, keepdims=True)
        if weights is None:
            weights = tf.ones_like(label_sum)
        weights = tf.squeeze(weights)

        nonzero_mask = tf.greater(tf.reshape(label_sum, [-1]), 0.0)
        labels = tf.where(nonzero_mask, labels,
                          _EPSILON * tf.ones_like(labels))
        weights = tf.where(nonzero_mask, weights, tf.zeros_like(weights))

        gains = tf.pow(2., tf.cast(labels, dtype=tf.float32)) - 1.
        ranks = utils.approx_ranks(logits, alpha=alpha)
        discounts = 1. / tf.math.log1p(ranks)
        dcg = tf.reduce_sum(input_tensor=gains * discounts, axis=-1)
        cost = -dcg * tf.squeeze(utils.inverse_max_dcg(labels))
        return cost, weights
Beispiel #3
0
  def test_approx_ranks(self):
    logits = [[1., 3., 2., 0.], [4., 2., 1.5, 3.]]
    target_ranks = [[3., 1., 2., 4.], [1., 3., 4., 2.]]

    approx_ranks = utils.approx_ranks(logits, 100.)
    with tf.compat.v1.Session() as sess:
      approx_ranks = sess.run(approx_ranks)
      self.assertAllClose(approx_ranks, target_ranks)
Beispiel #4
0
def _approx_ndcg_loss(
    labels,
    logits,
    weights=None,
    reduction=core_losses.Reduction.SUM,
    name=None,
    alpha=10.):
  """Computes ApproxNDCG loss.

  ApproxNDCG ["A general approximation framework for direct optimization of
  information retrieval measures" by Qin et al.] is a smooth approximation
  to NDCG.

  Args:
    labels: A `Tensor` of the same shape as `logits` representing graded
      relevance.
    logits: A `Tensor` with shape [batch_size, list_size]. Each value is the
      ranking score of the corresponding item.
    weights: A scalar, a `Tensor` with shape [batch_size, 1] for list-wise
      weights, or a `Tensor` with shape [batch_size, list_size] for item-wise
      weights. If None, the weight of a list in the mini-batch is set to
      the sum of the labels of the items in that list.
    reduction: One of `tf.losses.Reduction` except `NONE`. Describes how to
      reduce training loss over batch.
    name: A string used as the name for this loss.
    alpha: The exponent in the generalized sigmoid function.

  Returns:
    An op for the ApproxNDCG loss.
  """
  with ops.name_scope(name, 'approx_ndcg_loss', (labels, logits, weights)):
    is_label_valid = utils.is_label_valid(labels)
    labels = array_ops.where(is_label_valid, labels,
                             array_ops.zeros_like(labels))
    logits = array_ops.where(
        is_label_valid, logits,
        -1e3 * array_ops.ones_like(logits) + math_ops.reduce_min(
            logits, axis=-1, keepdims=True))

    label_sum = math_ops.reduce_sum(labels, 1, keepdims=True)
    if weights is None:
      weights = array_ops.ones_like(label_sum)
    weights = array_ops.squeeze(weights)

    nonzero_mask = math_ops.greater(array_ops.reshape(label_sum, [-1]), 0.0)
    labels, logits, weights = [
        array_ops.boolean_mask(x, nonzero_mask)
        for x in [labels, logits, weights]
    ]

    gains = math_ops.pow(2., math_ops.to_float(labels)) - 1.
    ranks = utils.approx_ranks(logits, alpha=alpha)
    discounts = 1. / math_ops.log1p(ranks)
    dcg = math_ops.reduce_sum(gains * discounts, -1)
    cost = -dcg * array_ops.squeeze(utils.inverse_max_dcg(labels))

    return core_losses.compute_weighted_loss(
        cost, weights=weights, reduction=reduction)
Beispiel #5
0
def compute_unreduced_loss(labels, logits):
    """See `_RankingLoss`."""
    alpha = 10.0
    is_valid = utils.is_label_valid(labels)
    labels = tf.compat.v1.where(is_valid, labels, tf.zeros_like(labels))
    logits = tf.compat.v1.where(
        is_valid, logits, -1e3 * tf.ones_like(logits) +
        tf.reduce_min(input_tensor=logits, axis=-1, keepdims=True))

    label_sum = tf.reduce_sum(input_tensor=labels, axis=1, keepdims=True)
    nonzero_mask = tf.greater(tf.reshape(label_sum, [-1]), 0.0)
    labels = tf.compat.v1.where(nonzero_mask, labels,
                                _EPSILON * tf.ones_like(labels))
    gains = tf.pow(2., tf.cast(labels, dtype=tf.float32)) - 1.
    ranks = utils.approx_ranks(logits, alpha=alpha)
    discounts = 1. / tf.math.log1p(ranks)
    dcg = tf.reduce_sum(input_tensor=gains * discounts, axis=-1, keepdims=True)
    cost = -dcg * utils.inverse_max_dcg(labels)
    return cost, tf.reshape(tf.cast(nonzero_mask, dtype=tf.float32), [-1, 1])