def _generate_detections_v2(boxes: tf.Tensor, scores: tf.Tensor, pre_nms_top_k: int=5000, pre_nms_score_threshold: float=0.05, nms_iou_threshold: float=0.5, max_num_detections: int=100):
    'Generates the final detections given the model outputs.\n\n  This implementation unrolls classes dimension while using the tf.while_loop\n  to implement the batched NMS, so that it can be parallelized at the batch\n  dimension. It should give better performance comparing to v1 implementation.\n  It is TPU compatible.\n\n  Args:\n    boxes: A `tf.Tensor` with shape `[batch_size, N, num_classes, 4]` or\n      `[batch_size, N, 1, 4]`, which box predictions on all feature levels. The\n      N is the number of total anchors on all levels.\n    scores: A `tf.Tensor` with shape `[batch_size, N, num_classes]`, which\n      stacks class probability on all feature levels. The N is the number of\n      total anchors on all levels. The num_classes is the number of classes\n      predicted by the model. Note that the class_outputs here is the raw score.\n    pre_nms_top_k: An `int` number of top candidate detections per class before\n      NMS.\n    pre_nms_score_threshold: A `float` representing the threshold for deciding\n      when to remove boxes based on score.\n    nms_iou_threshold: A `float` representing the threshold for deciding whether\n      boxes overlap too much with respect to IOU.\n    max_num_detections: A `scalar` representing maximum number of boxes retained\n      over all classes.\n\n  Returns:\n    nms_boxes: A `float` tf.Tensor of shape [batch_size, max_num_detections, 4]\n      representing top detected boxes in [y1, x1, y2, x2].\n    nms_scores: A `float` tf.Tensor of shape [batch_size, max_num_detections]\n      representing sorted confidence scores for detected boxes. The values are\n      between [0, 1].\n    nms_classes: An `int` tf.Tensor of shape [batch_size, max_num_detections]\n      representing classes for detected boxes.\n    valid_detections: An `int` tf.Tensor of shape [batch_size] only the top\n      `valid_detections` boxes are valid detections.\n  '
    with tf.name_scope('generate_detections'):
        nmsed_boxes = []
        nmsed_classes = []
        nmsed_scores = []
        valid_detections = []
        (batch_size, _, num_classes_for_box, _) = boxes.get_shape().as_list()
        if (batch_size is None):
            batch_size = tf.shape(boxes)[0]
        (_, total_anchors, num_classes) = scores.get_shape().as_list()
        (scores, indices) = _select_top_k_scores(scores, min(total_anchors, pre_nms_top_k))
        for i in range(num_classes):
            boxes_i = boxes[:, :, min((num_classes_for_box - 1), i), :]
            scores_i = scores[:, :, i]
            boxes_i = tf.gather(boxes_i, indices[:, :, i], batch_dims=1, axis=1)
            (boxes_i, scores_i) = box_ops.filter_boxes_by_scores(boxes_i, scores_i, min_score_threshold=pre_nms_score_threshold)
            (nmsed_scores_i, nmsed_boxes_i) = nms.sorted_non_max_suppression_padded(tf.cast(scores_i, tf.float32), tf.cast(boxes_i, tf.float32), max_num_detections, iou_threshold=nms_iou_threshold)
            nmsed_classes_i = tf.fill([batch_size, max_num_detections], i)
            nmsed_boxes.append(nmsed_boxes_i)
            nmsed_scores.append(nmsed_scores_i)
            nmsed_classes.append(nmsed_classes_i)
    nmsed_boxes = tf.concat(nmsed_boxes, axis=1)
    nmsed_scores = tf.concat(nmsed_scores, axis=1)
    nmsed_classes = tf.concat(nmsed_classes, axis=1)
    (nmsed_scores, indices) = tf.nn.top_k(nmsed_scores, k=max_num_detections, sorted=True)
    nmsed_boxes = tf.gather(nmsed_boxes, indices, batch_dims=1, axis=1)
    nmsed_classes = tf.gather(nmsed_classes, indices, batch_dims=1)
    valid_detections = tf.reduce_sum(input_tensor=tf.cast(tf.greater(nmsed_scores, (- 1)), tf.int32), axis=1)
    return (nmsed_boxes, nmsed_scores, nmsed_classes, valid_detections)
Generates the final detections given the model outputs.

This implementation unrolls classes dimension while using the tf.while_loop
to implement the batched NMS, so that it can be parallelized at the batch
dimension. It should give better performance comparing to v1 implementation.
It is TPU compatible.

Args:
  boxes: A `tf.Tensor` with shape `[batch_size, N, num_classes, 4]` or
    `[batch_size, N, 1, 4]`, which box predictions on all feature levels. The
    N is the number of total anchors on all levels.
  scores: A `tf.Tensor` with shape `[batch_size, N, num_classes]`, which
    stacks class probability on all feature levels. The N is the number of
    total anchors on all levels. The num_classes is the number of classes
    predicted by the model. Note that the class_outputs here is the raw score.
  pre_nms_top_k: An `int` number of top candidate detections per class before
    NMS.
  pre_nms_score_threshold: A `float` representing the threshold for deciding
    when to remove boxes based on score.
  nms_iou_threshold: A `float` representing the threshold for deciding whether
    boxes overlap too much with respect to IOU.
  max_num_detections: A `scalar` representing maximum number of boxes retained
    over all classes.

Returns:
  nms_boxes: A `float` tf.Tensor of shape [batch_size, max_num_detections, 4]
    representing top detected boxes in [y1, x1, y2, x2].
  nms_scores: A `float` tf.Tensor of shape [batch_size, max_num_detections]
    representing sorted confidence scores for detected boxes. The values are
    between [0, 1].
  nms_classes: An `int` tf.Tensor of shape [batch_size, max_num_detections]
    representing classes for detected boxes.
  valid_detections: An `int` tf.Tensor of shape [batch_size] only the top
    `valid_detections` boxes are valid detections.
def _generate_detections_v2(boxes: tf.Tensor, scores: tf.Tensor, pre_nms_top_k: int=5000, pre_nms_score_threshold: float=0.05, nms_iou_threshold: float=0.5, max_num_detections: int=100):
    'Generates the final detections given the model outputs.\n\n  This implementation unrolls classes dimension while using the tf.while_loop\n  to implement the batched NMS, so that it can be parallelized at the batch\n  dimension. It should give better performance comparing to v1 implementation.\n  It is TPU compatible.\n\n  Args:\n    boxes: A `tf.Tensor` with shape `[batch_size, N, num_classes, 4]` or\n      `[batch_size, N, 1, 4]`, which box predictions on all feature levels. The\n      N is the number of total anchors on all levels.\n    scores: A `tf.Tensor` with shape `[batch_size, N, num_classes]`, which\n      stacks class probability on all feature levels. The N is the number of\n      total anchors on all levels. The num_classes is the number of classes\n      predicted by the model. Note that the class_outputs here is the raw score.\n    pre_nms_top_k: An `int` number of top candidate detections per class before\n      NMS.\n    pre_nms_score_threshold: A `float` representing the threshold for deciding\n      when to remove boxes based on score.\n    nms_iou_threshold: A `float` representing the threshold for deciding whether\n      boxes overlap too much with respect to IOU.\n    max_num_detections: A `scalar` representing maximum number of boxes retained\n      over all classes.\n\n  Returns:\n    nms_boxes: A `float` tf.Tensor of shape [batch_size, max_num_detections, 4]\n      representing top detected boxes in [y1, x1, y2, x2].\n    nms_scores: A `float` tf.Tensor of shape [batch_size, max_num_detections]\n      representing sorted confidence scores for detected boxes. The values are\n      between [0, 1].\n    nms_classes: An `int` tf.Tensor of shape [batch_size, max_num_detections]\n      representing classes for detected boxes.\n    valid_detections: An `int` tf.Tensor of shape [batch_size] only the top\n      `valid_detections` boxes are valid detections.\n  '
    with tf.name_scope('generate_detections'):
        nmsed_boxes = []
        nmsed_classes = []
        nmsed_scores = []
        valid_detections = []
        (batch_size, _, num_classes_for_box, _) = boxes.get_shape().as_list()
        if (batch_size is None):
            batch_size = tf.shape(boxes)[0]
        (_, total_anchors, num_classes) = scores.get_shape().as_list()
        (scores, indices) = _select_top_k_scores(scores, min(total_anchors, pre_nms_top_k))
        for i in range(num_classes):
            boxes_i = boxes[:, :, min((num_classes_for_box - 1), i), :]
            scores_i = scores[:, :, i]
            boxes_i = tf.gather(boxes_i, indices[:, :, i], batch_dims=1, axis=1)
            (boxes_i, scores_i) = box_ops.filter_boxes_by_scores(boxes_i, scores_i, min_score_threshold=pre_nms_score_threshold)
            (nmsed_scores_i, nmsed_boxes_i) = nms.sorted_non_max_suppression_padded(tf.cast(scores_i, tf.float32), tf.cast(boxes_i, tf.float32), max_num_detections, iou_threshold=nms_iou_threshold)
            nmsed_classes_i = tf.fill([batch_size, max_num_detections], i)
            nmsed_boxes.append(nmsed_boxes_i)
            nmsed_scores.append(nmsed_scores_i)
            nmsed_classes.append(nmsed_classes_i)
    nmsed_boxes = tf.concat(nmsed_boxes, axis=1)
    nmsed_scores = tf.concat(nmsed_scores, axis=1)
    nmsed_classes = tf.concat(nmsed_classes, axis=1)
    (nmsed_scores, indices) = tf.nn.top_k(nmsed_scores, k=max_num_detections, sorted=True)
    nmsed_boxes = tf.gather(nmsed_boxes, indices, batch_dims=1, axis=1)
    nmsed_classes = tf.gather(nmsed_classes, indices, batch_dims=1)
    valid_detections = tf.reduce_sum(input_tensor=tf.cast(tf.greater(nmsed_scores, (- 1)), tf.int32), axis=1)
    return (nmsed_boxes, nmsed_scores, nmsed_classes, valid_detections)