Unverified Commit 32e7d660 authored by pkulzc's avatar pkulzc Committed by GitHub
Browse files

Open Images Challenge 2018 tools, minor fixes and refactors. (#4661)

* Merged commit includes the following changes:
202804536  by Zhichao Lu:

    Return tf.data.Dataset from input_fn that goes into the estimator and use PER_HOST_V2 option for tpu input pipeline config.

    This change shaves off 100ms per step resulting in 25 minutes of total reduced training time for ssd mobilenet v1 (15k steps to convergence).

--
202769340  by Zhichao Lu:

    Adding as_matrix() transformation for image-level labels.

--
202768721  by Zhichao Lu:

    Challenge evaluation protocol modification: adding labelmaps creation.

--
202750966  by Zhichao Lu:

    Add the explicit names to two output nodes.

--
202732783  by Zhichao Lu:

    Enforcing that batch size is 1 for evaluation, and no original images are retained during evaluation when use_tpu=False (to avoid dynamic shapes).

--
202425430  by Zhichao Lu:

    Refactor input pipeline to improve performance.

--
202406389  by Zhichao Lu:

    Only check the validity of `warmup_learning_rate` if it will be used.

--
202330450  by Zhichao Lu:

    Adding the description of the flag input_image_label_annotations_csv to add
      image-level labels to tf.Example.

--
202029012  by Zhichao Lu:

    Enabling displaying relationship name in the final metrics output.

--
202024010  by Zhichao Lu:

    Update to the public README.

--
201999677  by Zhichao Lu:

    Fixing the way negative labels are handled in VRD evaluation.

--
201962313  by Zhichao Lu:

    Fix a bug in resize_to_range.

--
201808488  by Zhichao Lu:

    Update ssd_inception_v2_pets.config to use right filename of pets dataset tf records.

--
201779225  by Zhichao Lu:

    Update object detection API installation doc

--
201766518  by Zhichao Lu:

    Add shell script to create pycocotools package for CMLE.

--
201722377  by Zhichao Lu:

    Removes verified_labels field and uses groundtruth_image_classes field instead.

--
201616819  by Zhichao Lu:

    Disable eval_on_tpu since eval_metrics is not setup to execute on TPU.
    Do not use run_config.task_type to switch tpu mode for EVAL,
    since that won't work in unit test.
    Expand unit test to verify that the same instantiation of the Estimator can independently disable eval on TPU whereas training is enabled on TPU.

--
201524716  by Zhichao Lu:

    Disable export model to TPU, inference is not compatible with TPU.
    Add GOOGLE_INTERNAL support in object detection copy.bara.sky

--
201453347  by Zhichao Lu:

    Fixing bug when evaluating the quantized model.

--
200795826  by Zhichao Lu:

    Fixing parsing bug: image-level labels are parsed as tuples instead of numpy
    array.

--
200746134  by Zhichao Lu:

    Adding image_class_text and image_class_label fields into tf_example_decoder.py

--
200743003  by Zhichao Lu:

    Changes to model_main.py and model_tpu_main to enable training and continuous eval.

--
200736324  by Zhichao Lu:

    Replace deprecated squeeze_dims argument.

--
200730072  by Zhichao Lu:

    Make detections only during predict and eval mode while creating model function

--
200729699  by Zhichao Lu:

    Minor correction to internal documentation (definition of Huber loss)

--
200727142  by Zhichao Lu:

    Add command line parsing as a set of flags using argparse and add header to the
    resulting file.

--
200726169  by Zhichao Lu:

    A tutorial on running evaluation for the Open Images Challenge 2018.

--
200665093  by Zhichao Lu:

    Cleanup on variables_helper_test.py.

--
200652145  by Zhichao Lu:

    Add an option to write (non-frozen) graph when exporting inference graph.

--
200573810  by Zhichao Lu:

    Update ssd_mobilenet_v1_coco and ssd_inception_v2_coco download links to point to a newer version.

--
200498014  by Zhichao Lu:

    Add test for groundtruth mask resizing.

--
200453245  by Zhichao Lu:

    Cleaning up exporting_models.md along with exporting scripts

--
200311747  by Zhichao Lu:

    Resize groundtruth mask to match the size of the original image.

--
200287269  by Zhichao Lu:

    Having a option to use custom MatMul based crop_and_resize op as an alternate to the TF op in Faster-RCNN

--
200127859  by Zhichao Lu:

    Updating the instructions to run locally with new binary. Also updating pets configs since file path naming has changed.

--
200127044  by Zhichao Lu:

    A simpler evaluation util to compute Open Images Challenge
    2018 metric (object detection track).

--
200124019  by Zhichao Lu:

    Freshening up configuring_jobs.md

--
200086825  by Zhichao Lu:

    Make merge_multiple_label_boxes work for ssd model.

--
199843258  by Zhichao Lu:

    Allows inconsistent feature channels to be compatible with WeightSharedConvolutionalBoxPredictor.

--
199676082  by Zhichao Lu:

    Enable an override for `InputReader.shuffle` for object detection pipelines.

--
199599212  by Zhichao Lu:

    Markdown fixes.

--
199535432  by Zhichao Lu:

    Pass num_additional_channels to tf.example decoder in predict_input_fn.

--
199399439  by Zhichao Lu:

    Adding `num_additional_channels` field to specify how many additional channels to use in the model.

--

PiperOrigin-RevId: 202804536

* Add original model builder and docs back.
parent 86ac7a47
...@@ -109,7 +109,8 @@ def get_inputs(input_queue, ...@@ -109,7 +109,8 @@ def get_inputs(input_queue,
image_keys: a list of string keys for the images. image_keys: a list of string keys for the images.
locations_list: a list of tensors of shape [num_boxes, 4] locations_list: a list of tensors of shape [num_boxes, 4]
containing the corners of the groundtruth boxes. containing the corners of the groundtruth boxes.
classes_list: a list of padded one-hot tensors containing target classes. classes_list: a list of padded one-hot (or K-hot) float32 tensors containing
target classes.
masks_list: a list of 3-D float tensors of shape [num_boxes, image_height, masks_list: a list of 3-D float tensors of shape [num_boxes, image_height,
image_width] containing instance masks for objects if present in the image_width] containing instance masks for objects if present in the
input_queue. Else returns None. input_queue. Else returns None.
...@@ -141,6 +142,7 @@ def get_inputs(input_queue, ...@@ -141,6 +142,7 @@ def get_inputs(input_queue,
if merge_multiple_label_boxes: if merge_multiple_label_boxes:
location_gt, classes_gt, _ = util_ops.merge_boxes_with_multiple_labels( location_gt, classes_gt, _ = util_ops.merge_boxes_with_multiple_labels(
location_gt, classes_gt, num_classes) location_gt, classes_gt, num_classes)
classes_gt = tf.cast(classes_gt, tf.float32)
elif use_multiclass_scores: elif use_multiclass_scores:
classes_gt = tf.cast(read_data[fields.InputDataFields.multiclass_scores], classes_gt = tf.cast(read_data[fields.InputDataFields.multiclass_scores],
tf.float32) tf.float32)
......
...@@ -357,6 +357,12 @@ def merge_external_params_with_configs(configs, hparams=None, **kwargs): ...@@ -357,6 +357,12 @@ def merge_external_params_with_configs(configs, hparams=None, **kwargs):
_update_mask_type(configs, value) _update_mask_type(configs, value)
elif key == "eval_with_moving_averages": elif key == "eval_with_moving_averages":
_update_use_moving_averages(configs, value) _update_use_moving_averages(configs, value)
elif key == "train_shuffle":
_update_shuffle(configs["train_input_config"], value)
elif key == "eval_shuffle":
_update_shuffle(configs["eval_input_config"], value)
elif key == "retain_original_images_in_eval":
_update_retain_original_images(configs["eval_config"], value)
elif _is_generic_key(key): elif _is_generic_key(key):
_update_generic(configs, key, value) _update_generic(configs, key, value)
else: else:
...@@ -654,3 +660,28 @@ def _update_use_moving_averages(configs, use_moving_averages): ...@@ -654,3 +660,28 @@ def _update_use_moving_averages(configs, use_moving_averages):
should be loaded during evaluation. should be loaded during evaluation.
""" """
configs["eval_config"].use_moving_averages = use_moving_averages configs["eval_config"].use_moving_averages = use_moving_averages
def _update_shuffle(input_config, shuffle):
"""Updates input configuration to reflect a new shuffle configuration.
The input_config object is updated in place, and hence not returned.
Args:
input_config: A input_reader_pb2.InputReader.
shuffle: Whether or not to shuffle the input data before reading.
"""
input_config.shuffle = shuffle
def _update_retain_original_images(eval_config, retain_original_images):
"""Updates eval config with option to retain original images.
The eval_config object is updated in place, and hence not returned.
Args:
eval_config: A eval_pb2.EvalConfig.
retain_original_images: Boolean indicating whether to retain original images
in eval mode.
"""
eval_config.retain_original_images = retain_original_images
...@@ -547,7 +547,7 @@ class ConfigUtilTest(tf.test.TestCase): ...@@ -547,7 +547,7 @@ class ConfigUtilTest(tf.test.TestCase):
configs, eval_with_moving_averages=True) configs, eval_with_moving_averages=True)
self.assertEqual(True, configs["eval_config"].use_moving_averages) self.assertEqual(True, configs["eval_config"].use_moving_averages)
def test_get_image_resizer_config(self): def testGetImageResizerConfig(self):
"""Tests that number of classes can be retrieved.""" """Tests that number of classes can be retrieved."""
model_config = model_pb2.DetectionModel() model_config = model_pb2.DetectionModel()
model_config.faster_rcnn.image_resizer.fixed_shape_resizer.height = 100 model_config.faster_rcnn.image_resizer.fixed_shape_resizer.height = 100
...@@ -556,14 +556,14 @@ class ConfigUtilTest(tf.test.TestCase): ...@@ -556,14 +556,14 @@ class ConfigUtilTest(tf.test.TestCase):
self.assertEqual(image_resizer_config.fixed_shape_resizer.height, 100) self.assertEqual(image_resizer_config.fixed_shape_resizer.height, 100)
self.assertEqual(image_resizer_config.fixed_shape_resizer.width, 300) self.assertEqual(image_resizer_config.fixed_shape_resizer.width, 300)
def test_get_spatial_image_size_from_fixed_shape_resizer_config(self): def testGetSpatialImageSizeFromFixedShapeResizerConfig(self):
image_resizer_config = image_resizer_pb2.ImageResizer() image_resizer_config = image_resizer_pb2.ImageResizer()
image_resizer_config.fixed_shape_resizer.height = 100 image_resizer_config.fixed_shape_resizer.height = 100
image_resizer_config.fixed_shape_resizer.width = 200 image_resizer_config.fixed_shape_resizer.width = 200
image_shape = config_util.get_spatial_image_size(image_resizer_config) image_shape = config_util.get_spatial_image_size(image_resizer_config)
self.assertAllEqual(image_shape, [100, 200]) self.assertAllEqual(image_shape, [100, 200])
def test_get_spatial_image_size_from_aspect_preserving_resizer_config(self): def testGetSpatialImageSizeFromAspectPreservingResizerConfig(self):
image_resizer_config = image_resizer_pb2.ImageResizer() image_resizer_config = image_resizer_pb2.ImageResizer()
image_resizer_config.keep_aspect_ratio_resizer.min_dimension = 100 image_resizer_config.keep_aspect_ratio_resizer.min_dimension = 100
image_resizer_config.keep_aspect_ratio_resizer.max_dimension = 600 image_resizer_config.keep_aspect_ratio_resizer.max_dimension = 600
...@@ -571,13 +571,62 @@ class ConfigUtilTest(tf.test.TestCase): ...@@ -571,13 +571,62 @@ class ConfigUtilTest(tf.test.TestCase):
image_shape = config_util.get_spatial_image_size(image_resizer_config) image_shape = config_util.get_spatial_image_size(image_resizer_config)
self.assertAllEqual(image_shape, [600, 600]) self.assertAllEqual(image_shape, [600, 600])
def test_get_spatial_image_size_from_aspect_preserving_resizer_dynamic(self): def testGetSpatialImageSizeFromAspectPreservingResizerDynamic(self):
image_resizer_config = image_resizer_pb2.ImageResizer() image_resizer_config = image_resizer_pb2.ImageResizer()
image_resizer_config.keep_aspect_ratio_resizer.min_dimension = 100 image_resizer_config.keep_aspect_ratio_resizer.min_dimension = 100
image_resizer_config.keep_aspect_ratio_resizer.max_dimension = 600 image_resizer_config.keep_aspect_ratio_resizer.max_dimension = 600
image_shape = config_util.get_spatial_image_size(image_resizer_config) image_shape = config_util.get_spatial_image_size(image_resizer_config)
self.assertAllEqual(image_shape, [-1, -1]) self.assertAllEqual(image_shape, [-1, -1])
def testEvalShuffle(self):
"""Tests that `eval_shuffle` keyword arguments are applied correctly."""
original_shuffle = True
desired_shuffle = False
pipeline_config_path = os.path.join(self.get_temp_dir(), "pipeline.config")
pipeline_config = pipeline_pb2.TrainEvalPipelineConfig()
pipeline_config.eval_input_reader.shuffle = original_shuffle
_write_config(pipeline_config, pipeline_config_path)
configs = config_util.get_configs_from_pipeline_file(pipeline_config_path)
configs = config_util.merge_external_params_with_configs(
configs, eval_shuffle=desired_shuffle)
eval_shuffle = configs["eval_input_config"].shuffle
self.assertEqual(desired_shuffle, eval_shuffle)
def testTrainShuffle(self):
"""Tests that `train_shuffle` keyword arguments are applied correctly."""
original_shuffle = True
desired_shuffle = False
pipeline_config_path = os.path.join(self.get_temp_dir(), "pipeline.config")
pipeline_config = pipeline_pb2.TrainEvalPipelineConfig()
pipeline_config.train_input_reader.shuffle = original_shuffle
_write_config(pipeline_config, pipeline_config_path)
configs = config_util.get_configs_from_pipeline_file(pipeline_config_path)
configs = config_util.merge_external_params_with_configs(
configs, train_shuffle=desired_shuffle)
train_shuffle = configs["train_input_config"].shuffle
self.assertEqual(desired_shuffle, train_shuffle)
def testOverWriteRetainOriginalImages(self):
"""Tests that `train_shuffle` keyword arguments are applied correctly."""
original_retain_original_images = True
desired_retain_original_images = False
pipeline_config_path = os.path.join(self.get_temp_dir(), "pipeline.config")
pipeline_config = pipeline_pb2.TrainEvalPipelineConfig()
pipeline_config.eval_config.retain_original_images = (
original_retain_original_images)
_write_config(pipeline_config, pipeline_config_path)
configs = config_util.get_configs_from_pipeline_file(pipeline_config_path)
configs = config_util.merge_external_params_with_configs(
configs, retain_original_images_in_eval=desired_retain_original_images)
retain_original_images = configs["eval_config"].retain_original_images
self.assertEqual(desired_retain_original_images, retain_original_images)
if __name__ == "__main__": if __name__ == "__main__":
tf.test.main() tf.test.main()
...@@ -72,7 +72,7 @@ def recursive_parse_xml_to_dict(xml): ...@@ -72,7 +72,7 @@ def recursive_parse_xml_to_dict(xml):
Returns: Returns:
Python dictionary holding XML contents. Python dictionary holding XML contents.
""" """
if not len(xml): if not xml:
return {xml.tag: xml.text} return {xml.tag: xml.text}
result = {} result = {}
for child in xml: for child in xml:
...@@ -86,61 +86,3 @@ def recursive_parse_xml_to_dict(xml): ...@@ -86,61 +86,3 @@ def recursive_parse_xml_to_dict(xml):
return {xml.tag: result} return {xml.tag: result}
def make_initializable_iterator(dataset):
"""Creates an iterator, and initializes tables.
This is useful in cases where make_one_shot_iterator wouldn't work because
the graph contains a hash table that needs to be initialized.
Args:
dataset: A `tf.data.Dataset` object.
Returns:
A `tf.data.Iterator`.
"""
iterator = dataset.make_initializable_iterator()
tf.add_to_collection(tf.GraphKeys.TABLE_INITIALIZERS, iterator.initializer)
return iterator
def read_dataset(file_read_func, decode_func, input_files, config):
"""Reads a dataset, and handles repetition and shuffling.
Args:
file_read_func: Function to use in tf.data.Dataset.interleave, to read
every individual file into a tf.data.Dataset.
decode_func: Function to apply to all records.
input_files: A list of file paths to read.
config: A input_reader_builder.InputReader object.
Returns:
A tf.data.Dataset based on config.
"""
# Shard, shuffle, and read files.
filenames = tf.gfile.Glob(input_files)
num_readers = config.num_readers
if num_readers > len(filenames):
num_readers = len(filenames)
tf.logging.warning('num_readers has been reduced to %d to match input file '
'shards.' % num_readers)
filename_dataset = tf.data.Dataset.from_tensor_slices(tf.unstack(filenames))
if config.shuffle:
filename_dataset = filename_dataset.shuffle(
config.filenames_shuffle_buffer_size)
elif num_readers > 1:
tf.logging.warning('`shuffle` is false, but the input data stream is '
'still slightly shuffled since `num_readers` > 1.')
filename_dataset = filename_dataset.repeat(config.num_epochs or None)
records_dataset = filename_dataset.apply(
tf.contrib.data.parallel_interleave(
file_read_func,
cycle_length=num_readers,
block_length=config.read_block_length,
sloppy=config.shuffle))
if config.shuffle:
records_dataset = records_dataset.shuffle(config.shuffle_buffer_size)
tensor_dataset = records_dataset.map(
decode_func, num_parallel_calls=config.num_parallel_map_calls)
return tensor_dataset.prefetch(config.prefetch_size)
...@@ -16,39 +16,13 @@ ...@@ -16,39 +16,13 @@
"""Tests for object_detection.utils.dataset_util.""" """Tests for object_detection.utils.dataset_util."""
import os import os
import numpy as np
import tensorflow as tf import tensorflow as tf
from object_detection.protos import input_reader_pb2
from object_detection.utils import dataset_util from object_detection.utils import dataset_util
class DatasetUtilTest(tf.test.TestCase): class DatasetUtilTest(tf.test.TestCase):
def setUp(self):
self._path_template = os.path.join(self.get_temp_dir(), 'examples_%s.txt')
for i in range(5):
path = self._path_template % i
with tf.gfile.Open(path, 'wb') as f:
f.write('\n'.join([str(i + 1), str((i + 1) * 10)]))
self._shuffle_path_template = os.path.join(self.get_temp_dir(),
'shuffle_%s.txt')
for i in range(2):
path = self._shuffle_path_template % i
with tf.gfile.Open(path, 'wb') as f:
f.write('\n'.join([str(i)] * 5))
def _get_dataset_next(self, files, config, batch_size):
def decode_func(value):
return [tf.string_to_number(value, out_type=tf.int32)]
dataset = dataset_util.read_dataset(
tf.data.TextLineDataset, decode_func, files, config)
dataset = dataset.batch(batch_size)
return dataset.make_one_shot_iterator().get_next()
def test_read_examples_list(self): def test_read_examples_list(self):
example_list_data = """example1 1\nexample2 2""" example_list_data = """example1 1\nexample2 2"""
example_list_path = os.path.join(self.get_temp_dir(), 'examples.txt') example_list_path = os.path.join(self.get_temp_dir(), 'examples.txt')
...@@ -58,84 +32,6 @@ class DatasetUtilTest(tf.test.TestCase): ...@@ -58,84 +32,6 @@ class DatasetUtilTest(tf.test.TestCase):
examples = dataset_util.read_examples_list(example_list_path) examples = dataset_util.read_examples_list(example_list_path)
self.assertListEqual(['example1', 'example2'], examples) self.assertListEqual(['example1', 'example2'], examples)
def test_make_initializable_iterator_with_hashTable(self):
keys = [1, 0, -1]
dataset = tf.data.Dataset.from_tensor_slices([[1, 2, -1, 5]])
table = tf.contrib.lookup.HashTable(
initializer=tf.contrib.lookup.KeyValueTensorInitializer(
keys=keys,
values=list(reversed(keys))),
default_value=100)
dataset = dataset.map(table.lookup)
data = dataset_util.make_initializable_iterator(dataset).get_next()
init = tf.tables_initializer()
with self.test_session() as sess:
sess.run(init)
self.assertAllEqual(sess.run(data), [-1, 100, 1, 100])
def test_read_dataset(self):
config = input_reader_pb2.InputReader()
config.num_readers = 1
config.shuffle = False
data = self._get_dataset_next([self._path_template % '*'], config,
batch_size=20)
with self.test_session() as sess:
self.assertAllEqual(sess.run(data),
[[1, 10, 2, 20, 3, 30, 4, 40, 5, 50, 1, 10, 2, 20, 3,
30, 4, 40, 5, 50]])
def test_reduce_num_reader(self):
config = input_reader_pb2.InputReader()
config.num_readers = 10
config.shuffle = False
data = self._get_dataset_next([self._path_template % '*'], config,
batch_size=20)
with self.test_session() as sess:
self.assertAllEqual(sess.run(data),
[[1, 10, 2, 20, 3, 30, 4, 40, 5, 50, 1, 10, 2, 20, 3,
30, 4, 40, 5, 50]])
def test_enable_shuffle(self):
config = input_reader_pb2.InputReader()
config.num_readers = 1
config.shuffle = True
data = self._get_dataset_next(
[self._shuffle_path_template % '*'], config, batch_size=10)
expected_non_shuffle_output = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1]
with self.test_session() as sess:
self.assertTrue(
np.any(np.not_equal(sess.run(data), expected_non_shuffle_output)))
def test_disable_shuffle_(self):
config = input_reader_pb2.InputReader()
config.num_readers = 1
config.shuffle = False
data = self._get_dataset_next(
[self._shuffle_path_template % '*'], config, batch_size=10)
expected_non_shuffle_output = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1]
with self.test_session() as sess:
self.assertAllEqual(sess.run(data), [expected_non_shuffle_output])
def test_read_dataset_single_epoch(self):
config = input_reader_pb2.InputReader()
config.num_epochs = 1
config.num_readers = 1
config.shuffle = False
data = self._get_dataset_next([self._path_template % '0'], config,
batch_size=30)
with self.test_session() as sess:
# First batch will retrieve as much as it can, second batch will fail.
self.assertAllEqual(sess.run(data), [[1, 10]])
self.assertRaises(tf.errors.OutOfRangeError, sess.run, data)
if __name__ == '__main__': if __name__ == '__main__':
tf.test.main() tf.test.main()
...@@ -90,9 +90,6 @@ def cosine_decay_with_warmup(global_step, ...@@ -90,9 +90,6 @@ def cosine_decay_with_warmup(global_step,
ValueError: if warmup_learning_rate is larger than learning_rate_base, ValueError: if warmup_learning_rate is larger than learning_rate_base,
or if warmup_steps is larger than total_steps. or if warmup_steps is larger than total_steps.
""" """
if learning_rate_base < warmup_learning_rate:
raise ValueError('learning_rate_base must be larger '
'or equal to warmup_learning_rate.')
if total_steps < warmup_steps: if total_steps < warmup_steps:
raise ValueError('total_steps must be larger or equal to ' raise ValueError('total_steps must be larger or equal to '
'warmup_steps.') 'warmup_steps.')
...@@ -104,6 +101,9 @@ def cosine_decay_with_warmup(global_step, ...@@ -104,6 +101,9 @@ def cosine_decay_with_warmup(global_step,
learning_rate = tf.where(global_step > warmup_steps + hold_base_rate_steps, learning_rate = tf.where(global_step > warmup_steps + hold_base_rate_steps,
learning_rate, learning_rate_base) learning_rate, learning_rate_base)
if warmup_steps > 0: if warmup_steps > 0:
if learning_rate_base < warmup_learning_rate:
raise ValueError('learning_rate_base must be larger or equal to '
'warmup_learning_rate.')
slope = (learning_rate_base - warmup_learning_rate) / warmup_steps slope = (learning_rate_base - warmup_learning_rate) / warmup_steps
warmup_rate = slope * tf.cast(global_step, warmup_rate = slope * tf.cast(global_step,
tf.float32) + warmup_learning_rate tf.float32) + warmup_learning_rate
......
...@@ -525,8 +525,8 @@ class OpenImagesDetectionChallengeEvaluator(OpenImagesDetectionEvaluator): ...@@ -525,8 +525,8 @@ class OpenImagesDetectionChallengeEvaluator(OpenImagesDetectionEvaluator):
standard_fields.InputDataFields.groundtruth_classes: integer numpy array standard_fields.InputDataFields.groundtruth_classes: integer numpy array
of shape [num_boxes] containing 1-indexed groundtruth classes for the of shape [num_boxes] containing 1-indexed groundtruth classes for the
boxes. boxes.
standard_fields.InputDataFields.verified_labels: integer 1D numpy array standard_fields.InputDataFields.groundtruth_image_classes: integer 1D
containing all classes for which labels are verified. numpy array containing all classes for which labels are verified.
standard_fields.InputDataFields.groundtruth_group_of: Optional length standard_fields.InputDataFields.groundtruth_group_of: Optional length
M numpy boolean array denoting whether a groundtruth box contains a M numpy boolean array denoting whether a groundtruth box contains a
group of instances. group of instances.
...@@ -541,7 +541,7 @@ class OpenImagesDetectionChallengeEvaluator(OpenImagesDetectionEvaluator): ...@@ -541,7 +541,7 @@ class OpenImagesDetectionChallengeEvaluator(OpenImagesDetectionEvaluator):
self._label_id_offset) self._label_id_offset)
self._evaluatable_labels[image_id] = np.unique( self._evaluatable_labels[image_id] = np.unique(
np.concatenate(((groundtruth_dict.get( np.concatenate(((groundtruth_dict.get(
standard_fields.InputDataFields.verified_labels, standard_fields.InputDataFields.groundtruth_image_classes,
np.array([], dtype=int)) - self._label_id_offset), np.array([], dtype=int)) - self._label_id_offset),
groundtruth_classes))) groundtruth_classes)))
...@@ -839,6 +839,9 @@ class ObjectDetectionEvaluation(object): ...@@ -839,6 +839,9 @@ class ObjectDetectionEvaluation(object):
if self.use_weighted_mean_ap: if self.use_weighted_mean_ap:
all_scores = np.append(all_scores, scores) all_scores = np.append(all_scores, scores)
all_tp_fp_labels = np.append(all_tp_fp_labels, tp_fp_labels) all_tp_fp_labels = np.append(all_tp_fp_labels, tp_fp_labels)
print 'Scores and tpfp per class label: {}'.format(class_index)
print tp_fp_labels
print scores
precision, recall = metrics.compute_precision_recall( precision, recall = metrics.compute_precision_recall(
scores, tp_fp_labels, self.num_gt_instances_per_class[class_index]) scores, tp_fp_labels, self.num_gt_instances_per_class[class_index])
self.precisions_per_class.append(precision) self.precisions_per_class.append(precision)
......
...@@ -131,7 +131,7 @@ class OpenImagesDetectionChallengeEvaluatorTest(tf.test.TestCase): ...@@ -131,7 +131,7 @@ class OpenImagesDetectionChallengeEvaluatorTest(tf.test.TestCase):
groundtruth_class_labels, groundtruth_class_labels,
standard_fields.InputDataFields.groundtruth_group_of: standard_fields.InputDataFields.groundtruth_group_of:
groundtruth_is_group_of_list, groundtruth_is_group_of_list,
standard_fields.InputDataFields.verified_labels: standard_fields.InputDataFields.groundtruth_image_classes:
groundtruth_verified_labels, groundtruth_verified_labels,
}) })
image_key = 'img2' image_key = 'img2'
......
...@@ -129,80 +129,88 @@ class FreezeGradientsMatchingRegexTest(tf.test.TestCase): ...@@ -129,80 +129,88 @@ class FreezeGradientsMatchingRegexTest(tf.test.TestCase):
class GetVariablesAvailableInCheckpointTest(tf.test.TestCase): class GetVariablesAvailableInCheckpointTest(tf.test.TestCase):
def test_return_all_variables_from_checkpoint(self): def test_return_all_variables_from_checkpoint(self):
variables = [ with tf.Graph().as_default():
tf.Variable(1.0, name='weights'), variables = [
tf.Variable(1.0, name='biases') tf.Variable(1.0, name='weights'),
] tf.Variable(1.0, name='biases')
checkpoint_path = os.path.join(self.get_temp_dir(), 'graph.pb') ]
init_op = tf.global_variables_initializer() checkpoint_path = os.path.join(self.get_temp_dir(), 'model.ckpt')
saver = tf.train.Saver(variables) init_op = tf.global_variables_initializer()
with self.test_session() as sess: saver = tf.train.Saver(variables)
sess.run(init_op) with self.test_session() as sess:
saver.save(sess, checkpoint_path) sess.run(init_op)
out_variables = variables_helper.get_variables_available_in_checkpoint( saver.save(sess, checkpoint_path)
variables, checkpoint_path) out_variables = variables_helper.get_variables_available_in_checkpoint(
variables, checkpoint_path)
self.assertItemsEqual(out_variables, variables) self.assertItemsEqual(out_variables, variables)
def test_return_variables_available_in_checkpoint(self): def test_return_variables_available_in_checkpoint(self):
checkpoint_path = os.path.join(self.get_temp_dir(), 'graph.pb') checkpoint_path = os.path.join(self.get_temp_dir(), 'model.ckpt')
weight_variable = tf.Variable(1.0, name='weights') with tf.Graph().as_default():
global_step = tf.train.get_or_create_global_step() weight_variable = tf.Variable(1.0, name='weights')
graph1_variables = [ global_step = tf.train.get_or_create_global_step()
weight_variable, graph1_variables = [
global_step weight_variable,
] global_step
init_op = tf.global_variables_initializer() ]
saver = tf.train.Saver(graph1_variables) init_op = tf.global_variables_initializer()
with self.test_session() as sess: saver = tf.train.Saver(graph1_variables)
sess.run(init_op) with self.test_session() as sess:
saver.save(sess, checkpoint_path) sess.run(init_op)
saver.save(sess, checkpoint_path)
graph2_variables = graph1_variables + [tf.Variable(1.0, name='biases')]
out_variables = variables_helper.get_variables_available_in_checkpoint( with tf.Graph().as_default():
graph2_variables, checkpoint_path, include_global_step=False) graph2_variables = graph1_variables + [tf.Variable(1.0, name='biases')]
out_variables = variables_helper.get_variables_available_in_checkpoint(
graph2_variables, checkpoint_path, include_global_step=False)
self.assertItemsEqual(out_variables, [weight_variable]) self.assertItemsEqual(out_variables, [weight_variable])
def test_return_variables_available_an_checkpoint_with_dict_inputs(self): def test_return_variables_available_an_checkpoint_with_dict_inputs(self):
checkpoint_path = os.path.join(self.get_temp_dir(), 'graph.pb') checkpoint_path = os.path.join(self.get_temp_dir(), 'model.ckpt')
graph1_variables = [ with tf.Graph().as_default():
tf.Variable(1.0, name='ckpt_weights'), graph1_variables = [
] tf.Variable(1.0, name='ckpt_weights'),
init_op = tf.global_variables_initializer() ]
saver = tf.train.Saver(graph1_variables) init_op = tf.global_variables_initializer()
with self.test_session() as sess: saver = tf.train.Saver(graph1_variables)
sess.run(init_op) with self.test_session() as sess:
saver.save(sess, checkpoint_path) sess.run(init_op)
saver.save(sess, checkpoint_path)
with tf.Graph().as_default():
graph2_variables_dict = {
'ckpt_weights': tf.Variable(1.0, name='weights'),
'ckpt_biases': tf.Variable(1.0, name='biases')
}
out_variables = variables_helper.get_variables_available_in_checkpoint(
graph2_variables_dict, checkpoint_path)
graph2_variables_dict = {
'ckpt_weights': tf.Variable(1.0, name='weights'),
'ckpt_biases': tf.Variable(1.0, name='biases')
}
out_variables = variables_helper.get_variables_available_in_checkpoint(
graph2_variables_dict, checkpoint_path)
self.assertTrue(isinstance(out_variables, dict)) self.assertTrue(isinstance(out_variables, dict))
self.assertItemsEqual(out_variables.keys(), ['ckpt_weights']) self.assertItemsEqual(out_variables.keys(), ['ckpt_weights'])
self.assertTrue(out_variables['ckpt_weights'].op.name == 'weights') self.assertTrue(out_variables['ckpt_weights'].op.name == 'weights')
def test_return_variables_with_correct_sizes(self): def test_return_variables_with_correct_sizes(self):
checkpoint_path = os.path.join(self.get_temp_dir(), 'graph.pb') checkpoint_path = os.path.join(self.get_temp_dir(), 'model.ckpt')
bias_variable = tf.Variable(3.0, name='biases') with tf.Graph().as_default():
global_step = tf.train.get_or_create_global_step() bias_variable = tf.Variable(3.0, name='biases')
graph1_variables = [ global_step = tf.train.get_or_create_global_step()
tf.Variable([[1.0, 2.0], [3.0, 4.0]], name='weights'), graph1_variables = [
bias_variable, tf.Variable([[1.0, 2.0], [3.0, 4.0]], name='weights'),
global_step bias_variable,
] global_step
init_op = tf.global_variables_initializer() ]
saver = tf.train.Saver(graph1_variables) init_op = tf.global_variables_initializer()
with self.test_session() as sess: saver = tf.train.Saver(graph1_variables)
sess.run(init_op) with self.test_session() as sess:
saver.save(sess, checkpoint_path) sess.run(init_op)
saver.save(sess, checkpoint_path)
graph2_variables = [
tf.Variable([1.0, 2.0], name='weights'), # Note the new variable shape. with tf.Graph().as_default():
bias_variable, graph2_variables = [
global_step tf.Variable([1.0, 2.0], name='weights'), # New variable shape.
] bias_variable,
global_step
]
out_variables = variables_helper.get_variables_available_in_checkpoint( out_variables = variables_helper.get_variables_available_in_checkpoint(
graph2_variables, checkpoint_path, include_global_step=True) graph2_variables, checkpoint_path, include_global_step=True)
......
...@@ -128,7 +128,7 @@ class VRDDetectionEvaluator(object_detection_evaluation.DetectionEvaluator): ...@@ -128,7 +128,7 @@ class VRDDetectionEvaluator(object_detection_evaluation.DetectionEvaluator):
structures shape [M, 1], representing the class labels of the structures shape [M, 1], representing the class labels of the
corresponding bounding boxes and possibly additional classes (see corresponding bounding boxes and possibly additional classes (see
datatype label_data_type above). datatype label_data_type above).
standard_fields.InputDataFields.verified_labels: numpy array standard_fields.InputDataFields.groundtruth_image_classes: numpy array
of shape [K] containing verified labels. of shape [K] containing verified labels.
Raises: Raises:
ValueError: On adding groundtruth for an image more than once. ValueError: On adding groundtruth for an image more than once.
...@@ -152,8 +152,8 @@ class VRDDetectionEvaluator(object_detection_evaluation.DetectionEvaluator): ...@@ -152,8 +152,8 @@ class VRDDetectionEvaluator(object_detection_evaluation.DetectionEvaluator):
all_classes.append(groundtruth_class_tuples[field]) all_classes.append(groundtruth_class_tuples[field])
groudtruth_positive_classes = np.unique(np.concatenate(all_classes)) groudtruth_positive_classes = np.unique(np.concatenate(all_classes))
verified_labels = groundtruth_dict.get( verified_labels = groundtruth_dict.get(
standard_fields.InputDataFields.verified_labels, np.array( standard_fields.InputDataFields.groundtruth_image_classes,
[], dtype=int)) np.array([], dtype=int))
self._evaluatable_labels[image_id] = np.unique( self._evaluatable_labels[image_id] = np.unique(
np.concatenate((verified_labels, groudtruth_positive_classes))) np.concatenate((verified_labels, groudtruth_positive_classes)))
...@@ -184,17 +184,18 @@ class VRDDetectionEvaluator(object_detection_evaluation.DetectionEvaluator): ...@@ -184,17 +184,18 @@ class VRDDetectionEvaluator(object_detection_evaluation.DetectionEvaluator):
standard_fields.DetectionResultFields.detection_classes] standard_fields.DetectionResultFields.detection_classes]
detection_box_tuples = detections_dict[ detection_box_tuples = detections_dict[
standard_fields.DetectionResultFields.detection_boxes] standard_fields.DetectionResultFields.detection_boxes]
negative_selector = np.zeros(num_detections, dtype=bool)
selector = np.ones(num_detections, dtype=bool) selector = np.ones(num_detections, dtype=bool)
# Only check boxable labels # Only check boxable labels
for field in detection_box_tuples.dtype.fields: for field in detection_box_tuples.dtype.fields:
# Verify if one of the labels is negative (this is sure FP) # Verify if one of the labels is negative (this is sure FP)
selector |= np.isin(detection_class_tuples[field], negative_selector |= np.isin(detection_class_tuples[field],
self._negative_labels[image_id]) self._negative_labels[image_id])
# Verify if all labels are verified # Verify if all labels are verified
selector |= np.isin(detection_class_tuples[field], selector &= np.isin(detection_class_tuples[field],
self._evaluatable_labels[image_id]) self._evaluatable_labels[image_id])
selector |= negative_selector
self._evaluation.add_single_detected_image_info( self._evaluation.add_single_detected_image_info(
image_key=image_id, image_key=image_id,
detected_box_tuples=self._process_detection_boxes( detected_box_tuples=self._process_detection_boxes(
......
...@@ -39,7 +39,7 @@ class VRDRelationDetectionEvaluatorTest(tf.test.TestCase): ...@@ -39,7 +39,7 @@ class VRDRelationDetectionEvaluatorTest(tf.test.TestCase):
groundtruth_box_tuples1, groundtruth_box_tuples1,
standard_fields.InputDataFields.groundtruth_classes: standard_fields.InputDataFields.groundtruth_classes:
groundtruth_class_tuples1, groundtruth_class_tuples1,
standard_fields.InputDataFields.verified_labels: standard_fields.InputDataFields.groundtruth_image_classes:
groundtruth_verified_labels1 groundtruth_verified_labels1
}) })
...@@ -71,11 +71,12 @@ class VRDRelationDetectionEvaluatorTest(tf.test.TestCase): ...@@ -71,11 +71,12 @@ class VRDRelationDetectionEvaluatorTest(tf.test.TestCase):
image_key = 'img1' image_key = 'img1'
detected_box_tuples = np.array( detected_box_tuples = np.array(
[([0, 0.3, 1, 1], [1.1, 1, 2, 2]), ([0, 0, 1, 1], [1, 1, 2, 2])], [([0, 0.3, 1, 1], [1.1, 1, 2, 2]), ([0, 0, 1, 1], [1, 1, 2, 2]),
([0.5, 0, 1, 1], [1, 1, 3, 3])],
dtype=vrd_evaluation.vrd_box_data_type) dtype=vrd_evaluation.vrd_box_data_type)
detected_class_tuples = np.array( detected_class_tuples = np.array(
[(1, 2, 5), (1, 2, 3)], dtype=vrd_evaluation.label_data_type) [(1, 2, 5), (1, 2, 3), (1, 6, 3)], dtype=vrd_evaluation.label_data_type)
detected_scores = np.array([0.7, 0.8], dtype=float) detected_scores = np.array([0.7, 0.8, 0.9], dtype=float)
self.vrd_eval.add_single_detected_image_info( self.vrd_eval.add_single_detected_image_info(
image_key, { image_key, {
standard_fields.DetectionResultFields.detection_boxes: standard_fields.DetectionResultFields.detection_boxes:
...@@ -121,7 +122,7 @@ class VRDPhraseDetectionEvaluatorTest(tf.test.TestCase): ...@@ -121,7 +122,7 @@ class VRDPhraseDetectionEvaluatorTest(tf.test.TestCase):
groundtruth_box_tuples1, groundtruth_box_tuples1,
standard_fields.InputDataFields.groundtruth_classes: standard_fields.InputDataFields.groundtruth_classes:
groundtruth_class_tuples1, groundtruth_class_tuples1,
standard_fields.InputDataFields.verified_labels: standard_fields.InputDataFields.groundtruth_image_classes:
groundtruth_verified_labels1 groundtruth_verified_labels1
}) })
...@@ -154,11 +155,12 @@ class VRDPhraseDetectionEvaluatorTest(tf.test.TestCase): ...@@ -154,11 +155,12 @@ class VRDPhraseDetectionEvaluatorTest(tf.test.TestCase):
image_key = 'img1' image_key = 'img1'
detected_box_tuples = np.array( detected_box_tuples = np.array(
[([0, 0.3, 0.5, 0.5], [0.3, 0.3, 1.0, 1.0]), [([0, 0.3, 0.5, 0.5], [0.3, 0.3, 1.0, 1.0]),
([0, 0, 1.2, 1.2], [0.0, 0.0, 2.0, 2.0])], ([0, 0, 1.2, 1.2], [0.0, 0.0, 2.0, 2.0]),
([0.5, 0, 1, 1], [1, 1, 3, 3])],
dtype=vrd_evaluation.vrd_box_data_type) dtype=vrd_evaluation.vrd_box_data_type)
detected_class_tuples = np.array( detected_class_tuples = np.array(
[(1, 2, 5), (1, 2, 3)], dtype=vrd_evaluation.label_data_type) [(1, 2, 5), (1, 2, 3), (1, 6, 3)], dtype=vrd_evaluation.label_data_type)
detected_scores = np.array([0.7, 0.8], dtype=float) detected_scores = np.array([0.7, 0.8, 0.9], dtype=float)
self.vrd_eval.add_single_detected_image_info( self.vrd_eval.add_single_detected_image_info(
image_key, { image_key, {
standard_fields.DetectionResultFields.detection_boxes: standard_fields.DetectionResultFields.detection_boxes:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment