'Computes localization and classification losses after hard mining.
Args:
location_losses: a float tensor of shape [num_images, num_anchors]
representing anchorwise localization losses.
cls_losses: a float tensor of shape [num_images, num_anchors]
representing anchorwise classification losses.
decoded_boxlist_list: a list of decoded BoxList representing location
predictions for each image.
match_list: an optional list of matcher.Match objects encoding the match
between anchors and groundtruth boxes for each image of the batch,
with rows of the Match objects corresponding to groundtruth boxes
and columns corresponding to anchors.  Match objects in match_list are
used to reference which anchors are positive, negative or ignored.  If
self._max_negatives_per_positive exists, these are then used to enforce
a prespecified negative to positive ratio.
Returns:
mined_location_loss: a float scalar with sum of localization losses from
selected hard examples.
mined_cls_loss: a float scalar with sum of classification losses from
selected hard examples.
Raises:
ValueError: if location_losses, cls_losses and decoded_boxlist_list do
not have compatible shapes (i.e., they must correspond to the same
number of images).
ValueError: if match_list is specified but its length does not match
len(decoded_boxlist_list).'

def __call__(self, location_losses, cls_losses, decoded_boxlist_list, match_list=None):

    mined_location_losses = []
    mined_cls_losses = []
    location_losses = tf.unstack(location_losses)
    cls_losses = tf.unstack(cls_losses)
    num_images = len(decoded_boxlist_list)
    if (not match_list):
        match_list = (num_images * [None])
    if (not (len(location_losses) == len(decoded_boxlist_list) == len(cls_losses))):
        raise ValueError('location_losses,    cls_losses    and    decoded_boxlist_list    do    not    have    compatible    shapes.')
    if (not isinstance(match_list, list)):
        raise ValueError('match_list    must    be    a    list.')
    if (len(match_list) != len(decoded_boxlist_list)):
        raise ValueError('match_list    must    either    be    None    or    have    length=len(decoded_boxlist_list).')
    num_positives_list = []
    num_negatives_list = []
    for (ind, detection_boxlist) in enumerate(decoded_boxlist_list):
        box_locations = detection_boxlist.get()
        match = match_list[ind]
        image_losses = cls_losses[ind]
        if (self._loss_type == 'loc'):
            image_losses = location_losses[ind]
        elif (self._loss_type == 'both'):
            image_losses *= self._cls_loss_weight
            image_losses += (location_losses[ind] * self._loc_loss_weight)
        if (self._num_hard_examples is not None):
            num_hard_examples = self._num_hard_examples
        else:
            num_hard_examples = detection_boxlist.num_boxes()
        selected_indices = tf.image.non_max_suppression(box_locations, image_losses, num_hard_examples, self._iou_threshold)
        if ((self._max_negatives_per_positive is not None) and match):
            (selected_indices, num_positives, num_negatives) = self._subsample_selection_to_desired_neg_pos_ratio(selected_indices, match, self._max_negatives_per_positive, self._min_negatives_per_image)
            num_positives_list.append(num_positives)
            num_negatives_list.append(num_negatives)
        mined_location_losses.append(tf.reduce_sum(tf.gather(location_losses[ind], selected_indices)))
        mined_cls_losses.append(tf.reduce_sum(tf.gather(cls_losses[ind], selected_indices)))
    location_loss = tf.reduce_sum(tf.stack(mined_location_losses))
    cls_loss = tf.reduce_sum(tf.stack(mined_cls_losses))
    if (match and self._max_negatives_per_positive):
        self._num_positives_list = num_positives_list
        self._num_negatives_list = num_negatives_list
    return (location_loss, cls_loss)
