|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"""Tests for feature map generators.""" |
|
|
|
from absl.testing import parameterized |
|
|
|
import numpy as np |
|
import tensorflow as tf |
|
|
|
from google.protobuf import text_format |
|
|
|
from object_detection.builders import hyperparams_builder |
|
from object_detection.models import feature_map_generators |
|
from object_detection.protos import hyperparams_pb2 |
|
|
|
INCEPTION_V2_LAYOUT = { |
|
'from_layer': ['Mixed_3c', 'Mixed_4c', 'Mixed_5c', '', '', ''], |
|
'layer_depth': [-1, -1, -1, 512, 256, 256], |
|
'anchor_strides': [16, 32, 64, -1, -1, -1], |
|
'layer_target_norm': [20.0, -1, -1, -1, -1, -1], |
|
} |
|
|
|
INCEPTION_V3_LAYOUT = { |
|
'from_layer': ['Mixed_5d', 'Mixed_6e', 'Mixed_7c', '', '', ''], |
|
'layer_depth': [-1, -1, -1, 512, 256, 128], |
|
'anchor_strides': [16, 32, 64, -1, -1, -1], |
|
'aspect_ratios': [1.0, 2.0, 1.0/2, 3.0, 1.0/3] |
|
} |
|
|
|
EMBEDDED_SSD_MOBILENET_V1_LAYOUT = { |
|
'from_layer': ['Conv2d_11_pointwise', 'Conv2d_13_pointwise', '', '', ''], |
|
'layer_depth': [-1, -1, 512, 256, 256], |
|
'conv_kernel_size': [-1, -1, 3, 3, 2], |
|
} |
|
|
|
SSD_MOBILENET_V1_WEIGHT_SHARED_LAYOUT = { |
|
'from_layer': ['Conv2d_13_pointwise', '', '', ''], |
|
'layer_depth': [-1, 256, 256, 256], |
|
} |
|
|
|
|
|
@parameterized.parameters( |
|
{'use_keras': False}, |
|
{'use_keras': True}, |
|
) |
|
class MultiResolutionFeatureMapGeneratorTest(tf.test.TestCase): |
|
|
|
def _build_conv_hyperparams(self): |
|
conv_hyperparams = hyperparams_pb2.Hyperparams() |
|
conv_hyperparams_text_proto = """ |
|
regularizer { |
|
l2_regularizer { |
|
} |
|
} |
|
initializer { |
|
truncated_normal_initializer { |
|
} |
|
} |
|
""" |
|
text_format.Merge(conv_hyperparams_text_proto, conv_hyperparams) |
|
return hyperparams_builder.KerasLayerHyperparams(conv_hyperparams) |
|
|
|
def _build_feature_map_generator(self, feature_map_layout, use_keras, |
|
pool_residual=False): |
|
if use_keras: |
|
return feature_map_generators.KerasMultiResolutionFeatureMaps( |
|
feature_map_layout=feature_map_layout, |
|
depth_multiplier=1, |
|
min_depth=32, |
|
insert_1x1_conv=True, |
|
freeze_batchnorm=False, |
|
is_training=True, |
|
conv_hyperparams=self._build_conv_hyperparams(), |
|
name='FeatureMaps' |
|
) |
|
else: |
|
def feature_map_generator(image_features): |
|
return feature_map_generators.multi_resolution_feature_maps( |
|
feature_map_layout=feature_map_layout, |
|
depth_multiplier=1, |
|
min_depth=32, |
|
insert_1x1_conv=True, |
|
image_features=image_features, |
|
pool_residual=pool_residual) |
|
return feature_map_generator |
|
|
|
def test_get_expected_feature_map_shapes_with_inception_v2(self, use_keras): |
|
image_features = { |
|
'Mixed_3c': tf.random_uniform([4, 28, 28, 256], dtype=tf.float32), |
|
'Mixed_4c': tf.random_uniform([4, 14, 14, 576], dtype=tf.float32), |
|
'Mixed_5c': tf.random_uniform([4, 7, 7, 1024], dtype=tf.float32) |
|
} |
|
feature_map_generator = self._build_feature_map_generator( |
|
feature_map_layout=INCEPTION_V2_LAYOUT, |
|
use_keras=use_keras |
|
) |
|
feature_maps = feature_map_generator(image_features) |
|
|
|
expected_feature_map_shapes = { |
|
'Mixed_3c': (4, 28, 28, 256), |
|
'Mixed_4c': (4, 14, 14, 576), |
|
'Mixed_5c': (4, 7, 7, 1024), |
|
'Mixed_5c_2_Conv2d_3_3x3_s2_512': (4, 4, 4, 512), |
|
'Mixed_5c_2_Conv2d_4_3x3_s2_256': (4, 2, 2, 256), |
|
'Mixed_5c_2_Conv2d_5_3x3_s2_256': (4, 1, 1, 256)} |
|
|
|
init_op = tf.global_variables_initializer() |
|
with self.test_session() as sess: |
|
sess.run(init_op) |
|
out_feature_maps = sess.run(feature_maps) |
|
out_feature_map_shapes = dict( |
|
(key, value.shape) for key, value in out_feature_maps.items()) |
|
self.assertDictEqual(expected_feature_map_shapes, out_feature_map_shapes) |
|
|
|
def test_get_expected_feature_map_shapes_with_inception_v2_use_depthwise( |
|
self, use_keras): |
|
image_features = { |
|
'Mixed_3c': tf.random_uniform([4, 28, 28, 256], dtype=tf.float32), |
|
'Mixed_4c': tf.random_uniform([4, 14, 14, 576], dtype=tf.float32), |
|
'Mixed_5c': tf.random_uniform([4, 7, 7, 1024], dtype=tf.float32) |
|
} |
|
layout_copy = INCEPTION_V2_LAYOUT.copy() |
|
layout_copy['use_depthwise'] = True |
|
feature_map_generator = self._build_feature_map_generator( |
|
feature_map_layout=layout_copy, |
|
use_keras=use_keras |
|
) |
|
feature_maps = feature_map_generator(image_features) |
|
|
|
expected_feature_map_shapes = { |
|
'Mixed_3c': (4, 28, 28, 256), |
|
'Mixed_4c': (4, 14, 14, 576), |
|
'Mixed_5c': (4, 7, 7, 1024), |
|
'Mixed_5c_2_Conv2d_3_3x3_s2_512': (4, 4, 4, 512), |
|
'Mixed_5c_2_Conv2d_4_3x3_s2_256': (4, 2, 2, 256), |
|
'Mixed_5c_2_Conv2d_5_3x3_s2_256': (4, 1, 1, 256)} |
|
|
|
init_op = tf.global_variables_initializer() |
|
with self.test_session() as sess: |
|
sess.run(init_op) |
|
out_feature_maps = sess.run(feature_maps) |
|
out_feature_map_shapes = dict( |
|
(key, value.shape) for key, value in out_feature_maps.items()) |
|
self.assertDictEqual(expected_feature_map_shapes, out_feature_map_shapes) |
|
|
|
def test_get_expected_feature_map_shapes_use_explicit_padding( |
|
self, use_keras): |
|
image_features = { |
|
'Mixed_3c': tf.random_uniform([4, 28, 28, 256], dtype=tf.float32), |
|
'Mixed_4c': tf.random_uniform([4, 14, 14, 576], dtype=tf.float32), |
|
'Mixed_5c': tf.random_uniform([4, 7, 7, 1024], dtype=tf.float32) |
|
} |
|
layout_copy = INCEPTION_V2_LAYOUT.copy() |
|
layout_copy['use_explicit_padding'] = True |
|
feature_map_generator = self._build_feature_map_generator( |
|
feature_map_layout=layout_copy, |
|
use_keras=use_keras |
|
) |
|
feature_maps = feature_map_generator(image_features) |
|
|
|
expected_feature_map_shapes = { |
|
'Mixed_3c': (4, 28, 28, 256), |
|
'Mixed_4c': (4, 14, 14, 576), |
|
'Mixed_5c': (4, 7, 7, 1024), |
|
'Mixed_5c_2_Conv2d_3_3x3_s2_512': (4, 4, 4, 512), |
|
'Mixed_5c_2_Conv2d_4_3x3_s2_256': (4, 2, 2, 256), |
|
'Mixed_5c_2_Conv2d_5_3x3_s2_256': (4, 1, 1, 256)} |
|
|
|
init_op = tf.global_variables_initializer() |
|
with self.test_session() as sess: |
|
sess.run(init_op) |
|
out_feature_maps = sess.run(feature_maps) |
|
out_feature_map_shapes = dict( |
|
(key, value.shape) for key, value in out_feature_maps.items()) |
|
self.assertDictEqual(expected_feature_map_shapes, out_feature_map_shapes) |
|
|
|
def test_get_expected_feature_map_shapes_with_inception_v3(self, use_keras): |
|
image_features = { |
|
'Mixed_5d': tf.random_uniform([4, 35, 35, 256], dtype=tf.float32), |
|
'Mixed_6e': tf.random_uniform([4, 17, 17, 576], dtype=tf.float32), |
|
'Mixed_7c': tf.random_uniform([4, 8, 8, 1024], dtype=tf.float32) |
|
} |
|
|
|
feature_map_generator = self._build_feature_map_generator( |
|
feature_map_layout=INCEPTION_V3_LAYOUT, |
|
use_keras=use_keras |
|
) |
|
feature_maps = feature_map_generator(image_features) |
|
|
|
expected_feature_map_shapes = { |
|
'Mixed_5d': (4, 35, 35, 256), |
|
'Mixed_6e': (4, 17, 17, 576), |
|
'Mixed_7c': (4, 8, 8, 1024), |
|
'Mixed_7c_2_Conv2d_3_3x3_s2_512': (4, 4, 4, 512), |
|
'Mixed_7c_2_Conv2d_4_3x3_s2_256': (4, 2, 2, 256), |
|
'Mixed_7c_2_Conv2d_5_3x3_s2_128': (4, 1, 1, 128)} |
|
|
|
init_op = tf.global_variables_initializer() |
|
with self.test_session() as sess: |
|
sess.run(init_op) |
|
out_feature_maps = sess.run(feature_maps) |
|
out_feature_map_shapes = dict( |
|
(key, value.shape) for key, value in out_feature_maps.items()) |
|
self.assertDictEqual(expected_feature_map_shapes, out_feature_map_shapes) |
|
|
|
def test_get_expected_feature_map_shapes_with_embedded_ssd_mobilenet_v1( |
|
self, use_keras): |
|
image_features = { |
|
'Conv2d_11_pointwise': tf.random_uniform([4, 16, 16, 512], |
|
dtype=tf.float32), |
|
'Conv2d_13_pointwise': tf.random_uniform([4, 8, 8, 1024], |
|
dtype=tf.float32), |
|
} |
|
|
|
feature_map_generator = self._build_feature_map_generator( |
|
feature_map_layout=EMBEDDED_SSD_MOBILENET_V1_LAYOUT, |
|
use_keras=use_keras |
|
) |
|
feature_maps = feature_map_generator(image_features) |
|
|
|
expected_feature_map_shapes = { |
|
'Conv2d_11_pointwise': (4, 16, 16, 512), |
|
'Conv2d_13_pointwise': (4, 8, 8, 1024), |
|
'Conv2d_13_pointwise_2_Conv2d_2_3x3_s2_512': (4, 4, 4, 512), |
|
'Conv2d_13_pointwise_2_Conv2d_3_3x3_s2_256': (4, 2, 2, 256), |
|
'Conv2d_13_pointwise_2_Conv2d_4_2x2_s2_256': (4, 1, 1, 256)} |
|
|
|
init_op = tf.global_variables_initializer() |
|
with self.test_session() as sess: |
|
sess.run(init_op) |
|
out_feature_maps = sess.run(feature_maps) |
|
out_feature_map_shapes = dict( |
|
(key, value.shape) for key, value in out_feature_maps.items()) |
|
self.assertDictEqual(expected_feature_map_shapes, out_feature_map_shapes) |
|
|
|
def test_feature_map_shapes_with_pool_residual_ssd_mobilenet_v1( |
|
self, use_keras): |
|
image_features = { |
|
'Conv2d_13_pointwise': tf.random_uniform([4, 8, 8, 1024], |
|
dtype=tf.float32), |
|
} |
|
|
|
feature_map_generator = self._build_feature_map_generator( |
|
feature_map_layout=SSD_MOBILENET_V1_WEIGHT_SHARED_LAYOUT, |
|
use_keras=use_keras, |
|
pool_residual=True |
|
) |
|
feature_maps = feature_map_generator(image_features) |
|
|
|
expected_feature_map_shapes = { |
|
'Conv2d_13_pointwise': (4, 8, 8, 1024), |
|
'Conv2d_13_pointwise_2_Conv2d_1_3x3_s2_256': (4, 4, 4, 256), |
|
'Conv2d_13_pointwise_2_Conv2d_2_3x3_s2_256': (4, 2, 2, 256), |
|
'Conv2d_13_pointwise_2_Conv2d_3_3x3_s2_256': (4, 1, 1, 256)} |
|
|
|
init_op = tf.global_variables_initializer() |
|
with self.test_session() as sess: |
|
sess.run(init_op) |
|
out_feature_maps = sess.run(feature_maps) |
|
out_feature_map_shapes = dict( |
|
(key, value.shape) for key, value in out_feature_maps.items()) |
|
self.assertDictEqual(expected_feature_map_shapes, out_feature_map_shapes) |
|
|
|
def test_get_expected_variable_names_with_inception_v2(self, use_keras): |
|
image_features = { |
|
'Mixed_3c': tf.random_uniform([4, 28, 28, 256], dtype=tf.float32), |
|
'Mixed_4c': tf.random_uniform([4, 14, 14, 576], dtype=tf.float32), |
|
'Mixed_5c': tf.random_uniform([4, 7, 7, 1024], dtype=tf.float32) |
|
} |
|
feature_map_generator = self._build_feature_map_generator( |
|
feature_map_layout=INCEPTION_V2_LAYOUT, |
|
use_keras=use_keras |
|
) |
|
feature_maps = feature_map_generator(image_features) |
|
|
|
expected_slim_variables = set([ |
|
'Mixed_5c_1_Conv2d_3_1x1_256/weights', |
|
'Mixed_5c_1_Conv2d_3_1x1_256/biases', |
|
'Mixed_5c_2_Conv2d_3_3x3_s2_512/weights', |
|
'Mixed_5c_2_Conv2d_3_3x3_s2_512/biases', |
|
'Mixed_5c_1_Conv2d_4_1x1_128/weights', |
|
'Mixed_5c_1_Conv2d_4_1x1_128/biases', |
|
'Mixed_5c_2_Conv2d_4_3x3_s2_256/weights', |
|
'Mixed_5c_2_Conv2d_4_3x3_s2_256/biases', |
|
'Mixed_5c_1_Conv2d_5_1x1_128/weights', |
|
'Mixed_5c_1_Conv2d_5_1x1_128/biases', |
|
'Mixed_5c_2_Conv2d_5_3x3_s2_256/weights', |
|
'Mixed_5c_2_Conv2d_5_3x3_s2_256/biases', |
|
]) |
|
|
|
expected_keras_variables = set([ |
|
'FeatureMaps/Mixed_5c_1_Conv2d_3_1x1_256_conv/kernel', |
|
'FeatureMaps/Mixed_5c_1_Conv2d_3_1x1_256_conv/bias', |
|
'FeatureMaps/Mixed_5c_2_Conv2d_3_3x3_s2_512_conv/kernel', |
|
'FeatureMaps/Mixed_5c_2_Conv2d_3_3x3_s2_512_conv/bias', |
|
'FeatureMaps/Mixed_5c_1_Conv2d_4_1x1_128_conv/kernel', |
|
'FeatureMaps/Mixed_5c_1_Conv2d_4_1x1_128_conv/bias', |
|
'FeatureMaps/Mixed_5c_2_Conv2d_4_3x3_s2_256_conv/kernel', |
|
'FeatureMaps/Mixed_5c_2_Conv2d_4_3x3_s2_256_conv/bias', |
|
'FeatureMaps/Mixed_5c_1_Conv2d_5_1x1_128_conv/kernel', |
|
'FeatureMaps/Mixed_5c_1_Conv2d_5_1x1_128_conv/bias', |
|
'FeatureMaps/Mixed_5c_2_Conv2d_5_3x3_s2_256_conv/kernel', |
|
'FeatureMaps/Mixed_5c_2_Conv2d_5_3x3_s2_256_conv/bias', |
|
]) |
|
|
|
init_op = tf.global_variables_initializer() |
|
with self.test_session() as sess: |
|
sess.run(init_op) |
|
sess.run(feature_maps) |
|
actual_variable_set = set( |
|
[var.op.name for var in tf.trainable_variables()]) |
|
if use_keras: |
|
self.assertSetEqual(expected_keras_variables, actual_variable_set) |
|
else: |
|
self.assertSetEqual(expected_slim_variables, actual_variable_set) |
|
|
|
def test_get_expected_variable_names_with_inception_v2_use_depthwise( |
|
self, |
|
use_keras): |
|
image_features = { |
|
'Mixed_3c': tf.random_uniform([4, 28, 28, 256], dtype=tf.float32), |
|
'Mixed_4c': tf.random_uniform([4, 14, 14, 576], dtype=tf.float32), |
|
'Mixed_5c': tf.random_uniform([4, 7, 7, 1024], dtype=tf.float32) |
|
} |
|
layout_copy = INCEPTION_V2_LAYOUT.copy() |
|
layout_copy['use_depthwise'] = True |
|
feature_map_generator = self._build_feature_map_generator( |
|
feature_map_layout=layout_copy, |
|
use_keras=use_keras |
|
) |
|
feature_maps = feature_map_generator(image_features) |
|
|
|
expected_slim_variables = set([ |
|
'Mixed_5c_1_Conv2d_3_1x1_256/weights', |
|
'Mixed_5c_1_Conv2d_3_1x1_256/biases', |
|
'Mixed_5c_2_Conv2d_3_3x3_s2_512_depthwise/depthwise_weights', |
|
'Mixed_5c_2_Conv2d_3_3x3_s2_512_depthwise/biases', |
|
'Mixed_5c_2_Conv2d_3_3x3_s2_512/weights', |
|
'Mixed_5c_2_Conv2d_3_3x3_s2_512/biases', |
|
'Mixed_5c_1_Conv2d_4_1x1_128/weights', |
|
'Mixed_5c_1_Conv2d_4_1x1_128/biases', |
|
'Mixed_5c_2_Conv2d_4_3x3_s2_256_depthwise/depthwise_weights', |
|
'Mixed_5c_2_Conv2d_4_3x3_s2_256_depthwise/biases', |
|
'Mixed_5c_2_Conv2d_4_3x3_s2_256/weights', |
|
'Mixed_5c_2_Conv2d_4_3x3_s2_256/biases', |
|
'Mixed_5c_1_Conv2d_5_1x1_128/weights', |
|
'Mixed_5c_1_Conv2d_5_1x1_128/biases', |
|
'Mixed_5c_2_Conv2d_5_3x3_s2_256_depthwise/depthwise_weights', |
|
'Mixed_5c_2_Conv2d_5_3x3_s2_256_depthwise/biases', |
|
'Mixed_5c_2_Conv2d_5_3x3_s2_256/weights', |
|
'Mixed_5c_2_Conv2d_5_3x3_s2_256/biases', |
|
]) |
|
|
|
expected_keras_variables = set([ |
|
'FeatureMaps/Mixed_5c_1_Conv2d_3_1x1_256_conv/kernel', |
|
'FeatureMaps/Mixed_5c_1_Conv2d_3_1x1_256_conv/bias', |
|
('FeatureMaps/Mixed_5c_2_Conv2d_3_3x3_s2_512_depthwise_conv/' |
|
'depthwise_kernel'), |
|
('FeatureMaps/Mixed_5c_2_Conv2d_3_3x3_s2_512_depthwise_conv/' |
|
'bias'), |
|
'FeatureMaps/Mixed_5c_2_Conv2d_3_3x3_s2_512_conv/kernel', |
|
'FeatureMaps/Mixed_5c_2_Conv2d_3_3x3_s2_512_conv/bias', |
|
'FeatureMaps/Mixed_5c_1_Conv2d_4_1x1_128_conv/kernel', |
|
'FeatureMaps/Mixed_5c_1_Conv2d_4_1x1_128_conv/bias', |
|
('FeatureMaps/Mixed_5c_2_Conv2d_4_3x3_s2_256_depthwise_conv/' |
|
'depthwise_kernel'), |
|
('FeatureMaps/Mixed_5c_2_Conv2d_4_3x3_s2_256_depthwise_conv/' |
|
'bias'), |
|
'FeatureMaps/Mixed_5c_2_Conv2d_4_3x3_s2_256_conv/kernel', |
|
'FeatureMaps/Mixed_5c_2_Conv2d_4_3x3_s2_256_conv/bias', |
|
'FeatureMaps/Mixed_5c_1_Conv2d_5_1x1_128_conv/kernel', |
|
'FeatureMaps/Mixed_5c_1_Conv2d_5_1x1_128_conv/bias', |
|
('FeatureMaps/Mixed_5c_2_Conv2d_5_3x3_s2_256_depthwise_conv/' |
|
'depthwise_kernel'), |
|
('FeatureMaps/Mixed_5c_2_Conv2d_5_3x3_s2_256_depthwise_conv/' |
|
'bias'), |
|
'FeatureMaps/Mixed_5c_2_Conv2d_5_3x3_s2_256_conv/kernel', |
|
'FeatureMaps/Mixed_5c_2_Conv2d_5_3x3_s2_256_conv/bias', |
|
]) |
|
|
|
init_op = tf.global_variables_initializer() |
|
with self.test_session() as sess: |
|
sess.run(init_op) |
|
sess.run(feature_maps) |
|
actual_variable_set = set( |
|
[var.op.name for var in tf.trainable_variables()]) |
|
if use_keras: |
|
self.assertSetEqual(expected_keras_variables, actual_variable_set) |
|
else: |
|
self.assertSetEqual(expected_slim_variables, actual_variable_set) |
|
|
|
|
|
@parameterized.parameters({'use_native_resize_op': True}, |
|
{'use_native_resize_op': False}) |
|
class FPNFeatureMapGeneratorTest(tf.test.TestCase, parameterized.TestCase): |
|
|
|
def test_get_expected_feature_map_shapes(self, use_native_resize_op): |
|
image_features = [ |
|
('block2', tf.random_uniform([4, 8, 8, 256], dtype=tf.float32)), |
|
('block3', tf.random_uniform([4, 4, 4, 256], dtype=tf.float32)), |
|
('block4', tf.random_uniform([4, 2, 2, 256], dtype=tf.float32)), |
|
('block5', tf.random_uniform([4, 1, 1, 256], dtype=tf.float32)) |
|
] |
|
feature_maps = feature_map_generators.fpn_top_down_feature_maps( |
|
image_features=image_features, |
|
depth=128, |
|
use_native_resize_op=use_native_resize_op) |
|
|
|
expected_feature_map_shapes = { |
|
'top_down_block2': (4, 8, 8, 128), |
|
'top_down_block3': (4, 4, 4, 128), |
|
'top_down_block4': (4, 2, 2, 128), |
|
'top_down_block5': (4, 1, 1, 128) |
|
} |
|
|
|
init_op = tf.global_variables_initializer() |
|
with self.test_session() as sess: |
|
sess.run(init_op) |
|
out_feature_maps = sess.run(feature_maps) |
|
out_feature_map_shapes = {key: value.shape |
|
for key, value in out_feature_maps.items()} |
|
self.assertDictEqual(out_feature_map_shapes, expected_feature_map_shapes) |
|
|
|
def test_use_bounded_activations_add_operations(self, use_native_resize_op): |
|
tf_graph = tf.Graph() |
|
with tf_graph.as_default(): |
|
image_features = [('block2', |
|
tf.random_uniform([4, 8, 8, 256], dtype=tf.float32)), |
|
('block3', |
|
tf.random_uniform([4, 4, 4, 256], dtype=tf.float32)), |
|
('block4', |
|
tf.random_uniform([4, 2, 2, 256], dtype=tf.float32)), |
|
('block5', |
|
tf.random_uniform([4, 1, 1, 256], dtype=tf.float32))] |
|
feature_map_generators.fpn_top_down_feature_maps( |
|
image_features=image_features, |
|
depth=128, |
|
use_bounded_activations=True, |
|
use_native_resize_op=use_native_resize_op) |
|
|
|
expected_added_operations = dict.fromkeys([ |
|
'top_down/clip_by_value', 'top_down/clip_by_value_1', |
|
'top_down/clip_by_value_2', 'top_down/clip_by_value_3', |
|
'top_down/clip_by_value_4', 'top_down/clip_by_value_5', |
|
'top_down/clip_by_value_6' |
|
]) |
|
op_names = {op.name: None for op in tf_graph.get_operations()} |
|
self.assertDictContainsSubset(expected_added_operations, op_names) |
|
|
|
def test_use_bounded_activations_clip_value(self, use_native_resize_op): |
|
tf_graph = tf.Graph() |
|
with tf_graph.as_default(): |
|
image_features = [ |
|
('block2', 255 * tf.ones([4, 8, 8, 256], dtype=tf.float32)), |
|
('block3', 255 * tf.ones([4, 4, 4, 256], dtype=tf.float32)), |
|
('block4', 255 * tf.ones([4, 2, 2, 256], dtype=tf.float32)), |
|
('block5', 255 * tf.ones([4, 1, 1, 256], dtype=tf.float32)) |
|
] |
|
feature_map_generators.fpn_top_down_feature_maps( |
|
image_features=image_features, |
|
depth=128, |
|
use_bounded_activations=True, |
|
use_native_resize_op=use_native_resize_op) |
|
|
|
expected_clip_by_value_ops = [ |
|
'top_down/clip_by_value', 'top_down/clip_by_value_1', |
|
'top_down/clip_by_value_2', 'top_down/clip_by_value_3', |
|
'top_down/clip_by_value_4', 'top_down/clip_by_value_5', |
|
'top_down/clip_by_value_6' |
|
] |
|
|
|
|
|
activations = {} |
|
for clip_by_value_op in expected_clip_by_value_ops: |
|
clip_input_tensor = tf_graph.get_operation_by_name( |
|
'{}/Minimum'.format(clip_by_value_op)).inputs[0] |
|
clip_output_tensor = tf_graph.get_tensor_by_name( |
|
'{}:0'.format(clip_by_value_op)) |
|
activations.update({ |
|
'before_{}'.format(clip_by_value_op): clip_input_tensor, |
|
'after_{}'.format(clip_by_value_op): clip_output_tensor, |
|
}) |
|
|
|
expected_lower_bound = -feature_map_generators.ACTIVATION_BOUND |
|
expected_upper_bound = feature_map_generators.ACTIVATION_BOUND |
|
init_op = tf.global_variables_initializer() |
|
with self.test_session() as session: |
|
session.run(init_op) |
|
activations_output = session.run(activations) |
|
for clip_by_value_op in expected_clip_by_value_ops: |
|
|
|
|
|
activations_before_clipping = ( |
|
activations_output['before_{}'.format(clip_by_value_op)]) |
|
before_clipping_lower_bound = np.amin(activations_before_clipping) |
|
before_clipping_upper_bound = np.amax(activations_before_clipping) |
|
self.assertLessEqual(before_clipping_lower_bound, |
|
expected_lower_bound) |
|
self.assertGreaterEqual(before_clipping_upper_bound, |
|
expected_upper_bound) |
|
|
|
|
|
activations_after_clipping = ( |
|
activations_output['after_{}'.format(clip_by_value_op)]) |
|
after_clipping_lower_bound = np.amin(activations_after_clipping) |
|
after_clipping_upper_bound = np.amax(activations_after_clipping) |
|
self.assertGreaterEqual(after_clipping_lower_bound, |
|
expected_lower_bound) |
|
self.assertLessEqual(after_clipping_upper_bound, expected_upper_bound) |
|
|
|
def test_get_expected_feature_map_shapes_with_depthwise( |
|
self, use_native_resize_op): |
|
image_features = [ |
|
('block2', tf.random_uniform([4, 8, 8, 256], dtype=tf.float32)), |
|
('block3', tf.random_uniform([4, 4, 4, 256], dtype=tf.float32)), |
|
('block4', tf.random_uniform([4, 2, 2, 256], dtype=tf.float32)), |
|
('block5', tf.random_uniform([4, 1, 1, 256], dtype=tf.float32)) |
|
] |
|
feature_maps = feature_map_generators.fpn_top_down_feature_maps( |
|
image_features=image_features, |
|
depth=128, |
|
use_depthwise=True, |
|
use_native_resize_op=use_native_resize_op) |
|
|
|
expected_feature_map_shapes = { |
|
'top_down_block2': (4, 8, 8, 128), |
|
'top_down_block3': (4, 4, 4, 128), |
|
'top_down_block4': (4, 2, 2, 128), |
|
'top_down_block5': (4, 1, 1, 128) |
|
} |
|
|
|
init_op = tf.global_variables_initializer() |
|
with self.test_session() as sess: |
|
sess.run(init_op) |
|
out_feature_maps = sess.run(feature_maps) |
|
out_feature_map_shapes = {key: value.shape |
|
for key, value in out_feature_maps.items()} |
|
self.assertDictEqual(out_feature_map_shapes, expected_feature_map_shapes) |
|
|
|
|
|
class GetDepthFunctionTest(tf.test.TestCase): |
|
|
|
def test_return_min_depth_when_multiplier_is_small(self): |
|
depth_fn = feature_map_generators.get_depth_fn(depth_multiplier=0.5, |
|
min_depth=16) |
|
self.assertEqual(depth_fn(16), 16) |
|
|
|
def test_return_correct_depth_with_multiplier(self): |
|
depth_fn = feature_map_generators.get_depth_fn(depth_multiplier=0.5, |
|
min_depth=16) |
|
self.assertEqual(depth_fn(64), 32) |
|
|
|
|
|
@parameterized.parameters( |
|
{'replace_pool_with_conv': False}, |
|
{'replace_pool_with_conv': True}, |
|
) |
|
class PoolingPyramidFeatureMapGeneratorTest(tf.test.TestCase): |
|
|
|
def test_get_expected_feature_map_shapes(self, replace_pool_with_conv): |
|
image_features = { |
|
'image_features': tf.random_uniform([4, 19, 19, 1024]) |
|
} |
|
feature_maps = feature_map_generators.pooling_pyramid_feature_maps( |
|
base_feature_map_depth=1024, |
|
num_layers=6, |
|
image_features=image_features, |
|
replace_pool_with_conv=replace_pool_with_conv) |
|
|
|
expected_pool_feature_map_shapes = { |
|
'Base_Conv2d_1x1_1024': (4, 19, 19, 1024), |
|
'MaxPool2d_0_2x2': (4, 10, 10, 1024), |
|
'MaxPool2d_1_2x2': (4, 5, 5, 1024), |
|
'MaxPool2d_2_2x2': (4, 3, 3, 1024), |
|
'MaxPool2d_3_2x2': (4, 2, 2, 1024), |
|
'MaxPool2d_4_2x2': (4, 1, 1, 1024), |
|
} |
|
|
|
expected_conv_feature_map_shapes = { |
|
'Base_Conv2d_1x1_1024': (4, 19, 19, 1024), |
|
'Conv2d_0_3x3_s2_1024': (4, 10, 10, 1024), |
|
'Conv2d_1_3x3_s2_1024': (4, 5, 5, 1024), |
|
'Conv2d_2_3x3_s2_1024': (4, 3, 3, 1024), |
|
'Conv2d_3_3x3_s2_1024': (4, 2, 2, 1024), |
|
'Conv2d_4_3x3_s2_1024': (4, 1, 1, 1024), |
|
} |
|
|
|
init_op = tf.global_variables_initializer() |
|
with self.test_session() as sess: |
|
sess.run(init_op) |
|
out_feature_maps = sess.run(feature_maps) |
|
out_feature_map_shapes = {key: value.shape |
|
for key, value in out_feature_maps.items()} |
|
if replace_pool_with_conv: |
|
self.assertDictEqual(expected_conv_feature_map_shapes, |
|
out_feature_map_shapes) |
|
else: |
|
self.assertDictEqual(expected_pool_feature_map_shapes, |
|
out_feature_map_shapes) |
|
|
|
def test_get_expected_variable_names(self, replace_pool_with_conv): |
|
image_features = { |
|
'image_features': tf.random_uniform([4, 19, 19, 1024]) |
|
} |
|
feature_maps = feature_map_generators.pooling_pyramid_feature_maps( |
|
base_feature_map_depth=1024, |
|
num_layers=6, |
|
image_features=image_features, |
|
replace_pool_with_conv=replace_pool_with_conv) |
|
|
|
expected_pool_variables = set([ |
|
'Base_Conv2d_1x1_1024/weights', |
|
'Base_Conv2d_1x1_1024/biases', |
|
]) |
|
|
|
expected_conv_variables = set([ |
|
'Base_Conv2d_1x1_1024/weights', |
|
'Base_Conv2d_1x1_1024/biases', |
|
'Conv2d_0_3x3_s2_1024/weights', |
|
'Conv2d_0_3x3_s2_1024/biases', |
|
'Conv2d_1_3x3_s2_1024/weights', |
|
'Conv2d_1_3x3_s2_1024/biases', |
|
'Conv2d_2_3x3_s2_1024/weights', |
|
'Conv2d_2_3x3_s2_1024/biases', |
|
'Conv2d_3_3x3_s2_1024/weights', |
|
'Conv2d_3_3x3_s2_1024/biases', |
|
'Conv2d_4_3x3_s2_1024/weights', |
|
'Conv2d_4_3x3_s2_1024/biases', |
|
]) |
|
|
|
init_op = tf.global_variables_initializer() |
|
with self.test_session() as sess: |
|
sess.run(init_op) |
|
sess.run(feature_maps) |
|
actual_variable_set = set( |
|
[var.op.name for var in tf.trainable_variables()]) |
|
if replace_pool_with_conv: |
|
self.assertSetEqual(expected_conv_variables, actual_variable_set) |
|
else: |
|
self.assertSetEqual(expected_pool_variables, actual_variable_set) |
|
|
|
|
|
if __name__ == '__main__': |
|
tf.test.main() |
|
|