deanna-emery's picture
updates
93528c6
raw
history blame
10.8 kB
# Copyright 2023 The TensorFlow Authors. All Rights Reserved.
#
# 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 metrics.py."""
from absl.testing import parameterized
import tensorflow as tf, tf_keras
from official.vision.evaluation import instance_metrics
class InstanceMetricsTest(tf.test.TestCase, parameterized.TestCase):
def test_compute_coco_ap(self):
precisions = [1.0, 1.0, 0.5, 0.8, 0.4, 0.5, 0.2, 0.3]
recalls = [0.0, 0.1, 0.1, 0.5, 0.5, 0.7, 0.7, 1.0]
self.assertAllClose(
instance_metrics.COCOAveragePrecision(recalls_desc=False)(
precisions, recalls
),
0.613861,
atol=1e-4,
)
precisions.reverse()
recalls.reverse()
self.assertAllClose(
instance_metrics.COCOAveragePrecision(recalls_desc=True)(
precisions, recalls
),
0.613861,
atol=1e-4,
)
def test_compute_voc10_ap(self):
precisions = [1.0, 1.0, 0.5, 0.8, 0.4, 0.5, 0.2, 0.3]
recalls = [0.0, 0.1, 0.1, 0.5, 0.5, 0.7, 0.7, 1.0]
self.assertAllClose(
instance_metrics.VOC2010AveragePrecision(recalls_desc=False)(
precisions, recalls
),
0.61,
atol=1e-4,
)
precisions.reverse()
recalls.reverse()
self.assertAllClose(
instance_metrics.VOC2010AveragePrecision(recalls_desc=True)(
precisions, recalls
),
0.61,
atol=1e-4,
)
def test_match_detections_to_gts(self):
coco_matching_algorithm = instance_metrics.COCOMatchingAlgorithm(
iou_thresholds=(0.5, 0.85)
)
detection_is_tp, gt_is_tp = coco_matching_algorithm(
detection_to_gt_ious=tf.constant([[[0.8, 0.7, 0.95], [0.9, 0.6, 0.3]]]),
detection_classes=tf.constant([[1, 1]]),
detection_scores=tf.constant([[0.6, 0.8]]),
gt_classes=tf.constant([[1, 1, 2]]),
)
self.assertAllEqual(detection_is_tp, [[[True, False], [True, True]]])
self.assertAllEqual(
gt_is_tp, [[[True, True], [True, False], [False, False]]]
)
def test_shift_and_rescale_boxes(self):
self.assertAllClose(
instance_metrics._shift_and_rescale_boxes(
boxes=[[[2, 3, 4, 9], [15, 17, 18, 23]]], output_boundary=(20, 20)
),
[[[0.0, 0.0, 2.0, 6.0], [13.0, 14.0, 16.0, 20.0]]],
atol=1e-4,
)
self.assertAllClose(
instance_metrics._shift_and_rescale_boxes(
boxes=[[[-2, -1, 0, 5], [11, 13, 14, 19]]], output_boundary=(20, 20)
),
[[[0.0, 0.0, 2.0, 6.0], [13.0, 14.0, 16.0, 20.0]]],
atol=1e-4,
)
self.assertAllClose(
instance_metrics._shift_and_rescale_boxes(
boxes=[[[2, 3, 4, 9], [15, 17, 18, 23]]], output_boundary=(10, 10)
),
[[[0.0, 0.0, 1.0, 3.0], [6.5, 7.0, 8.0, 10.0]]],
atol=1e-4,
)
self.assertAllClose(
instance_metrics._shift_and_rescale_boxes(
boxes=[[[-2, -1, 0, 5], [11, 13, 14, 19]]], output_boundary=(10, 10)
),
[[[0.0, 0.0, 1.0, 3.0], [6.5, 7.0, 8.0, 10.0]]],
atol=1e-4,
)
self.assertAllClose(
instance_metrics._shift_and_rescale_boxes(
boxes=[[[2, 3, 4, 9], [-1, -1, -1, -1]]], output_boundary=(10, 10)
),
[[[0.0, 0.0, 2.0, 6.0], [0.0, 0.0, 0.0, 0.0]]],
atol=1e-4,
)
def test_count_detection_type(self):
result = instance_metrics._count_detection_type(
detection_type_mask=tf.constant(
[[[True], [True], [False]], [[True], [True], [False]]]
),
detection_classes=tf.constant([[1, 2, 3], [2, 3, 4]]),
flattened_binned_confidence_one_hot=tf.constant([
[False, True, False],
[True, False, False],
[False, True, False],
[True, False, False],
[False, False, True],
[False, False, True],
]),
num_classes=5,
)
self.assertAllClose(
result,
[[
[0.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[2.0, 0.0, 0.0],
[0.0, 0.0, 1.0],
[0.0, 0.0, 0.0],
]],
atol=1e-4,
)
@parameterized.parameters(True, False)
def test_instance_metrics(self, use_mask):
metrics = instance_metrics.InstanceMetrics(
name='per_class_ap',
num_classes=3,
use_masks=use_mask,
iou_thresholds=(0.1, 0.5),
confidence_thresholds=(0.2, 0.7),
mask_output_boundary=(32, 32),
average_precision_algorithms={
'ap_coco': instance_metrics.COCOAveragePrecision(),
'ap_voc10': instance_metrics.VOC2010AveragePrecision(),
},
)
y_true = {
'boxes': [[
[12, 12, 15, 15],
[16, 16, 20, 20],
[0, 0, 5, 5],
[6, 6, 10, 10],
]],
# 1x1 mask
'masks': [[[[1.0]], [[0.9]], [[0.8]], [[0.7]]]],
'classes': [[2, 1, 1, 1]],
'image_info': tf.constant(
[[[32, 32], [32, 32], [1, 1], [0, 0]]], dtype=tf.float32
),
}
y_pred = {
'detection_boxes': [[
[12, 12, 15, 15],
# The duplicate detection with lower score won't be counted as TP.
[12, 12, 15, 15],
[16, 19, 20, 20],
[1, 1, 6, 6],
[6, 6, 11, 11],
]],
# 1x1 mask
'detection_masks': [[[[1.0]], [[0.9]], [[0.8]], [[0.7]], [[0.6]]]],
'detection_classes': [[1, 1, 1, 2, 1]],
'detection_scores': [[0.3, 0.25, 0.4, 0.6, 0.8]],
}
metrics.update_state(y_true, y_pred)
result = metrics.result()
self.assertAllClose(
result['ap_coco'],
[[0.0, 0.663366, 0.0], [0.0, 0.336634, 0.0]],
atol=1e-4,
)
self.assertAllClose(
result['ap_voc10'],
[[0.0, 2.0 / 3.0, 0.0], [0.0, 1.0 / 3.0, 0.0]],
atol=1e-4,
)
self.assertAllClose(
result['precisions'],
[
[[0.0, 0.5, 0.0], [0.0, 0.25, 0.0]],
[[0.0, 1.0, 0.0], [0.0, 1.0, 0.0]],
],
atol=1e-4,
)
self.assertAllClose(
result['recalls'],
[
[[0.0, 2.0 / 3.0, 0.0], [0.0, 1.0 / 3.0, 0.0]],
[[0.0, 1.0 / 3, 0.0], [0.0, 1.0 / 3, 0.0]],
],
atol=1e-4,
)
self.assertAllEqual(result['valid_classes'], [False, True, True])
def test_mask_metrics_with_instance_rescaled(self):
metrics = instance_metrics.InstanceMetrics(
name='per_class_ap',
use_masks=True,
num_classes=3,
iou_thresholds=(0.5,),
confidence_thresholds=(0.5,),
mask_output_boundary=(10, 10),
average_precision_algorithms={
'ap_coco': instance_metrics.COCOAveragePrecision(),
'ap_voc10': instance_metrics.VOC2010AveragePrecision(),
},
)
y_true = {
# Instances are rescaled to (10, 10) boundary.
'boxes': [[[0, 0, 8, 8], [10, 10, 20, 20]]],
'masks': [[
[
[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 0],
[1, 1, 1, 0],
],
[
[1, 1, 0, 0],
[1, 1, 0, 0],
[1, 1, 0, 0],
[1, 1, 0, 0],
],
]],
'classes': [[1, 2]],
'image_info': tf.constant(
[[[20, 20], [20, 20], [1, 1], [0, 0]]], dtype=tf.float32
),
}
y_pred = {
# Instances are rescaled to (10, 10) boundary.
'detection_boxes': [[[0, 1, 8, 9], [10, 10, 20, 20]]],
'detection_masks': [[
[
[1, 1, 1, 0],
[1, 1, 1, 0],
[1, 1, 1, 0],
[1, 1, 1, 0],
],
[
[0, 0, 0, 0],
[0, 0, 0, 0],
[1, 1, 1, 1],
[1, 1, 1, 1],
],
]],
'detection_classes': [[1, 2]],
'detection_scores': [[0.9, 0.8]],
}
metrics.update_state(y_true, y_pred)
result = metrics.result()
self.assertAllClose(
result['precisions'],
[[[0.0, 1.0, 0.0]]],
atol=1e-4,
)
self.assertAllClose(
result['recalls'],
[[[0.0, 1.0, 0.0]]],
atol=1e-4,
)
self.assertAllClose(
result['ap_coco'],
[[0.0, 1.0, 0.0]],
atol=1e-4,
)
self.assertAllClose(
result['ap_voc10'],
[[0.0, 1.0, 0.0]],
atol=1e-4,
)
self.assertAllEqual(result['valid_classes'], [False, True, True])
@parameterized.parameters(True, False)
def test_instance_metrics_with_crowd(self, use_mask):
metrics = instance_metrics.InstanceMetrics(
name='per_class_ap',
use_masks=use_mask,
num_classes=2,
iou_thresholds=(0.5,),
confidence_thresholds=(0.5,),
mask_output_boundary=(20, 20),
average_precision_algorithms={
'ap_coco': instance_metrics.COCOAveragePrecision(),
'ap_voc10': instance_metrics.VOC2010AveragePrecision(),
},
)
y_true = {
'boxes': [[[0, 1, 4, 10], [0, 5, 4, 11]]],
'masks': [[[[1]], [[1]]]],
'classes': [[1, 1]],
'image_info': tf.constant(
[[[20, 20], [20, 20], [1, 1], [0, 0]]], dtype=tf.float32
),
'is_crowds': [[True, False]],
}
y_pred = {
# Over 50% of first box [0, 0, 4, 4] matches the crowd instance
# [0, 1, 4, 10], so it's excluded from the false positives.
'detection_boxes': [[[0, 0, 4, 4], [1, 5, 5, 11]]],
'detection_masks': [[[[1]], [[1]]]],
'detection_classes': [[1, 1]],
'detection_scores': [[0.9, 0.8]],
}
metrics.update_state(y_true, y_pred)
result = metrics.result()
self.assertAllClose(
result['precisions'],
[[[0.0, 1.0]]],
atol=1e-4,
)
self.assertAllClose(
result['recalls'],
[[[0.0, 1.0]]],
atol=1e-4,
)
self.assertAllClose(
result['ap_coco'],
[[0.0, 1.0]],
atol=1e-4,
)
self.assertAllClose(
result['ap_voc10'],
[[0.0, 1.0]],
atol=1e-4,
)
self.assertAllEqual(result['valid_classes'], [False, True])
if __name__ == '__main__':
tf.test.main()