| # 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. |
| # ============================================================================== |
| """Functional tests for 3d pooling operations.""" |
| |
| from __future__ import absolute_import |
| from __future__ import division |
| from __future__ import print_function |
| |
| import numpy as np |
| |
| from tensorflow.python.framework import constant_op |
| from tensorflow.python.framework import test_util |
| from tensorflow.python.ops import gradient_checker |
| from tensorflow.python.ops import gradients_impl |
| from tensorflow.python.ops import nn_ops |
| import tensorflow.python.ops.nn_grad # pylint: disable=unused-import |
| from tensorflow.python.platform import test |
| |
| |
| def GetTestConfigs(): |
| """Get all the valid tests configs to run. |
| |
| Returns: |
| all the valid test configs as tuples of data_format and use_gpu. |
| """ |
| test_configs = [("NDHWC", False), ("NDHWC", True)] |
| if test.is_gpu_available(cuda_only=True): |
| # "NCHW" format is currently supported exclusively on CUDA GPUs. |
| test_configs += [("NCDHW", True)] |
| return test_configs |
| |
| |
| # TODO(mjanusz): Add microbenchmarks for 3d pooling. |
| class PoolingTest(test.TestCase): |
| |
| def _VerifyOneTest(self, pool_func, input_sizes, window, strides, padding, |
| data_format, expected, use_gpu): |
| """Verifies the output values of the pooling function. |
| |
| Args: |
| pool_func: Function to be called: co.MaxPool, co.AvgPool. |
| input_sizes: Input tensor dimensions. |
| window: Tuple of kernel dims: planes, rows, cols. |
| strides: Tuple of strides for dims: planes, rows, cols. |
| padding: Padding type. |
| data_format: The data format we use to run the pooling operation. |
| expected: An array containing the expected operation outputs. |
| use_gpu: Whether to run ops on GPU. |
| """ |
| total_size = 1 |
| for s in input_sizes: |
| total_size *= s |
| # Initializes the input tensor with array containing incrementing |
| # numbers from 1. |
| x = [f * 1.0 for f in range(1, total_size + 1)] |
| with self.cached_session(use_gpu=use_gpu) as sess: |
| t = constant_op.constant(x, shape=input_sizes) |
| window = [1] + list(window) + [1] |
| strides = [1] + list(strides) + [1] |
| if data_format == "NCDHW": |
| t = test_util.NHWCToNCHW(t) |
| window = test_util.NHWCToNCHW(window) |
| strides = test_util.NHWCToNCHW(strides) |
| t = pool_func( |
| t, |
| ksize=window, |
| strides=strides, |
| padding=padding, |
| data_format=data_format) |
| if data_format == "NCDHW": |
| t = test_util.NCHWToNHWC(t) |
| vals = self.evaluate(t) |
| # Verifies values. |
| actual = vals.flatten() |
| self.assertAllClose(expected, actual) |
| |
| def _VerifyValues(self, pool_func, input_sizes, window, strides, |
| padding, expected): |
| for data_format, use_gpu in GetTestConfigs(): |
| self._VerifyOneTest(pool_func, input_sizes, window, strides, padding, |
| data_format, expected, use_gpu) |
| |
| def testAvgPool3dValidPadding(self): |
| expected_output = [20.5, 21.5, 22.5] |
| self._VerifyValues( |
| nn_ops.avg_pool3d, |
| input_sizes=[1, 3, 3, 3, 3], |
| window=(2, 2, 2), |
| strides=(2, 2, 2), |
| padding="VALID", |
| expected=expected_output) |
| |
| def testAvgPool3dSamePadding(self): |
| expected_output = [20.5, 21.5, 22.5, 26.5, 27.5, 28.5] |
| self._VerifyValues( |
| nn_ops.avg_pool3d, |
| input_sizes=[1, 2, 2, 4, 3], |
| window=(2, 2, 2), |
| strides=(2, 2, 2), |
| padding="SAME", |
| expected=expected_output) |
| |
| def testAvgPool3dSamePaddingDifferentStrides(self): |
| expected_output = [1.5, 4.5, 7.5, 17.5, 20.5, 23.5, 33.5, 36.5, 39.5] |
| self._VerifyValues( |
| nn_ops.avg_pool3d, |
| input_sizes=[1, 5, 8, 1, 1], |
| window=(1, 2, 3), |
| strides=(2, 3, 1), |
| padding="SAME", |
| expected=expected_output) |
| |
| def testMaxPool3dValidPadding(self): |
| expected_output = [40.0, 41.0, 42.0] |
| self._VerifyValues( |
| nn_ops.max_pool3d, |
| input_sizes=[1, 3, 3, 3, 3], |
| window=(2, 2, 2), |
| strides=(2, 2, 2), |
| padding="VALID", |
| expected=expected_output) |
| |
| def testMaxPool3dSamePadding(self): |
| expected_output = [31., 32., 33., 34., 35., 36.] |
| self._VerifyValues( |
| nn_ops.max_pool3d, |
| input_sizes=[1, 2, 2, 3, 3], |
| window=(2, 2, 2), |
| strides=(2, 2, 2), |
| padding="SAME", |
| expected=expected_output) |
| |
| def testMaxPool3dSamePaddingDifferentStrides(self): |
| expected_output = [2., 5., 8., 18., 21., 24., 34., 37., 40.] |
| self._VerifyValues( |
| nn_ops.max_pool3d, |
| input_sizes=[1, 5, 8, 1, 1], |
| window=(1, 2, 3), |
| strides=(2, 3, 1), |
| padding="SAME", |
| expected=expected_output) |
| |
| # Test pooling on a larger input, with different stride and kernel |
| # size for the 'z' dimension. |
| |
| # Simulate max pooling in numpy to get the expected output. |
| input_data = np.arange(1, 5 * 27 * 27 * 64 + 1).reshape((5, 27, 27, 64)) |
| input_data = np.pad(input_data, [[0, 0], [0, 1], [0, 1], [0, 0]], |
| mode="constant") |
| expected_output = input_data[:, 1::2, 1::2, :] |
| expected_output[:, -1, :, :] = input_data[:, -2, 1::2, :] |
| expected_output[:, :, -1, :] = input_data[:, 1::2, -2, :] |
| expected_output[:, -1, -1, :] = input_data[:, -2, -2, :] |
| |
| self._VerifyValues( |
| nn_ops.max_pool3d, |
| input_sizes=[1, 5, 27, 27, 64], |
| window=(1, 2, 2), |
| strides=(1, 2, 2), |
| padding="SAME", |
| expected=expected_output.flatten()) |
| |
| def testKernelSmallerThanStride(self): |
| self._VerifyValues( |
| nn_ops.max_pool3d, |
| input_sizes=[1, 3, 3, 3, 1], |
| window=[1, 1, 1], |
| strides=[2, 2, 2], |
| padding="SAME", |
| expected=[1, 3, 7, 9, 19, 21, 25, 27]) |
| |
| self._VerifyValues( |
| nn_ops.max_pool3d, |
| input_sizes=[1, 7, 7, 7, 1], |
| window=[2, 2, 2], |
| strides=[3, 3, 3], |
| padding="VALID", |
| expected=[58, 61, 79, 82, 205, 208, 226, 229]) |
| |
| self._VerifyValues( |
| nn_ops.avg_pool3d, |
| input_sizes=[1, 3, 3, 3, 1], |
| window=[1, 1, 1], |
| strides=[2, 2, 2], |
| padding="SAME", |
| expected=[1, 3, 7, 9, 19, 21, 25, 27]) |
| |
| self._VerifyValues( |
| nn_ops.avg_pool3d, |
| input_sizes=[1, 7, 7, 7, 1], |
| window=[2, 2, 2], |
| strides=[3, 3, 3], |
| padding="VALID", |
| expected=[29.5, 32.5, 50.5, 53.5, 176.5, 179.5, 197.5, 200.5]) |
| |
| def _ConstructAndTestGradientForConfig(self, |
| pool_func, |
| input_sizes, |
| output_sizes, |
| window, |
| strides, |
| padding, |
| data_format, |
| use_gpu): |
| """Verifies the gradients of a pooling function. |
| |
| Args: |
| pool_func: Function to be called, co.MaxPool, co.AvgPool, |
| or the Lua version. |
| input_sizes: Input tensor dimensions. |
| output_sizes: Output tensor dimensions. |
| window: Tuple of kernel dims: planes, rows, cols. |
| strides: Tuple of strides for dims: planes, rows, cols. |
| padding: Padding type. |
| data_format: Data format string. |
| use_gpu: Whether to run on GPU. |
| """ |
| total_size = 1 |
| for s in input_sizes: |
| total_size *= s |
| # Initializes the input tensor with array containing incrementing |
| # numbers from 1. |
| x = np.arange(1, total_size + 1, dtype=np.float32) |
| with self.cached_session(use_gpu=use_gpu): |
| input_tensor = constant_op.constant(x, shape=input_sizes, name="input") |
| err_g_margin = 1e-3 |
| err_gg_margin = 1.5e-2 |
| if pool_func == nn_ops.avg_pool3d: |
| func_name = "avg_pool3d" |
| x_init_value = None |
| else: |
| x_init_value = np.asfarray(np.arange(1, total_size + 1), |
| dtype=np.float32).reshape(input_sizes) |
| func_name = "max_pool3d" |
| |
| ksize = [1, window[0], window[1], window[2], 1] |
| strides = [1, strides[0], strides[1], strides[2], 1] |
| t = input_tensor |
| |
| if data_format == "NCDHW": |
| ksize = test_util.NHWCToNCHW(ksize) |
| strides = test_util.NHWCToNCHW(strides) |
| t = test_util.NHWCToNCHW(t) |
| output_sizes = test_util.NHWCToNCHW(output_sizes) |
| |
| t = pool_func( |
| t, |
| ksize=ksize, |
| strides=strides, |
| padding=padding, |
| data_format=data_format, |
| name=func_name) |
| t_g = gradients_impl.gradients(t**2, input_tensor)[0] |
| |
| err_g = gradient_checker.compute_gradient_error( |
| input_tensor, |
| input_sizes, |
| t, |
| output_sizes, |
| x_init_value=x_init_value, |
| delta=1e-2) |
| err_gg = gradient_checker.compute_gradient_error( |
| input_tensor, |
| input_sizes, |
| t_g, |
| input_sizes, |
| x_init_value=x_init_value, |
| delta=1e-2) |
| |
| print("%s gradient error = " % func_name, err_g) |
| self.assertLess(err_g, err_g_margin) |
| print("%s second-order gradient error = " % func_name, err_gg) |
| self.assertLess(err_gg, err_gg_margin) |
| |
| def _ConstructAndTestGradient(self, |
| pool_func, |
| **kwargs): |
| """Runs _ConstructAndTestGradientForConfig for all tests configurations.""" |
| |
| for data_format, use_gpu in GetTestConfigs(): |
| self._ConstructAndTestGradientForConfig(pool_func, |
| data_format=data_format, |
| use_gpu=use_gpu, |
| **kwargs) |
| |
| @test_util.run_deprecated_v1 |
| def testMaxPoolGradValidPadding1_1_3d(self): |
| self._ConstructAndTestGradient( |
| nn_ops.max_pool3d, |
| input_sizes=[1, 3, 3, 3, 1], |
| output_sizes=[1, 3, 3, 3, 1], |
| window=(1, 1, 1), |
| strides=(1, 1, 1), |
| padding="VALID") |
| |
| @test_util.run_deprecated_v1 |
| def testMaxPoolGradValidPadding2_1_6_3d(self): |
| self._ConstructAndTestGradient( |
| nn_ops.max_pool3d, |
| input_sizes=[1, 2, 3, 4, 2], |
| output_sizes=[1, 1, 2, 3, 2], |
| window=(2, 2, 2), |
| strides=(1, 1, 1), |
| padding="VALID") |
| |
| @test_util.run_deprecated_v1 |
| def testMaxPoolGradValidPadding2_1_7_3d(self): |
| self._ConstructAndTestGradient( |
| nn_ops.max_pool3d, |
| input_sizes=[1, 3, 2, 7, 1], |
| output_sizes=[1, 2, 1, 6, 1], |
| window=(2, 2, 2), |
| strides=(1, 1, 1), |
| padding="VALID") |
| |
| @test_util.run_deprecated_v1 |
| def testMaxPoolGradValidPadding1_2_3d(self): |
| self._ConstructAndTestGradient( |
| nn_ops.max_pool3d, |
| input_sizes=[1, 3, 3, 3, 1], |
| output_sizes=[1, 2, 2, 2, 1], |
| window=(1, 1, 1), |
| strides=(2, 2, 2), |
| padding="VALID") |
| |
| @test_util.run_deprecated_v1 |
| def testMaxPoolGradValidPadding2_2_3d(self): |
| self._ConstructAndTestGradient( |
| nn_ops.max_pool3d, |
| input_sizes=[2, 2, 2, 2, 1], |
| output_sizes=[2, 1, 1, 1, 1], |
| window=(2, 2, 2), |
| strides=(2, 2, 2), |
| padding="VALID") |
| |
| @test_util.run_deprecated_v1 |
| def testMaxPoolGradSamePadding1_1_3d(self): |
| self._ConstructAndTestGradient( |
| nn_ops.max_pool3d, |
| input_sizes=[1, 3, 2, 4, 1], |
| output_sizes=[1, 3, 2, 4, 1], |
| window=(1, 1, 1), |
| strides=(1, 1, 1), |
| padding="SAME") |
| |
| @test_util.run_deprecated_v1 |
| def testMaxPoolGradSamePadding1_2_3d(self): |
| self._ConstructAndTestGradient( |
| nn_ops.max_pool3d, |
| input_sizes=[1, 3, 2, 4, 1], |
| output_sizes=[1, 2, 1, 2, 1], |
| window=(1, 1, 1), |
| strides=(2, 2, 2), |
| padding="SAME") |
| |
| @test_util.run_deprecated_v1 |
| def testMaxPoolGradSamePadding2_1_3d(self): |
| self._ConstructAndTestGradient( |
| nn_ops.max_pool3d, |
| input_sizes=[1, 3, 2, 4, 1], |
| output_sizes=[1, 3, 2, 4, 1], |
| window=(2, 2, 2), |
| strides=(1, 1, 1), |
| padding="SAME") |
| |
| @test_util.run_deprecated_v1 |
| def testMaxPoolGradSamePadding2_2_3d(self): |
| self._ConstructAndTestGradient( |
| nn_ops.max_pool3d, |
| input_sizes=[1, 5, 2, 4, 2], |
| output_sizes=[1, 3, 1, 2, 2], |
| window=(2, 2, 2), |
| strides=(2, 2, 2), |
| padding="SAME") |
| |
| @test_util.run_deprecated_v1 |
| def testMaxPoolGradSamePadding3_1_3d(self): |
| self._ConstructAndTestGradient( |
| nn_ops.max_pool3d, |
| input_sizes=[1, 3, 4, 2, 1], |
| output_sizes=[1, 3, 4, 2, 1], |
| window=(3, 3, 3), |
| strides=(1, 1, 1), |
| padding="SAME") |
| |
| @test_util.run_deprecated_v1 |
| def testAvgPoolGradValidPadding1_1_3d(self): |
| self._ConstructAndTestGradient( |
| nn_ops.avg_pool3d, |
| input_sizes=[1, 3, 3, 3, 1], |
| output_sizes=[1, 3, 3, 3, 1], |
| window=(1, 1, 1), |
| strides=(1, 1, 1), |
| padding="VALID") |
| |
| @test_util.run_deprecated_v1 |
| def testAvgPoolGradValidPadding1_2_3d(self): |
| self._ConstructAndTestGradient( |
| nn_ops.avg_pool3d, |
| input_sizes=[1, 3, 3, 3, 1], |
| output_sizes=[1, 2, 2, 2, 1], |
| window=(1, 1, 1), |
| strides=(2, 2, 2), |
| padding="VALID") |
| |
| @test_util.run_deprecated_v1 |
| def testAvgPoolGradValidPadding2_1_3d(self): |
| self._ConstructAndTestGradient( |
| nn_ops.avg_pool3d, |
| input_sizes=[1, 3, 3, 3, 2], |
| output_sizes=[1, 2, 2, 2, 2], |
| window=(2, 2, 2), |
| strides=(1, 1, 1), |
| padding="VALID") |
| |
| @test_util.run_deprecated_v1 |
| def testAvgPoolGradValidPadding2_2_3d(self): |
| self._ConstructAndTestGradient( |
| nn_ops.avg_pool3d, |
| input_sizes=[2, 2, 2, 2, 2], |
| output_sizes=[2, 1, 1, 1, 2], |
| window=(2, 2, 2), |
| strides=(2, 2, 2), |
| padding="VALID") |
| |
| @test_util.run_deprecated_v1 |
| def testAvgPoolGradSamePadding1_1_3d(self): |
| self._ConstructAndTestGradient( |
| nn_ops.avg_pool3d, |
| input_sizes=[1, 3, 2, 4, 2], |
| output_sizes=[1, 3, 2, 4, 2], |
| window=(1, 1, 1), |
| strides=(1, 1, 1), |
| padding="SAME") |
| |
| @test_util.run_deprecated_v1 |
| def testAvgPoolGradSamePadding1_2_3d(self): |
| self._ConstructAndTestGradient( |
| nn_ops.avg_pool3d, |
| input_sizes=[1, 3, 2, 4, 2], |
| output_sizes=[1, 2, 1, 2, 2], |
| window=(1, 1, 1), |
| strides=(2, 2, 2), |
| padding="SAME") |
| |
| @test_util.run_deprecated_v1 |
| def testAvgPoolGradSamePadding2_1_3d(self): |
| self._ConstructAndTestGradient( |
| nn_ops.avg_pool3d, |
| input_sizes=[1, 2, 2, 2, 1], |
| output_sizes=[1, 2, 2, 2, 1], |
| window=(2, 2, 2), |
| strides=(1, 1, 1), |
| padding="SAME") |
| |
| @test_util.run_deprecated_v1 |
| def testAvgPoolGradSamePadding2_2_3d(self): |
| self._ConstructAndTestGradient( |
| nn_ops.avg_pool3d, |
| input_sizes=[1, 5, 2, 4, 1], |
| output_sizes=[1, 3, 1, 2, 1], |
| window=(2, 2, 2), |
| strides=(2, 2, 2), |
| padding="SAME") |
| |
| @test_util.run_deprecated_v1 |
| def testAvgPoolGradSamePadding3_1_3d(self): |
| self._ConstructAndTestGradient( |
| nn_ops.avg_pool3d, |
| input_sizes=[1, 3, 6, 2, 1], |
| output_sizes=[1, 3, 6, 2, 1], |
| window=(3, 3, 3), |
| strides=(1, 1, 1), |
| padding="SAME") |
| |
| |
| if __name__ == "__main__": |
| test.main() |