Home | History | Annotate | Download | only in kernel_tests
      1 # Copyright 2016 The TensorFlow Authors. All Rights Reserved.
      2 #
      3 # Licensed under the Apache License, Version 2.0 (the "License");
      4 # you may not use this file except in compliance with the License.
      5 # You may obtain a copy of the License at
      6 #
      7 #     http://www.apache.org/licenses/LICENSE-2.0
      8 #
      9 # Unless required by applicable law or agreed to in writing, software
     10 # distributed under the License is distributed on an "AS IS" BASIS,
     11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 # See the License for the specific language governing permissions and
     13 # limitations under the License.
     14 # ==============================================================================
     15 """Functional tests for 3d pooling operations."""
     16 
     17 from __future__ import absolute_import
     18 from __future__ import division
     19 from __future__ import print_function
     20 
     21 import numpy as np
     22 
     23 from tensorflow.python.framework import constant_op
     24 from tensorflow.python.framework import test_util
     25 from tensorflow.python.ops import gradient_checker
     26 from tensorflow.python.ops import gradients_impl
     27 from tensorflow.python.ops import nn_ops
     28 import tensorflow.python.ops.nn_grad  # pylint: disable=unused-import
     29 from tensorflow.python.platform import test
     30 
     31 
     32 def GetTestConfigs():
     33   """Get all the valid tests configs to run.
     34 
     35   Returns:
     36     all the valid test configs as tuples of data_format and use_gpu.
     37   """
     38   test_configs = [("NDHWC", False), ("NDHWC", True)]
     39   if test.is_gpu_available(cuda_only=True):
     40     # "NCHW" format is currently supported exclusively on CUDA GPUs.
     41     test_configs += [("NCDHW", True)]
     42   return test_configs
     43 
     44 
     45 # TODO(mjanusz): Add microbenchmarks for 3d pooling.
     46 class PoolingTest(test.TestCase):
     47 
     48   def _VerifyOneTest(self, pool_func, input_sizes, window, strides, padding,
     49                      data_format, expected, use_gpu):
     50     """Verifies the output values of the pooling function.
     51 
     52     Args:
     53       pool_func: Function to be called: co.MaxPool, co.AvgPool.
     54       input_sizes: Input tensor dimensions.
     55       window: Tuple of kernel dims: planes, rows, cols.
     56       strides: Tuple of strides for dims: planes, rows, cols.
     57       padding: Padding type.
     58       data_format: The data format we use to run the pooling operation.
     59       expected: An array containing the expected operation outputs.
     60       use_gpu: Whether to run ops on GPU.
     61     """
     62     total_size = 1
     63     for s in input_sizes:
     64       total_size *= s
     65     # Initializes the input tensor with array containing incrementing
     66     # numbers from 1.
     67     x = [f * 1.0 for f in range(1, total_size + 1)]
     68     with self.test_session(use_gpu=use_gpu) as sess:
     69       t = constant_op.constant(x, shape=input_sizes)
     70       window = [1] + list(window) + [1]
     71       strides = [1] + list(strides) + [1]
     72       if data_format == "NCDHW":
     73         t = test_util.NHWCToNCHW(t)
     74         window = test_util.NHWCToNCHW(window)
     75         strides = test_util.NHWCToNCHW(strides)
     76       t = pool_func(
     77           t,
     78           ksize=window,
     79           strides=strides,
     80           padding=padding,
     81           data_format=data_format)
     82       if data_format == "NCDHW":
     83         t = test_util.NCHWToNHWC(t)
     84       vals = sess.run(t)
     85     # Verifies values.
     86     actual = vals.flatten()
     87     self.assertAllClose(expected, actual)
     88 
     89   def _VerifyValues(self, pool_func, input_sizes, window, strides,
     90                     padding, expected):
     91     for data_format, use_gpu in GetTestConfigs():
     92       self._VerifyOneTest(pool_func, input_sizes, window, strides, padding,
     93                           data_format, expected, use_gpu)
     94 
     95   def testAvgPool3dValidPadding(self):
     96     expected_output = [20.5, 21.5, 22.5]
     97     self._VerifyValues(
     98         nn_ops.avg_pool3d,
     99         input_sizes=[1, 3, 3, 3, 3],
    100         window=(2, 2, 2),
    101         strides=(2, 2, 2),
    102         padding="VALID",
    103         expected=expected_output)
    104 
    105   def testAvgPool3dSamePadding(self):
    106     expected_output = [20.5, 21.5, 22.5, 26.5, 27.5, 28.5]
    107     self._VerifyValues(
    108         nn_ops.avg_pool3d,
    109         input_sizes=[1, 2, 2, 4, 3],
    110         window=(2, 2, 2),
    111         strides=(2, 2, 2),
    112         padding="SAME",
    113         expected=expected_output)
    114 
    115   def testAvgPool3dSamePaddingDifferentStrides(self):
    116     expected_output = [1.5, 4.5, 7.5, 17.5, 20.5, 23.5, 33.5, 36.5, 39.5]
    117     self._VerifyValues(
    118         nn_ops.avg_pool3d,
    119         input_sizes=[1, 5, 8, 1, 1],
    120         window=(1, 2, 3),
    121         strides=(2, 3, 1),
    122         padding="SAME",
    123         expected=expected_output)
    124 
    125   def testMaxPool3dValidPadding(self):
    126     expected_output = [40.0, 41.0, 42.0]
    127     self._VerifyValues(
    128         nn_ops.max_pool3d,
    129         input_sizes=[1, 3, 3, 3, 3],
    130         window=(2, 2, 2),
    131         strides=(2, 2, 2),
    132         padding="VALID",
    133         expected=expected_output)
    134 
    135   def testMaxPool3dSamePadding(self):
    136     expected_output = [31., 32., 33., 34., 35., 36.]
    137     self._VerifyValues(
    138         nn_ops.max_pool3d,
    139         input_sizes=[1, 2, 2, 3, 3],
    140         window=(2, 2, 2),
    141         strides=(2, 2, 2),
    142         padding="SAME",
    143         expected=expected_output)
    144 
    145   def testMaxPool3dSamePaddingDifferentStrides(self):
    146     expected_output = [2., 5., 8., 18., 21., 24., 34., 37., 40.]
    147     self._VerifyValues(
    148         nn_ops.max_pool3d,
    149         input_sizes=[1, 5, 8, 1, 1],
    150         window=(1, 2, 3),
    151         strides=(2, 3, 1),
    152         padding="SAME",
    153         expected=expected_output)
    154 
    155     # Test pooling on a larger input, with different stride and kernel
    156     # size for the 'z' dimension.
    157 
    158     # Simulate max pooling in numpy to get the expected output.
    159     input_data = np.arange(1, 5 * 27 * 27 * 64 + 1).reshape((5, 27, 27, 64))
    160     input_data = np.pad(input_data, [[0, 0], [0, 1], [0, 1], [0, 0]],
    161                         mode="constant")
    162     expected_output = input_data[:, 1::2, 1::2, :]
    163     expected_output[:, -1, :, :] = input_data[:, -2, 1::2, :]
    164     expected_output[:, :, -1, :] = input_data[:, 1::2, -2, :]
    165     expected_output[:, -1, -1, :] = input_data[:, -2, -2, :]
    166 
    167     self._VerifyValues(
    168         nn_ops.max_pool3d,
    169         input_sizes=[1, 5, 27, 27, 64],
    170         window=(1, 2, 2),
    171         strides=(1, 2, 2),
    172         padding="SAME",
    173         expected=expected_output.flatten())
    174 
    175   def testKernelSmallerThanStride(self):
    176     self._VerifyValues(
    177         nn_ops.max_pool3d,
    178         input_sizes=[1, 3, 3, 3, 1],
    179         window=[1, 1, 1],
    180         strides=[2, 2, 2],
    181         padding="SAME",
    182         expected=[1, 3, 7, 9, 19, 21, 25, 27])
    183 
    184     self._VerifyValues(
    185         nn_ops.max_pool3d,
    186         input_sizes=[1, 7, 7, 7, 1],
    187         window=[2, 2, 2],
    188         strides=[3, 3, 3],
    189         padding="VALID",
    190         expected=[58, 61, 79, 82, 205, 208, 226, 229])
    191 
    192     self._VerifyValues(
    193         nn_ops.avg_pool3d,
    194         input_sizes=[1, 3, 3, 3, 1],
    195         window=[1, 1, 1],
    196         strides=[2, 2, 2],
    197         padding="SAME",
    198         expected=[1, 3, 7, 9, 19, 21, 25, 27])
    199 
    200     self._VerifyValues(
    201         nn_ops.avg_pool3d,
    202         input_sizes=[1, 7, 7, 7, 1],
    203         window=[2, 2, 2],
    204         strides=[3, 3, 3],
    205         padding="VALID",
    206         expected=[29.5, 32.5, 50.5, 53.5, 176.5, 179.5, 197.5, 200.5])
    207 
    208   def _ConstructAndTestGradientForConfig(self,
    209                                          pool_func,
    210                                          input_sizes,
    211                                          output_sizes,
    212                                          window,
    213                                          strides,
    214                                          padding,
    215                                          data_format,
    216                                          use_gpu):
    217     """Verifies the gradients of a pooling function.
    218 
    219     Args:
    220       pool_func: Function to be called, co.MaxPool, co.AvgPool,
    221         or the Lua version.
    222       input_sizes: Input tensor dimensions.
    223       output_sizes: Output tensor dimensions.
    224       window: Tuple of kernel dims: planes, rows, cols.
    225       strides: Tuple of strides for dims: planes, rows, cols.
    226       padding: Padding type.
    227       data_format: Data format string.
    228       use_gpu: Whether to run on GPU.
    229     """
    230     total_size = 1
    231     for s in input_sizes:
    232       total_size *= s
    233     # Initializes the input tensor with array containing incrementing
    234     # numbers from 1.
    235     x = np.arange(1, total_size + 1, dtype=np.float32)
    236     with self.test_session(use_gpu=use_gpu):
    237       input_tensor = constant_op.constant(x, shape=input_sizes, name="input")
    238       err_g_margin = 1e-3
    239       err_gg_margin = 1.5e-2
    240       if pool_func == nn_ops.avg_pool3d:
    241         func_name = "avg_pool3d"
    242         x_init_value = None
    243       else:
    244         x_init_value = np.asfarray(np.arange(1, total_size + 1),
    245                                    dtype=np.float32).reshape(input_sizes)
    246         func_name = "max_pool3d"
    247 
    248       ksize = [1, window[0], window[1], window[2], 1]
    249       strides = [1, strides[0], strides[1], strides[2], 1]
    250       t = input_tensor
    251 
    252       if data_format == "NCDHW":
    253         ksize = test_util.NHWCToNCHW(ksize)
    254         strides = test_util.NHWCToNCHW(strides)
    255         t = test_util.NHWCToNCHW(t)
    256 
    257       t = pool_func(
    258           t,
    259           ksize=ksize,
    260           strides=strides,
    261           padding=padding,
    262           data_format=data_format,
    263           name=func_name)
    264       t_g = gradients_impl.gradients(t**2, input_tensor)[0]
    265 
    266       err_g = gradient_checker.compute_gradient_error(
    267           input_tensor,
    268           input_sizes,
    269           t,
    270           output_sizes,
    271           x_init_value=x_init_value,
    272           delta=1e-2)
    273       err_gg = gradient_checker.compute_gradient_error(
    274           input_tensor,
    275           input_sizes,
    276           t_g,
    277           input_sizes,
    278           x_init_value=x_init_value,
    279           delta=1e-2)
    280 
    281     print("%s gradient error = " % func_name, err_g)
    282     self.assertLess(err_g, err_g_margin)
    283     print("%s second-order gradient error = " % func_name, err_gg)
    284     self.assertLess(err_gg, err_gg_margin)
    285 
    286   def _ConstructAndTestGradient(self,
    287                                 pool_func,
    288                                 **kwargs):
    289     """Runs _ConstructAndTestGradientForConfig for all tests configurations."""
    290 
    291     for data_format, use_gpu in GetTestConfigs():
    292       self._ConstructAndTestGradientForConfig(pool_func,
    293                                               data_format=data_format,
    294                                               use_gpu=use_gpu,
    295                                               **kwargs)
    296 
    297   def testMaxPoolGradValidPadding1_1_3d(self):
    298     self._ConstructAndTestGradient(
    299         nn_ops.max_pool3d,
    300         input_sizes=[1, 3, 3, 3, 1],
    301         output_sizes=[1, 3, 3, 3, 1],
    302         window=(1, 1, 1),
    303         strides=(1, 1, 1),
    304         padding="VALID")
    305 
    306   def testMaxPoolGradValidPadding2_1_6_3d(self):
    307     self._ConstructAndTestGradient(
    308         nn_ops.max_pool3d,
    309         input_sizes=[1, 2, 3, 4, 2],
    310         output_sizes=[1, 1, 2, 3, 2],
    311         window=(2, 2, 2),
    312         strides=(1, 1, 1),
    313         padding="VALID")
    314 
    315   def testMaxPoolGradValidPadding2_1_7_3d(self):
    316     self._ConstructAndTestGradient(
    317         nn_ops.max_pool3d,
    318         input_sizes=[1, 3, 2, 7, 1],
    319         output_sizes=[1, 2, 1, 6, 1],
    320         window=(2, 2, 2),
    321         strides=(1, 1, 1),
    322         padding="VALID")
    323 
    324   def testMaxPoolGradValidPadding1_2_3d(self):
    325     self._ConstructAndTestGradient(
    326         nn_ops.max_pool3d,
    327         input_sizes=[1, 3, 3, 3, 1],
    328         output_sizes=[1, 2, 2, 2, 1],
    329         window=(1, 1, 1),
    330         strides=(2, 2, 2),
    331         padding="VALID")
    332 
    333   def testMaxPoolGradValidPadding2_2_3d(self):
    334     self._ConstructAndTestGradient(
    335         nn_ops.max_pool3d,
    336         input_sizes=[2, 2, 2, 2, 1],
    337         output_sizes=[2, 1, 1, 1, 1],
    338         window=(2, 2, 2),
    339         strides=(2, 2, 2),
    340         padding="VALID")
    341 
    342   def testMaxPoolGradSamePadding1_1_3d(self):
    343     self._ConstructAndTestGradient(
    344         nn_ops.max_pool3d,
    345         input_sizes=[1, 3, 2, 4, 1],
    346         output_sizes=[1, 3, 2, 4, 1],
    347         window=(1, 1, 1),
    348         strides=(1, 1, 1),
    349         padding="SAME")
    350 
    351   def testMaxPoolGradSamePadding1_2_3d(self):
    352     self._ConstructAndTestGradient(
    353         nn_ops.max_pool3d,
    354         input_sizes=[1, 3, 2, 4, 1],
    355         output_sizes=[1, 2, 1, 2, 1],
    356         window=(1, 1, 1),
    357         strides=(2, 2, 2),
    358         padding="SAME")
    359 
    360   def testMaxPoolGradSamePadding2_1_3d(self):
    361     self._ConstructAndTestGradient(
    362         nn_ops.max_pool3d,
    363         input_sizes=[1, 3, 2, 4, 1],
    364         output_sizes=[1, 3, 2, 4, 1],
    365         window=(2, 2, 2),
    366         strides=(1, 1, 1),
    367         padding="SAME")
    368 
    369   def testMaxPoolGradSamePadding2_2_3d(self):
    370     self._ConstructAndTestGradient(
    371         nn_ops.max_pool3d,
    372         input_sizes=[1, 5, 2, 4, 2],
    373         output_sizes=[1, 3, 1, 2, 2],
    374         window=(2, 2, 2),
    375         strides=(2, 2, 2),
    376         padding="SAME")
    377 
    378   def testMaxPoolGradSamePadding3_1_3d(self):
    379     self._ConstructAndTestGradient(
    380         nn_ops.max_pool3d,
    381         input_sizes=[1, 3, 4, 2, 1],
    382         output_sizes=[1, 3, 4, 2, 1],
    383         window=(3, 3, 3),
    384         strides=(1, 1, 1),
    385         padding="SAME")
    386 
    387   def testAvgPoolGradValidPadding1_1_3d(self):
    388     self._ConstructAndTestGradient(
    389         nn_ops.avg_pool3d,
    390         input_sizes=[1, 3, 3, 3, 1],
    391         output_sizes=[1, 3, 3, 3, 1],
    392         window=(1, 1, 1),
    393         strides=(1, 1, 1),
    394         padding="VALID")
    395 
    396   def testAvgPoolGradValidPadding1_2_3d(self):
    397     self._ConstructAndTestGradient(
    398         nn_ops.avg_pool3d,
    399         input_sizes=[1, 3, 3, 3, 1],
    400         output_sizes=[1, 2, 2, 2, 1],
    401         window=(1, 1, 1),
    402         strides=(2, 2, 2),
    403         padding="VALID")
    404 
    405   def testAvgPoolGradValidPadding2_1_3d(self):
    406     self._ConstructAndTestGradient(
    407         nn_ops.avg_pool3d,
    408         input_sizes=[1, 3, 3, 3, 2],
    409         output_sizes=[1, 2, 2, 2, 2],
    410         window=(2, 2, 2),
    411         strides=(1, 1, 1),
    412         padding="VALID")
    413 
    414   def testAvgPoolGradValidPadding2_2_3d(self):
    415     self._ConstructAndTestGradient(
    416         nn_ops.avg_pool3d,
    417         input_sizes=[2, 2, 2, 2, 2],
    418         output_sizes=[2, 1, 1, 1, 2],
    419         window=(2, 2, 2),
    420         strides=(2, 2, 2),
    421         padding="VALID")
    422 
    423   def testAvgPoolGradSamePadding1_1_3d(self):
    424     self._ConstructAndTestGradient(
    425         nn_ops.avg_pool3d,
    426         input_sizes=[1, 3, 2, 4, 2],
    427         output_sizes=[1, 3, 2, 4, 2],
    428         window=(1, 1, 1),
    429         strides=(1, 1, 1),
    430         padding="SAME")
    431 
    432   def testAvgPoolGradSamePadding1_2_3d(self):
    433     self._ConstructAndTestGradient(
    434         nn_ops.avg_pool3d,
    435         input_sizes=[1, 3, 2, 4, 2],
    436         output_sizes=[1, 2, 1, 2, 2],
    437         window=(1, 1, 1),
    438         strides=(2, 2, 2),
    439         padding="SAME")
    440 
    441   def testAvgPoolGradSamePadding2_1_3d(self):
    442     self._ConstructAndTestGradient(
    443         nn_ops.avg_pool3d,
    444         input_sizes=[1, 2, 2, 2, 1],
    445         output_sizes=[1, 2, 2, 2, 1],
    446         window=(2, 2, 2),
    447         strides=(1, 1, 1),
    448         padding="SAME")
    449 
    450   def testAvgPoolGradSamePadding2_2_3d(self):
    451     self._ConstructAndTestGradient(
    452         nn_ops.avg_pool3d,
    453         input_sizes=[1, 5, 2, 4, 1],
    454         output_sizes=[1, 3, 1, 2, 1],
    455         window=(2, 2, 2),
    456         strides=(2, 2, 2),
    457         padding="SAME")
    458 
    459   def testAvgPoolGradSamePadding3_1_3d(self):
    460     self._ConstructAndTestGradient(
    461         nn_ops.avg_pool3d,
    462         input_sizes=[1, 3, 6, 2, 1],
    463         output_sizes=[1, 3, 6, 2, 1],
    464         window=(3, 3, 3),
    465         strides=(1, 1, 1),
    466         padding="SAME")
    467 
    468 
    469 if __name__ == "__main__":
    470   test.main()
    471