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