From dc9f89fb59e26f0a66f53c8eca9480caa8054101 Mon Sep 17 00:00:00 2001 From: Zhenyu Tan Date: Thu, 10 Sep 2020 16:51:49 -0700 Subject: [PATCH] Internal change PiperOrigin-RevId: 331045692 --- official/vision/beta/ops/anchor.py | 4 +- .../vision/detection/dataloader/anchor.py | 4 +- .../utils/object_detection/target_assigner.py | 4 +- official/vision/keras_cv/__init__.py | 1 + official/vision/keras_cv/ops/__init__.py | 16 +++ .../vision/keras_cv/ops/iou_similarity.py | 102 ++++++++++++++++++ 6 files changed, 125 insertions(+), 6 deletions(-) create mode 100644 official/vision/keras_cv/ops/__init__.py create mode 100644 official/vision/keras_cv/ops/iou_similarity.py diff --git a/official/vision/beta/ops/anchor.py b/official/vision/beta/ops/anchor.py index 2e6274225..cca0ed0f8 100644 --- a/official/vision/beta/ops/anchor.py +++ b/official/vision/beta/ops/anchor.py @@ -17,12 +17,12 @@ import collections # Import libraries import tensorflow as tf +from official.vision import keras_cv from official.vision.beta.ops.experimental import anchor_generator from official.vision.detection.utils.object_detection import argmax_matcher from official.vision.detection.utils.object_detection import balanced_positive_negative_sampler from official.vision.detection.utils.object_detection import box_list from official.vision.detection.utils.object_detection import faster_rcnn_box_coder -from official.vision.detection.utils.object_detection import region_similarity_calculator from official.vision.detection.utils.object_detection import target_assigner @@ -135,7 +135,7 @@ class AnchorLabeler(object): upper-bound threshold to assign negative labels for anchors. An anchor with a score below the threshold is labeled negative. """ - similarity_calc = region_similarity_calculator.IouSimilarity() + similarity_calc = keras_cv.ops.IouSimilarity() matcher = argmax_matcher.ArgMaxMatcher( match_threshold, unmatched_threshold=unmatched_threshold, diff --git a/official/vision/detection/dataloader/anchor.py b/official/vision/detection/dataloader/anchor.py index dac340b7e..96232ad5f 100644 --- a/official/vision/detection/dataloader/anchor.py +++ b/official/vision/detection/dataloader/anchor.py @@ -21,11 +21,11 @@ from __future__ import print_function import collections import tensorflow as tf +from official.vision import keras_cv from official.vision.detection.utils.object_detection import argmax_matcher from official.vision.detection.utils.object_detection import balanced_positive_negative_sampler from official.vision.detection.utils.object_detection import box_list from official.vision.detection.utils.object_detection import faster_rcnn_box_coder -from official.vision.detection.utils.object_detection import region_similarity_calculator from official.vision.detection.utils.object_detection import target_assigner @@ -134,7 +134,7 @@ class AnchorLabeler(object): upper-bound threshold to assign negative labels for anchors. An anchor with a score below the threshold is labeled negative. """ - similarity_calc = region_similarity_calculator.IouSimilarity() + similarity_calc = keras_cv.ops.IouSimilarity() matcher = argmax_matcher.ArgMaxMatcher( match_threshold, unmatched_threshold=unmatched_threshold, diff --git a/official/vision/detection/utils/object_detection/target_assigner.py b/official/vision/detection/utils/object_detection/target_assigner.py index 0044b1486..798ae018f 100644 --- a/official/vision/detection/utils/object_detection/target_assigner.py +++ b/official/vision/detection/utils/object_detection/target_assigner.py @@ -151,8 +151,8 @@ class TargetAssigner(object): groundtruth_weights = tf.ones([num_gt_boxes], dtype=tf.float32) with tf.control_dependencies( [unmatched_shape_assert, labels_and_box_shapes_assert]): - match_quality_matrix = self._similarity_calc.compare( - groundtruth_boxes, anchors) + match_quality_matrix = self._similarity_calc( + groundtruth_boxes.get(), anchors.get()) match = self._matcher.match(match_quality_matrix, **params) reg_targets = self._create_regression_targets(anchors, groundtruth_boxes, match) diff --git a/official/vision/keras_cv/__init__.py b/official/vision/keras_cv/__init__.py index 4692325e1..c6f2e39ae 100644 --- a/official/vision/keras_cv/__init__.py +++ b/official/vision/keras_cv/__init__.py @@ -15,3 +15,4 @@ """Keras-NLP package definition.""" # pylint: disable=wildcard-import from official.vision.keras_cv.losses import * +from official.vision.keras_cv.ops import * diff --git a/official/vision/keras_cv/ops/__init__.py b/official/vision/keras_cv/ops/__init__.py new file mode 100644 index 000000000..8361f0e8c --- /dev/null +++ b/official/vision/keras_cv/ops/__init__.py @@ -0,0 +1,16 @@ +# Copyright 2020 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. +# ============================================================================== +"""Keras-CV layers package definition.""" +from official.vision.keras_cv.ops.iou_similarity import IouSimilarity diff --git a/official/vision/keras_cv/ops/iou_similarity.py b/official/vision/keras_cv/ops/iou_similarity.py new file mode 100644 index 000000000..45557c094 --- /dev/null +++ b/official/vision/keras_cv/ops/iou_similarity.py @@ -0,0 +1,102 @@ +# Copyright 2020 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. +# ============================================================================== +"""Region Similarity Calculators.""" + +import tensorflow as tf + + +def area(box): + """Computes area of boxes. + + Args: + box: a float Tensor with [N, 4]. + + Returns: + a float tensor with [N]. + """ + with tf.name_scope('Area'): + y_min, x_min, y_max, x_max = tf.split( + value=box, num_or_size_splits=4, axis=1) + return tf.squeeze((y_max - y_min) * (x_max - x_min), [1]) + + +def intersection(box1, box2): + """Compute pairwise intersection areas between boxes. + + Args: + box1: a float Tensor with [N, 4]. + box2: a float Tensor with [M, 4]. + + Returns: + a float tensor with shape [N, M] representing pairwise intersections + """ + with tf.name_scope('Intersection'): + y_min1, x_min1, y_max1, x_max1 = tf.split( + value=box1, num_or_size_splits=4, axis=1) + y_min2, x_min2, y_max2, x_max2 = tf.split( + value=box2, num_or_size_splits=4, axis=1) + y_min_max = tf.minimum(y_max1, tf.transpose(a=y_max2)) + y_max_min = tf.maximum(y_min1, tf.transpose(a=y_min2)) + intersect_heights = tf.maximum(0.0, y_min_max - y_max_min) + x_min_max = tf.minimum(x_max1, tf.transpose(a=x_max2)) + x_max_min = tf.maximum(x_min1, tf.transpose(a=x_min2)) + intersect_widths = tf.maximum(0.0, x_min_max - x_max_min) + return intersect_heights * intersect_widths + + +def iou(box1, box2): + """Computes pairwise intersection-over-union between box collections. + + Args: + box1: a float Tensor with [N, 4]. + box2: a float Tensor with [M, 4]. + + Returns: + a tensor with shape [N, M] representing pairwise iou scores. + """ + intersections = intersection(box1, box2) + areas1 = area(box1) + areas2 = area(box2) + unions = ( + tf.expand_dims(areas1, 1) + tf.expand_dims(areas2, 0) - intersections) + return tf.where( + tf.equal(intersections, 0.0), tf.zeros_like(intersections), + tf.truediv(intersections, unions)) + + +class IouSimilarity(): + """Class to compute similarity based on Intersection over Union (IOU) metric. + + """ + + def __call__(self, groundtruth_boxes, anchors): + """Compute pairwise IOU similarity between ground truth boxes and anchors. + + Args: + groundtruth_boxes: a float Tensor with N boxes. + anchors: a float Tensor with M boxes. + + Returns: + A tensor with shape [N, M] representing pairwise iou scores. + + Input shape: + groundtruth_boxes: [N, 4] + anchors: [M, 4] + + Output shape: + [N, M] + """ + with tf.name_scope('IOU'): + return iou(groundtruth_boxes, anchors) -- GitLab