"test/gemm_xdl/gemm_fp32.cpp" did not exist on "0c79af12e882c29c1f5a2895e6f749cdee9e15b7"
Commit b1025b3b authored by syiming's avatar syiming
Browse files

Merge remote-tracking branch 'upstream/master' into fasterrcnn_fpn_keras_feature_extractor

parents 69ce1c45 e9df75ab
...@@ -13,13 +13,15 @@ ...@@ -13,13 +13,15 @@
# limitations under the License. # limitations under the License.
# ============================================================================== # ==============================================================================
"""Tests for ssd_mobilenet_edgetpu_feature_extractor.""" """Tests for ssd_mobilenet_edgetpu_feature_extractor."""
import unittest
import tensorflow.compat.v1 as tf import tensorflow.compat.v1 as tf
from object_detection.models import ssd_mobilenet_edgetpu_feature_extractor from object_detection.models import ssd_mobilenet_edgetpu_feature_extractor
from object_detection.models import ssd_mobilenet_edgetpu_feature_extractor_testbase from object_detection.models import ssd_mobilenet_edgetpu_feature_extractor_testbase
from object_detection.utils import tf_version
@unittest.skipIf(tf_version.is_tf2(), 'Skipping TF1.X only test.')
class SsdMobilenetEdgeTPUFeatureExtractorTest( class SsdMobilenetEdgeTPUFeatureExtractorTest(
ssd_mobilenet_edgetpu_feature_extractor_testbase ssd_mobilenet_edgetpu_feature_extractor_testbase
._SsdMobilenetEdgeTPUFeatureExtractorTestBase): ._SsdMobilenetEdgeTPUFeatureExtractorTestBase):
......
...@@ -17,20 +17,16 @@ ...@@ -17,20 +17,16 @@
By using parameterized test decorator, this test serves for both Slim-based and By using parameterized test decorator, this test serves for both Slim-based and
Keras-based Mobilenet V1 feature extractors in SSD. Keras-based Mobilenet V1 feature extractors in SSD.
""" """
from absl.testing import parameterized import unittest
import numpy as np import numpy as np
import tensorflow.compat.v1 as tf import tensorflow.compat.v1 as tf
from object_detection.models import ssd_feature_extractor_test from object_detection.models import ssd_feature_extractor_test
from object_detection.models import ssd_mobilenet_v1_feature_extractor from object_detection.models import ssd_mobilenet_v1_feature_extractor
from object_detection.models import ssd_mobilenet_v1_keras_feature_extractor from object_detection.utils import tf_version
@parameterized.parameters( @unittest.skipIf(tf_version.is_tf2(), 'Skipping TF1.X only test.')
{'use_keras': False},
{'use_keras': True},
)
class SsdMobilenetV1FeatureExtractorTest( class SsdMobilenetV1FeatureExtractorTest(
ssd_feature_extractor_test.SsdFeatureExtractorTestBase): ssd_feature_extractor_test.SsdFeatureExtractorTestBase):
...@@ -59,31 +55,17 @@ class SsdMobilenetV1FeatureExtractorTest( ...@@ -59,31 +55,17 @@ class SsdMobilenetV1FeatureExtractorTest(
an ssd_meta_arch.SSDFeatureExtractor object. an ssd_meta_arch.SSDFeatureExtractor object.
""" """
min_depth = 32 min_depth = 32
if use_keras: del use_keras
return (ssd_mobilenet_v1_keras_feature_extractor return ssd_mobilenet_v1_feature_extractor.SSDMobileNetV1FeatureExtractor(
.SSDMobileNetV1KerasFeatureExtractor( is_training,
is_training=is_training, depth_multiplier,
depth_multiplier=depth_multiplier, min_depth,
min_depth=min_depth, pad_to_multiple,
pad_to_multiple=pad_to_multiple, self.conv_hyperparams_fn,
conv_hyperparams=self._build_conv_hyperparams( use_explicit_padding=use_explicit_padding,
add_batch_norm=False), num_layers=num_layers)
freeze_batchnorm=False,
inplace_batchnorm_update=False,
use_explicit_padding=use_explicit_padding,
num_layers=num_layers,
name='MobilenetV1'))
else:
return ssd_mobilenet_v1_feature_extractor.SSDMobileNetV1FeatureExtractor(
is_training,
depth_multiplier,
min_depth,
pad_to_multiple,
self.conv_hyperparams_fn,
use_explicit_padding=use_explicit_padding,
num_layers=num_layers)
def test_extract_features_returns_correct_shapes_128(self, use_keras): def test_extract_features_returns_correct_shapes_128(self):
image_height = 128 image_height = 128
image_width = 128 image_width = 128
depth_multiplier = 1.0 depth_multiplier = 1.0
...@@ -99,7 +81,7 @@ class SsdMobilenetV1FeatureExtractorTest( ...@@ -99,7 +81,7 @@ class SsdMobilenetV1FeatureExtractorTest(
pad_to_multiple, pad_to_multiple,
expected_feature_map_shape, expected_feature_map_shape,
use_explicit_padding=False, use_explicit_padding=False,
use_keras=use_keras) use_keras=False)
self.check_extract_features_returns_correct_shape( self.check_extract_features_returns_correct_shape(
2, 2,
image_height, image_height,
...@@ -108,9 +90,9 @@ class SsdMobilenetV1FeatureExtractorTest( ...@@ -108,9 +90,9 @@ class SsdMobilenetV1FeatureExtractorTest(
pad_to_multiple, pad_to_multiple,
expected_feature_map_shape, expected_feature_map_shape,
use_explicit_padding=True, use_explicit_padding=True,
use_keras=use_keras) use_keras=False)
def test_extract_features_returns_correct_shapes_299(self, use_keras): def test_extract_features_returns_correct_shapes_299(self):
image_height = 299 image_height = 299
image_width = 299 image_width = 299
depth_multiplier = 1.0 depth_multiplier = 1.0
...@@ -126,7 +108,7 @@ class SsdMobilenetV1FeatureExtractorTest( ...@@ -126,7 +108,7 @@ class SsdMobilenetV1FeatureExtractorTest(
pad_to_multiple, pad_to_multiple,
expected_feature_map_shape, expected_feature_map_shape,
use_explicit_padding=False, use_explicit_padding=False,
use_keras=use_keras) use_keras=False)
self.check_extract_features_returns_correct_shape( self.check_extract_features_returns_correct_shape(
2, 2,
image_height, image_height,
...@@ -135,9 +117,9 @@ class SsdMobilenetV1FeatureExtractorTest( ...@@ -135,9 +117,9 @@ class SsdMobilenetV1FeatureExtractorTest(
pad_to_multiple, pad_to_multiple,
expected_feature_map_shape, expected_feature_map_shape,
use_explicit_padding=True, use_explicit_padding=True,
use_keras=use_keras) use_keras=False)
def test_extract_features_with_dynamic_image_shape(self, use_keras): def test_extract_features_with_dynamic_image_shape(self):
image_height = 128 image_height = 128
image_width = 128 image_width = 128
depth_multiplier = 1.0 depth_multiplier = 1.0
...@@ -153,7 +135,7 @@ class SsdMobilenetV1FeatureExtractorTest( ...@@ -153,7 +135,7 @@ class SsdMobilenetV1FeatureExtractorTest(
pad_to_multiple, pad_to_multiple,
expected_feature_map_shape, expected_feature_map_shape,
use_explicit_padding=False, use_explicit_padding=False,
use_keras=use_keras) use_keras=False)
self.check_extract_features_returns_correct_shape( self.check_extract_features_returns_correct_shape(
2, 2,
image_height, image_height,
...@@ -162,10 +144,10 @@ class SsdMobilenetV1FeatureExtractorTest( ...@@ -162,10 +144,10 @@ class SsdMobilenetV1FeatureExtractorTest(
pad_to_multiple, pad_to_multiple,
expected_feature_map_shape, expected_feature_map_shape,
use_explicit_padding=True, use_explicit_padding=True,
use_keras=use_keras) use_keras=False)
def test_extract_features_returns_correct_shapes_enforcing_min_depth( def test_extract_features_returns_correct_shapes_enforcing_min_depth(
self, use_keras): self):
image_height = 299 image_height = 299
image_width = 299 image_width = 299
depth_multiplier = 0.5**12 depth_multiplier = 0.5**12
...@@ -181,7 +163,7 @@ class SsdMobilenetV1FeatureExtractorTest( ...@@ -181,7 +163,7 @@ class SsdMobilenetV1FeatureExtractorTest(
pad_to_multiple, pad_to_multiple,
expected_feature_map_shape, expected_feature_map_shape,
use_explicit_padding=False, use_explicit_padding=False,
use_keras=use_keras) use_keras=False)
self.check_extract_features_returns_correct_shape( self.check_extract_features_returns_correct_shape(
2, 2,
image_height, image_height,
...@@ -190,10 +172,10 @@ class SsdMobilenetV1FeatureExtractorTest( ...@@ -190,10 +172,10 @@ class SsdMobilenetV1FeatureExtractorTest(
pad_to_multiple, pad_to_multiple,
expected_feature_map_shape, expected_feature_map_shape,
use_explicit_padding=True, use_explicit_padding=True,
use_keras=use_keras) use_keras=False)
def test_extract_features_returns_correct_shapes_with_pad_to_multiple( def test_extract_features_returns_correct_shapes_with_pad_to_multiple(
self, use_keras): self):
image_height = 299 image_height = 299
image_width = 299 image_width = 299
depth_multiplier = 1.0 depth_multiplier = 1.0
...@@ -209,7 +191,7 @@ class SsdMobilenetV1FeatureExtractorTest( ...@@ -209,7 +191,7 @@ class SsdMobilenetV1FeatureExtractorTest(
pad_to_multiple, pad_to_multiple,
expected_feature_map_shape, expected_feature_map_shape,
use_explicit_padding=False, use_explicit_padding=False,
use_keras=use_keras) use_keras=False)
self.check_extract_features_returns_correct_shape( self.check_extract_features_returns_correct_shape(
2, 2,
image_height, image_height,
...@@ -218,10 +200,10 @@ class SsdMobilenetV1FeatureExtractorTest( ...@@ -218,10 +200,10 @@ class SsdMobilenetV1FeatureExtractorTest(
pad_to_multiple, pad_to_multiple,
expected_feature_map_shape, expected_feature_map_shape,
use_explicit_padding=True, use_explicit_padding=True,
use_keras=use_keras) use_keras=False)
def test_extract_features_raises_error_with_invalid_image_size( def test_extract_features_raises_error_with_invalid_image_size(
self, use_keras): self):
image_height = 32 image_height = 32
image_width = 32 image_width = 32
depth_multiplier = 1.0 depth_multiplier = 1.0
...@@ -231,34 +213,34 @@ class SsdMobilenetV1FeatureExtractorTest( ...@@ -231,34 +213,34 @@ class SsdMobilenetV1FeatureExtractorTest(
image_width, image_width,
depth_multiplier, depth_multiplier,
pad_to_multiple, pad_to_multiple,
use_keras=use_keras) use_keras=False)
def test_preprocess_returns_correct_value_range(self, use_keras): def test_preprocess_returns_correct_value_range(self):
image_height = 128 image_height = 128
image_width = 128 image_width = 128
depth_multiplier = 1 depth_multiplier = 1
pad_to_multiple = 1 pad_to_multiple = 1
test_image = np.random.rand(2, image_height, image_width, 3) test_image = np.random.rand(2, image_height, image_width, 3)
feature_extractor = self._create_feature_extractor( feature_extractor = self._create_feature_extractor(
depth_multiplier, pad_to_multiple, use_keras=use_keras) depth_multiplier, pad_to_multiple, use_keras=False)
preprocessed_image = feature_extractor.preprocess(test_image) preprocessed_image = feature_extractor.preprocess(test_image)
self.assertTrue(np.all(np.less_equal(np.abs(preprocessed_image), 1.0))) self.assertTrue(np.all(np.less_equal(np.abs(preprocessed_image), 1.0)))
def test_variables_only_created_in_scope(self, use_keras): def test_variables_only_created_in_scope(self):
depth_multiplier = 1 depth_multiplier = 1
pad_to_multiple = 1 pad_to_multiple = 1
scope_name = 'MobilenetV1' scope_name = 'MobilenetV1'
self.check_feature_extractor_variables_under_scope( self.check_feature_extractor_variables_under_scope(
depth_multiplier, pad_to_multiple, scope_name, use_keras=use_keras) depth_multiplier, pad_to_multiple, scope_name, use_keras=False)
def test_variable_count(self, use_keras): def test_variable_count(self):
depth_multiplier = 1 depth_multiplier = 1
pad_to_multiple = 1 pad_to_multiple = 1
variables = self.get_feature_extractor_variables( variables = self.get_feature_extractor_variables(
depth_multiplier, pad_to_multiple, use_keras=use_keras) depth_multiplier, pad_to_multiple, use_keras=False)
self.assertEqual(len(variables), 151) self.assertEqual(len(variables), 151)
def test_has_fused_batchnorm(self, use_keras): def test_has_fused_batchnorm(self):
image_height = 40 image_height = 40
image_width = 40 image_width = 40
depth_multiplier = 1 depth_multiplier = 1
...@@ -266,17 +248,14 @@ class SsdMobilenetV1FeatureExtractorTest( ...@@ -266,17 +248,14 @@ class SsdMobilenetV1FeatureExtractorTest(
image_placeholder = tf.placeholder(tf.float32, image_placeholder = tf.placeholder(tf.float32,
[1, image_height, image_width, 3]) [1, image_height, image_width, 3])
feature_extractor = self._create_feature_extractor( feature_extractor = self._create_feature_extractor(
depth_multiplier, pad_to_multiple, use_keras=use_keras) depth_multiplier, pad_to_multiple, use_keras=False)
preprocessed_image = feature_extractor.preprocess(image_placeholder) preprocessed_image = feature_extractor.preprocess(image_placeholder)
if use_keras: _ = feature_extractor.extract_features(preprocessed_image)
_ = feature_extractor(preprocessed_image)
else:
_ = feature_extractor.extract_features(preprocessed_image)
self.assertTrue( self.assertTrue(
any('FusedBatchNorm' in op.type any('FusedBatchNorm' in op.type
for op in tf.get_default_graph().get_operations())) for op in tf.get_default_graph().get_operations()))
def test_extract_features_with_fewer_layers(self, use_keras): def test_extract_features_with_fewer_layers(self):
image_height = 128 image_height = 128
image_width = 128 image_width = 128
depth_multiplier = 1.0 depth_multiplier = 1.0
...@@ -286,7 +265,7 @@ class SsdMobilenetV1FeatureExtractorTest( ...@@ -286,7 +265,7 @@ class SsdMobilenetV1FeatureExtractorTest(
self.check_extract_features_returns_correct_shape( self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple, 2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_explicit_padding=False, num_layers=4, expected_feature_map_shape, use_explicit_padding=False, num_layers=4,
use_keras=use_keras) use_keras=False)
if __name__ == '__main__': if __name__ == '__main__':
......
# Copyright 2017 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 SSD Mobilenet V1 feature extractors.
By using parameterized test decorator, this test serves for both Slim-based and
Keras-based Mobilenet V1 feature extractors in SSD.
"""
import unittest
import numpy as np
import tensorflow.compat.v1 as tf
from object_detection.models import ssd_feature_extractor_test
from object_detection.models import ssd_mobilenet_v1_keras_feature_extractor
from object_detection.utils import tf_version
@unittest.skipIf(tf_version.is_tf1(), 'Skipping TF2.X only test.')
class SsdMobilenetV1FeatureExtractorTest(
ssd_feature_extractor_test.SsdFeatureExtractorTestBase):
def _create_feature_extractor(self,
depth_multiplier,
pad_to_multiple,
use_explicit_padding=False,
num_layers=6,
is_training=False,
use_keras=False):
"""Constructs a new feature extractor.
Args:
depth_multiplier: float depth multiplier for feature extractor
pad_to_multiple: the nearest multiple to zero pad the input height and
width dimensions to.
use_explicit_padding: Use 'VALID' padding for convolutions, but prepad
inputs so that the output dimensions are the same as if 'SAME' padding
were used.
num_layers: number of SSD layers.
is_training: whether the network is in training mode.
use_keras: if True builds a keras-based feature extractor, if False builds
a slim-based one.
Returns:
an ssd_meta_arch.SSDFeatureExtractor object.
"""
del use_keras
min_depth = 32
return (ssd_mobilenet_v1_keras_feature_extractor
.SSDMobileNetV1KerasFeatureExtractor(
is_training=is_training,
depth_multiplier=depth_multiplier,
min_depth=min_depth,
pad_to_multiple=pad_to_multiple,
conv_hyperparams=self._build_conv_hyperparams(
add_batch_norm=False),
freeze_batchnorm=False,
inplace_batchnorm_update=False,
use_explicit_padding=use_explicit_padding,
num_layers=num_layers,
name='MobilenetV1'))
def test_extract_features_returns_correct_shapes_128(self):
image_height = 128
image_width = 128
depth_multiplier = 1.0
pad_to_multiple = 1
expected_feature_map_shape = [(2, 8, 8, 512), (2, 4, 4, 1024),
(2, 2, 2, 512), (2, 1, 1, 256),
(2, 1, 1, 256), (2, 1, 1, 128)]
self.check_extract_features_returns_correct_shape(
2,
image_height,
image_width,
depth_multiplier,
pad_to_multiple,
expected_feature_map_shape,
use_explicit_padding=False,
use_keras=True)
self.check_extract_features_returns_correct_shape(
2,
image_height,
image_width,
depth_multiplier,
pad_to_multiple,
expected_feature_map_shape,
use_explicit_padding=True,
use_keras=True)
def test_extract_features_returns_correct_shapes_299(self):
image_height = 299
image_width = 299
depth_multiplier = 1.0
pad_to_multiple = 1
expected_feature_map_shape = [(2, 19, 19, 512), (2, 10, 10, 1024),
(2, 5, 5, 512), (2, 3, 3, 256),
(2, 2, 2, 256), (2, 1, 1, 128)]
self.check_extract_features_returns_correct_shape(
2,
image_height,
image_width,
depth_multiplier,
pad_to_multiple,
expected_feature_map_shape,
use_explicit_padding=False,
use_keras=True)
self.check_extract_features_returns_correct_shape(
2,
image_height,
image_width,
depth_multiplier,
pad_to_multiple,
expected_feature_map_shape,
use_explicit_padding=True,
use_keras=True)
def test_extract_features_with_dynamic_image_shape(self):
image_height = 128
image_width = 128
depth_multiplier = 1.0
pad_to_multiple = 1
expected_feature_map_shape = [(2, 8, 8, 512), (2, 4, 4, 1024),
(2, 2, 2, 512), (2, 1, 1, 256),
(2, 1, 1, 256), (2, 1, 1, 128)]
self.check_extract_features_returns_correct_shapes_with_dynamic_inputs(
2,
image_height,
image_width,
depth_multiplier,
pad_to_multiple,
expected_feature_map_shape,
use_explicit_padding=False,
use_keras=True)
self.check_extract_features_returns_correct_shape(
2,
image_height,
image_width,
depth_multiplier,
pad_to_multiple,
expected_feature_map_shape,
use_explicit_padding=True,
use_keras=True)
def test_extract_features_returns_correct_shapes_enforcing_min_depth(
self):
image_height = 299
image_width = 299
depth_multiplier = 0.5**12
pad_to_multiple = 1
expected_feature_map_shape = [(2, 19, 19, 32), (2, 10, 10, 32),
(2, 5, 5, 32), (2, 3, 3, 32), (2, 2, 2, 32),
(2, 1, 1, 32)]
self.check_extract_features_returns_correct_shape(
2,
image_height,
image_width,
depth_multiplier,
pad_to_multiple,
expected_feature_map_shape,
use_explicit_padding=False,
use_keras=True)
self.check_extract_features_returns_correct_shape(
2,
image_height,
image_width,
depth_multiplier,
pad_to_multiple,
expected_feature_map_shape,
use_explicit_padding=True,
use_keras=True)
def test_extract_features_returns_correct_shapes_with_pad_to_multiple(
self):
image_height = 299
image_width = 299
depth_multiplier = 1.0
pad_to_multiple = 32
expected_feature_map_shape = [(2, 20, 20, 512), (2, 10, 10, 1024),
(2, 5, 5, 512), (2, 3, 3, 256),
(2, 2, 2, 256), (2, 1, 1, 128)]
self.check_extract_features_returns_correct_shape(
2,
image_height,
image_width,
depth_multiplier,
pad_to_multiple,
expected_feature_map_shape,
use_explicit_padding=False,
use_keras=True)
self.check_extract_features_returns_correct_shape(
2,
image_height,
image_width,
depth_multiplier,
pad_to_multiple,
expected_feature_map_shape,
use_explicit_padding=True,
use_keras=True)
def test_extract_features_raises_error_with_invalid_image_size(
self):
image_height = 32
image_width = 32
depth_multiplier = 1.0
pad_to_multiple = 1
self.check_extract_features_raises_error_with_invalid_image_size(
image_height,
image_width,
depth_multiplier,
pad_to_multiple,
use_keras=True)
def test_preprocess_returns_correct_value_range(self):
image_height = 128
image_width = 128
depth_multiplier = 1
pad_to_multiple = 1
test_image = np.random.rand(2, image_height, image_width, 3)
feature_extractor = self._create_feature_extractor(
depth_multiplier, pad_to_multiple, use_keras=True)
preprocessed_image = feature_extractor.preprocess(test_image)
self.assertTrue(np.all(np.less_equal(np.abs(preprocessed_image), 1.0)))
def test_extract_features_with_fewer_layers(self):
image_height = 128
image_width = 128
depth_multiplier = 1.0
pad_to_multiple = 1
expected_feature_map_shape = [(2, 8, 8, 512), (2, 4, 4, 1024),
(2, 2, 2, 512), (2, 1, 1, 256)]
self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_explicit_padding=False, num_layers=4,
use_keras=True)
if __name__ == '__main__':
tf.test.main()
...@@ -18,19 +18,16 @@ ...@@ -18,19 +18,16 @@
By using parameterized test decorator, this test serves for both Slim-based and By using parameterized test decorator, this test serves for both Slim-based and
Keras-based Mobilenet V1 FPN feature extractors in SSD. Keras-based Mobilenet V1 FPN feature extractors in SSD.
""" """
from absl.testing import parameterized import unittest
import numpy as np import numpy as np
import tensorflow.compat.v1 as tf import tensorflow.compat.v1 as tf
from object_detection.models import ssd_feature_extractor_test from object_detection.models import ssd_feature_extractor_test
from object_detection.models import ssd_mobilenet_v1_fpn_feature_extractor from object_detection.models import ssd_mobilenet_v1_fpn_feature_extractor
from object_detection.models import ssd_mobilenet_v1_fpn_keras_feature_extractor from object_detection.utils import tf_version
@parameterized.parameters( @unittest.skipIf(tf_version.is_tf2(), 'Skipping TF1.X only test.')
{'use_keras': False},
{'use_keras': True},
)
class SsdMobilenetV1FpnFeatureExtractorTest( class SsdMobilenetV1FpnFeatureExtractorTest(
ssd_feature_extractor_test.SsdFeatureExtractorTestBase): ssd_feature_extractor_test.SsdFeatureExtractorTestBase):
...@@ -52,33 +49,19 @@ class SsdMobilenetV1FpnFeatureExtractorTest( ...@@ -52,33 +49,19 @@ class SsdMobilenetV1FpnFeatureExtractorTest(
Returns: Returns:
an ssd_meta_arch.SSDFeatureExtractor object. an ssd_meta_arch.SSDFeatureExtractor object.
""" """
del use_keras
min_depth = 32 min_depth = 32
if use_keras: return (ssd_mobilenet_v1_fpn_feature_extractor.
return (ssd_mobilenet_v1_fpn_keras_feature_extractor. SSDMobileNetV1FpnFeatureExtractor(
SSDMobileNetV1FpnKerasFeatureExtractor( is_training,
is_training=is_training, depth_multiplier,
depth_multiplier=depth_multiplier, min_depth,
min_depth=min_depth, pad_to_multiple,
pad_to_multiple=pad_to_multiple, self.conv_hyperparams_fn,
conv_hyperparams=self._build_conv_hyperparams( use_depthwise=True,
add_batch_norm=False), use_explicit_padding=use_explicit_padding))
freeze_batchnorm=False,
inplace_batchnorm_update=False, def test_extract_features_returns_correct_shapes_256(self):
use_explicit_padding=use_explicit_padding,
use_depthwise=True,
name='MobilenetV1_FPN'))
else:
return (ssd_mobilenet_v1_fpn_feature_extractor.
SSDMobileNetV1FpnFeatureExtractor(
is_training,
depth_multiplier,
min_depth,
pad_to_multiple,
self.conv_hyperparams_fn,
use_depthwise=True,
use_explicit_padding=use_explicit_padding))
def test_extract_features_returns_correct_shapes_256(self, use_keras):
image_height = 256 image_height = 256
image_width = 256 image_width = 256
depth_multiplier = 1.0 depth_multiplier = 1.0
...@@ -89,13 +72,13 @@ class SsdMobilenetV1FpnFeatureExtractorTest( ...@@ -89,13 +72,13 @@ class SsdMobilenetV1FpnFeatureExtractorTest(
self.check_extract_features_returns_correct_shape( self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple, 2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_explicit_padding=False, expected_feature_map_shape, use_explicit_padding=False,
use_keras=use_keras) use_keras=False)
self.check_extract_features_returns_correct_shape( self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple, 2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_explicit_padding=True, expected_feature_map_shape, use_explicit_padding=True,
use_keras=use_keras) use_keras=False)
def test_extract_features_returns_correct_shapes_384(self, use_keras): def test_extract_features_returns_correct_shapes_384(self):
image_height = 320 image_height = 320
image_width = 320 image_width = 320
depth_multiplier = 1.0 depth_multiplier = 1.0
...@@ -106,13 +89,13 @@ class SsdMobilenetV1FpnFeatureExtractorTest( ...@@ -106,13 +89,13 @@ class SsdMobilenetV1FpnFeatureExtractorTest(
self.check_extract_features_returns_correct_shape( self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple, 2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_explicit_padding=False, expected_feature_map_shape, use_explicit_padding=False,
use_keras=use_keras) use_keras=False)
self.check_extract_features_returns_correct_shape( self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple, 2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_explicit_padding=True, expected_feature_map_shape, use_explicit_padding=True,
use_keras=use_keras) use_keras=False)
def test_extract_features_with_dynamic_image_shape(self, use_keras): def test_extract_features_with_dynamic_image_shape(self):
image_height = 256 image_height = 256
image_width = 256 image_width = 256
depth_multiplier = 1.0 depth_multiplier = 1.0
...@@ -123,14 +106,14 @@ class SsdMobilenetV1FpnFeatureExtractorTest( ...@@ -123,14 +106,14 @@ class SsdMobilenetV1FpnFeatureExtractorTest(
self.check_extract_features_returns_correct_shapes_with_dynamic_inputs( self.check_extract_features_returns_correct_shapes_with_dynamic_inputs(
2, image_height, image_width, depth_multiplier, pad_to_multiple, 2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_explicit_padding=False, expected_feature_map_shape, use_explicit_padding=False,
use_keras=use_keras) use_keras=False)
self.check_extract_features_returns_correct_shapes_with_dynamic_inputs( self.check_extract_features_returns_correct_shapes_with_dynamic_inputs(
2, image_height, image_width, depth_multiplier, pad_to_multiple, 2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_explicit_padding=True, expected_feature_map_shape, use_explicit_padding=True,
use_keras=use_keras) use_keras=False)
def test_extract_features_returns_correct_shapes_with_pad_to_multiple( def test_extract_features_returns_correct_shapes_with_pad_to_multiple(
self, use_keras): self):
image_height = 299 image_height = 299
image_width = 299 image_width = 299
depth_multiplier = 1.0 depth_multiplier = 1.0
...@@ -141,14 +124,14 @@ class SsdMobilenetV1FpnFeatureExtractorTest( ...@@ -141,14 +124,14 @@ class SsdMobilenetV1FpnFeatureExtractorTest(
self.check_extract_features_returns_correct_shape( self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple, 2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_explicit_padding=False, expected_feature_map_shape, use_explicit_padding=False,
use_keras=use_keras) use_keras=False)
self.check_extract_features_returns_correct_shape( self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple, 2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_explicit_padding=True, expected_feature_map_shape, use_explicit_padding=True,
use_keras=use_keras) use_keras=False)
def test_extract_features_returns_correct_shapes_enforcing_min_depth( def test_extract_features_returns_correct_shapes_enforcing_min_depth(
self, use_keras): self):
image_height = 256 image_height = 256
image_width = 256 image_width = 256
depth_multiplier = 0.5**12 depth_multiplier = 0.5**12
...@@ -159,23 +142,23 @@ class SsdMobilenetV1FpnFeatureExtractorTest( ...@@ -159,23 +142,23 @@ class SsdMobilenetV1FpnFeatureExtractorTest(
self.check_extract_features_returns_correct_shape( self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple, 2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_explicit_padding=False, expected_feature_map_shape, use_explicit_padding=False,
use_keras=use_keras) use_keras=False)
self.check_extract_features_returns_correct_shape( self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple, 2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_explicit_padding=True, expected_feature_map_shape, use_explicit_padding=True,
use_keras=use_keras) use_keras=False)
def test_extract_features_raises_error_with_invalid_image_size( def test_extract_features_raises_error_with_invalid_image_size(
self, use_keras): self):
image_height = 32 image_height = 32
image_width = 32 image_width = 32
depth_multiplier = 1.0 depth_multiplier = 1.0
pad_to_multiple = 1 pad_to_multiple = 1
self.check_extract_features_raises_error_with_invalid_image_size( self.check_extract_features_raises_error_with_invalid_image_size(
image_height, image_width, depth_multiplier, pad_to_multiple, image_height, image_width, depth_multiplier, pad_to_multiple,
use_keras=use_keras) use_keras=False)
def test_preprocess_returns_correct_value_range(self, use_keras): def test_preprocess_returns_correct_value_range(self):
image_height = 256 image_height = 256
image_width = 256 image_width = 256
depth_multiplier = 1 depth_multiplier = 1
...@@ -183,25 +166,25 @@ class SsdMobilenetV1FpnFeatureExtractorTest( ...@@ -183,25 +166,25 @@ class SsdMobilenetV1FpnFeatureExtractorTest(
test_image = np.random.rand(2, image_height, image_width, 3) test_image = np.random.rand(2, image_height, image_width, 3)
feature_extractor = self._create_feature_extractor(depth_multiplier, feature_extractor = self._create_feature_extractor(depth_multiplier,
pad_to_multiple, pad_to_multiple,
use_keras=use_keras) use_keras=False)
preprocessed_image = feature_extractor.preprocess(test_image) preprocessed_image = feature_extractor.preprocess(test_image)
self.assertTrue(np.all(np.less_equal(np.abs(preprocessed_image), 1.0))) self.assertTrue(np.all(np.less_equal(np.abs(preprocessed_image), 1.0)))
def test_variables_only_created_in_scope(self, use_keras): def test_variables_only_created_in_scope(self):
depth_multiplier = 1 depth_multiplier = 1
pad_to_multiple = 1 pad_to_multiple = 1
scope_name = 'MobilenetV1' scope_name = 'MobilenetV1'
self.check_feature_extractor_variables_under_scope( self.check_feature_extractor_variables_under_scope(
depth_multiplier, pad_to_multiple, scope_name, use_keras=use_keras) depth_multiplier, pad_to_multiple, scope_name, use_keras=False)
def test_variable_count(self, use_keras): def test_variable_count(self):
depth_multiplier = 1 depth_multiplier = 1
pad_to_multiple = 1 pad_to_multiple = 1
variables = self.get_feature_extractor_variables( variables = self.get_feature_extractor_variables(
depth_multiplier, pad_to_multiple, use_keras=use_keras) depth_multiplier, pad_to_multiple, use_keras=False)
self.assertEqual(len(variables), 153) self.assertEqual(len(variables), 153)
def test_fused_batchnorm(self, use_keras): def test_fused_batchnorm(self):
image_height = 256 image_height = 256
image_width = 256 image_width = 256
depth_multiplier = 1 depth_multiplier = 1
...@@ -210,12 +193,9 @@ class SsdMobilenetV1FpnFeatureExtractorTest( ...@@ -210,12 +193,9 @@ class SsdMobilenetV1FpnFeatureExtractorTest(
[1, image_height, image_width, 3]) [1, image_height, image_width, 3])
feature_extractor = self._create_feature_extractor(depth_multiplier, feature_extractor = self._create_feature_extractor(depth_multiplier,
pad_to_multiple, pad_to_multiple,
use_keras=use_keras) use_keras=False)
preprocessed_image = feature_extractor.preprocess(image_placeholder) preprocessed_image = feature_extractor.preprocess(image_placeholder)
if use_keras: _ = feature_extractor.extract_features(preprocessed_image)
_ = feature_extractor(preprocessed_image)
else:
_ = feature_extractor.extract_features(preprocessed_image)
self.assertTrue( self.assertTrue(
any('FusedBatchNorm' in op.type any('FusedBatchNorm' in op.type
......
# Copyright 2018 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 ssd_mobilenet_v1_fpn_feature_extractor.
By using parameterized test decorator, this test serves for both Slim-based and
Keras-based Mobilenet V1 FPN feature extractors in SSD.
"""
import unittest
import numpy as np
import tensorflow.compat.v1 as tf
from object_detection.models import ssd_feature_extractor_test
from object_detection.models import ssd_mobilenet_v1_fpn_keras_feature_extractor
from object_detection.utils import tf_version
@unittest.skipIf(tf_version.is_tf1(), 'Skipping TF2.X only test.')
class SsdMobilenetV1FpnFeatureExtractorTest(
ssd_feature_extractor_test.SsdFeatureExtractorTestBase):
def _create_feature_extractor(self, depth_multiplier, pad_to_multiple,
is_training=True, use_explicit_padding=False,
use_keras=True):
"""Constructs a new feature extractor.
Args:
depth_multiplier: float depth multiplier for feature extractor
pad_to_multiple: the nearest multiple to zero pad the input height and
width dimensions to.
is_training: whether the network is in training mode.
use_explicit_padding: Use 'VALID' padding for convolutions, but prepad
inputs so that the output dimensions are the same as if 'SAME' padding
were used.
use_keras: if True builds a keras-based feature extractor, if False builds
a slim-based one.
Returns:
an ssd_meta_arch.SSDFeatureExtractor object.
"""
min_depth = 32
del use_keras
return (ssd_mobilenet_v1_fpn_keras_feature_extractor.
SSDMobileNetV1FpnKerasFeatureExtractor(
is_training=is_training,
depth_multiplier=depth_multiplier,
min_depth=min_depth,
pad_to_multiple=pad_to_multiple,
conv_hyperparams=self._build_conv_hyperparams(
add_batch_norm=False),
freeze_batchnorm=False,
inplace_batchnorm_update=False,
use_explicit_padding=use_explicit_padding,
use_depthwise=True,
name='MobilenetV1_FPN'))
def test_extract_features_returns_correct_shapes_256(self):
image_height = 256
image_width = 256
depth_multiplier = 1.0
pad_to_multiple = 1
expected_feature_map_shape = [(2, 32, 32, 256), (2, 16, 16, 256),
(2, 8, 8, 256), (2, 4, 4, 256),
(2, 2, 2, 256)]
self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_explicit_padding=False,
use_keras=True)
self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_explicit_padding=True,
use_keras=True)
def test_extract_features_returns_correct_shapes_384(self):
image_height = 320
image_width = 320
depth_multiplier = 1.0
pad_to_multiple = 1
expected_feature_map_shape = [(2, 40, 40, 256), (2, 20, 20, 256),
(2, 10, 10, 256), (2, 5, 5, 256),
(2, 3, 3, 256)]
self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_explicit_padding=False,
use_keras=True)
self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_explicit_padding=True,
use_keras=True)
def test_extract_features_with_dynamic_image_shape(self):
image_height = 256
image_width = 256
depth_multiplier = 1.0
pad_to_multiple = 1
expected_feature_map_shape = [(2, 32, 32, 256), (2, 16, 16, 256),
(2, 8, 8, 256), (2, 4, 4, 256),
(2, 2, 2, 256)]
self.check_extract_features_returns_correct_shapes_with_dynamic_inputs(
2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_explicit_padding=False,
use_keras=True)
self.check_extract_features_returns_correct_shapes_with_dynamic_inputs(
2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_explicit_padding=True,
use_keras=True)
def test_extract_features_returns_correct_shapes_with_pad_to_multiple(
self):
image_height = 299
image_width = 299
depth_multiplier = 1.0
pad_to_multiple = 32
expected_feature_map_shape = [(2, 40, 40, 256), (2, 20, 20, 256),
(2, 10, 10, 256), (2, 5, 5, 256),
(2, 3, 3, 256)]
self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_explicit_padding=False,
use_keras=True)
self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_explicit_padding=True,
use_keras=True)
def test_extract_features_returns_correct_shapes_enforcing_min_depth(
self):
image_height = 256
image_width = 256
depth_multiplier = 0.5**12
pad_to_multiple = 1
expected_feature_map_shape = [(2, 32, 32, 32), (2, 16, 16, 32),
(2, 8, 8, 32), (2, 4, 4, 32),
(2, 2, 2, 32)]
self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_explicit_padding=False,
use_keras=True)
self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_explicit_padding=True,
use_keras=True)
def test_extract_features_raises_error_with_invalid_image_size(
self):
image_height = 32
image_width = 32
depth_multiplier = 1.0
pad_to_multiple = 1
self.check_extract_features_raises_error_with_invalid_image_size(
image_height, image_width, depth_multiplier, pad_to_multiple,
use_keras=True)
def test_preprocess_returns_correct_value_range(self):
image_height = 256
image_width = 256
depth_multiplier = 1
pad_to_multiple = 1
test_image = np.random.rand(2, image_height, image_width, 3)
feature_extractor = self._create_feature_extractor(depth_multiplier,
pad_to_multiple,
use_keras=True)
preprocessed_image = feature_extractor.preprocess(test_image)
self.assertTrue(np.all(np.less_equal(np.abs(preprocessed_image), 1.0)))
if __name__ == '__main__':
tf.test.main()
...@@ -123,7 +123,7 @@ class SSDMobileNetV1FpnKerasFeatureExtractor( ...@@ -123,7 +123,7 @@ class SSDMobileNetV1FpnKerasFeatureExtractor(
'Conv2d_3_pointwise', 'Conv2d_5_pointwise', 'Conv2d_11_pointwise', 'Conv2d_3_pointwise', 'Conv2d_5_pointwise', 'Conv2d_11_pointwise',
'Conv2d_13_pointwise' 'Conv2d_13_pointwise'
] ]
self._mobilenet_v1 = None self.classification_backbone = None
self._fpn_features_generator = None self._fpn_features_generator = None
self._coarse_feature_layers = [] self._coarse_feature_layers = []
...@@ -147,7 +147,7 @@ class SSDMobileNetV1FpnKerasFeatureExtractor( ...@@ -147,7 +147,7 @@ class SSDMobileNetV1FpnKerasFeatureExtractor(
name='conv_pw_11_relu').output name='conv_pw_11_relu').output
conv2d_13_pointwise = full_mobilenet_v1.get_layer( conv2d_13_pointwise = full_mobilenet_v1.get_layer(
name='conv_pw_13_relu').output name='conv_pw_13_relu').output
self._mobilenet_v1 = tf.keras.Model( self.classification_backbone = tf.keras.Model(
inputs=full_mobilenet_v1.inputs, inputs=full_mobilenet_v1.inputs,
outputs=[conv2d_3_pointwise, conv2d_5_pointwise, outputs=[conv2d_3_pointwise, conv2d_5_pointwise,
conv2d_11_pointwise, conv2d_13_pointwise] conv2d_11_pointwise, conv2d_13_pointwise]
...@@ -218,7 +218,7 @@ class SSDMobileNetV1FpnKerasFeatureExtractor( ...@@ -218,7 +218,7 @@ class SSDMobileNetV1FpnKerasFeatureExtractor(
preprocessed_inputs = shape_utils.check_min_image_dim( preprocessed_inputs = shape_utils.check_min_image_dim(
33, preprocessed_inputs) 33, preprocessed_inputs)
image_features = self._mobilenet_v1( image_features = self.classification_backbone(
ops.pad_to_multiple(preprocessed_inputs, self._pad_to_multiple)) ops.pad_to_multiple(preprocessed_inputs, self._pad_to_multiple))
feature_block_list = [] feature_block_list = []
...@@ -243,3 +243,14 @@ class SSDMobileNetV1FpnKerasFeatureExtractor( ...@@ -243,3 +243,14 @@ class SSDMobileNetV1FpnKerasFeatureExtractor(
last_feature_map = layer(last_feature_map) last_feature_map = layer(last_feature_map)
feature_maps.append(last_feature_map) feature_maps.append(last_feature_map)
return feature_maps return feature_maps
def restore_from_classification_checkpoint_fn(self, feature_extractor_scope):
"""Returns a map for restoring from an (object-based) checkpoint.
Args:
feature_extractor_scope: A scope name for the feature extractor (unused).
Returns:
A dict mapping keys to Keras models
"""
return {'feature_extractor': self.classification_backbone}
...@@ -93,7 +93,7 @@ class SSDMobileNetV1KerasFeatureExtractor( ...@@ -93,7 +93,7 @@ class SSDMobileNetV1KerasFeatureExtractor(
'use_explicit_padding': self._use_explicit_padding, 'use_explicit_padding': self._use_explicit_padding,
'use_depthwise': self._use_depthwise, 'use_depthwise': self._use_depthwise,
} }
self._mobilenet_v1 = None self.classification_backbone = None
self._feature_map_generator = None self._feature_map_generator = None
def build(self, input_shape): def build(self, input_shape):
...@@ -111,7 +111,7 @@ class SSDMobileNetV1KerasFeatureExtractor( ...@@ -111,7 +111,7 @@ class SSDMobileNetV1KerasFeatureExtractor(
name='conv_pw_11_relu').output name='conv_pw_11_relu').output
conv2d_13_pointwise = full_mobilenet_v1.get_layer( conv2d_13_pointwise = full_mobilenet_v1.get_layer(
name='conv_pw_13_relu').output name='conv_pw_13_relu').output
self._mobilenet_v1 = tf.keras.Model( self.classification_backbone = tf.keras.Model(
inputs=full_mobilenet_v1.inputs, inputs=full_mobilenet_v1.inputs,
outputs=[conv2d_11_pointwise, conv2d_13_pointwise]) outputs=[conv2d_11_pointwise, conv2d_13_pointwise])
self._feature_map_generator = ( self._feature_map_generator = (
...@@ -155,7 +155,7 @@ class SSDMobileNetV1KerasFeatureExtractor( ...@@ -155,7 +155,7 @@ class SSDMobileNetV1KerasFeatureExtractor(
preprocessed_inputs = shape_utils.check_min_image_dim( preprocessed_inputs = shape_utils.check_min_image_dim(
33, preprocessed_inputs) 33, preprocessed_inputs)
image_features = self._mobilenet_v1( image_features = self.classification_backbone(
ops.pad_to_multiple(preprocessed_inputs, self._pad_to_multiple)) ops.pad_to_multiple(preprocessed_inputs, self._pad_to_multiple))
feature_maps = self._feature_map_generator({ feature_maps = self._feature_map_generator({
...@@ -163,3 +163,14 @@ class SSDMobileNetV1KerasFeatureExtractor( ...@@ -163,3 +163,14 @@ class SSDMobileNetV1KerasFeatureExtractor(
'Conv2d_13_pointwise': image_features[1]}) 'Conv2d_13_pointwise': image_features[1]})
return list(feature_maps.values()) return list(feature_maps.values())
def restore_from_classification_checkpoint_fn(self, feature_extractor_scope):
"""Returns a map for restoring from an (object-based) checkpoint.
Args:
feature_extractor_scope: A scope name for the feature extractor (unused).
Returns:
A dict mapping keys to Keras models
"""
return {'feature_extractor': self.classification_backbone}
...@@ -14,13 +14,16 @@ ...@@ -14,13 +14,16 @@
# ============================================================================== # ==============================================================================
"""Tests for ssd_mobilenet_v1_ppn_feature_extractor.""" """Tests for ssd_mobilenet_v1_ppn_feature_extractor."""
import unittest
import numpy as np import numpy as np
import tensorflow.compat.v1 as tf import tensorflow.compat.v1 as tf
from object_detection.models import ssd_feature_extractor_test from object_detection.models import ssd_feature_extractor_test
from object_detection.models import ssd_mobilenet_v1_ppn_feature_extractor from object_detection.models import ssd_mobilenet_v1_ppn_feature_extractor
from object_detection.utils import tf_version
@unittest.skipIf(tf_version.is_tf2(), 'Skipping TF1.X only test.')
class SsdMobilenetV1PpnFeatureExtractorTest( class SsdMobilenetV1PpnFeatureExtractorTest(
ssd_feature_extractor_test.SsdFeatureExtractorTestBase): ssd_feature_extractor_test.SsdFeatureExtractorTestBase):
......
...@@ -14,20 +14,17 @@ ...@@ -14,20 +14,17 @@
# ============================================================================== # ==============================================================================
"""Tests for ssd_mobilenet_v2_feature_extractor.""" """Tests for ssd_mobilenet_v2_feature_extractor."""
from absl.testing import parameterized import unittest
import numpy as np import numpy as np
import tensorflow.compat.v1 as tf import tensorflow.compat.v1 as tf
from object_detection.models import ssd_feature_extractor_test from object_detection.models import ssd_feature_extractor_test
from object_detection.models import ssd_mobilenet_v2_feature_extractor from object_detection.models import ssd_mobilenet_v2_feature_extractor
from object_detection.models import ssd_mobilenet_v2_keras_feature_extractor from object_detection.utils import tf_version
@parameterized.parameters( @unittest.skipIf(tf_version.is_tf2(), 'Skipping TF1.X only test.')
{'use_keras': False},
{'use_keras': True},
)
class SsdMobilenetV2FeatureExtractorTest( class SsdMobilenetV2FeatureExtractorTest(
ssd_feature_extractor_test.SsdFeatureExtractorTestBase): ssd_feature_extractor_test.SsdFeatureExtractorTestBase):
...@@ -35,8 +32,7 @@ class SsdMobilenetV2FeatureExtractorTest( ...@@ -35,8 +32,7 @@ class SsdMobilenetV2FeatureExtractorTest(
depth_multiplier, depth_multiplier,
pad_to_multiple, pad_to_multiple,
use_explicit_padding=False, use_explicit_padding=False,
num_layers=6, num_layers=6):
use_keras=False):
"""Constructs a new feature extractor. """Constructs a new feature extractor.
Args: Args:
...@@ -47,36 +43,20 @@ class SsdMobilenetV2FeatureExtractorTest( ...@@ -47,36 +43,20 @@ class SsdMobilenetV2FeatureExtractorTest(
inputs so that the output dimensions are the same as if 'SAME' padding inputs so that the output dimensions are the same as if 'SAME' padding
were used. were used.
num_layers: number of SSD layers. num_layers: number of SSD layers.
use_keras: if True builds a keras-based feature extractor, if False builds
a slim-based one.
Returns: Returns:
an ssd_meta_arch.SSDFeatureExtractor object. an ssd_meta_arch.SSDFeatureExtractor object.
""" """
min_depth = 32 min_depth = 32
if use_keras: return ssd_mobilenet_v2_feature_extractor.SSDMobileNetV2FeatureExtractor(
return (ssd_mobilenet_v2_keras_feature_extractor. False,
SSDMobileNetV2KerasFeatureExtractor( depth_multiplier,
is_training=False, min_depth,
depth_multiplier=depth_multiplier, pad_to_multiple,
min_depth=min_depth, self.conv_hyperparams_fn,
pad_to_multiple=pad_to_multiple, use_explicit_padding=use_explicit_padding,
conv_hyperparams=self._build_conv_hyperparams(), num_layers=num_layers)
freeze_batchnorm=False,
inplace_batchnorm_update=False, def test_extract_features_returns_correct_shapes_128(self):
use_explicit_padding=use_explicit_padding,
num_layers=num_layers,
name='MobilenetV2'))
else:
return ssd_mobilenet_v2_feature_extractor.SSDMobileNetV2FeatureExtractor(
False,
depth_multiplier,
min_depth,
pad_to_multiple,
self.conv_hyperparams_fn,
use_explicit_padding=use_explicit_padding,
num_layers=num_layers)
def test_extract_features_returns_correct_shapes_128(self, use_keras):
image_height = 128 image_height = 128
image_width = 128 image_width = 128
depth_multiplier = 1.0 depth_multiplier = 1.0
...@@ -86,10 +66,10 @@ class SsdMobilenetV2FeatureExtractorTest( ...@@ -86,10 +66,10 @@ class SsdMobilenetV2FeatureExtractorTest(
(2, 1, 1, 256), (2, 1, 1, 128)] (2, 1, 1, 256), (2, 1, 1, 128)]
self.check_extract_features_returns_correct_shape( self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple, 2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_keras=use_keras) expected_feature_map_shape)
def test_extract_features_returns_correct_shapes_128_explicit_padding( def test_extract_features_returns_correct_shapes_128_explicit_padding(
self, use_keras): self):
image_height = 128 image_height = 128
image_width = 128 image_width = 128
depth_multiplier = 1.0 depth_multiplier = 1.0
...@@ -99,11 +79,10 @@ class SsdMobilenetV2FeatureExtractorTest( ...@@ -99,11 +79,10 @@ class SsdMobilenetV2FeatureExtractorTest(
(2, 1, 1, 256), (2, 1, 1, 128)] (2, 1, 1, 256), (2, 1, 1, 128)]
self.check_extract_features_returns_correct_shape( self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple, 2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_explicit_padding=True, expected_feature_map_shape, use_explicit_padding=True)
use_keras=use_keras)
def test_extract_features_returns_correct_shapes_with_dynamic_inputs( def test_extract_features_returns_correct_shapes_with_dynamic_inputs(
self, use_keras): self):
image_height = 128 image_height = 128
image_width = 128 image_width = 128
depth_multiplier = 1.0 depth_multiplier = 1.0
...@@ -113,9 +92,9 @@ class SsdMobilenetV2FeatureExtractorTest( ...@@ -113,9 +92,9 @@ class SsdMobilenetV2FeatureExtractorTest(
(2, 1, 1, 256), (2, 1, 1, 128)] (2, 1, 1, 256), (2, 1, 1, 128)]
self.check_extract_features_returns_correct_shapes_with_dynamic_inputs( self.check_extract_features_returns_correct_shapes_with_dynamic_inputs(
2, image_height, image_width, depth_multiplier, pad_to_multiple, 2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_keras=use_keras) expected_feature_map_shape)
def test_extract_features_returns_correct_shapes_299(self, use_keras): def test_extract_features_returns_correct_shapes_299(self):
image_height = 299 image_height = 299
image_width = 299 image_width = 299
depth_multiplier = 1.0 depth_multiplier = 1.0
...@@ -125,10 +104,10 @@ class SsdMobilenetV2FeatureExtractorTest( ...@@ -125,10 +104,10 @@ class SsdMobilenetV2FeatureExtractorTest(
(2, 2, 2, 256), (2, 1, 1, 128)] (2, 2, 2, 256), (2, 1, 1, 128)]
self.check_extract_features_returns_correct_shape( self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple, 2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_keras=use_keras) expected_feature_map_shape)
def test_extract_features_returns_correct_shapes_enforcing_min_depth( def test_extract_features_returns_correct_shapes_enforcing_min_depth(
self, use_keras): self):
image_height = 299 image_height = 299
image_width = 299 image_width = 299
depth_multiplier = 0.5**12 depth_multiplier = 0.5**12
...@@ -138,10 +117,10 @@ class SsdMobilenetV2FeatureExtractorTest( ...@@ -138,10 +117,10 @@ class SsdMobilenetV2FeatureExtractorTest(
(2, 2, 2, 32), (2, 1, 1, 32)] (2, 2, 2, 32), (2, 1, 1, 32)]
self.check_extract_features_returns_correct_shape( self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple, 2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_keras=use_keras) expected_feature_map_shape)
def test_extract_features_returns_correct_shapes_with_pad_to_multiple( def test_extract_features_returns_correct_shapes_with_pad_to_multiple(
self, use_keras): self):
image_height = 299 image_height = 299
image_width = 299 image_width = 299
depth_multiplier = 1.0 depth_multiplier = 1.0
...@@ -151,45 +130,43 @@ class SsdMobilenetV2FeatureExtractorTest( ...@@ -151,45 +130,43 @@ class SsdMobilenetV2FeatureExtractorTest(
(2, 2, 2, 256), (2, 1, 1, 128)] (2, 2, 2, 256), (2, 1, 1, 128)]
self.check_extract_features_returns_correct_shape( self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple, 2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_keras=use_keras) expected_feature_map_shape)
def test_extract_features_raises_error_with_invalid_image_size( def test_extract_features_raises_error_with_invalid_image_size(
self, use_keras): self):
image_height = 32 image_height = 32
image_width = 32 image_width = 32
depth_multiplier = 1.0 depth_multiplier = 1.0
pad_to_multiple = 1 pad_to_multiple = 1
self.check_extract_features_raises_error_with_invalid_image_size( self.check_extract_features_raises_error_with_invalid_image_size(
image_height, image_width, depth_multiplier, pad_to_multiple, image_height, image_width, depth_multiplier, pad_to_multiple)
use_keras=use_keras)
def test_preprocess_returns_correct_value_range(self, use_keras): def test_preprocess_returns_correct_value_range(self):
image_height = 128 image_height = 128
image_width = 128 image_width = 128
depth_multiplier = 1 depth_multiplier = 1
pad_to_multiple = 1 pad_to_multiple = 1
test_image = np.random.rand(4, image_height, image_width, 3) test_image = np.random.rand(4, image_height, image_width, 3)
feature_extractor = self._create_feature_extractor(depth_multiplier, feature_extractor = self._create_feature_extractor(depth_multiplier,
pad_to_multiple, pad_to_multiple)
use_keras=use_keras)
preprocessed_image = feature_extractor.preprocess(test_image) preprocessed_image = feature_extractor.preprocess(test_image)
self.assertTrue(np.all(np.less_equal(np.abs(preprocessed_image), 1.0))) self.assertTrue(np.all(np.less_equal(np.abs(preprocessed_image), 1.0)))
def test_variables_only_created_in_scope(self, use_keras): def test_variables_only_created_in_scope(self):
depth_multiplier = 1 depth_multiplier = 1
pad_to_multiple = 1 pad_to_multiple = 1
scope_name = 'MobilenetV2' scope_name = 'MobilenetV2'
self.check_feature_extractor_variables_under_scope( self.check_feature_extractor_variables_under_scope(
depth_multiplier, pad_to_multiple, scope_name, use_keras=use_keras) depth_multiplier, pad_to_multiple, scope_name)
def test_variable_count(self, use_keras): def test_variable_count(self):
depth_multiplier = 1 depth_multiplier = 1
pad_to_multiple = 1 pad_to_multiple = 1
variables = self.get_feature_extractor_variables( variables = self.get_feature_extractor_variables(
depth_multiplier, pad_to_multiple, use_keras=use_keras) depth_multiplier, pad_to_multiple)
self.assertEqual(len(variables), 292) self.assertEqual(len(variables), 292)
def test_has_fused_batchnorm(self, use_keras): def test_has_fused_batchnorm(self):
image_height = 40 image_height = 40
image_width = 40 image_width = 40
depth_multiplier = 1 depth_multiplier = 1
...@@ -197,17 +174,13 @@ class SsdMobilenetV2FeatureExtractorTest( ...@@ -197,17 +174,13 @@ class SsdMobilenetV2FeatureExtractorTest(
image_placeholder = tf.placeholder(tf.float32, image_placeholder = tf.placeholder(tf.float32,
[1, image_height, image_width, 3]) [1, image_height, image_width, 3])
feature_extractor = self._create_feature_extractor(depth_multiplier, feature_extractor = self._create_feature_extractor(depth_multiplier,
pad_to_multiple, pad_to_multiple)
use_keras=use_keras)
preprocessed_image = feature_extractor.preprocess(image_placeholder) preprocessed_image = feature_extractor.preprocess(image_placeholder)
if use_keras: _ = feature_extractor.extract_features(preprocessed_image)
_ = feature_extractor(preprocessed_image)
else:
_ = feature_extractor.extract_features(preprocessed_image)
self.assertTrue(any('FusedBatchNorm' in op.type self.assertTrue(any('FusedBatchNorm' in op.type
for op in tf.get_default_graph().get_operations())) for op in tf.get_default_graph().get_operations()))
def test_extract_features_with_fewer_layers(self, use_keras): def test_extract_features_with_fewer_layers(self):
image_height = 128 image_height = 128
image_width = 128 image_width = 128
depth_multiplier = 1.0 depth_multiplier = 1.0
...@@ -216,8 +189,7 @@ class SsdMobilenetV2FeatureExtractorTest( ...@@ -216,8 +189,7 @@ class SsdMobilenetV2FeatureExtractorTest(
(2, 2, 2, 512), (2, 1, 1, 256)] (2, 2, 2, 512), (2, 1, 1, 256)]
self.check_extract_features_returns_correct_shape( self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple, 2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_explicit_padding=False, num_layers=4, expected_feature_map_shape, use_explicit_padding=False, num_layers=4)
use_keras=use_keras)
if __name__ == '__main__': if __name__ == '__main__':
......
# Copyright 2018 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 ssd_mobilenet_v2_feature_extractor."""
import unittest
import numpy as np
import tensorflow.compat.v1 as tf
from object_detection.models import ssd_feature_extractor_test
from object_detection.models import ssd_mobilenet_v2_keras_feature_extractor
from object_detection.utils import tf_version
@unittest.skipIf(tf_version.is_tf1(), 'Skipping TF2.X only test.')
class SsdMobilenetV2FeatureExtractorTest(
ssd_feature_extractor_test.SsdFeatureExtractorTestBase):
def _create_feature_extractor(self,
depth_multiplier,
pad_to_multiple,
use_explicit_padding=False,
num_layers=6,
use_keras=False):
"""Constructs a new feature extractor.
Args:
depth_multiplier: float depth multiplier for feature extractor
pad_to_multiple: the nearest multiple to zero pad the input height and
width dimensions to.
use_explicit_padding: use 'VALID' padding for convolutions, but prepad
inputs so that the output dimensions are the same as if 'SAME' padding
were used.
num_layers: number of SSD layers.
use_keras: unused argument.
Returns:
an ssd_meta_arch.SSDFeatureExtractor object.
"""
del use_keras
min_depth = 32
return (ssd_mobilenet_v2_keras_feature_extractor.
SSDMobileNetV2KerasFeatureExtractor(
is_training=False,
depth_multiplier=depth_multiplier,
min_depth=min_depth,
pad_to_multiple=pad_to_multiple,
conv_hyperparams=self._build_conv_hyperparams(),
freeze_batchnorm=False,
inplace_batchnorm_update=False,
use_explicit_padding=use_explicit_padding,
num_layers=num_layers,
name='MobilenetV2'))
def test_extract_features_returns_correct_shapes_128(self):
image_height = 128
image_width = 128
depth_multiplier = 1.0
pad_to_multiple = 1
expected_feature_map_shape = [(2, 8, 8, 576), (2, 4, 4, 1280),
(2, 2, 2, 512), (2, 1, 1, 256),
(2, 1, 1, 256), (2, 1, 1, 128)]
self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_keras=True)
def test_extract_features_returns_correct_shapes_128_explicit_padding(
self):
image_height = 128
image_width = 128
depth_multiplier = 1.0
pad_to_multiple = 1
expected_feature_map_shape = [(2, 8, 8, 576), (2, 4, 4, 1280),
(2, 2, 2, 512), (2, 1, 1, 256),
(2, 1, 1, 256), (2, 1, 1, 128)]
self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_explicit_padding=True, use_keras=True)
def test_extract_features_returns_correct_shapes_with_dynamic_inputs(
self):
image_height = 128
image_width = 128
depth_multiplier = 1.0
pad_to_multiple = 1
expected_feature_map_shape = [(2, 8, 8, 576), (2, 4, 4, 1280),
(2, 2, 2, 512), (2, 1, 1, 256),
(2, 1, 1, 256), (2, 1, 1, 128)]
self.check_extract_features_returns_correct_shapes_with_dynamic_inputs(
2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_keras=True)
def test_extract_features_returns_correct_shapes_299(self):
image_height = 299
image_width = 299
depth_multiplier = 1.0
pad_to_multiple = 1
expected_feature_map_shape = [(2, 19, 19, 576), (2, 10, 10, 1280),
(2, 5, 5, 512), (2, 3, 3, 256),
(2, 2, 2, 256), (2, 1, 1, 128)]
self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_keras=True)
def test_extract_features_returns_correct_shapes_enforcing_min_depth(
self):
image_height = 299
image_width = 299
depth_multiplier = 0.5**12
pad_to_multiple = 1
expected_feature_map_shape = [(2, 19, 19, 192), (2, 10, 10, 32),
(2, 5, 5, 32), (2, 3, 3, 32),
(2, 2, 2, 32), (2, 1, 1, 32)]
self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_keras=True)
def test_extract_features_returns_correct_shapes_with_pad_to_multiple(
self):
image_height = 299
image_width = 299
depth_multiplier = 1.0
pad_to_multiple = 32
expected_feature_map_shape = [(2, 20, 20, 576), (2, 10, 10, 1280),
(2, 5, 5, 512), (2, 3, 3, 256),
(2, 2, 2, 256), (2, 1, 1, 128)]
self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_keras=True)
def test_extract_features_raises_error_with_invalid_image_size(
self):
image_height = 32
image_width = 32
depth_multiplier = 1.0
pad_to_multiple = 1
self.check_extract_features_raises_error_with_invalid_image_size(
image_height, image_width, depth_multiplier, pad_to_multiple,
use_keras=True)
def test_preprocess_returns_correct_value_range(self):
image_height = 128
image_width = 128
depth_multiplier = 1
pad_to_multiple = 1
test_image = np.random.rand(4, image_height, image_width, 3)
feature_extractor = self._create_feature_extractor(depth_multiplier,
pad_to_multiple)
preprocessed_image = feature_extractor.preprocess(test_image)
self.assertTrue(np.all(np.less_equal(np.abs(preprocessed_image), 1.0)))
def test_variables_only_created_in_scope(self):
depth_multiplier = 1
pad_to_multiple = 1
scope_name = 'MobilenetV2'
self.check_feature_extractor_variables_under_scope(
depth_multiplier, pad_to_multiple, scope_name, use_keras=True)
def test_variable_count(self):
depth_multiplier = 1
pad_to_multiple = 1
variables = self.get_feature_extractor_variables(
depth_multiplier, pad_to_multiple, use_keras=True)
self.assertEqual(len(variables), 292)
def test_extract_features_with_fewer_layers(self):
image_height = 128
image_width = 128
depth_multiplier = 1.0
pad_to_multiple = 1
expected_feature_map_shape = [(2, 8, 8, 576), (2, 4, 4, 1280),
(2, 2, 2, 512), (2, 1, 1, 256)]
self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_explicit_padding=False, num_layers=4,
use_keras=True)
if __name__ == '__main__':
tf.test.main()
...@@ -18,31 +18,23 @@ ...@@ -18,31 +18,23 @@
By using parameterized test decorator, this test serves for both Slim-based and By using parameterized test decorator, this test serves for both Slim-based and
Keras-based Mobilenet V2 FPN feature extractors in SSD. Keras-based Mobilenet V2 FPN feature extractors in SSD.
""" """
import unittest
from absl.testing import parameterized from absl.testing import parameterized
import numpy as np import numpy as np
import tensorflow.compat.v1 as tf import tensorflow.compat.v1 as tf
from object_detection.models import ssd_feature_extractor_test from object_detection.models import ssd_feature_extractor_test
from object_detection.models import ssd_mobilenet_v2_fpn_feature_extractor from object_detection.models import ssd_mobilenet_v2_fpn_feature_extractor
from object_detection.models import ssd_mobilenet_v2_fpn_keras_feature_extractor from object_detection.utils import tf_version
@unittest.skipIf(tf_version.is_tf2(), 'Skipping TF1.X only test.')
@parameterized.parameters( @parameterized.parameters(
{ {
'use_depthwise': False, 'use_depthwise': False
'use_keras': True
}, },
{ {
'use_depthwise': True, 'use_depthwise': True
'use_keras': True
},
{
'use_depthwise': False,
'use_keras': False
},
{
'use_depthwise': True,
'use_keras': False
}, },
) )
class SsdMobilenetV2FpnFeatureExtractorTest( class SsdMobilenetV2FpnFeatureExtractorTest(
...@@ -71,34 +63,20 @@ class SsdMobilenetV2FpnFeatureExtractorTest( ...@@ -71,34 +63,20 @@ class SsdMobilenetV2FpnFeatureExtractorTest(
Returns: Returns:
an ssd_meta_arch.SSDFeatureExtractor object. an ssd_meta_arch.SSDFeatureExtractor object.
""" """
del use_keras
min_depth = 32 min_depth = 32
if use_keras: return (ssd_mobilenet_v2_fpn_feature_extractor
return (ssd_mobilenet_v2_fpn_keras_feature_extractor .SSDMobileNetV2FpnFeatureExtractor(
.SSDMobileNetV2FpnKerasFeatureExtractor( is_training,
is_training=is_training, depth_multiplier,
depth_multiplier=depth_multiplier, min_depth,
min_depth=min_depth, pad_to_multiple,
pad_to_multiple=pad_to_multiple, self.conv_hyperparams_fn,
conv_hyperparams=self._build_conv_hyperparams( use_depthwise=use_depthwise,
add_batch_norm=False), use_explicit_padding=use_explicit_padding))
freeze_batchnorm=False,
inplace_batchnorm_update=False,
use_explicit_padding=use_explicit_padding,
use_depthwise=use_depthwise,
name='MobilenetV2_FPN'))
else:
return (ssd_mobilenet_v2_fpn_feature_extractor
.SSDMobileNetV2FpnFeatureExtractor(
is_training,
depth_multiplier,
min_depth,
pad_to_multiple,
self.conv_hyperparams_fn,
use_depthwise=use_depthwise,
use_explicit_padding=use_explicit_padding))
def test_extract_features_returns_correct_shapes_256(self, use_keras, def test_extract_features_returns_correct_shapes_256(self, use_depthwise):
use_depthwise): use_keras = False
image_height = 256 image_height = 256
image_width = 256 image_width = 256
depth_multiplier = 1.0 depth_multiplier = 1.0
...@@ -127,8 +105,8 @@ class SsdMobilenetV2FpnFeatureExtractorTest( ...@@ -127,8 +105,8 @@ class SsdMobilenetV2FpnFeatureExtractorTest(
use_keras=use_keras, use_keras=use_keras,
use_depthwise=use_depthwise) use_depthwise=use_depthwise)
def test_extract_features_returns_correct_shapes_384(self, use_keras, def test_extract_features_returns_correct_shapes_384(self, use_depthwise):
use_depthwise): use_keras = False
image_height = 320 image_height = 320
image_width = 320 image_width = 320
depth_multiplier = 1.0 depth_multiplier = 1.0
...@@ -157,8 +135,9 @@ class SsdMobilenetV2FpnFeatureExtractorTest( ...@@ -157,8 +135,9 @@ class SsdMobilenetV2FpnFeatureExtractorTest(
use_keras=use_keras, use_keras=use_keras,
use_depthwise=use_depthwise) use_depthwise=use_depthwise)
def test_extract_features_with_dynamic_image_shape(self, use_keras, def test_extract_features_with_dynamic_image_shape(self,
use_depthwise): use_depthwise):
use_keras = False
image_height = 256 image_height = 256
image_width = 256 image_width = 256
depth_multiplier = 1.0 depth_multiplier = 1.0
...@@ -188,7 +167,8 @@ class SsdMobilenetV2FpnFeatureExtractorTest( ...@@ -188,7 +167,8 @@ class SsdMobilenetV2FpnFeatureExtractorTest(
use_depthwise=use_depthwise) use_depthwise=use_depthwise)
def test_extract_features_returns_correct_shapes_with_pad_to_multiple( def test_extract_features_returns_correct_shapes_with_pad_to_multiple(
self, use_keras, use_depthwise): self, use_depthwise):
use_keras = False
image_height = 299 image_height = 299
image_width = 299 image_width = 299
depth_multiplier = 1.0 depth_multiplier = 1.0
...@@ -218,7 +198,8 @@ class SsdMobilenetV2FpnFeatureExtractorTest( ...@@ -218,7 +198,8 @@ class SsdMobilenetV2FpnFeatureExtractorTest(
use_depthwise=use_depthwise) use_depthwise=use_depthwise)
def test_extract_features_returns_correct_shapes_enforcing_min_depth( def test_extract_features_returns_correct_shapes_enforcing_min_depth(
self, use_keras, use_depthwise): self, use_depthwise):
use_keras = False
image_height = 256 image_height = 256
image_width = 256 image_width = 256
depth_multiplier = 0.5**12 depth_multiplier = 0.5**12
...@@ -248,7 +229,8 @@ class SsdMobilenetV2FpnFeatureExtractorTest( ...@@ -248,7 +229,8 @@ class SsdMobilenetV2FpnFeatureExtractorTest(
use_depthwise=use_depthwise) use_depthwise=use_depthwise)
def test_extract_features_raises_error_with_invalid_image_size( def test_extract_features_raises_error_with_invalid_image_size(
self, use_keras, use_depthwise): self, use_depthwise):
use_keras = False
image_height = 32 image_height = 32
image_width = 32 image_width = 32
depth_multiplier = 1.0 depth_multiplier = 1.0
...@@ -261,8 +243,9 @@ class SsdMobilenetV2FpnFeatureExtractorTest( ...@@ -261,8 +243,9 @@ class SsdMobilenetV2FpnFeatureExtractorTest(
use_keras=use_keras, use_keras=use_keras,
use_depthwise=use_depthwise) use_depthwise=use_depthwise)
def test_preprocess_returns_correct_value_range(self, use_keras, def test_preprocess_returns_correct_value_range(self,
use_depthwise): use_depthwise):
use_keras = False
image_height = 256 image_height = 256
image_width = 256 image_width = 256
depth_multiplier = 1 depth_multiplier = 1
...@@ -276,7 +259,8 @@ class SsdMobilenetV2FpnFeatureExtractorTest( ...@@ -276,7 +259,8 @@ class SsdMobilenetV2FpnFeatureExtractorTest(
preprocessed_image = feature_extractor.preprocess(test_image) preprocessed_image = feature_extractor.preprocess(test_image)
self.assertTrue(np.all(np.less_equal(np.abs(preprocessed_image), 1.0))) self.assertTrue(np.all(np.less_equal(np.abs(preprocessed_image), 1.0)))
def test_variables_only_created_in_scope(self, use_keras, use_depthwise): def test_variables_only_created_in_scope(self, use_depthwise):
use_keras = False
depth_multiplier = 1 depth_multiplier = 1
pad_to_multiple = 1 pad_to_multiple = 1
scope_name = 'MobilenetV2' scope_name = 'MobilenetV2'
...@@ -287,7 +271,8 @@ class SsdMobilenetV2FpnFeatureExtractorTest( ...@@ -287,7 +271,8 @@ class SsdMobilenetV2FpnFeatureExtractorTest(
use_keras=use_keras, use_keras=use_keras,
use_depthwise=use_depthwise) use_depthwise=use_depthwise)
def test_fused_batchnorm(self, use_keras, use_depthwise): def test_fused_batchnorm(self, use_depthwise):
use_keras = False
image_height = 256 image_height = 256
image_width = 256 image_width = 256
depth_multiplier = 1 depth_multiplier = 1
...@@ -300,15 +285,13 @@ class SsdMobilenetV2FpnFeatureExtractorTest( ...@@ -300,15 +285,13 @@ class SsdMobilenetV2FpnFeatureExtractorTest(
use_keras=use_keras, use_keras=use_keras,
use_depthwise=use_depthwise) use_depthwise=use_depthwise)
preprocessed_image = feature_extractor.preprocess(image_placeholder) preprocessed_image = feature_extractor.preprocess(image_placeholder)
if use_keras: _ = feature_extractor.extract_features(preprocessed_image)
_ = feature_extractor(preprocessed_image)
else:
_ = feature_extractor.extract_features(preprocessed_image)
self.assertTrue( self.assertTrue(
any('FusedBatchNorm' in op.type any('FusedBatchNorm' in op.type
for op in tf.get_default_graph().get_operations())) for op in tf.get_default_graph().get_operations()))
def test_variable_count(self, use_keras, use_depthwise): def test_variable_count(self, use_depthwise):
use_keras = False
depth_multiplier = 1 depth_multiplier = 1
pad_to_multiple = 1 pad_to_multiple = 1
variables = self.get_feature_extractor_variables( variables = self.get_feature_extractor_variables(
...@@ -321,8 +304,9 @@ class SsdMobilenetV2FpnFeatureExtractorTest( ...@@ -321,8 +304,9 @@ class SsdMobilenetV2FpnFeatureExtractorTest(
expected_variables_len = 278 expected_variables_len = 278
self.assertEqual(len(variables), expected_variables_len) self.assertEqual(len(variables), expected_variables_len)
def test_get_expected_feature_map_variable_names(self, use_keras, def test_get_expected_feature_map_variable_names(self,
use_depthwise): use_depthwise):
use_keras = False
depth_multiplier = 1.0 depth_multiplier = 1.0
pad_to_multiple = 1 pad_to_multiple = 1
...@@ -360,44 +344,6 @@ class SsdMobilenetV2FpnFeatureExtractorTest( ...@@ -360,44 +344,6 @@ class SsdMobilenetV2FpnFeatureExtractorTest(
'MobilenetV2/fpn/projection_2/weights', 'MobilenetV2/fpn/projection_2/weights',
'MobilenetV2/fpn/projection_3/weights', 'MobilenetV2/fpn/projection_3/weights',
]) ])
keras_expected_feature_maps_variables = set([
# Keras Mobilenet V2 feature maps
'MobilenetV2_FPN/block_4_depthwise/depthwise_kernel',
'MobilenetV2_FPN/block_7_depthwise/depthwise_kernel',
'MobilenetV2_FPN/block_14_depthwise/depthwise_kernel',
'MobilenetV2_FPN/Conv_1/kernel',
# FPN layers
'MobilenetV2_FPN/bottom_up_Conv2d_20_conv/kernel',
'MobilenetV2_FPN/bottom_up_Conv2d_21_conv/kernel',
'MobilenetV2_FPN/FeatureMaps/top_down/smoothing_1_conv/kernel',
'MobilenetV2_FPN/FeatureMaps/top_down/smoothing_2_conv/kernel',
'MobilenetV2_FPN/FeatureMaps/top_down/projection_1/kernel',
'MobilenetV2_FPN/FeatureMaps/top_down/projection_2/kernel',
'MobilenetV2_FPN/FeatureMaps/top_down/projection_3/kernel'
])
keras_expected_feature_maps_variables_with_depthwise = set([
# Keras Mobilenet V2 feature maps
'MobilenetV2_FPN/block_4_depthwise/depthwise_kernel',
'MobilenetV2_FPN/block_7_depthwise/depthwise_kernel',
'MobilenetV2_FPN/block_14_depthwise/depthwise_kernel',
'MobilenetV2_FPN/Conv_1/kernel',
# FPN layers
'MobilenetV2_FPN/bottom_up_Conv2d_20_depthwise_conv/depthwise_kernel',
'MobilenetV2_FPN/bottom_up_Conv2d_20_depthwise_conv/pointwise_kernel',
'MobilenetV2_FPN/bottom_up_Conv2d_21_depthwise_conv/depthwise_kernel',
'MobilenetV2_FPN/bottom_up_Conv2d_21_depthwise_conv/pointwise_kernel',
('MobilenetV2_FPN/FeatureMaps/top_down/smoothing_1_depthwise_conv/'
'depthwise_kernel'),
('MobilenetV2_FPN/FeatureMaps/top_down/smoothing_1_depthwise_conv/'
'pointwise_kernel'),
('MobilenetV2_FPN/FeatureMaps/top_down/smoothing_2_depthwise_conv/'
'depthwise_kernel'),
('MobilenetV2_FPN/FeatureMaps/top_down/smoothing_2_depthwise_conv/'
'pointwise_kernel'),
'MobilenetV2_FPN/FeatureMaps/top_down/projection_1/kernel',
'MobilenetV2_FPN/FeatureMaps/top_down/projection_2/kernel',
'MobilenetV2_FPN/FeatureMaps/top_down/projection_3/kernel'
])
g = tf.Graph() g = tf.Graph()
with g.as_default(): with g.as_default():
...@@ -407,18 +353,12 @@ class SsdMobilenetV2FpnFeatureExtractorTest( ...@@ -407,18 +353,12 @@ class SsdMobilenetV2FpnFeatureExtractorTest(
pad_to_multiple, pad_to_multiple,
use_keras=use_keras, use_keras=use_keras,
use_depthwise=use_depthwise) use_depthwise=use_depthwise)
if use_keras:
_ = feature_extractor(preprocessed_inputs) _ = feature_extractor.extract_features(preprocessed_inputs)
expected_feature_maps_variables = keras_expected_feature_maps_variables expected_feature_maps_variables = slim_expected_feature_maps_variables
if use_depthwise: if use_depthwise:
expected_feature_maps_variables = ( expected_feature_maps_variables = (
keras_expected_feature_maps_variables_with_depthwise) slim_expected_feature_maps_variables_with_depthwise)
else:
_ = feature_extractor.extract_features(preprocessed_inputs)
expected_feature_maps_variables = slim_expected_feature_maps_variables
if use_depthwise:
expected_feature_maps_variables = (
slim_expected_feature_maps_variables_with_depthwise)
actual_variable_set = set([ actual_variable_set = set([
var.op.name for var in g.get_collection(tf.GraphKeys.GLOBAL_VARIABLES) var.op.name for var in g.get_collection(tf.GraphKeys.GLOBAL_VARIABLES)
]) ])
......
# Copyright 2018 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 ssd_mobilenet_v2_fpn_feature_extractor.
By using parameterized test decorator, this test serves for both Slim-based and
Keras-based Mobilenet V2 FPN feature extractors in SSD.
"""
import unittest
from absl.testing import parameterized
import numpy as np
import tensorflow.compat.v1 as tf
from object_detection.models import ssd_feature_extractor_test
from object_detection.models import ssd_mobilenet_v2_fpn_keras_feature_extractor
from object_detection.utils import tf_version
@unittest.skipIf(tf_version.is_tf1(), 'Skipping TF2.X only test.')
@parameterized.parameters(
{
'use_depthwise': False,
},
{
'use_depthwise': True,
},
)
class SsdMobilenetV2FpnFeatureExtractorTest(
ssd_feature_extractor_test.SsdFeatureExtractorTestBase):
def _create_feature_extractor(self,
depth_multiplier,
pad_to_multiple,
is_training=True,
use_explicit_padding=False,
use_keras=False,
use_depthwise=False):
"""Constructs a new feature extractor.
Args:
depth_multiplier: float depth multiplier for feature extractor
pad_to_multiple: the nearest multiple to zero pad the input height and
width dimensions to.
is_training: whether the network is in training mode.
use_explicit_padding: Use 'VALID' padding for convolutions, but prepad
inputs so that the output dimensions are the same as if 'SAME' padding
were used.
use_keras: if True builds a keras-based feature extractor, if False builds
a slim-based one.
use_depthwise: Whether to use depthwise convolutions.
Returns:
an ssd_meta_arch.SSDFeatureExtractor object.
"""
del use_keras
min_depth = 32
return (ssd_mobilenet_v2_fpn_keras_feature_extractor
.SSDMobileNetV2FpnKerasFeatureExtractor(
is_training=is_training,
depth_multiplier=depth_multiplier,
min_depth=min_depth,
pad_to_multiple=pad_to_multiple,
conv_hyperparams=self._build_conv_hyperparams(
add_batch_norm=False),
freeze_batchnorm=False,
inplace_batchnorm_update=False,
use_explicit_padding=use_explicit_padding,
use_depthwise=use_depthwise,
name='MobilenetV2_FPN'))
def test_extract_features_returns_correct_shapes_256(self,
use_depthwise):
use_keras = True
image_height = 256
image_width = 256
depth_multiplier = 1.0
pad_to_multiple = 1
expected_feature_map_shape = [(2, 32, 32, 256), (2, 16, 16, 256),
(2, 8, 8, 256), (2, 4, 4, 256),
(2, 2, 2, 256)]
self.check_extract_features_returns_correct_shape(
2,
image_height,
image_width,
depth_multiplier,
pad_to_multiple,
expected_feature_map_shape,
use_explicit_padding=False,
use_keras=use_keras,
use_depthwise=use_depthwise)
self.check_extract_features_returns_correct_shape(
2,
image_height,
image_width,
depth_multiplier,
pad_to_multiple,
expected_feature_map_shape,
use_explicit_padding=True,
use_keras=use_keras,
use_depthwise=use_depthwise)
def test_extract_features_returns_correct_shapes_384(self,
use_depthwise):
use_keras = True
image_height = 320
image_width = 320
depth_multiplier = 1.0
pad_to_multiple = 1
expected_feature_map_shape = [(2, 40, 40, 256), (2, 20, 20, 256),
(2, 10, 10, 256), (2, 5, 5, 256),
(2, 3, 3, 256)]
self.check_extract_features_returns_correct_shape(
2,
image_height,
image_width,
depth_multiplier,
pad_to_multiple,
expected_feature_map_shape,
use_explicit_padding=False,
use_keras=use_keras,
use_depthwise=use_depthwise)
self.check_extract_features_returns_correct_shape(
2,
image_height,
image_width,
depth_multiplier,
pad_to_multiple,
expected_feature_map_shape,
use_explicit_padding=True,
use_keras=use_keras,
use_depthwise=use_depthwise)
def test_extract_features_with_dynamic_image_shape(self,
use_depthwise):
use_keras = True
image_height = 256
image_width = 256
depth_multiplier = 1.0
pad_to_multiple = 1
expected_feature_map_shape = [(2, 32, 32, 256), (2, 16, 16, 256),
(2, 8, 8, 256), (2, 4, 4, 256),
(2, 2, 2, 256)]
self.check_extract_features_returns_correct_shapes_with_dynamic_inputs(
2,
image_height,
image_width,
depth_multiplier,
pad_to_multiple,
expected_feature_map_shape,
use_explicit_padding=False,
use_keras=use_keras,
use_depthwise=use_depthwise)
self.check_extract_features_returns_correct_shapes_with_dynamic_inputs(
2,
image_height,
image_width,
depth_multiplier,
pad_to_multiple,
expected_feature_map_shape,
use_explicit_padding=True,
use_keras=use_keras,
use_depthwise=use_depthwise)
def test_extract_features_returns_correct_shapes_with_pad_to_multiple(
self, use_depthwise):
use_keras = True
image_height = 299
image_width = 299
depth_multiplier = 1.0
pad_to_multiple = 32
expected_feature_map_shape = [(2, 40, 40, 256), (2, 20, 20, 256),
(2, 10, 10, 256), (2, 5, 5, 256),
(2, 3, 3, 256)]
self.check_extract_features_returns_correct_shape(
2,
image_height,
image_width,
depth_multiplier,
pad_to_multiple,
expected_feature_map_shape,
use_explicit_padding=False,
use_keras=use_keras,
use_depthwise=use_depthwise)
self.check_extract_features_returns_correct_shape(
2,
image_height,
image_width,
depth_multiplier,
pad_to_multiple,
expected_feature_map_shape,
use_explicit_padding=True,
use_keras=use_keras,
use_depthwise=use_depthwise)
def test_extract_features_returns_correct_shapes_enforcing_min_depth(
self, use_depthwise):
use_keras = True
image_height = 256
image_width = 256
depth_multiplier = 0.5**12
pad_to_multiple = 1
expected_feature_map_shape = [(2, 32, 32, 32), (2, 16, 16, 32),
(2, 8, 8, 32), (2, 4, 4, 32),
(2, 2, 2, 32)]
self.check_extract_features_returns_correct_shape(
2,
image_height,
image_width,
depth_multiplier,
pad_to_multiple,
expected_feature_map_shape,
use_explicit_padding=False,
use_keras=use_keras,
use_depthwise=use_depthwise)
self.check_extract_features_returns_correct_shape(
2,
image_height,
image_width,
depth_multiplier,
pad_to_multiple,
expected_feature_map_shape,
use_explicit_padding=True,
use_keras=use_keras,
use_depthwise=use_depthwise)
def test_extract_features_raises_error_with_invalid_image_size(
self, use_depthwise=False):
use_keras = True
image_height = 32
image_width = 32
depth_multiplier = 1.0
pad_to_multiple = 1
self.check_extract_features_raises_error_with_invalid_image_size(
image_height,
image_width,
depth_multiplier,
pad_to_multiple,
use_keras=use_keras,
use_depthwise=use_depthwise)
def test_preprocess_returns_correct_value_range(self,
use_depthwise):
use_keras = True
image_height = 256
image_width = 256
depth_multiplier = 1
pad_to_multiple = 1
test_image = np.random.rand(2, image_height, image_width, 3)
feature_extractor = self._create_feature_extractor(
depth_multiplier,
pad_to_multiple,
use_keras=use_keras,
use_depthwise=use_depthwise)
preprocessed_image = feature_extractor.preprocess(test_image)
self.assertTrue(np.all(np.less_equal(np.abs(preprocessed_image), 1.0)))
if __name__ == '__main__':
tf.test.main()
...@@ -123,7 +123,7 @@ class SSDMobileNetV2FpnKerasFeatureExtractor( ...@@ -123,7 +123,7 @@ class SSDMobileNetV2FpnKerasFeatureExtractor(
self._conv_defs = _create_modified_mobilenet_config() self._conv_defs = _create_modified_mobilenet_config()
self._use_native_resize_op = use_native_resize_op self._use_native_resize_op = use_native_resize_op
self._feature_blocks = ['layer_4', 'layer_7', 'layer_14', 'layer_19'] self._feature_blocks = ['layer_4', 'layer_7', 'layer_14', 'layer_19']
self._mobilenet_v2 = None self.classification_backbone = None
self._fpn_features_generator = None self._fpn_features_generator = None
self._coarse_feature_layers = [] self._coarse_feature_layers = []
...@@ -147,7 +147,7 @@ class SSDMobileNetV2FpnKerasFeatureExtractor( ...@@ -147,7 +147,7 @@ class SSDMobileNetV2FpnKerasFeatureExtractor(
outputs.append(full_mobilenet_v2.get_layer(output_layer_name).output) outputs.append(full_mobilenet_v2.get_layer(output_layer_name).output)
layer_19 = full_mobilenet_v2.get_layer(name='out_relu').output layer_19 = full_mobilenet_v2.get_layer(name='out_relu').output
outputs.append(layer_19) outputs.append(layer_19)
self._mobilenet_v2 = tf.keras.Model( self.classification_backbone = tf.keras.Model(
inputs=full_mobilenet_v2.inputs, inputs=full_mobilenet_v2.inputs,
outputs=outputs) outputs=outputs)
# pylint:disable=g-long-lambda # pylint:disable=g-long-lambda
...@@ -216,7 +216,7 @@ class SSDMobileNetV2FpnKerasFeatureExtractor( ...@@ -216,7 +216,7 @@ class SSDMobileNetV2FpnKerasFeatureExtractor(
preprocessed_inputs = shape_utils.check_min_image_dim( preprocessed_inputs = shape_utils.check_min_image_dim(
33, preprocessed_inputs) 33, preprocessed_inputs)
image_features = self._mobilenet_v2( image_features = self.classification_backbone(
ops.pad_to_multiple(preprocessed_inputs, self._pad_to_multiple)) ops.pad_to_multiple(preprocessed_inputs, self._pad_to_multiple))
feature_block_list = [] feature_block_list = []
...@@ -241,3 +241,14 @@ class SSDMobileNetV2FpnKerasFeatureExtractor( ...@@ -241,3 +241,14 @@ class SSDMobileNetV2FpnKerasFeatureExtractor(
last_feature_map = layer(last_feature_map) last_feature_map = layer(last_feature_map)
feature_maps.append(last_feature_map) feature_maps.append(last_feature_map)
return feature_maps return feature_maps
def restore_from_classification_checkpoint_fn(self, feature_extractor_scope):
"""Returns a map for restoring from an (object-based) checkpoint.
Args:
feature_extractor_scope: A scope name for the feature extractor (unused).
Returns:
A dict mapping keys to Keras models
"""
return {'feature_extractor': self.classification_backbone}
...@@ -97,7 +97,7 @@ class SSDMobileNetV2KerasFeatureExtractor( ...@@ -97,7 +97,7 @@ class SSDMobileNetV2KerasFeatureExtractor(
'use_explicit_padding': self._use_explicit_padding, 'use_explicit_padding': self._use_explicit_padding,
} }
self.mobilenet_v2 = None self.classification_backbone = None
self.feature_map_generator = None self.feature_map_generator = None
def build(self, input_shape): def build(self, input_shape):
...@@ -114,7 +114,7 @@ class SSDMobileNetV2KerasFeatureExtractor( ...@@ -114,7 +114,7 @@ class SSDMobileNetV2KerasFeatureExtractor(
conv2d_11_pointwise = full_mobilenet_v2.get_layer( conv2d_11_pointwise = full_mobilenet_v2.get_layer(
name='block_13_expand_relu').output name='block_13_expand_relu').output
conv2d_13_pointwise = full_mobilenet_v2.get_layer(name='out_relu').output conv2d_13_pointwise = full_mobilenet_v2.get_layer(name='out_relu').output
self.mobilenet_v2 = tf.keras.Model( self.classification_backbone = tf.keras.Model(
inputs=full_mobilenet_v2.inputs, inputs=full_mobilenet_v2.inputs,
outputs=[conv2d_11_pointwise, conv2d_13_pointwise]) outputs=[conv2d_11_pointwise, conv2d_13_pointwise])
self.feature_map_generator = ( self.feature_map_generator = (
...@@ -158,7 +158,7 @@ class SSDMobileNetV2KerasFeatureExtractor( ...@@ -158,7 +158,7 @@ class SSDMobileNetV2KerasFeatureExtractor(
preprocessed_inputs = shape_utils.check_min_image_dim( preprocessed_inputs = shape_utils.check_min_image_dim(
33, preprocessed_inputs) 33, preprocessed_inputs)
image_features = self.mobilenet_v2( image_features = self.classification_backbone(
ops.pad_to_multiple(preprocessed_inputs, self._pad_to_multiple)) ops.pad_to_multiple(preprocessed_inputs, self._pad_to_multiple))
feature_maps = self.feature_map_generator({ feature_maps = self.feature_map_generator({
...@@ -166,3 +166,14 @@ class SSDMobileNetV2KerasFeatureExtractor( ...@@ -166,3 +166,14 @@ class SSDMobileNetV2KerasFeatureExtractor(
'layer_19': image_features[1]}) 'layer_19': image_features[1]})
return list(feature_maps.values()) return list(feature_maps.values())
def restore_from_classification_checkpoint_fn(self, feature_extractor_scope):
"""Returns a map for restoring from an (object-based) checkpoint.
Args:
feature_extractor_scope: A scope name for the feature extractor (unused).
Returns:
A dict mapping keys to Keras models
"""
return {'feature_extractor': self.classification_backbone}
...@@ -14,13 +14,16 @@ ...@@ -14,13 +14,16 @@
# limitations under the License. # limitations under the License.
# ============================================================================== # ==============================================================================
"""Tests for ssd_mobilenet_v2_nas_fpn_feature_extractor.""" """Tests for ssd_mobilenet_v2_nas_fpn_feature_extractor."""
import unittest
import numpy as np import numpy as np
import tensorflow.compat.v1 as tf import tensorflow.compat.v1 as tf
from object_detection.models import ssd_feature_extractor_test from object_detection.models import ssd_feature_extractor_test
from object_detection.models import ssd_mobilenet_v2_mnasfpn_feature_extractor as mnasfpn_feature_extractor from object_detection.models import ssd_mobilenet_v2_mnasfpn_feature_extractor as mnasfpn_feature_extractor
from object_detection.utils import tf_version
@unittest.skipIf(tf_version.is_tf2(), 'Skipping TF1.X only test.')
class SsdMobilenetV2MnasFPNFeatureExtractorTest( class SsdMobilenetV2MnasFPNFeatureExtractorTest(
ssd_feature_extractor_test.SsdFeatureExtractorTestBase): ssd_feature_extractor_test.SsdFeatureExtractorTestBase):
......
...@@ -13,17 +13,15 @@ ...@@ -13,17 +13,15 @@
# limitations under the License. # limitations under the License.
# ============================================================================== # ==============================================================================
"""Tests for ssd_mobilenet_v3_feature_extractor.""" """Tests for ssd_mobilenet_v3_feature_extractor."""
import unittest
import tensorflow.compat.v1 as tf import tensorflow.compat.v1 as tf
import tf_slim as slim
from object_detection.models import ssd_mobilenet_v3_feature_extractor from object_detection.models import ssd_mobilenet_v3_feature_extractor
from object_detection.models import ssd_mobilenet_v3_feature_extractor_testbase from object_detection.models import ssd_mobilenet_v3_feature_extractor_testbase
from object_detection.utils import tf_version
slim = slim @unittest.skipIf(tf_version.is_tf2(), 'Skipping TF1.X only test.')
class SsdMobilenetV3LargeFeatureExtractorTest( class SsdMobilenetV3LargeFeatureExtractorTest(
ssd_mobilenet_v3_feature_extractor_testbase ssd_mobilenet_v3_feature_extractor_testbase
._SsdMobilenetV3FeatureExtractorTestBase): ._SsdMobilenetV3FeatureExtractorTestBase):
...@@ -63,6 +61,7 @@ class SsdMobilenetV3LargeFeatureExtractorTest( ...@@ -63,6 +61,7 @@ class SsdMobilenetV3LargeFeatureExtractorTest(
use_explicit_padding=use_explicit_padding)) use_explicit_padding=use_explicit_padding))
@unittest.skipIf(tf_version.is_tf2(), 'Skipping TF1.X only test.')
class SsdMobilenetV3SmallFeatureExtractorTest( class SsdMobilenetV3SmallFeatureExtractorTest(
ssd_mobilenet_v3_feature_extractor_testbase ssd_mobilenet_v3_feature_extractor_testbase
._SsdMobilenetV3FeatureExtractorTestBase): ._SsdMobilenetV3FeatureExtractorTestBase):
......
...@@ -27,7 +27,10 @@ from object_detection.models import feature_map_generators ...@@ -27,7 +27,10 @@ from object_detection.models import feature_map_generators
from object_detection.utils import context_manager from object_detection.utils import context_manager
from object_detection.utils import ops from object_detection.utils import ops
from object_detection.utils import variables_helper from object_detection.utils import variables_helper
from nets.nasnet import pnasnet try:
from nets.nasnet import pnasnet # pylint: disable=g-import-not-at-top
except: # pylint: disable=bare-except
pass
def pnasnet_large_arg_scope_for_detection(is_batch_norm_training=False): def pnasnet_large_arg_scope_for_detection(is_batch_norm_training=False):
......
...@@ -14,13 +14,16 @@ ...@@ -14,13 +14,16 @@
# ============================================================================== # ==============================================================================
"""Tests for ssd_pnas_feature_extractor.""" """Tests for ssd_pnas_feature_extractor."""
import unittest
import numpy as np import numpy as np
import tensorflow.compat.v1 as tf import tensorflow.compat.v1 as tf
from object_detection.models import ssd_feature_extractor_test from object_detection.models import ssd_feature_extractor_test
from object_detection.models import ssd_pnasnet_feature_extractor from object_detection.models import ssd_pnasnet_feature_extractor
from object_detection.utils import tf_version
@unittest.skipIf(tf_version.is_tf2(), 'Skipping TF1.X only test.')
class SsdPnasNetFeatureExtractorTest( class SsdPnasNetFeatureExtractorTest(
ssd_feature_extractor_test.SsdFeatureExtractorTestBase): ssd_feature_extractor_test.SsdFeatureExtractorTestBase):
......
...@@ -19,24 +19,20 @@ from __future__ import division ...@@ -19,24 +19,20 @@ from __future__ import division
from __future__ import print_function from __future__ import print_function
import abc import abc
from absl.testing import parameterized
import numpy as np import numpy as np
from six.moves import zip from six.moves import zip
import tensorflow.compat.v1 as tf import tensorflow.compat.v1 as tf
from object_detection.models import ssd_feature_extractor_test from object_detection.models import ssd_feature_extractor_test
from object_detection.utils import test_utils
@parameterized.parameters(
{'use_keras': False},
{'use_keras': True},
)
class SSDResnetFPNFeatureExtractorTestBase( class SSDResnetFPNFeatureExtractorTestBase(
ssd_feature_extractor_test.SsdFeatureExtractorTestBase): ssd_feature_extractor_test.SsdFeatureExtractorTestBase):
"""Helper test class for SSD Resnet v1 FPN feature extractors.""" """Helper test class for SSD Resnet v1 FPN feature extractors."""
@abc.abstractmethod @abc.abstractmethod
def _resnet_scope_name(self, use_keras): def _resnet_scope_name(self):
pass pass
@abc.abstractmethod @abc.abstractmethod
...@@ -52,7 +48,7 @@ class SSDResnetFPNFeatureExtractorTestBase( ...@@ -52,7 +48,7 @@ class SSDResnetFPNFeatureExtractorTestBase(
use_keras=False): use_keras=False):
pass pass
def test_extract_features_returns_correct_shapes_256(self, use_keras): def test_extract_features_returns_correct_shapes_256(self):
image_height = 256 image_height = 256
image_width = 256 image_width = 256
depth_multiplier = 1.0 depth_multiplier = 1.0
...@@ -62,10 +58,10 @@ class SSDResnetFPNFeatureExtractorTestBase( ...@@ -62,10 +58,10 @@ class SSDResnetFPNFeatureExtractorTestBase(
(2, 2, 2, 256)] (2, 2, 2, 256)]
self.check_extract_features_returns_correct_shape( self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple, 2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape) expected_feature_map_shape, use_keras=self.is_tf2())
def test_extract_features_returns_correct_shapes_with_dynamic_inputs( def test_extract_features_returns_correct_shapes_with_dynamic_inputs(
self, use_keras): self):
image_height = 256 image_height = 256
image_width = 256 image_width = 256
depth_multiplier = 1.0 depth_multiplier = 1.0
...@@ -75,10 +71,10 @@ class SSDResnetFPNFeatureExtractorTestBase( ...@@ -75,10 +71,10 @@ class SSDResnetFPNFeatureExtractorTestBase(
(2, 2, 2, 256)] (2, 2, 2, 256)]
self.check_extract_features_returns_correct_shapes_with_dynamic_inputs( self.check_extract_features_returns_correct_shapes_with_dynamic_inputs(
2, image_height, image_width, depth_multiplier, pad_to_multiple, 2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_keras=use_keras) expected_feature_map_shape, use_keras=self.is_tf2())
def test_extract_features_returns_correct_shapes_with_depth_multiplier( def test_extract_features_returns_correct_shapes_with_depth_multiplier(
self, use_keras): self):
image_height = 256 image_height = 256
image_width = 256 image_width = 256
depth_multiplier = 0.5 depth_multiplier = 0.5
...@@ -91,10 +87,10 @@ class SSDResnetFPNFeatureExtractorTestBase( ...@@ -91,10 +87,10 @@ class SSDResnetFPNFeatureExtractorTestBase(
(2, 2, 2, expected_num_channels)] (2, 2, 2, expected_num_channels)]
self.check_extract_features_returns_correct_shape( self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple, 2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_keras=use_keras) expected_feature_map_shape, use_keras=self.is_tf2())
def test_extract_features_returns_correct_shapes_with_min_depth( def test_extract_features_returns_correct_shapes_with_min_depth(
self, use_keras): self):
image_height = 256 image_height = 256
image_width = 256 image_width = 256
depth_multiplier = 1.0 depth_multiplier = 1.0
...@@ -106,23 +102,24 @@ class SSDResnetFPNFeatureExtractorTestBase( ...@@ -106,23 +102,24 @@ class SSDResnetFPNFeatureExtractorTestBase(
(2, 4, 4, min_depth), (2, 4, 4, min_depth),
(2, 2, 2, min_depth)] (2, 2, 2, min_depth)]
def graph_fn(image_tensor): with test_utils.GraphContextOrNone() as g:
image_tensor = tf.random.uniform([2, image_height, image_width, 3])
feature_extractor = self._create_feature_extractor( feature_extractor = self._create_feature_extractor(
depth_multiplier, pad_to_multiple, min_depth=min_depth, depth_multiplier, pad_to_multiple, min_depth=min_depth,
use_keras=use_keras) use_keras=self.is_tf2())
if use_keras:
def graph_fn():
if self.is_tf2():
return feature_extractor(image_tensor) return feature_extractor(image_tensor)
return feature_extractor.extract_features(image_tensor) return feature_extractor.extract_features(image_tensor)
image_tensor = np.random.rand(2, image_height, image_width, feature_maps = self.execute(graph_fn, [], graph=g)
3).astype(np.float32)
feature_maps = self.execute(graph_fn, [image_tensor])
for feature_map, expected_shape in zip(feature_maps, for feature_map, expected_shape in zip(feature_maps,
expected_feature_map_shape): expected_feature_map_shape):
self.assertAllEqual(feature_map.shape, expected_shape) self.assertAllEqual(feature_map.shape, expected_shape)
def test_extract_features_returns_correct_shapes_with_pad_to_multiple( def test_extract_features_returns_correct_shapes_with_pad_to_multiple(
self, use_keras): self):
image_height = 254 image_height = 254
image_width = 254 image_width = 254
depth_multiplier = 1.0 depth_multiplier = 1.0
...@@ -133,55 +130,62 @@ class SSDResnetFPNFeatureExtractorTestBase( ...@@ -133,55 +130,62 @@ class SSDResnetFPNFeatureExtractorTestBase(
self.check_extract_features_returns_correct_shape( self.check_extract_features_returns_correct_shape(
2, image_height, image_width, depth_multiplier, pad_to_multiple, 2, image_height, image_width, depth_multiplier, pad_to_multiple,
expected_feature_map_shape, use_keras=use_keras) expected_feature_map_shape, use_keras=self.is_tf2())
def test_extract_features_raises_error_with_invalid_image_size( def test_extract_features_raises_error_with_invalid_image_size(
self, use_keras): self):
image_height = 32 image_height = 32
image_width = 32 image_width = 32
depth_multiplier = 1.0 depth_multiplier = 1.0
pad_to_multiple = 1 pad_to_multiple = 1
self.check_extract_features_raises_error_with_invalid_image_size( self.check_extract_features_raises_error_with_invalid_image_size(
image_height, image_width, depth_multiplier, pad_to_multiple, image_height, image_width, depth_multiplier, pad_to_multiple,
use_keras=use_keras) use_keras=self.is_tf2())
def test_preprocess_returns_correct_value_range(self, use_keras): def test_preprocess_returns_correct_value_range(self):
image_height = 128 image_height = 128
image_width = 128 image_width = 128
depth_multiplier = 1 depth_multiplier = 1
pad_to_multiple = 1 pad_to_multiple = 1
test_image = tf.constant(np.random.rand(4, image_height, image_width, 3)) test_image_np = np.random.rand(4, image_height, image_width, 3)
feature_extractor = self._create_feature_extractor(depth_multiplier, with test_utils.GraphContextOrNone() as g:
pad_to_multiple, test_image = tf.constant(test_image_np)
use_keras=use_keras) feature_extractor = self._create_feature_extractor(
preprocessed_image = feature_extractor.preprocess(test_image) depth_multiplier, pad_to_multiple, use_keras=self.is_tf2())
with self.test_session() as sess:
test_image_out, preprocessed_image_out = sess.run( def graph_fn():
[test_image, preprocessed_image]) preprocessed_image = feature_extractor.preprocess(test_image)
self.assertAllClose(preprocessed_image_out, return preprocessed_image
test_image_out - [[123.68, 116.779, 103.939]])
preprocessed_image_out = self.execute(graph_fn, [], graph=g)
def test_variables_only_created_in_scope(self, use_keras): self.assertAllClose(preprocessed_image_out,
test_image_np - [[123.68, 116.779, 103.939]])
def test_variables_only_created_in_scope(self):
if self.is_tf2():
self.skipTest('test_variables_only_created_in_scope is only tf1')
depth_multiplier = 1 depth_multiplier = 1
pad_to_multiple = 1 pad_to_multiple = 1
scope_name = self._resnet_scope_name(use_keras) scope_name = self._resnet_scope_name()
self.check_feature_extractor_variables_under_scope( self.check_feature_extractor_variables_under_scope(
depth_multiplier, depth_multiplier,
pad_to_multiple, pad_to_multiple,
scope_name, scope_name,
use_keras=use_keras) use_keras=self.is_tf2())
def test_variable_count(self, use_keras): def test_variable_count(self):
if self.is_tf2():
self.skipTest('test_variable_count is only tf1')
depth_multiplier = 1 depth_multiplier = 1
pad_to_multiple = 1 pad_to_multiple = 1
variables = self.get_feature_extractor_variables( variables = self.get_feature_extractor_variables(
depth_multiplier, depth_multiplier,
pad_to_multiple, pad_to_multiple,
use_keras=use_keras) use_keras=self.is_tf2())
# The number of expected variables in resnet_v1_50, resnet_v1_101, # The number of expected variables in resnet_v1_50, resnet_v1_101,
# and resnet_v1_152 is 279, 534, and 789 respectively. # and resnet_v1_152 is 279, 534, and 789 respectively.
expected_variables_len = 279 expected_variables_len = 279
scope_name = self._resnet_scope_name(use_keras) scope_name = self._resnet_scope_name()
if scope_name in ('ResNet101V1_FPN', 'resnet_v1_101'): if scope_name in ('ResNet101V1_FPN', 'resnet_v1_101'):
expected_variables_len = 534 expected_variables_len = 534
elif scope_name in ('ResNet152V1_FPN', 'resnet_v1_152'): elif scope_name in ('ResNet152V1_FPN', 'resnet_v1_152'):
......
...@@ -13,13 +13,15 @@ ...@@ -13,13 +13,15 @@
# limitations under the License. # limitations under the License.
# ============================================================================== # ==============================================================================
"""Tests for ssd resnet v1 FPN feature extractors.""" """Tests for ssd resnet v1 FPN feature extractors."""
import unittest
import tensorflow.compat.v1 as tf import tensorflow.compat.v1 as tf
from object_detection.models import ssd_resnet_v1_fpn_feature_extractor from object_detection.models import ssd_resnet_v1_fpn_feature_extractor
from object_detection.models import ssd_resnet_v1_fpn_feature_extractor_testbase from object_detection.models import ssd_resnet_v1_fpn_feature_extractor_testbase
from object_detection.models import ssd_resnet_v1_fpn_keras_feature_extractor from object_detection.utils import tf_version
@unittest.skipIf(tf_version.is_tf2(), 'Skipping TF1.X only test.')
class SSDResnet50V1FeatureExtractorTest( class SSDResnet50V1FeatureExtractorTest(
ssd_resnet_v1_fpn_feature_extractor_testbase. ssd_resnet_v1_fpn_feature_extractor_testbase.
SSDResnetFPNFeatureExtractorTestBase): SSDResnetFPNFeatureExtractorTestBase):
...@@ -29,31 +31,17 @@ class SSDResnet50V1FeatureExtractorTest( ...@@ -29,31 +31,17 @@ class SSDResnet50V1FeatureExtractorTest(
use_explicit_padding=False, min_depth=32, use_explicit_padding=False, min_depth=32,
use_keras=False): use_keras=False):
is_training = True is_training = True
if use_keras: return (
return (ssd_resnet_v1_fpn_keras_feature_extractor. ssd_resnet_v1_fpn_feature_extractor.SSDResnet50V1FpnFeatureExtractor(
SSDResNet50V1FpnKerasFeatureExtractor( is_training, depth_multiplier, min_depth, pad_to_multiple,
is_training=is_training, self.conv_hyperparams_fn,
depth_multiplier=depth_multiplier, use_explicit_padding=use_explicit_padding))
min_depth=min_depth,
pad_to_multiple=pad_to_multiple,
conv_hyperparams=self._build_conv_hyperparams(
add_batch_norm=False),
freeze_batchnorm=False,
inplace_batchnorm_update=False,
name='ResNet50V1_FPN'))
else:
return (
ssd_resnet_v1_fpn_feature_extractor.SSDResnet50V1FpnFeatureExtractor(
is_training, depth_multiplier, min_depth, pad_to_multiple,
self.conv_hyperparams_fn,
use_explicit_padding=use_explicit_padding))
def _resnet_scope_name(self, use_keras=False): def _resnet_scope_name(self):
if use_keras:
return 'ResNet50V1_FPN'
return 'resnet_v1_50' return 'resnet_v1_50'
@unittest.skipIf(tf_version.is_tf2(), 'Skipping TF1.X only test.')
class SSDResnet101V1FeatureExtractorTest( class SSDResnet101V1FeatureExtractorTest(
ssd_resnet_v1_fpn_feature_extractor_testbase. ssd_resnet_v1_fpn_feature_extractor_testbase.
SSDResnetFPNFeatureExtractorTestBase): SSDResnetFPNFeatureExtractorTestBase):
...@@ -63,31 +51,17 @@ class SSDResnet101V1FeatureExtractorTest( ...@@ -63,31 +51,17 @@ class SSDResnet101V1FeatureExtractorTest(
use_explicit_padding=False, min_depth=32, use_explicit_padding=False, min_depth=32,
use_keras=False): use_keras=False):
is_training = True is_training = True
if use_keras: return (
return (ssd_resnet_v1_fpn_keras_feature_extractor. ssd_resnet_v1_fpn_feature_extractor.SSDResnet101V1FpnFeatureExtractor(
SSDResNet101V1FpnKerasFeatureExtractor( is_training, depth_multiplier, min_depth, pad_to_multiple,
is_training=is_training, self.conv_hyperparams_fn,
depth_multiplier=depth_multiplier, use_explicit_padding=use_explicit_padding))
min_depth=min_depth,
pad_to_multiple=pad_to_multiple,
conv_hyperparams=self._build_conv_hyperparams(
add_batch_norm=False),
freeze_batchnorm=False,
inplace_batchnorm_update=False,
name='ResNet101V1_FPN'))
else:
return (
ssd_resnet_v1_fpn_feature_extractor.SSDResnet101V1FpnFeatureExtractor(
is_training, depth_multiplier, min_depth, pad_to_multiple,
self.conv_hyperparams_fn,
use_explicit_padding=use_explicit_padding))
def _resnet_scope_name(self, use_keras): def _resnet_scope_name(self):
if use_keras:
return 'ResNet101V1_FPN'
return 'resnet_v1_101' return 'resnet_v1_101'
@unittest.skipIf(tf_version.is_tf2(), 'Skipping TF1.X only test.')
class SSDResnet152V1FeatureExtractorTest( class SSDResnet152V1FeatureExtractorTest(
ssd_resnet_v1_fpn_feature_extractor_testbase. ssd_resnet_v1_fpn_feature_extractor_testbase.
SSDResnetFPNFeatureExtractorTestBase): SSDResnetFPNFeatureExtractorTestBase):
...@@ -97,28 +71,13 @@ class SSDResnet152V1FeatureExtractorTest( ...@@ -97,28 +71,13 @@ class SSDResnet152V1FeatureExtractorTest(
use_explicit_padding=False, min_depth=32, use_explicit_padding=False, min_depth=32,
use_keras=False): use_keras=False):
is_training = True is_training = True
if use_keras: return (
return (ssd_resnet_v1_fpn_keras_feature_extractor. ssd_resnet_v1_fpn_feature_extractor.SSDResnet152V1FpnFeatureExtractor(
SSDResNet152V1FpnKerasFeatureExtractor( is_training, depth_multiplier, min_depth, pad_to_multiple,
is_training=is_training, self.conv_hyperparams_fn,
depth_multiplier=depth_multiplier, use_explicit_padding=use_explicit_padding))
min_depth=min_depth,
pad_to_multiple=pad_to_multiple,
conv_hyperparams=self._build_conv_hyperparams(
add_batch_norm=False),
freeze_batchnorm=False,
inplace_batchnorm_update=False,
name='ResNet152V1_FPN'))
else:
return (
ssd_resnet_v1_fpn_feature_extractor.SSDResnet152V1FpnFeatureExtractor(
is_training, depth_multiplier, min_depth, pad_to_multiple,
self.conv_hyperparams_fn,
use_explicit_padding=use_explicit_padding))
def _resnet_scope_name(self, use_keras): def _resnet_scope_name(self):
if use_keras:
return 'ResNet152V1_FPN'
return 'resnet_v1_152' return 'resnet_v1_152'
......
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