X-Git-Url: https://gerrit.akraino.org/r/gitweb?a=blobdiff_plain;f=example-apps%2FPDD%2Fpcb-defect-detection%2Flibs%2Fnetworks%2Fslim_nets%2Fresnet_v1_test.py;fp=example-apps%2FPDD%2Fpcb-defect-detection%2Flibs%2Fnetworks%2Fslim_nets%2Fresnet_v1_test.py;h=5b27a18d45606c00e8a0d38d5ceb4286c9c548a5;hb=a785567fb9acfc68536767d20f60ba917ae85aa1;hp=0000000000000000000000000000000000000000;hpb=94a133e696b9b2a7f73544462c2714986fa7ab4a;p=ealt-edge.git diff --git a/example-apps/PDD/pcb-defect-detection/libs/networks/slim_nets/resnet_v1_test.py b/example-apps/PDD/pcb-defect-detection/libs/networks/slim_nets/resnet_v1_test.py new file mode 100755 index 0000000..5b27a18 --- /dev/null +++ b/example-apps/PDD/pcb-defect-detection/libs/networks/slim_nets/resnet_v1_test.py @@ -0,0 +1,440 @@ +# Copyright 2016 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 slim.slim_nets.resnet_v1.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import numpy as np +import tensorflow as tf + +from nets import resnet_utils +from nets import resnet_v1 + +slim = tf.contrib.slim + + +def create_test_input(batch_size, height, width, channels): + """Create test input tensor. + + Args: + batch_size: The number of images per batch or `None` if unknown. + height: The height of each image or `None` if unknown. + width: The width of each image or `None` if unknown. + channels: The number of channels per image or `None` if unknown. + + Returns: + Either a placeholder `Tensor` of dimension + [batch_size, height, width, channels] if any of the inputs are `None` or a + constant `Tensor` with the mesh grid values along the spatial dimensions. + """ + if None in [batch_size, height, width, channels]: + return tf.placeholder(tf.float32, (batch_size, height, width, channels)) + else: + return tf.to_float( + np.tile( + np.reshape( + np.reshape(np.arange(height), [height, 1]) + + np.reshape(np.arange(width), [1, width]), + [1, height, width, 1]), + [batch_size, 1, 1, channels])) + + +class ResnetUtilsTest(tf.test.TestCase): + + def testSubsampleThreeByThree(self): + x = tf.reshape(tf.to_float(tf.range(9)), [1, 3, 3, 1]) + x = resnet_utils.subsample(x, 2) + expected = tf.reshape(tf.constant([0, 2, 6, 8]), [1, 2, 2, 1]) + with self.test_session(): + self.assertAllClose(x.eval(), expected.eval()) + + def testSubsampleFourByFour(self): + x = tf.reshape(tf.to_float(tf.range(16)), [1, 4, 4, 1]) + x = resnet_utils.subsample(x, 2) + expected = tf.reshape(tf.constant([0, 2, 8, 10]), [1, 2, 2, 1]) + with self.test_session(): + self.assertAllClose(x.eval(), expected.eval()) + + def testConv2DSameEven(self): + n, n2 = 4, 2 + + # Input image. + x = create_test_input(1, n, n, 1) + + # Convolution kernel. + w = create_test_input(1, 3, 3, 1) + w = tf.reshape(w, [3, 3, 1, 1]) + + tf.get_variable('Conv/weights', initializer=w) + tf.get_variable('Conv/biases', initializer=tf.zeros([1])) + tf.get_variable_scope().reuse_variables() + + y1 = slim.conv2d(x, 1, [3, 3], stride=1, scope='Conv') + y1_expected = tf.to_float([[14, 28, 43, 26], + [28, 48, 66, 37], + [43, 66, 84, 46], + [26, 37, 46, 22]]) + y1_expected = tf.reshape(y1_expected, [1, n, n, 1]) + + y2 = resnet_utils.subsample(y1, 2) + y2_expected = tf.to_float([[14, 43], + [43, 84]]) + y2_expected = tf.reshape(y2_expected, [1, n2, n2, 1]) + + y3 = resnet_utils.conv2d_same(x, 1, 3, stride=2, scope='Conv') + y3_expected = y2_expected + + y4 = slim.conv2d(x, 1, [3, 3], stride=2, scope='Conv') + y4_expected = tf.to_float([[48, 37], + [37, 22]]) + y4_expected = tf.reshape(y4_expected, [1, n2, n2, 1]) + + with self.test_session() as sess: + sess.run(tf.global_variables_initializer()) + self.assertAllClose(y1.eval(), y1_expected.eval()) + self.assertAllClose(y2.eval(), y2_expected.eval()) + self.assertAllClose(y3.eval(), y3_expected.eval()) + self.assertAllClose(y4.eval(), y4_expected.eval()) + + def testConv2DSameOdd(self): + n, n2 = 5, 3 + + # Input image. + x = create_test_input(1, n, n, 1) + + # Convolution kernel. + w = create_test_input(1, 3, 3, 1) + w = tf.reshape(w, [3, 3, 1, 1]) + + tf.get_variable('Conv/weights', initializer=w) + tf.get_variable('Conv/biases', initializer=tf.zeros([1])) + tf.get_variable_scope().reuse_variables() + + y1 = slim.conv2d(x, 1, [3, 3], stride=1, scope='Conv') + y1_expected = tf.to_float([[14, 28, 43, 58, 34], + [28, 48, 66, 84, 46], + [43, 66, 84, 102, 55], + [58, 84, 102, 120, 64], + [34, 46, 55, 64, 30]]) + y1_expected = tf.reshape(y1_expected, [1, n, n, 1]) + + y2 = resnet_utils.subsample(y1, 2) + y2_expected = tf.to_float([[14, 43, 34], + [43, 84, 55], + [34, 55, 30]]) + y2_expected = tf.reshape(y2_expected, [1, n2, n2, 1]) + + y3 = resnet_utils.conv2d_same(x, 1, 3, stride=2, scope='Conv') + y3_expected = y2_expected + + y4 = slim.conv2d(x, 1, [3, 3], stride=2, scope='Conv') + y4_expected = y2_expected + + with self.test_session() as sess: + sess.run(tf.global_variables_initializer()) + self.assertAllClose(y1.eval(), y1_expected.eval()) + self.assertAllClose(y2.eval(), y2_expected.eval()) + self.assertAllClose(y3.eval(), y3_expected.eval()) + self.assertAllClose(y4.eval(), y4_expected.eval()) + + def _resnet_plain(self, inputs, blocks, output_stride=None, scope=None): + """A plain ResNet without extra layers before or after the ResNet blocks.""" + with tf.variable_scope(scope, values=[inputs]): + with slim.arg_scope([slim.conv2d], outputs_collections='end_points'): + net = resnet_utils.stack_blocks_dense(inputs, blocks, output_stride) + end_points = slim.utils.convert_collection_to_dict('end_points') + return net, end_points + + def testEndPointsV1(self): + """Test the end points of a tiny v1 bottleneck network.""" + blocks = [ + resnet_v1.resnet_v1_block( + 'block1', base_depth=1, num_units=2, stride=2), + resnet_v1.resnet_v1_block( + 'block2', base_depth=2, num_units=2, stride=1), + ] + inputs = create_test_input(2, 32, 16, 3) + with slim.arg_scope(resnet_utils.resnet_arg_scope()): + _, end_points = self._resnet_plain(inputs, blocks, scope='tiny') + expected = [ + 'tiny/block1/unit_1/bottleneck_v1/shortcut', + 'tiny/block1/unit_1/bottleneck_v1/conv1', + 'tiny/block1/unit_1/bottleneck_v1/conv2', + 'tiny/block1/unit_1/bottleneck_v1/conv3', + 'tiny/block1/unit_2/bottleneck_v1/conv1', + 'tiny/block1/unit_2/bottleneck_v1/conv2', + 'tiny/block1/unit_2/bottleneck_v1/conv3', + 'tiny/block2/unit_1/bottleneck_v1/shortcut', + 'tiny/block2/unit_1/bottleneck_v1/conv1', + 'tiny/block2/unit_1/bottleneck_v1/conv2', + 'tiny/block2/unit_1/bottleneck_v1/conv3', + 'tiny/block2/unit_2/bottleneck_v1/conv1', + 'tiny/block2/unit_2/bottleneck_v1/conv2', + 'tiny/block2/unit_2/bottleneck_v1/conv3'] + self.assertItemsEqual(expected, end_points) + + def _stack_blocks_nondense(self, net, blocks): + """A simplified ResNet Block stacker without output stride control.""" + for block in blocks: + with tf.variable_scope(block.scope, 'block', [net]): + for i, unit in enumerate(block.args): + with tf.variable_scope('unit_%d' % (i + 1), values=[net]): + net = block.unit_fn(net, rate=1, **unit) + return net + + def testAtrousValuesBottleneck(self): + """Verify the values of dense feature extraction by atrous convolution. + + Make sure that dense feature extraction by stack_blocks_dense() followed by + subsampling gives identical results to feature extraction at the nominal + network output stride using the simple self._stack_blocks_nondense() above. + """ + block = resnet_v1.resnet_v1_block + blocks = [ + block('block1', base_depth=1, num_units=2, stride=2), + block('block2', base_depth=2, num_units=2, stride=2), + block('block3', base_depth=4, num_units=2, stride=2), + block('block4', base_depth=8, num_units=2, stride=1), + ] + nominal_stride = 8 + + # Test both odd and even input dimensions. + height = 30 + width = 31 + with slim.arg_scope(resnet_utils.resnet_arg_scope()): + with slim.arg_scope([slim.batch_norm], is_training=False): + for output_stride in [1, 2, 4, 8, None]: + with tf.Graph().as_default(): + with self.test_session() as sess: + tf.set_random_seed(0) + inputs = create_test_input(1, height, width, 3) + # Dense feature extraction followed by subsampling. + output = resnet_utils.stack_blocks_dense(inputs, + blocks, + output_stride) + if output_stride is None: + factor = 1 + else: + factor = nominal_stride // output_stride + + output = resnet_utils.subsample(output, factor) + # Make the two networks use the same weights. + tf.get_variable_scope().reuse_variables() + # Feature extraction at the nominal network rate. + expected = self._stack_blocks_nondense(inputs, blocks) + sess.run(tf.global_variables_initializer()) + output, expected = sess.run([output, expected]) + self.assertAllClose(output, expected, atol=1e-4, rtol=1e-4) + + +class ResnetCompleteNetworkTest(tf.test.TestCase): + """Tests with complete small ResNet v1 networks.""" + + def _resnet_small(self, + inputs, + num_classes=None, + is_training=True, + global_pool=True, + output_stride=None, + include_root_block=True, + reuse=None, + scope='resnet_v1_small'): + """A shallow and thin ResNet v1 for faster tests.""" + block = resnet_v1.resnet_v1_block + blocks = [ + block('block1', base_depth=1, num_units=3, stride=2), + block('block2', base_depth=2, num_units=3, stride=2), + block('block3', base_depth=4, num_units=3, stride=2), + block('block4', base_depth=8, num_units=2, stride=1), + ] + return resnet_v1.resnet_v1(inputs, blocks, num_classes, + is_training=is_training, + global_pool=global_pool, + output_stride=output_stride, + include_root_block=include_root_block, + reuse=reuse, + scope=scope) + + def testClassificationEndPoints(self): + global_pool = True + num_classes = 10 + inputs = create_test_input(2, 224, 224, 3) + with slim.arg_scope(resnet_utils.resnet_arg_scope()): + logits, end_points = self._resnet_small(inputs, num_classes, + global_pool=global_pool, + scope='resnet') + self.assertTrue(logits.op.name.startswith('resnet/logits')) + self.assertListEqual(logits.get_shape().as_list(), [2, 1, 1, num_classes]) + self.assertTrue('predictions' in end_points) + self.assertListEqual(end_points['predictions'].get_shape().as_list(), + [2, 1, 1, num_classes]) + + def testClassificationShapes(self): + global_pool = True + num_classes = 10 + inputs = create_test_input(2, 224, 224, 3) + with slim.arg_scope(resnet_utils.resnet_arg_scope()): + _, end_points = self._resnet_small(inputs, num_classes, + global_pool=global_pool, + scope='resnet') + endpoint_to_shape = { + 'resnet/block1': [2, 28, 28, 4], + 'resnet/block2': [2, 14, 14, 8], + 'resnet/block3': [2, 7, 7, 16], + 'resnet/block4': [2, 7, 7, 32]} + for endpoint in endpoint_to_shape: + shape = endpoint_to_shape[endpoint] + self.assertListEqual(end_points[endpoint].get_shape().as_list(), shape) + + def testFullyConvolutionalEndpointShapes(self): + global_pool = False + num_classes = 10 + inputs = create_test_input(2, 321, 321, 3) + with slim.arg_scope(resnet_utils.resnet_arg_scope()): + _, end_points = self._resnet_small(inputs, num_classes, + global_pool=global_pool, + scope='resnet') + endpoint_to_shape = { + 'resnet/block1': [2, 41, 41, 4], + 'resnet/block2': [2, 21, 21, 8], + 'resnet/block3': [2, 11, 11, 16], + 'resnet/block4': [2, 11, 11, 32]} + for endpoint in endpoint_to_shape: + shape = endpoint_to_shape[endpoint] + self.assertListEqual(end_points[endpoint].get_shape().as_list(), shape) + + def testRootlessFullyConvolutionalEndpointShapes(self): + global_pool = False + num_classes = 10 + inputs = create_test_input(2, 128, 128, 3) + with slim.arg_scope(resnet_utils.resnet_arg_scope()): + _, end_points = self._resnet_small(inputs, num_classes, + global_pool=global_pool, + include_root_block=False, + scope='resnet') + endpoint_to_shape = { + 'resnet/block1': [2, 64, 64, 4], + 'resnet/block2': [2, 32, 32, 8], + 'resnet/block3': [2, 16, 16, 16], + 'resnet/block4': [2, 16, 16, 32]} + for endpoint in endpoint_to_shape: + shape = endpoint_to_shape[endpoint] + self.assertListEqual(end_points[endpoint].get_shape().as_list(), shape) + + def testAtrousFullyConvolutionalEndpointShapes(self): + global_pool = False + num_classes = 10 + output_stride = 8 + inputs = create_test_input(2, 321, 321, 3) + with slim.arg_scope(resnet_utils.resnet_arg_scope()): + _, end_points = self._resnet_small(inputs, + num_classes, + global_pool=global_pool, + output_stride=output_stride, + scope='resnet') + endpoint_to_shape = { + 'resnet/block1': [2, 41, 41, 4], + 'resnet/block2': [2, 41, 41, 8], + 'resnet/block3': [2, 41, 41, 16], + 'resnet/block4': [2, 41, 41, 32]} + for endpoint in endpoint_to_shape: + shape = endpoint_to_shape[endpoint] + self.assertListEqual(end_points[endpoint].get_shape().as_list(), shape) + + def testAtrousFullyConvolutionalValues(self): + """Verify dense feature extraction with atrous convolution.""" + nominal_stride = 32 + for output_stride in [4, 8, 16, 32, None]: + with slim.arg_scope(resnet_utils.resnet_arg_scope()): + with tf.Graph().as_default(): + with self.test_session() as sess: + tf.set_random_seed(0) + inputs = create_test_input(2, 81, 81, 3) + # Dense feature extraction followed by subsampling. + output, _ = self._resnet_small(inputs, None, is_training=False, + global_pool=False, + output_stride=output_stride) + if output_stride is None: + factor = 1 + else: + factor = nominal_stride // output_stride + output = resnet_utils.subsample(output, factor) + # Make the two networks use the same weights. + tf.get_variable_scope().reuse_variables() + # Feature extraction at the nominal network rate. + expected, _ = self._resnet_small(inputs, None, is_training=False, + global_pool=False) + sess.run(tf.global_variables_initializer()) + self.assertAllClose(output.eval(), expected.eval(), + atol=1e-4, rtol=1e-4) + + def testUnknownBatchSize(self): + batch = 2 + height, width = 65, 65 + global_pool = True + num_classes = 10 + inputs = create_test_input(None, height, width, 3) + with slim.arg_scope(resnet_utils.resnet_arg_scope()): + logits, _ = self._resnet_small(inputs, num_classes, + global_pool=global_pool, + scope='resnet') + self.assertTrue(logits.op.name.startswith('resnet/logits')) + self.assertListEqual(logits.get_shape().as_list(), + [None, 1, 1, num_classes]) + images = create_test_input(batch, height, width, 3) + with self.test_session() as sess: + sess.run(tf.global_variables_initializer()) + output = sess.run(logits, {inputs: images.eval()}) + self.assertEqual(output.shape, (batch, 1, 1, num_classes)) + + def testFullyConvolutionalUnknownHeightWidth(self): + batch = 2 + height, width = 65, 65 + global_pool = False + inputs = create_test_input(batch, None, None, 3) + with slim.arg_scope(resnet_utils.resnet_arg_scope()): + output, _ = self._resnet_small(inputs, None, global_pool=global_pool) + self.assertListEqual(output.get_shape().as_list(), + [batch, None, None, 32]) + images = create_test_input(batch, height, width, 3) + with self.test_session() as sess: + sess.run(tf.global_variables_initializer()) + output = sess.run(output, {inputs: images.eval()}) + self.assertEqual(output.shape, (batch, 3, 3, 32)) + + def testAtrousFullyConvolutionalUnknownHeightWidth(self): + batch = 2 + height, width = 65, 65 + global_pool = False + output_stride = 8 + inputs = create_test_input(batch, None, None, 3) + with slim.arg_scope(resnet_utils.resnet_arg_scope()): + output, _ = self._resnet_small(inputs, + None, + global_pool=global_pool, + output_stride=output_stride) + self.assertListEqual(output.get_shape().as_list(), + [batch, None, None, 32]) + images = create_test_input(batch, height, width, 3) + with self.test_session() as sess: + sess.run(tf.global_variables_initializer()) + output = sess.run(output, {inputs: images.eval()}) + self.assertEqual(output.shape, (batch, 9, 9, 32)) + + +if __name__ == '__main__': + tf.test.main()