//  [python]
def __call__(self, inputs):
    boxes = []
    class_scores = []
    object_scores = []
    levels = list(inputs.keys())
    min_level = int(min(levels))
    max_level = int(max(levels))

    # Aggregate boxes over each scale.
    for i in range(min_level, max_level + 1):
      key = str(i)
      object_scores_, boxes_, class_scores_ = self.parse_prediction_path(
          key, inputs[key])
      boxes.append(boxes_)
      class_scores.append(class_scores_)
      object_scores.append(object_scores_)

    # Collate all predicitons.
    boxes = tf.concat(boxes, axis=1)
    object_scores = tf.concat(object_scores, axis=1)
    class_scores = tf.concat(class_scores, axis=1)

    # Get masks to threshold all the predicitons.
    object_mask = tf.cast(object_scores > self._thresh, object_scores.dtype)
    class_mask = tf.cast(class_scores > self._thresh, class_scores.dtype)

    # Apply thresholds mask to all the predictions.
    object_scores *= object_mask
    class_scores *= (tf.expand_dims(object_mask, axis=-1) * class_mask)

    # Make a copy of the original dtype.
    dtype = object_scores.dtype

    if not self._apply_nms:
      return {
          'bbox': tf.expand_dims(tf.cast(boxes, dtype=tf.float32), axis=-2),
          'classes': tf.cast(class_scores, dtype=tf.float32),
          'confidence': object_scores,
          'num_detections': self._max_boxes,
      }

    # Apply nms.
    if self._nms_version == 'greedy':
      # Greedy NMS.
      boxes, object_scores, class_scores, num_detections = (
          tf.image.combined_non_max_suppression(
              tf.expand_dims(tf.cast(boxes, dtype=tf.float32), axis=-2),
              tf.cast(class_scores, dtype=tf.float32),
              self._pre_nms_points,
              self._max_boxes,
              iou_threshold=self._nms_thresh,
              score_threshold=self._thresh,
          )
      )
    elif self._nms_version == 'v1':
      (boxes, object_scores, class_scores, num_detections, _) = (
          detection_generator._generate_detections_v1(  # pylint:disable=protected-access
              tf.expand_dims(tf.cast(boxes, dtype=tf.float32), axis=-2),
              tf.cast(class_scores, dtype=tf.float32),
              pre_nms_top_k=self._pre_nms_points,
              max_num_detections=self._max_boxes,
              nms_iou_threshold=self._nms_thresh,
              pre_nms_score_threshold=self._thresh,
          )
      )

    elif self._nms_version == 'v2' or self._nms_version == 'iou':
      (boxes, object_scores, class_scores, num_detections) = (
          detection_generator._generate_detections_v2(  # pylint:disable=protected-access
              tf.expand_dims(tf.cast(boxes, dtype=tf.float32), axis=-2),
              tf.cast(class_scores, dtype=tf.float32),
              pre_nms_top_k=self._pre_nms_points,
              max_num_detections=self._max_boxes,
              nms_iou_threshold=self._nms_thresh,
              pre_nms_score_threshold=self._thresh,
              use_class_agnostic_nms=self._use_class_agnostic_nms,
          )
      )

    # Cast the boxes and predicitons back to original datatype.
    boxes = tf.cast(boxes, dtype)
    class_scores = tf.cast(class_scores, dtype)
    object_scores = tf.cast(object_scores, dtype)

    # Format and return
    return {
        'bbox': boxes,
        'classes': class_scores,
        'confidence': object_scores,
        'num_detections': num_detections,
    }