'Computes scalar RPN loss tensors.
Uses self._proposal_target_assigner to obtain regression and classification
targets for the first stage RPN, samples a "minibatch" of anchors to
participate in the loss computation, and returns the RPN losses.
Args:
rpn_box_encodings: A 4-D float tensor of shape
[batch_size, num_anchors, self._box_coder.code_size] containing
predicted proposal box encodings.
rpn_objectness_predictions_with_background: A 2-D float tensor of shape
[batch_size, num_anchors, 2] containing objectness predictions
(logits) for each of the anchors with 0 corresponding to background
and 1 corresponding to object.
anchors: A 2-D tensor of shape [num_anchors, 4] representing anchors
for the first stage RPN.  Note that `num_anchors` can differ depending
on whether the model is created in training or inference mode.
groundtruth_boxlists: A list of BoxLists containing coordinates of the
groundtruth boxes.
groundtruth_classes_with_background_list: A list of 2-D one-hot
(or k-hot) tensors of shape [num_boxes, num_classes+1] containing the
class targets with the 0th index assumed to map to the background class.
Returns:
a dictionary mapping loss keys (`first_stage_localization_loss`,
`first_stage_objectness_loss`) to scalar tensors representing
corresponding loss values.'

def _loss_rpn(self, rpn_box_encodings, rpn_objectness_predictions_with_background, anchors, groundtruth_boxlists, groundtruth_classes_with_background_list):

    with tf.name_scope('RPNLoss'):
        (batch_cls_targets, batch_cls_weights, batch_reg_targets, batch_reg_weights, _) = target_assigner.batch_assign_targets(self._proposal_target_assigner, box_list.BoxList(anchors), groundtruth_boxlists, (len(groundtruth_boxlists) * [None]))
        batch_cls_targets = tf.squeeze(batch_cls_targets, axis=2)
        def _minibatch_subsample_fn(inputs):
            (cls_targets, cls_weights) = inputs
            return self._first_stage_sampler.subsample(tf.cast(cls_weights, tf.bool), self._first_stage_minibatch_size, tf.cast(cls_targets, tf.bool))
        batch_sampled_indices = tf.to_float(tf.map_fn(_minibatch_subsample_fn, [batch_cls_targets, batch_cls_weights], dtype=tf.bool, parallel_iterations=self._parallel_iterations, back_prop=True))
        normalizer = tf.reduce_sum(batch_sampled_indices, axis=1)
        batch_one_hot_targets = tf.one_hot(tf.to_int32(batch_cls_targets), depth=2)
        sampled_reg_indices = tf.multiply(batch_sampled_indices, batch_reg_weights)
        localization_losses = self._first_stage_localization_loss(rpn_box_encodings, batch_reg_targets, weights=sampled_reg_indices)
        objectness_losses = self._first_stage_objectness_loss(rpn_objectness_predictions_with_background, batch_one_hot_targets, weights=batch_sampled_indices)
        localization_loss = tf.reduce_mean((tf.reduce_sum(localization_losses, axis=1) / normalizer))
        objectness_loss = tf.reduce_mean((tf.reduce_sum(objectness_losses, axis=1) / normalizer))
        loss_dict = {'first_stage_localization_loss': (self._first_stage_loc_loss_weight * localization_loss), 'first_stage_objectness_loss': (self._first_stage_obj_loss_weight * objectness_loss)}
    return loss_dict
