Spaces:
Runtime error
Runtime error
| # coding=utf-8 | |
| # Copyright 2021 The Deeplab2 Authors. | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| """Tests for the COCO Instance AP metric.""" | |
| from absl import logging | |
| import numpy as np | |
| import tensorflow as tf | |
| from deeplab2.evaluation import coco_instance_ap | |
| from deeplab2.evaluation import test_utils | |
| # See the definition of the color names at: | |
| # https://en.wikipedia.org/wiki/Web_colors. | |
| _CLASS_COLOR_MAP = { | |
| (0, 0, 0): 0, | |
| (0, 0, 255): 1, # Person (blue). | |
| (255, 0, 0): 2, # Bear (red). | |
| (0, 255, 0): 3, # Tree (lime). | |
| (255, 0, 255): 4, # Bird (fuchsia). | |
| (0, 255, 255): 5, # Sky (aqua). | |
| (255, 255, 0): 6, # Cat (yellow). | |
| } | |
| def combine_maps(semantic_map, instance_map, label_divisor): | |
| combined_map = instance_map + semantic_map * label_divisor | |
| return tf.cast(combined_map, tf.int32) | |
| class CocoInstanceApTest(tf.test.TestCase): | |
| def test_evaluates_single_image(self): | |
| groundtruth_boxes = [ | |
| [0.25, 0.4, 0.75, 1.0], | |
| ] | |
| groundtruth_classes = [8] | |
| groundtruth_masks = [[ | |
| [0, 0, 0, 0, 0], | |
| [0, 0, 1, 1, 0], | |
| [0, 0, 1, 1, 1], | |
| [0, 0, 0, 0, 0], | |
| ]] | |
| groundtruth_is_crowd = [False] | |
| detection_masks = [[ | |
| [0, 0, 0, 0, 0], | |
| [0, 0, 1, 1, 0], | |
| [0, 0, 1, 1, 0], | |
| [0, 0, 0, 0, 0], | |
| ]] | |
| detection_scores = [0.8] | |
| detection_classes = [8] | |
| groundtruth_boxes = tf.constant(groundtruth_boxes, dtype=tf.float32) | |
| groundtruth_classes = tf.constant(groundtruth_classes, dtype=tf.int32) | |
| groundtruth_masks = tf.constant(groundtruth_masks, dtype=tf.uint8) | |
| groundtruth_is_crowd = tf.constant(groundtruth_is_crowd, dtype=tf.bool) | |
| detection_masks = tf.constant(detection_masks, dtype=tf.uint8) | |
| detection_scores = tf.constant(detection_scores, dtype=tf.float32) | |
| detection_classes = tf.constant(detection_classes, dtype=tf.int32) | |
| metric_obj = coco_instance_ap.InstanceAveragePrecision() | |
| metric_obj.update_state(groundtruth_boxes, groundtruth_classes, | |
| groundtruth_masks, groundtruth_is_crowd, | |
| detection_masks, detection_scores, | |
| detection_classes) | |
| result = metric_obj.result().numpy() | |
| # The IoU for the foreground match is 0.8. So it is a TP for 7/10 of the IoU | |
| # thresholds. | |
| expected_result = [0.7, 1, 1, 0.7, -1, -1, 0.7, 0.7, 0.7, 0.7, -1, -1] | |
| np.testing.assert_array_almost_equal(result, expected_result) | |
| class PanopticInstanceApTest(tf.test.TestCase): | |
| def test_evaluates_single_image(self): | |
| num_classes = 3 | |
| things_list = [1, 2] | |
| label_divisor = 256 | |
| ignore_label = 0 | |
| instance_class_map = { | |
| 0: 0, | |
| 47: 1, | |
| 97: 1, | |
| 133: 1, | |
| 150: 1, | |
| 174: 1, | |
| 198: 2, | |
| 215: 1, | |
| 244: 1, | |
| 255: 1, | |
| } | |
| gt_instances, gt_classes = test_utils.panoptic_segmentation_with_class_map( | |
| 'team_gt_instance.png', instance_class_map) | |
| gt_panoptic = combine_maps(gt_classes, gt_instances, label_divisor) | |
| pred_classes = test_utils.read_segmentation_with_rgb_color_map( | |
| 'team_pred_class.png', _CLASS_COLOR_MAP) | |
| pred_instances = test_utils.read_test_image( | |
| 'team_pred_instance.png', image_format='L') | |
| pred_panoptic = combine_maps(pred_classes, pred_instances, label_divisor) | |
| semantic_probability = tf.ones( | |
| tf.concat([tf.shape(pred_panoptic), [num_classes]], 0)) | |
| instance_score_map = tf.ones(tf.shape(pred_panoptic)) | |
| metric_obj = coco_instance_ap.PanopticInstanceAveragePrecision( | |
| num_classes, things_list, label_divisor, ignore_label) | |
| metric_obj.update_state(gt_panoptic, pred_panoptic, semantic_probability, | |
| instance_score_map) | |
| result = metric_obj.result().numpy() | |
| logging.info('result = %s', result) | |
| expected_result = [ | |
| 0.2549, 0.9356, 0.1215, -1.0, 0.2399, 0.501, 0.0812, 0.2688, 0.2688, | |
| -1.0, 0.2583, 0.5 | |
| ] | |
| np.testing.assert_almost_equal(result, expected_result, decimal=4) | |
| def test_evaluates_with_scores(self): | |
| num_classes = 3 | |
| things_list = list(range(num_classes)) | |
| label_divisor = 256 | |
| ignore_label = 0 | |
| gt_classes = tf.constant([ | |
| [1, 1, 2, 2], | |
| [1, 1, 2, 2], | |
| [0, 0, 2, 2], | |
| [0, 0, 2, 2], | |
| ], tf.int32) | |
| pred_classes = tf.constant([ | |
| [1, 1, 1, 1], | |
| [1, 1, 1, 1], | |
| [0, 0, 2, 2], | |
| [0, 0, 2, 2], | |
| ], tf.int32) | |
| instances = tf.constant([ | |
| [1, 1, 2, 2], | |
| [1, 1, 2, 2], | |
| [0, 0, 3, 3], | |
| [0, 0, 3, 3], | |
| ], tf.int32) | |
| gt_panoptic = combine_maps(gt_classes, instances, label_divisor) | |
| pred_panoptic = combine_maps(pred_classes, instances, label_divisor) | |
| semantic_probability = tf.constant([ | |
| [ | |
| [0, 0, 0, 0], | |
| [0, 0, 0, 0], | |
| [1, 1, 0, 0], | |
| [1, 1, 0, 0], | |
| ], | |
| [ | |
| [1, 1, 1, 1], | |
| [1, 1, 1, 1], | |
| [0, 0, 0, 0], | |
| [0, 0, 0, 0], | |
| ], | |
| [ | |
| [0, 0, 0, 0], | |
| [0, 0, 0, 0], | |
| [0, 0, 1, 1], | |
| [0, 0, 1, 1], | |
| ], | |
| ], tf.float32) | |
| semantic_probability = tf.transpose(semantic_probability, [1, 2, 0]) | |
| # This score map gives higher score to the incorrect instance. | |
| bad_instance_scores = tf.constant([ | |
| [0.4, 0.4, 0.9, 0.9], | |
| [0.4, 0.4, 0.9, 0.9], | |
| [0.0, 0.0, 0.8, 0.8], | |
| [0.0, 0.0, 0.8, 0.8], | |
| ], tf.float32) | |
| metric_obj = coco_instance_ap.PanopticInstanceAveragePrecision( | |
| num_classes, things_list, label_divisor, ignore_label) | |
| metric_obj.update_state(gt_panoptic, pred_panoptic, semantic_probability, | |
| bad_instance_scores) | |
| bad_result = metric_obj.result().numpy() | |
| logging.info('bad_result = %s', bad_result) | |
| expected_bad_result = [ | |
| 0.5025, 0.5025, 0.5025, 0.5025, -1., -1., 0.25, 0.75, 0.75, 0.75, -1., | |
| -1. | |
| ] | |
| np.testing.assert_almost_equal(bad_result, expected_bad_result, decimal=4) | |
| # This score map gives lower score to the incorrect instance. | |
| good_instance_scores = tf.constant([ | |
| [0.9, 0.9, 0.4, 0.4], | |
| [0.9, 0.9, 0.4, 0.4], | |
| [0.0, 0.0, 0.8, 0.8], | |
| [0.0, 0.0, 0.8, 0.8], | |
| ], tf.float32) | |
| metric_obj.reset_states() | |
| metric_obj.update_state(gt_panoptic, pred_panoptic, semantic_probability, | |
| good_instance_scores) | |
| good_result = metric_obj.result().numpy() | |
| logging.info('good_result = %s', good_result) | |
| # Since the correct instance(s) have higher score, the "good" scores should | |
| # give a result with higher AP. | |
| expected_good_result = [ | |
| 0.75248, 0.75248, 0.75248, 0.75248, -1, -1, 0.75, 0.75, 0.75, 0.75, -1, | |
| -1 | |
| ] | |
| np.testing.assert_almost_equal(good_result, expected_good_result, decimal=4) | |
| def test_ignores_crowds(self): | |
| num_classes = 3 | |
| things_list = list(range(num_classes)) | |
| label_divisor = 256 | |
| ignore_label = 0 | |
| gt_classes = tf.constant([ | |
| [1, 1, 2, 2], | |
| [1, 1, 2, 2], | |
| [0, 0, 2, 2], | |
| [0, 0, 2, 2], | |
| ], tf.int32) | |
| pred_classes = tf.constant([ | |
| [1, 1, 1, 1], | |
| [1, 1, 1, 1], | |
| [0, 0, 2, 2], | |
| [0, 0, 2, 2], | |
| ], tf.int32) | |
| instances = tf.constant([ | |
| [1, 1, 2, 2], | |
| [1, 1, 2, 2], | |
| [0, 0, 3, 3], | |
| [0, 0, 3, 3], | |
| ], tf.int32) | |
| is_crowd_map = tf.math.equal(instances, 2) | |
| gt_panoptic = combine_maps(gt_classes, instances, label_divisor) | |
| pred_panoptic = combine_maps(pred_classes, instances, label_divisor) | |
| semantic_probability = tf.ones( | |
| tf.concat([tf.shape(pred_panoptic), [num_classes]], 0)) | |
| instance_score_map = tf.ones(tf.shape(pred_panoptic)) | |
| metric_obj = coco_instance_ap.PanopticInstanceAveragePrecision( | |
| num_classes, things_list, label_divisor, ignore_label) | |
| metric_obj.update_state(gt_panoptic, pred_panoptic, semantic_probability, | |
| instance_score_map, is_crowd_map) | |
| result = metric_obj.result().numpy() | |
| logging.info('result = %s', result) | |
| # Expect perfect results (for the quantities that have an AP value), because | |
| # the only mistake is a "crowd" instance. | |
| expected_result = [1., 1., 1., 1., -1., -1., 1., 1., 1., 1., -1., -1.] | |
| np.testing.assert_almost_equal(result, expected_result, decimal=4) | |
| def test_ignores_stuff(self): | |
| num_classes = 4 | |
| things_list = [3] | |
| label_divisor = 256 | |
| ignore_label = 0 | |
| gt_classes = tf.constant([ | |
| [3, 3, 2, 2], | |
| [3, 3, 2, 2], | |
| [0, 0, 2, 2], | |
| [0, 0, 2, 2], | |
| ], tf.int32) | |
| pred_classes = tf.constant([ | |
| [3, 3, 1, 1], | |
| [3, 3, 1, 1], | |
| [0, 0, 2, 2], | |
| [0, 0, 2, 2], | |
| ], tf.int32) | |
| instances = tf.constant([ | |
| [1, 1, 2, 2], | |
| [1, 1, 2, 2], | |
| [0, 0, 3, 3], | |
| [0, 0, 3, 3], | |
| ], tf.int32) | |
| gt_panoptic = combine_maps(gt_classes, instances, label_divisor) | |
| pred_panoptic = combine_maps(pred_classes, instances, label_divisor) | |
| semantic_probability = tf.ones( | |
| tf.concat([tf.shape(pred_panoptic), [num_classes]], 0)) | |
| instance_score_map = tf.ones(tf.shape(pred_panoptic)) | |
| metric_obj = coco_instance_ap.PanopticInstanceAveragePrecision( | |
| num_classes, things_list, label_divisor, ignore_label) | |
| metric_obj.update_state(gt_panoptic, pred_panoptic, semantic_probability, | |
| instance_score_map) | |
| result = metric_obj.result().numpy() | |
| logging.info('result = %s', result) | |
| # Expect perfect results (for the quantities that have an AP value), because | |
| # the mistakes are all in "stuff" classes. | |
| expected_result = [1., 1., 1., 1., -1., -1., 1., 1., 1., 1., -1., -1.] | |
| np.testing.assert_almost_equal(result, expected_result, decimal=4) | |
| if __name__ == '__main__': | |
| tf.test.main() | |