pooling_ops_test.py revision b1d8c59e9b014b527fb2fbef9ce9afc14dbc4938
1# Copyright 2015 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 pooling operations."""
16
17from __future__ import absolute_import
18from __future__ import division
19from __future__ import print_function
20
21import os
22import numpy as np
23
24from tensorflow.python.framework import constant_op
25from tensorflow.python.framework import dtypes
26from tensorflow.python.framework import errors_impl
27from tensorflow.python.framework import test_util
28from tensorflow.python.ops import array_ops
29from tensorflow.python.ops import gen_array_ops
30from tensorflow.python.ops import gen_nn_ops
31from tensorflow.python.ops import gradient_checker
32from tensorflow.python.ops import gradients_impl
33from tensorflow.python.ops import nn_ops
34import tensorflow.python.ops.nn_grad  # pylint: disable=unused-import
35from tensorflow.python.platform import test
36from tensorflow.python.platform import tf_logging
37
38
39def GetTestConfigs(include_nchw_vect_c=False):
40  """Get all the valid tests configs to run.
41
42  Args:
43    include_nchw_vect_c: Whether to include NCHW_VECT_C in the test configs.
44
45  Returns:
46    all the valid test configs as tuples of data_format and use_gpu.
47  """
48  test_configs = [("NHWC", False), ("NHWC", True)]
49  if not test.is_gpu_available(cuda_only=True):
50    tf_logging.info("NCHW and NCHW_VECT_C tests skipped because not run with "
51                    "--config=cuda or no GPUs available.")
52    return test_configs
53  # "NCHW" format is currently supported exclusively on CUDA GPUs.
54  test_configs += [("NCHW", True)]
55  if include_nchw_vect_c:
56    if test.is_gpu_available(
57        cuda_only=True, min_cuda_compute_capability=(6, 1)):
58      test_configs += [("NCHW_VECT_C", True)]
59    else:
60      tf_logging.info("NCHW_VECT_C test skipped because no GPUs with "
61                      "compute capability >= 6.1 are available.")
62
63  return test_configs
64
65
66def GetShrunkInceptionMaxPoolShapes(shrink=30):
67  """Iterator for some of the max pool ops in the Inception 2015 model.
68
69  Args:
70    shrink: Factor to shrink depth relative to Inception.
71
72  Yields:
73    Tuple (name, input_size, filter_size, out_size, strides, padding)
74  """
75  names = ["maxpool2", "maxpool3", "maxpool4", "maxpool5"]
76  input_sizes = [[32, 71, 71, 192], [32, 35, 35, 288], [32, 17, 17, 1248],
77                 [32, 8, 8, 2048]]
78  filter_sizes = [[1, 3, 3, 1], [1, 3, 3, 1], [1, 3, 3, 1], [1, 3, 3, 1]]
79  output_sizes = [[32, 35, 35, 192], [32, 17, 17, 288], [32, 8, 8, 1248],
80                  [32, 8, 8, 2048]]
81  strides = [[1, 2, 2, 1], [1, 2, 2, 1], [1, 2, 2, 1], [1, 1, 1, 1]]
82  # Shrink each depth value
83  for i in input_sizes:
84    i[3] //= shrink
85  for o in output_sizes:
86    o[3] //= shrink
87  paddings = ["VALID", "VALID", "VALID", "SAME"]
88  for n, i, f, o, s, p in zip(names, input_sizes, filter_sizes, output_sizes,
89                              strides, paddings):
90    yield n, i, f, o, s, p
91
92
93class PoolingTest(test.TestCase):
94
95  def _VerifyOneType(self, pool_func, input_sizes, ksize, strides, padding,
96                     data_format, data_type, expected, use_gpu, v2):
97    """Verifies the output values of the pooling function.
98
99    Args:
100      pool_func: Function to be called, co.MaxPool, co.AvgPool,
101        or the Lua version.
102      input_sizes: Input tensor dimensions.
103      ksize: The kernel size dimensions
104      strides: The stride dimensions
105      padding: Padding type.
106      data_format: The data format we use to run the pooling operation.
107      data_type: The data type to use to run the pooling operation.
108      expected: An array containing the expected operation outputs.
109      use_gpu: Whether we are running on GPU.
110    """
111    total_size = 1
112    for s in input_sizes:
113      total_size *= s
114    if v2 and data_format != "NHWC":
115      tf_logging.info("v2 not supported for %s", data_format)
116      return
117    if data_format == "NCHW_VECT_C":
118      if data_type != dtypes.float32:
119        tf_logging.info("quantization to qint8 not implemented for %r",
120                        data_type)
121        return
122      if input_sizes[-1] % 4 != 0:
123        tf_logging.info("Skipping test for depth %d", input_sizes[-1])
124        return
125    tf_logging.info("Running %s test. %r %r %d %r %r %r", data_format, v2,
126                    input_sizes, total_size, pool_func, ksize, strides)
127    # Initializes the input tensor with array containing incrementing
128    # numbers from 1, wrapping round to -127 after 127 to support int8.
129    x = [((f + 128) % 255) - 127 for f in range(total_size)]
130    with self.test_session(use_gpu=use_gpu):
131      t = constant_op.constant(x, shape=input_sizes, dtype=data_type)
132      if data_format in ("NCHW", "NCHW_VECT_C"):
133        if data_format == "NCHW_VECT_C":
134          t = test_util.NHWCToNCHW_VECT_C(t)
135          t, _, _ = gen_array_ops.quantize_v2(t, -128.0, 127.0, dtypes.qint8)
136        else:
137          t = test_util.NHWCToNCHW(t)
138        ksize = test_util.NHWCToNCHW(ksize)
139        strides = test_util.NHWCToNCHW(strides)
140      ksize_placeholder = array_ops.placeholder(dtypes.int32, shape=[4])
141      strides_placeholder = array_ops.placeholder(dtypes.int32, shape=[4])
142      if v2:
143        t = pool_func(
144            t,
145            ksize=ksize_placeholder,
146            strides=strides_placeholder,
147            padding=padding,
148            data_format=data_format)
149      else:
150        t = pool_func(
151            t,
152            ksize=ksize,
153            strides=strides,
154            padding=padding,
155            data_format=data_format)
156      if data_format == "NCHW_VECT_C":
157        t = gen_array_ops.dequantize(t, -128, 127)
158        t = test_util.NCHW_VECT_CToNHWC(t)
159      elif data_format == "NCHW":
160        t = test_util.NCHWToNHWC(t)
161      if v2:
162        actual = t.eval(feed_dict={ksize_placeholder: ksize,
163                                   strides_placeholder: strides})
164      else:
165        actual = t.eval()
166        self.assertShapeEqual(actual, t)
167      self.assertAllCloseAccordingToType(expected, actual.flatten())
168
169  def _VerifyOneTest(self, pool_func, input_sizes, ksize, strides, padding,
170                     data_format, expected, use_gpu, v2):
171    """Verifies the output values of the pooling function.
172
173    Args:
174      pool_func: Function to be called, co.MaxPool, co.AvgPool,
175        or the Lua version.
176      input_sizes: Input tensor dimensions.
177      ksize: The kernel size dimensions
178      strides: The stride dimensions
179      padding: Padding type.
180      data_format: The data format we use to run the pooling operation.
181      expected: An array containing the expected operation outputs.
182      use_gpu: Whether we are running on GPU.
183    """
184    if data_format == "NCHW_VECT_C":
185      avg_pool_func = nn_ops.avg_pool
186      tf_logging.info("pool_func=%s", pool_func)
187      if pool_func == avg_pool_func:
188        tf_logging.info("NCHW_VECT_C not yet implemented for avg_pool")
189        return
190
191    self._VerifyOneType(pool_func, input_sizes, ksize, strides, padding,
192                        data_format, dtypes.float32, expected, use_gpu, v2)
193
194    if not use_gpu or test_util.CudaSupportsHalfMatMulAndConv():
195      self._VerifyOneType(pool_func, input_sizes, ksize, strides, padding,
196                          data_format, dtypes.float16, expected, use_gpu, v2)
197
198  def _VerifyValues(self, pool_func, input_sizes, ksize, strides, padding,
199                    expected, use_gpu, v2=False):
200    """Verifies the output values of the pooling function.
201
202    Args:
203      pool_func: Function to be called, co.MaxPool, co.AvgPool,
204        or the Lua version.
205      input_sizes: Input tensor dimensions.
206      ksize: The kernel size dimensions
207      strides: The stride dimensions
208      padding: Padding type.
209      expected: An array containing the expected operation outputs.
210      use_gpu: Whether we are running on GPU.
211    """
212    for (data_format, use_gpu_2) in GetTestConfigs(True):
213      if use_gpu_2 == use_gpu:
214        self._VerifyOneTest(pool_func, input_sizes, ksize, strides, padding,
215                            data_format, expected, use_gpu, v2)
216
217  def _testAvgPoolValidPadding(self, use_gpu):
218    expected_output = [7.0, 8.0, 9.0]
219    self._VerifyValues(
220        nn_ops.avg_pool,
221        input_sizes=[1, 3, 3, 3],
222        ksize=[1, 2, 2, 1],
223        strides=[1, 2, 2, 1],
224        padding="VALID",
225        expected=expected_output,
226        use_gpu=use_gpu)
227
228  def _testAvgPoolSamePadding(self, use_gpu):
229    expected_output = [8.5, 9.5, 10.5, 14.5, 15.5, 16.5]
230    self._VerifyValues(
231        nn_ops.avg_pool,
232        input_sizes=[1, 2, 4, 3],
233        ksize=[1, 2, 2, 1],
234        strides=[1, 2, 2, 1],
235        padding="SAME",
236        expected=expected_output,
237        use_gpu=use_gpu)
238
239  def _testAvgPoolSamePaddingNonSquareWindow(self, use_gpu):
240    # input is:
241    # [1.0, 2.0
242    #  3.0  4.0]
243    #
244    # Window of [x, x] should do:
245    #  [avg(1.0, 2.0), avg(2.0, padded0),
246    #   avg(3.0, 4.0), avg(4.0, padded0)]
247    self._VerifyValues(
248        nn_ops.avg_pool,
249        input_sizes=[1, 2, 2, 1],
250        ksize=[1, 1, 2, 1],
251        strides=[1, 1, 1, 1],
252        padding="SAME",
253        expected=[1.5, 2.0, 3.5, 4.0],
254        use_gpu=use_gpu)
255
256    # Window of [x,
257    #            x] should do:
258    #  [avg(1.0, 3.0), avg(2.0, 4.0)
259    #   avg(3.0, padded0), avg(4.0, padded0)]
260    self._VerifyValues(
261        nn_ops.avg_pool,
262        input_sizes=[1, 2, 2, 1],
263        ksize=[1, 2, 1, 1],
264        strides=[1, 1, 1, 1],
265        padding="SAME",
266        expected=[2.0, 3.0, 3.0, 4.0],
267        use_gpu=use_gpu)
268
269  def _testAvgPoolSamePaddingNonSquareWindowMultiBatch(self, use_gpu):
270    self._VerifyValues(
271        nn_ops.avg_pool,
272        input_sizes=[2, 2, 2, 2],
273        ksize=[1, 1, 2, 1],
274        strides=[1, 1, 1, 1],
275        padding="SAME",
276        expected=[
277            2.0, 3.0, 3.0, 4.0, 6.0, 7.0, 7.0, 8.0, 10.0, 11.0, 11.0, 12.0,
278            14.0, 15.0, 15.0, 16.0
279        ],
280        use_gpu=use_gpu)
281    self._VerifyValues(
282        nn_ops.avg_pool,
283        input_sizes=[2, 2, 2, 2],
284        ksize=[1, 2, 1, 1],
285        strides=[1, 1, 1, 1],
286        padding="SAME",
287        expected=[
288            3.0, 4.0, 5.0, 6.0, 5.0, 6.0, 7.0, 8.0, 11.0, 12.0, 13.0, 14.0,
289            13.0, 14.0, 15.0, 16.0
290        ],
291        use_gpu=use_gpu)
292
293  def _testAvgPoolValidPaddingUnevenStride(self, use_gpu):
294    self._VerifyValues(
295        nn_ops.avg_pool,
296        input_sizes=[1, 3, 3, 3],
297        ksize=[1, 2, 2, 1],
298        strides=[1, 1, 2, 1],
299        padding="VALID",
300        expected=[7.0, 8.0, 9.0, 16.0, 17.0, 18.0],
301        use_gpu=use_gpu)
302    self._VerifyValues(
303        nn_ops.avg_pool,
304        input_sizes=[1, 3, 3, 3],
305        ksize=[1, 2, 2, 1],
306        strides=[1, 2, 1, 1],
307        padding="VALID",
308        expected=[7.0, 8.0, 9.0, 10.0, 11.0, 12.0],
309        use_gpu=use_gpu)
310
311  def _testAvgPoolSamePadding4(self, use_gpu):
312    expected_output = [
313        11.0, 12.0, 13.0, 14.0, 19.0, 20.0, 21.0, 22.0, 43.0, 44.0, 45.0, 46.0,
314        51.0, 52.0, 53.0, 54.0
315    ]
316    self._VerifyValues(
317        nn_ops.avg_pool,
318        input_sizes=[1, 4, 4, 4],
319        ksize=[1, 2, 2, 1],
320        strides=[1, 2, 2, 1],
321        padding="SAME",
322        expected=expected_output,
323        use_gpu=use_gpu)
324
325  def _testAvgPoolSamePaddingPacket4(self, use_gpu):
326    expected_output = [
327        21.0, 22.0, 23.0, 24.0, 27.0, 28.0, 29.0, 30.0, 45.0, 46.0, 47.0, 48.0,
328        51.0, 52.0, 53.0, 54.0
329    ]
330    self._VerifyValues(
331        nn_ops.avg_pool,
332        input_sizes=[1, 4, 4, 4],
333        ksize=[1, 3, 3, 1],
334        strides=[1, 2, 2, 1],
335        padding="SAME",
336        expected=expected_output,
337        use_gpu=use_gpu)
338
339  def _testAvgPoolSamePaddingPacket8(self, use_gpu):
340    expected_output = [
341        -12.0, -11.0, -10.0, -9.0, -8.0, -7.0, -6.0, -5.0, 4.0, 5.0, 6.0, 7.0,
342        8.0, 9.0, 10.0, 11.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0,
343        32.0, 33.0, 34.0, 35.0, 36.0, 37.0, 38.0, -3.5, -54.0, -53.0, -52.0,
344        -51.0, -50.0, -49.0, -48.0, -47.0, -38.0, -37.0, -36.0, -35.0, -34.0,
345        -33.0, -32.0, -31.0, -22.0, -21.0, -20.0, -19.0, -18.0, -17.0, -16.0,
346        -15.0, -10.0, -9.0, -8.0, -7.0, -6.0, -5.0, -4.0, -3.0, -11.0, -10.0,
347        -9.0, -8.0, -7.0, -6.0, -5.0, -4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0,
348        12.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 33.0, 34.0, 35.0,
349        36.0, 37.0, 38.0, -3.5, -2.5, -85.0, -84.0, -83.0, -82.0, -81.0, -80.0,
350        -79.0, -78.0, -69.0, -68.0, -67.0, -66.0, -65.0, -64.0, -63.0, -62.0,
351        -53.0, -52.0, -51.0, -50.0, -49.0, -48.0, -47.0, -46.0, -41.0, -40.0,
352        -39.0, -38.0, -37.0, -36.0, -35.0, -34.0
353    ]
354
355    self._VerifyValues(
356        nn_ops.avg_pool,
357        input_sizes=[1, 8, 8, 8],
358        ksize=[1, 3, 3, 1],
359        strides=[1, 2, 2, 1],
360        padding="SAME",
361        expected=expected_output,
362        use_gpu=use_gpu)
363
364  def testAvgPooling(self):
365    for use_gpu in True, False:
366      self._testAvgPoolValidPadding(use_gpu)
367      self._testAvgPoolSamePadding(use_gpu)
368      self._testAvgPoolSamePaddingNonSquareWindow(use_gpu)
369      self._testAvgPoolSamePaddingNonSquareWindowMultiBatch(use_gpu)
370      self._testAvgPoolValidPaddingUnevenStride(use_gpu)
371      self._testAvgPoolSamePadding4(use_gpu)
372      self._testAvgPoolSamePaddingPacket4(use_gpu)
373      self._testAvgPoolSamePaddingPacket8(use_gpu)
374
375  def _testMaxPoolValidPadding(self, use_gpu):
376    expected_output = [13.0, 14.0, 15.0]
377    self._VerifyValues(
378        nn_ops.max_pool,
379        input_sizes=[1, 3, 3, 3],
380        ksize=[1, 2, 2, 1],
381        strides=[1, 2, 2, 1],
382        padding="VALID",
383        expected=expected_output,
384        use_gpu=use_gpu)
385
386    for v2 in [True, False]:
387      self._VerifyValues(
388          gen_nn_ops._max_pool_v2,
389          input_sizes=[1, 3, 3, 3],
390          ksize=[1, 2, 2, 1],
391          strides=[1, 2, 2, 1],
392          padding="VALID",
393          expected=expected_output,
394          use_gpu=use_gpu,
395          v2=v2)
396
397  def _testMaxPoolSamePadding(self, use_gpu):
398    expected_output = [13.0, 14.0, 15.0, 16.0, 17.0, 18.0]
399    self._VerifyValues(
400        nn_ops.max_pool,
401        input_sizes=[1, 2, 3, 3],
402        ksize=[1, 2, 2, 1],
403        strides=[1, 2, 2, 1],
404        padding="SAME",
405        expected=expected_output,
406        use_gpu=use_gpu)
407
408    for v2 in [True, False]:
409      self._VerifyValues(
410          gen_nn_ops._max_pool_v2,
411          input_sizes=[1, 2, 3, 3],
412          ksize=[1, 2, 2, 1],
413          strides=[1, 2, 2, 1],
414          padding="SAME",
415          expected=expected_output,
416          use_gpu=use_gpu,
417          v2=v2)
418
419  def _testMaxPoolSamePaddingNonSquareWindow(self, use_gpu):
420    # input is:
421    # [1.0, 2.0
422    #  3.0  4.0]
423    #
424    # Window of [x, x] should do:
425    #
426    #  [max(1.0, 2.0), max(2.0, padded0),
427    #   max(3.0, 4.0), max(4.0, padded0)]
428    self._VerifyValues(
429        nn_ops.max_pool,
430        input_sizes=[1, 2, 2, 1],
431        ksize=[1, 1, 2, 1],
432        strides=[1, 1, 1, 1],
433        padding="SAME",
434        expected=[2.0, 2.0, 4.0, 4.0],
435        use_gpu=use_gpu)
436
437    for v2 in [True, False]:
438      self._VerifyValues(
439          gen_nn_ops._max_pool_v2,
440          input_sizes=[1, 2, 2, 1],
441          ksize=[1, 1, 2, 1],
442          strides=[1, 1, 1, 1],
443          padding="SAME",
444          expected=[2.0, 2.0, 4.0, 4.0],
445          use_gpu=use_gpu,
446          v2=v2)
447
448  def _testMaxPoolValidPaddingUnevenStride(self, use_gpu):
449    self._VerifyValues(
450        nn_ops.max_pool,
451        input_sizes=[1, 4, 4, 1],
452        ksize=[1, 2, 2, 1],
453        strides=[1, 1, 2, 1],
454        padding="VALID",
455        expected=[6.0, 8.0, 10.0, 12.0, 14.0, 16.0],
456        use_gpu=use_gpu)
457    self._VerifyValues(
458        nn_ops.max_pool,
459        input_sizes=[1, 4, 4, 1],
460        ksize=[1, 2, 2, 1],
461        strides=[1, 2, 1, 1],
462        padding="VALID",
463        expected=[6.0, 7.0, 8.0, 14.0, 15.0, 16.0],
464        use_gpu=use_gpu)
465
466    for v2 in [True, False]:
467      self._VerifyValues(
468          gen_nn_ops._max_pool_v2,
469          input_sizes=[1, 4, 4, 1],
470          ksize=[1, 2, 2, 1],
471          strides=[1, 1, 2, 1],
472          padding="VALID",
473          expected=[6.0, 8.0, 10.0, 12.0, 14.0, 16.0],
474          use_gpu=use_gpu,
475          v2=v2)
476      self._VerifyValues(
477          gen_nn_ops._max_pool_v2,
478          input_sizes=[1, 4, 4, 1],
479          ksize=[1, 2, 2, 1],
480          strides=[1, 2, 1, 1],
481          padding="VALID",
482          expected=[6.0, 7.0, 8.0, 14.0, 15.0, 16.0],
483          use_gpu=use_gpu,
484          v2=v2)
485
486  def _testMaxPoolSamePaddingPacket4(self, use_gpu):
487    expected_output = [
488        21.0, 22.0, 23.0, 24.0, 29.0, 30.0, 31.0, 32.0, 53.0, 54.0, 55.0, 56.0,
489        61.0, 62.0, 63.0, 64.0
490    ]
491    self._VerifyValues(
492        nn_ops.max_pool,
493        input_sizes=[1, 4, 4, 4],
494        ksize=[1, 2, 2, 1],
495        strides=[1, 2, 2, 1],
496        padding="SAME",
497        expected=expected_output,
498        use_gpu=use_gpu)
499
500    for v2 in [True, False]:
501      self._VerifyValues(
502          gen_nn_ops._max_pool_v2,
503          input_sizes=[1, 4, 4, 4],
504          ksize=[1, 2, 2, 1],
505          strides=[1, 2, 2, 1],
506          padding="SAME",
507          expected=expected_output,
508          use_gpu=use_gpu,
509          v2=v2)
510
511  def _testMaxPoolSamePaddingPacket8(self, use_gpu):
512    expected_output = [
513        81.0, 82.0, 83.0, 84.0, 85.0, 86.0, 87.0, 88.0, 97.0, 98.0, 99.0, 100.0,
514        101.0, 102.0, 103.0, 104.0, 113.0, 114.0, 115.0, 116.0, 117.0, 118.0,
515        119.0, 120.0, 121.0, 122.0, 123.0, 124.0, 125.0, 126.0, 127.0, 120.0,
516        18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 34.0, 35.0, 36.0, 37.0,
517        38.0, 39.0, 40.0, 41.0, 50.0, 51.0, 52.0, 53.0, 54.0, 55.0, 56.0, 57.0,
518        58.0, 59.0, 60.0, 61.0, 62.0, 63.0, 64.0, 65.0, 82.0, 83.0, 84.0, 85.0,
519        86.0, 87.0, 88.0, 89.0, 98.0, 99.0, 100.0, 101.0, 102.0, 103.0, 104.0,
520        105.0, 114.0, 115.0, 116.0, 117.0, 118.0, 119.0, 120.0, 121.0, 122.0,
521        123.0, 124.0, 125.0, 126.0, 127.0, 120.0, 121.0, -45.0, -44.0, -43.0,
522        -42.0, -41.0, -40.0, -39.0, -38.0, -29.0, -28.0, -27.0, -26.0, -25.0,
523        -24.0, -23.0, -22.0, -13.0, -12.0, -11.0, -10.0, -9.0, -8.0, -7.0, -6.0,
524        -5.0, -4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0
525    ]
526    self._VerifyValues(
527        nn_ops.max_pool,
528        input_sizes=[1, 8, 8, 8],
529        ksize=[1, 3, 3, 1],
530        strides=[1, 2, 2, 1],
531        padding="SAME",
532        expected=expected_output,
533        use_gpu=use_gpu)
534
535    for v2 in [True, False]:
536      self._VerifyValues(
537          gen_nn_ops._max_pool_v2,
538          input_sizes=[1, 8, 8, 8],
539          ksize=[1, 3, 3, 1],
540          strides=[1, 2, 2, 1],
541          padding="SAME",
542          expected=expected_output,
543          use_gpu=use_gpu,
544          v2=v2)
545
546  def testMaxPooling(self):
547    for use_gpu in True, False:
548      self._testMaxPoolValidPadding(use_gpu)
549      self._testMaxPoolSamePadding(use_gpu)
550      self._testMaxPoolSamePaddingNonSquareWindow(use_gpu)
551      self._testMaxPoolValidPaddingUnevenStride(use_gpu)
552      self._testMaxPoolSamePaddingPacket4(use_gpu)
553      self._testMaxPoolSamePaddingPacket8(use_gpu)
554
555  # Tests for DepthwiseMaxPooling on CPU only.
556  def testDepthwiseMaxPool1x1DepthWindow1(self):
557    # input is:
558    # [1.0, ..., 10.0] along depth,
559    #
560    # We maxpool by depth in patches of 2.
561    self._VerifyValues(
562        nn_ops.max_pool,
563        input_sizes=[1, 1, 1, 10],
564        ksize=[1, 1, 1, 2],
565        strides=[1, 1, 1, 2],
566        padding="SAME",
567        expected=[2.0, 4.0, 6.0, 8.0, 10.0],
568        use_gpu=False)
569
570    for v2 in [True, False]:
571      self._VerifyValues(
572          gen_nn_ops._max_pool_v2,
573          input_sizes=[1, 1, 1, 10],
574          ksize=[1, 1, 1, 2],
575          strides=[1, 1, 1, 2],
576          padding="SAME",
577          expected=[2.0, 4.0, 6.0, 8.0, 10.0],
578          use_gpu=False,
579          v2=v2)
580
581  def testDepthwiseMaxPool2x2DepthWindow3(self):
582    # input is:
583    #
584    # a 2x2x6 cube, and we depthwise max across 3 to produce a 2x2x2
585    # output.  Each node has contiguous values, so the depthwise max
586    # should be multiples of 3.0.
587    self._VerifyValues(
588        nn_ops.max_pool,
589        input_sizes=[1, 2, 2, 6],
590        ksize=[1, 1, 1, 3],
591        strides=[1, 1, 1, 3],
592        padding="SAME",
593        expected=[3.0, 6.0, 9.0, 12.0, 15.0, 18.0, 21.0, 24.0],
594        use_gpu=False)
595
596    for v2 in [True, False]:
597      self._VerifyValues(
598          gen_nn_ops._max_pool_v2,
599          input_sizes=[1, 2, 2, 6],
600          ksize=[1, 1, 1, 3],
601          strides=[1, 1, 1, 3],
602          padding="SAME",
603          expected=[3.0, 6.0, 9.0, 12.0, 15.0, 18.0, 21.0, 24.0],
604          use_gpu=False,
605          v2=v2)
606
607  def testKernelSmallerThanStrideValid(self):
608    for use_gpu in [True, False]:
609      self._VerifyValues(
610          nn_ops.max_pool,
611          input_sizes=[1, 7, 7, 1],
612          ksize=[1, 2, 2, 1],
613          strides=[1, 3, 3, 1],
614          padding="VALID",
615          expected=[9, 12, 30, 33],
616          use_gpu=use_gpu)
617
618      for v2 in [True, False]:
619        self._VerifyValues(
620            gen_nn_ops._max_pool_v2,
621            input_sizes=[1, 7, 7, 1],
622            ksize=[1, 2, 2, 1],
623            strides=[1, 3, 3, 1],
624            padding="VALID",
625            expected=[9, 12, 30, 33],
626            use_gpu=use_gpu,
627            v2=v2)
628
629      self._VerifyValues(
630          nn_ops.avg_pool,
631          input_sizes=[1, 7, 7, 1],
632          ksize=[1, 2, 2, 1],
633          strides=[1, 3, 3, 1],
634          padding="VALID",
635          expected=[5, 8, 26, 29],
636          use_gpu=use_gpu)
637
638  def testKernelSmallerThanStrideSame(self):
639    for use_gpu in [True, False]:
640      for pool_func in [nn_ops.max_pool, nn_ops.avg_pool]:
641        self._VerifyValues(
642            pool_func,
643            input_sizes=[1, 3, 3, 1],
644            ksize=[1, 1, 1, 1],
645            strides=[1, 2, 2, 1],
646            padding="SAME",
647            expected=[1, 3, 7, 9],
648            use_gpu=use_gpu)
649
650        self._VerifyValues(
651            pool_func,
652            input_sizes=[1, 4, 4, 1],
653            ksize=[1, 1, 1, 1],
654            strides=[1, 2, 2, 1],
655            padding="SAME",
656            expected=[1, 3, 9, 11],
657            use_gpu=use_gpu)
658
659      for v2 in [True, False]:
660        self._VerifyValues(
661            gen_nn_ops._max_pool_v2,
662            input_sizes=[1, 3, 3, 1],
663            ksize=[1, 1, 1, 1],
664            strides=[1, 2, 2, 1],
665            padding="SAME",
666            expected=[1, 3, 7, 9],
667            use_gpu=use_gpu,
668            v2=v2)
669
670        self._VerifyValues(
671            gen_nn_ops._max_pool_v2,
672            input_sizes=[1, 4, 4, 1],
673            ksize=[1, 1, 1, 1],
674            strides=[1, 2, 2, 1],
675            padding="SAME",
676            expected=[1, 3, 9, 11],
677            use_gpu=use_gpu,
678            v2=v2)
679
680  def _testDepthwiseMaxPoolInvalidConfig(self,
681                                         in_size,
682                                         ksize,
683                                         strides,
684                                         error_msg,
685                                         use_gpu=False):
686    with self.test_session(use_gpu=use_gpu):
687      t = constant_op.constant(1.0, shape=in_size)
688      with self.assertRaisesRegexp(errors_impl.UnimplementedError, error_msg):
689        t = nn_ops.max_pool(
690            t, ksize=ksize, strides=strides, padding="SAME").eval()
691
692  def testDepthwiseMaxPoolInvalidConfigs(self):
693    self._testDepthwiseMaxPoolInvalidConfig(
694        [1, 2, 2, 4], [1, 2, 2, 2], [1, 1, 1, 2],
695        "exactly one of pooling across depth")
696    self._testDepthwiseMaxPoolInvalidConfig(
697        [1, 2, 2, 4], [1, 1, 1, 2], [1, 1, 1, 1],
698        "depth window to equal the depth stride")
699    self._testDepthwiseMaxPoolInvalidConfig([1, 2, 2, 4], [1, 1, 1, 3],
700                                            [1, 1, 1, 3], "evenly divide")
701    if test.is_gpu_available():
702      with self.test_session(use_gpu=True):
703        t = constant_op.constant(1.0, shape=[1, 2, 2, 4])
704        with self.assertRaisesOpError("for CPU devices"):
705          nn_ops.max_pool(
706              t, ksize=[1, 1, 1, 2], strides=[1, 1, 1, 2],
707              padding="SAME").eval()
708
709  # The following are tests that verify that the CPU and GPU implementations
710  # produce the same results.
711  def _CompareMaxPoolingFwd(self, input_shape, ksize, strides, padding):
712    for dtype in np.float64, np.float32, np.float16:
713      tensor_input = np.random.rand(*input_shape).astype(dtype)
714      with self.test_session(use_gpu=True):
715        t = constant_op.constant(tensor_input, shape=input_shape)
716        out_op, _ = nn_ops.max_pool_with_argmax(t, ksize, strides, padding)
717        gpu_val = out_op.eval()
718      with self.test_session(use_gpu=False):
719        t = constant_op.constant(tensor_input, shape=input_shape)
720        out_op = nn_ops.max_pool(t, ksize, strides, padding)
721        cpu_val = out_op.eval()
722      self.assertAllCloseAccordingToType(cpu_val, gpu_val)
723
724  def _CompareMaxPoolingBk(self, input_shape, output_shape, ksize, strides,
725                           padding):
726    for dtype in np.float64, np.float32, np.float16:
727      # Generate numbers in a narrow range, so that there are many duplicates
728      # in the input.
729      tensor_input = np.random.random_integers(0, 3, input_shape).astype(dtype)
730      tensor_output = np.random.rand(*output_shape).astype(dtype)
731      with self.test_session(use_gpu=True):
732        t = constant_op.constant(tensor_input, shape=input_shape)
733        _, argmax_op = nn_ops.max_pool_with_argmax(t, ksize, strides, padding)
734        argmax = argmax_op.eval()
735        grad_in = constant_op.constant(tensor_output, shape=output_shape)
736        out_op = gen_nn_ops._max_pool_grad_with_argmax(t, grad_in, argmax,
737                                                       ksize, strides, padding)
738        gpu_val = out_op.eval()
739        self.assertShapeEqual(gpu_val, out_op)
740      with self.test_session(use_gpu=False):
741        t = constant_op.constant(tensor_input, shape=input_shape)
742        out_op = nn_ops.max_pool(t, ksize, strides, padding)
743        orig_out = out_op.eval()
744        grad_in = constant_op.constant(tensor_output, shape=output_shape)
745        out_op = gen_nn_ops._max_pool_grad(t, orig_out, grad_in, ksize, strides,
746                                           padding)
747        cpu_val = out_op.eval()
748        self.assertShapeEqual(cpu_val, out_op)
749      # The CPU version accumulates its gradient on fp16, so it's less
750      # accurate than the GPU version that does the accumulation on fp32
751      self.assertAllCloseAccordingToType(
752          cpu_val, gpu_val, half_rtol=0.01, half_atol=0.01)
753
754  def _CompareMaxPoolingGradBk(self, input_shape, output_shape, ksize, strides,
755                               padding):
756    for dtype in np.float64, np.float32, np.float16:
757      # Generate numbers in a narrow range, so that there are many duplicates
758      # in the input.
759      tensor_input = np.random.random_integers(0, 3, input_shape).astype(dtype)
760      with self.test_session(use_gpu=True):
761        t = constant_op.constant(tensor_input, shape=input_shape)
762        _, argmax_op = nn_ops.max_pool_with_argmax(t, ksize, strides, padding)
763        argmax = argmax_op.eval()
764        grad_in = constant_op.constant(tensor_input, shape=input_shape)
765        out_op = gen_nn_ops._max_pool_grad_grad_with_argmax(
766            t, grad_in, argmax, ksize, strides, padding)
767        gpu_val = out_op.eval()
768        self.assertShapeEqual(gpu_val, out_op)
769      with self.test_session(use_gpu=False):
770        t = constant_op.constant(tensor_input, shape=input_shape)
771        out_op = nn_ops.max_pool(t, ksize, strides, padding)
772        orig_out = out_op.eval()
773        grad_in = constant_op.constant(tensor_input, shape=input_shape)
774        out_op = gen_nn_ops._max_pool_grad_grad(t, orig_out, grad_in, ksize,
775                                                strides, padding)
776        cpu_val = out_op.eval()
777        self.assertShapeEqual(cpu_val, out_op)
778      # The CPU version accumulates its gradient on fp16, so it's less
779      # accurate than the GPU version that does the accumulation on fp32
780      self.assertAllCloseAccordingToType(
781          cpu_val, gpu_val, half_rtol=0.01, half_atol=0.01)
782
783  def testMaxPoolingWithArgmax(self):
784    # MaxPoolWithArgMax is implemented only on CUDA.
785    if not test.is_gpu_available(cuda_only=True):
786      return
787    tensor_input = [1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0]
788    with self.test_session(use_gpu=True) as sess:
789      t = constant_op.constant(tensor_input, shape=[1, 3, 3, 1])
790      out_op, argmax_op = nn_ops.max_pool_with_argmax(
791          t,
792          ksize=[1, 2, 2, 1],
793          strides=[1, 1, 1, 1],
794          Targmax=dtypes.int64,
795          padding="VALID")
796      out, argmax = sess.run([out_op, argmax_op])
797      self.assertShapeEqual(out, out_op)
798      self.assertShapeEqual(argmax, argmax_op)
799      self.assertAllClose(out.ravel(), [1.0, 1.0, 1.0, 1.0])
800      self.assertAllEqual(argmax.ravel(), [0, 1, 3, 5])
801
802  def testMaxPoolingGradWithArgmax(self):
803    # MaxPoolWithArgMax is implemented only on CUDA.
804    if not test.is_gpu_available(cuda_only=True):
805      return
806    orig_input = [1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0]
807    tensor_input = [11.0, 12.0, 13.0, 14.0]
808    tensor_argmax = list(np.array([0, 1, 3, 5], dtype=np.int64))
809    with self.test_session(use_gpu=True):
810      orig_in = constant_op.constant(orig_input, shape=[1, 3, 3, 1])
811      t = constant_op.constant(tensor_input, shape=[1, 2, 2, 1])
812      argmax = constant_op.constant(
813          tensor_argmax, shape=[1, 2, 2, 1], dtype=dtypes.int64)
814      out_op = gen_nn_ops._max_pool_grad_with_argmax(
815          orig_in,
816          t,
817          argmax,
818          ksize=[1, 2, 2, 1],
819          strides=[1, 1, 1, 1],
820          padding="VALID")
821      out = out_op.eval().flatten()
822      self.assertAllClose(out,
823                          [11.0, 12.0, 0.0, 13.0, 0.0, 14.0, 0.0, 0.0, 0.0])
824
825  def testMaxPoolingGradGradWithArgmax(self):
826    # MaxPoolWithArgMax is implemented only on CUDA.
827    if not test.is_gpu_available(cuda_only=True):
828      return
829    orig_input = [1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0]
830    tensor_input = [11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0]
831    tensor_argmax = list(np.array([0, 1, 3, 5], dtype=np.int64))
832    with self.test_session(use_gpu=True):
833      orig_in = constant_op.constant(orig_input, shape=[1, 3, 3, 1])
834      t = constant_op.constant(tensor_input, shape=[1, 3, 3, 1])
835      argmax = constant_op.constant(
836          tensor_argmax, shape=[1, 2, 2, 1], dtype=dtypes.int64)
837      out_op = gen_nn_ops._max_pool_grad_grad_with_argmax(
838          orig_in,
839          t,
840          argmax,
841          ksize=[1, 2, 2, 1],
842          strides=[1, 1, 1, 1],
843          padding="VALID")
844      out = out_op.eval().flatten()
845      self.assertAllClose(out, [11.0, 12.0, 14.0, 16.0])
846
847  def _ConstructAndTestGradient(self,
848                                pool_func,
849                                input_sizes,
850                                output_sizes,
851                                window_rows,
852                                window_cols,
853                                row_stride,
854                                col_stride,
855                                padding,
856                                data_format,
857                                use_gpu,
858                                x_init_value=None):
859    """Verifies the gradients of the avg pooling function.
860
861    Args:
862      pool_func: Function to be called, co.MaxPool, co.AvgPool,
863        or the Lua version.
864      input_sizes: Input tensor dimensions.
865      output_sizes: Output tensor dimensions.
866      window_rows: kernel size in row dim
867      window_cols: kernel size in col dim
868      row_stride: Row Stride.
869      col_stride: Col Stride.
870      padding: Padding type.
871      data_format: Data format.
872      use_gpu: whether we are running on GPU
873      x_init_value: Values to be passed to the gradient checker.
874    """
875    assert input_sizes[0] == output_sizes[0]
876    assert input_sizes[3] == output_sizes[3]
877    total_size = 1
878    for s in input_sizes:
879      total_size *= s
880    # Initializes the input tensor with array containing incrementing
881    # numbers from 1.
882    x = [f * 1.0 for f in range(1, total_size + 1)]
883    with self.test_session(use_gpu=use_gpu):
884      input_tensor = constant_op.constant(x, shape=input_sizes, name="input")
885      if pool_func == nn_ops.avg_pool:
886        func_name = "avg_pool"
887        err_tolerance = 1e-4
888      else:
889        if x_init_value is None:
890          x_init_value = np.asfarray(
891              np.arange(1, total_size + 1),
892              dtype=np.float32).reshape(input_sizes)
893        func_name = "max_pool"
894        err_tolerance = 1e-3
895      if data_format == "NCHW":
896        ksize = [1, 1, window_rows, window_rows]
897        strides = [1, 1, row_stride, col_stride]
898        t = test_util.NHWCToNCHW(input_tensor)
899      else:
900        ksize = [1, window_rows, window_rows, 1]
901        strides = [1, row_stride, col_stride, 1]
902        t = input_tensor
903      t = pool_func(
904          t,
905          ksize=ksize,
906          strides=strides,
907          padding=padding,
908          data_format=data_format,
909          name=func_name)
910      if data_format == "NCHW":
911        t = test_util.NCHWToNHWC(t)
912
913      err = gradient_checker.compute_gradient_error(
914          input_tensor,
915          input_sizes,
916          t,
917          output_sizes,
918          x_init_value=x_init_value,
919          delta=1e-2)
920    print("%s gradient error = " % func_name, err)
921    self.assertLess(err, err_tolerance)
922
923  def _ConstructAndTestSecondGradient(self,
924                                      pool_func,
925                                      input_sizes,
926                                      output_sizes,
927                                      window_rows,
928                                      window_cols,
929                                      row_stride,
930                                      col_stride,
931                                      padding,
932                                      data_format,
933                                      use_gpu,
934                                      x_init_value=None):
935    """Verifies the second-order gradients of the pooling function.
936
937    Args:
938      pool_func: Function to be called, co.MaxPool, co.AvgPool,
939        or the Lua version.
940      input_sizes: Input tensor dimensions.
941      output_sizes: Output tensor dimensions.
942      window_rows: kernel size in row dim
943      window_cols: kernel size in col dim
944      row_stride: Row Stride.
945      col_stride: Col Stride.
946      padding: Padding type.
947      data_format: Data format.
948      use_gpu: whether we are running on GPU
949      x_init_value: Values to be passed to the gradient checker.
950    """
951    assert input_sizes[0] == output_sizes[0]
952    assert input_sizes[3] == output_sizes[3]
953    total_size = 1
954    for s in input_sizes:
955      total_size *= s
956    # Initializes the input tensor with array containing incrementing
957    # numbers from 1.
958    x = [f * 1.0 for f in range(1, total_size + 1)]
959    with self.test_session(use_gpu=use_gpu):
960      input_tensor = constant_op.constant(x, shape=input_sizes, name="input")
961      if pool_func == nn_ops.avg_pool:
962        func_name = "avg_pool"
963        err_tolerance = 1e-3
964      else:
965        if x_init_value is None:
966          x_init_value = np.asfarray(
967              np.arange(1, total_size + 1),
968              dtype=np.float32).reshape(input_sizes)
969        func_name = "max_pool"
970        err_tolerance = 1e-2
971      if data_format == "NCHW":
972        ksize = [1, 1, window_rows, window_rows]
973        strides = [1, 1, row_stride, col_stride]
974        t = test_util.NHWCToNCHW(input_tensor)
975      else:
976        ksize = [1, window_rows, window_rows, 1]
977        strides = [1, row_stride, col_stride, 1]
978        t = input_tensor
979      t = pool_func(
980          t,
981          ksize=ksize,
982          strides=strides,
983          padding=padding,
984          data_format=data_format,
985          name=func_name)
986      if data_format == "NCHW":
987        t = test_util.NHWCToNCHW(t)
988
989      t_g = gradients_impl.gradients(t**2, input_tensor)[0]
990      err = gradient_checker.compute_gradient_error(
991          input_tensor,
992          input_sizes,
993          t_g,
994          input_sizes,
995          x_init_value=x_init_value,
996          delta=1e-2)
997    print("%s second-order gradient error = " % func_name, err)
998    self.assertLess(err, err_tolerance)
999
1000  def _testMaxPoolGradValidPadding1_1(self, data_format, use_gpu):
1001    for pool_func in [gen_nn_ops._max_pool_v2, nn_ops.max_pool]:
1002      self._ConstructAndTestGradient(
1003          pool_func,
1004          input_sizes=[1, 3, 3, 1],
1005          output_sizes=[1, 3, 3, 1],
1006          window_rows=1,
1007          window_cols=1,
1008          row_stride=1,
1009          col_stride=1,
1010          padding="VALID",
1011          data_format=data_format,
1012          use_gpu=use_gpu)
1013
1014  def _testMaxPoolGradValidPadding2_1_6(self, data_format, use_gpu):
1015    for pool_func in [gen_nn_ops._max_pool_v2, nn_ops.max_pool]:
1016      self._ConstructAndTestGradient(
1017          pool_func,
1018          input_sizes=[2, 6, 6, 3],
1019          output_sizes=[2, 5, 5, 3],
1020          window_rows=2,
1021          window_cols=2,
1022          row_stride=1,
1023          col_stride=1,
1024          padding="VALID",
1025          data_format=data_format,
1026          use_gpu=use_gpu)
1027
1028  def _testMaxPoolGradValidPadding2_1_7(self, data_format, use_gpu):
1029    for pool_func in [gen_nn_ops._max_pool_v2, nn_ops.max_pool]:
1030      self._ConstructAndTestGradient(
1031          pool_func,
1032          input_sizes=[2, 7, 7, 3],
1033          output_sizes=[2, 6, 6, 3],
1034          window_rows=2,
1035          window_cols=2,
1036          row_stride=1,
1037          col_stride=1,
1038          padding="VALID",
1039          data_format=data_format,
1040          use_gpu=use_gpu)
1041
1042  def _testMaxPoolGradValidPadding1_2(self, data_format, use_gpu):
1043    for pool_func in [gen_nn_ops._max_pool_v2, nn_ops.max_pool]:
1044      self._ConstructAndTestGradient(
1045          pool_func,
1046          input_sizes=[1, 3, 3, 1],
1047          output_sizes=[1, 2, 2, 1],
1048          window_rows=1,
1049          window_cols=1,
1050          row_stride=2,
1051          col_stride=2,
1052          padding="VALID",
1053          data_format=data_format,
1054          use_gpu=use_gpu)
1055
1056  def _testMaxPoolGradValidPadding2_2(self, data_format, use_gpu):
1057    for pool_func in [gen_nn_ops._max_pool_v2, nn_ops.max_pool]:
1058      self._ConstructAndTestGradient(
1059          pool_func,
1060          input_sizes=[2, 2, 2, 3],
1061          output_sizes=[2, 1, 1, 3],
1062          window_rows=2,
1063          window_cols=2,
1064          row_stride=2,
1065          col_stride=2,
1066          padding="VALID",
1067          data_format=data_format,
1068          use_gpu=use_gpu)
1069
1070  def _testMaxPoolGradSamePadding1_1(self, data_format, use_gpu):
1071    for pool_func in [gen_nn_ops._max_pool_v2, nn_ops.max_pool]:
1072      self._ConstructAndTestGradient(
1073          pool_func,
1074          input_sizes=[2, 2, 4, 3],
1075          output_sizes=[2, 2, 4, 3],
1076          window_rows=1,
1077          window_cols=1,
1078          row_stride=1,
1079          col_stride=1,
1080          padding="SAME",
1081          data_format=data_format,
1082          use_gpu=use_gpu)
1083
1084  def _testMaxPoolGradSamePadding1_2(self, data_format, use_gpu):
1085    for pool_func in [gen_nn_ops._max_pool_v2, nn_ops.max_pool]:
1086      self._ConstructAndTestGradient(
1087          pool_func,
1088          input_sizes=[2, 2, 4, 3],
1089          output_sizes=[2, 1, 2, 3],
1090          window_rows=1,
1091          window_cols=1,
1092          row_stride=2,
1093          col_stride=2,
1094          padding="SAME",
1095          data_format=data_format,
1096          use_gpu=use_gpu)
1097
1098  def _testMaxPoolGradSamePadding2_1(self, data_format, use_gpu):
1099    for pool_func in [gen_nn_ops._max_pool_v2, nn_ops.max_pool]:
1100      self._ConstructAndTestGradient(
1101          pool_func,
1102          input_sizes=[2, 2, 4, 3],
1103          output_sizes=[2, 2, 4, 3],
1104          window_rows=2,
1105          window_cols=2,
1106          row_stride=1,
1107          col_stride=1,
1108          padding="SAME",
1109          data_format=data_format,
1110          use_gpu=use_gpu)
1111
1112  def _testMaxPoolGradSamePadding2_2(self, data_format, use_gpu):
1113    for pool_func in [gen_nn_ops._max_pool_v2, nn_ops.max_pool]:
1114      self._ConstructAndTestGradient(
1115          pool_func,
1116          input_sizes=[2, 2, 4, 3],
1117          output_sizes=[2, 1, 2, 3],
1118          window_rows=2,
1119          window_cols=2,
1120          row_stride=2,
1121          col_stride=2,
1122          padding="SAME",
1123          data_format=data_format,
1124          use_gpu=use_gpu)
1125
1126  def _testMaxPoolGradSamePadding3_1(self, data_format, use_gpu):
1127    for pool_func in [gen_nn_ops._max_pool_v2, nn_ops.max_pool]:
1128      self._ConstructAndTestGradient(
1129        pool_func,
1130        input_sizes=[1, 7, 7, 1],
1131        output_sizes=[1, 7, 7, 1],
1132        window_rows=3,
1133        window_cols=3,
1134        row_stride=1,
1135        col_stride=1,
1136        padding="SAME",
1137        data_format=data_format,
1138        use_gpu=use_gpu)
1139
1140  def testMaxPoolGrad(self):
1141    for (data_format, use_gpu) in GetTestConfigs():
1142      self._testMaxPoolGradValidPadding1_1(data_format, use_gpu)
1143      self._testMaxPoolGradValidPadding1_2(data_format, use_gpu)
1144      self._testMaxPoolGradValidPadding2_1_6(data_format, use_gpu)
1145      self._testMaxPoolGradValidPadding2_1_7(data_format, use_gpu)
1146      self._testMaxPoolGradValidPadding2_2(data_format, use_gpu)
1147      self._testMaxPoolGradSamePadding1_1(data_format, use_gpu)
1148      self._testMaxPoolGradSamePadding1_2(data_format, use_gpu)
1149      self._testMaxPoolGradSamePadding2_1(data_format, use_gpu)
1150      self._testMaxPoolGradSamePadding2_2(data_format, use_gpu)
1151      self._testMaxPoolGradSamePadding3_1(data_format, use_gpu)
1152
1153  def _MaxPoolGrad(self, orig_input, orig_output, grad, window_rows,
1154                   window_cols, row_stride, col_stride, padding, v2):
1155    """Max Pooling Gradient.
1156
1157    Args:
1158      orig_input: A float Tensor. The original input tensor.
1159      orig_output: A float Tensor. The original output tensor.
1160      grad: A float Tensor.
1161        The 4D (batch x rows x cols x depth) output backprop.
1162      window_rows: integer. Kernel size along rows dimension.
1163      window_cols: integer. Kernel size along cols dimension.
1164      row_stride: integer. Stride along rows dimension
1165      col_stride: integer. Stride along cols dimension
1166      padding: PoolingOpDef.Padding.  Padding type.
1167
1168    Returns:
1169      A Tensor.
1170    """
1171    pool_func = gen_nn_ops.max_pool_grad_v2 if v2 else gen_nn_ops._max_pool_grad
1172    return pool_func(orig_input, orig_output, grad,
1173                     [1, window_rows, window_cols, 1],
1174                     [1, row_stride, col_stride, 1], padding)
1175
1176  def _testMaxPoolGradDirect(self, input_data, output_backprop,
1177                             expected_input_backprop, input_sizes, output_sizes,
1178                             window_rows, window_cols, row_stride, col_stride,
1179                             padding, use_gpu, v2):
1180    pool_func = gen_nn_ops._max_pool_v2 if v2 else nn_ops.max_pool
1181    with self.test_session(use_gpu=use_gpu):
1182      input_tensor = constant_op.constant(input_data, shape=input_sizes)
1183      output_tensor = pool_func(input_tensor,
1184                                [1, window_rows, window_cols, 1],
1185                                [1, row_stride, col_stride, 1], padding)
1186      output_backprop_tensor = constant_op.constant(
1187          output_backprop, shape=output_sizes)
1188
1189      input_backprop_tensor = self._MaxPoolGrad(input_tensor, output_tensor,
1190                                                output_backprop_tensor,
1191                                                window_rows, window_cols,
1192                                                row_stride, col_stride,
1193                                                padding, v2)
1194
1195      actual_input_backprop = input_backprop_tensor.eval()
1196      self.assertShapeEqual(actual_input_backprop, input_backprop_tensor)
1197      actual_input_backprop = actual_input_backprop.flatten()
1198      actual_input_backprop = self._GetNdArray(actual_input_backprop)
1199
1200      actual_output = output_tensor.eval().flatten()
1201      actual_output = self._GetNdArray(actual_output)
1202
1203      self.assertAllClose(
1204          expected_input_backprop, actual_input_backprop, rtol=1e-6, atol=1e-6)
1205
1206  def _testMaxPoolGradDirect1_1(self):
1207    input_data = [
1208        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
1209        1.0, 1.0
1210    ]
1211    output_backprop = [11.0, 12.0, 13.0, 15.0, 16.0, 17.0, 19.0, 20.0, 21.0]
1212    expected_input_backprop = [
1213        11.0, 12.0, 13.0, 0.0, 15.0, 16.0, 17.0, 0.0, 19.0, 20.0, 21.0, 0.0,
1214        0.0, 0.0, 0.0, 0.0
1215    ]
1216
1217    for use_gpu in True, False:
1218      for v2 in [True, False]:
1219        self._testMaxPoolGradDirect(
1220            input_data,
1221            output_backprop,
1222            expected_input_backprop,
1223            input_sizes=[1, 4, 4, 1],
1224            output_sizes=[1, 3, 3, 1],
1225            window_rows=2,
1226            window_cols=2,
1227            row_stride=1,
1228            col_stride=1,
1229            padding="VALID",
1230            use_gpu=use_gpu,
1231            v2=v2)
1232
1233  def _testMaxPoolGradDirect1_2(self):
1234    input_data = [
1235        1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0,
1236        0.0, 1.0
1237    ]
1238    output_backprop = [11.0, 12.0, 13.0, 15.0, 16.0, 17.0, 19.0, 20.0, 21.0]
1239    expected_input_backprop = [
1240        11.0, 0.0, 25.0, 0.0, 0.0, 31.0, 0.0, 17.0, 19.0, 0.0, 41.0, 0.0, 0.0,
1241        0.0, 0.0, 0.0
1242    ]
1243
1244    for use_gpu in True, False:
1245      for v2 in [True, False]:
1246        self._testMaxPoolGradDirect(
1247            input_data,
1248            output_backprop,
1249            expected_input_backprop,
1250            input_sizes=[1, 4, 4, 1],
1251            output_sizes=[1, 3, 3, 1],
1252            window_rows=2,
1253            window_cols=2,
1254            row_stride=1,
1255            col_stride=1,
1256            padding="VALID",
1257            use_gpu=use_gpu,
1258            v2=v2)
1259
1260  def _testMaxPoolGradDirect1_3(self):
1261    input_data = [
1262        1.0,
1263        0.0,
1264        1.0,
1265        0.0,
1266        0.0,
1267        1.0,
1268        0.0,
1269        1.0,
1270        1.0,
1271        0.0,
1272        1.0,
1273        0.0,
1274        0.0,
1275        1.0,
1276        0.0,
1277        1.0,
1278    ]
1279    output_backprop = [
1280        11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0,
1281        23.0, 24.0, 25.0, 26.0
1282    ]
1283    expected_input_backprop = [
1284        54,
1285        0.0,
1286        62,
1287        0.0,
1288        0.0,
1289        60,
1290        0.0,
1291        22.0,
1292        47,
1293        0.0,
1294        51,
1295        0.0,
1296        0.0,
1297        0.0,
1298        0.0,
1299        0.0,
1300    ]
1301
1302    for use_gpu in True, False:
1303      for v2 in [True, False]:
1304        self._testMaxPoolGradDirect(
1305            input_data,
1306            output_backprop,
1307            expected_input_backprop,
1308            input_sizes=[1, 4, 4, 1],
1309            output_sizes=[1, 4, 4, 1],
1310            window_rows=3,
1311            window_cols=3,
1312            row_stride=1,
1313            col_stride=1,
1314            padding="SAME",
1315            use_gpu=use_gpu,
1316            v2=v2)
1317
1318  def _testMaxPoolGradDirectWithNans2_1(self):
1319    input_data = [float("nan")] * 16
1320    output_backprop = [11.0, 12.0, 13.0, 15.0, 16.0, 17.0, 19.0, 20.0, 21.0]
1321    # Test the CPU implementation, which propagates diffs in case of NaN
1322    expected_input_backprop_tf_cpu = [
1323        11.0, 12.0, 13.0, 0.0, 15.0, 16.0, 17.0, 0.0, 19.0, 20.0, 21.0, 0.0,
1324        0.0, 0.0, 0.0, 0.0
1325    ]
1326    for v2 in [True, False]:
1327      self._testMaxPoolGradDirect(
1328          input_data,
1329          output_backprop,
1330          expected_input_backprop_tf_cpu,
1331          input_sizes=[1, 4, 4, 1],
1332          output_sizes=[1, 3, 3, 1],
1333          window_rows=2,
1334          window_cols=2,
1335          row_stride=1,
1336          col_stride=1,
1337          padding="VALID",
1338          use_gpu=False,
1339          v2=v2)
1340
1341    if not test.is_gpu_available():
1342      return
1343
1344    # Test the GPU implementation that uses cudnn for now.
1345    saved_nanprop = os.environ.get("TF_ENABLE_MAXPOOL_NANPROP")
1346    # Do not propagate the diff in cases of NaNs
1347    os.environ["TF_ENABLE_MAXPOOL_NANPROP"] = "0"
1348    expected_input_backprop_cudnn = [
1349        0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
1350        0.0, 0.0
1351    ]
1352
1353    for v2 in [True, False]:
1354      self._testMaxPoolGradDirect(
1355          input_data,
1356          output_backprop,
1357          expected_input_backprop_cudnn,
1358          input_sizes=[1, 4, 4, 1],
1359          output_sizes=[1, 3, 3, 1],
1360          window_rows=2,
1361          window_cols=2,
1362          row_stride=1,
1363          col_stride=1,
1364          padding="VALID",
1365          use_gpu=True,
1366          v2=v2)
1367
1368    # Propagate the diff in cases of NaNs
1369    os.environ["TF_ENABLE_MAXPOOL_NANPROP"] = "1"
1370    expected_input_backprop_cudnn = expected_input_backprop_tf_cpu
1371
1372    for v2 in [True, False]:
1373      self._testMaxPoolGradDirect(
1374          input_data,
1375          output_backprop,
1376          expected_input_backprop_cudnn,
1377          input_sizes=[1, 4, 4, 1],
1378          output_sizes=[1, 3, 3, 1],
1379          window_rows=2,
1380          window_cols=2,
1381          row_stride=1,
1382          col_stride=1,
1383          padding="VALID",
1384          use_gpu=True,
1385          v2=v2)
1386
1387    if saved_nanprop:
1388      os.environ["TF_ENABLE_MAXPOOL_NANPROP"] = saved_nanprop
1389    else:
1390      del os.environ["TF_ENABLE_MAXPOOL_NANPROP"]
1391
1392  def _testMaxPoolGradDirectWithNans2_2(self):
1393    input_data = [float("nan")] * 16
1394    output_backprop = [
1395        float("nan"), 12.0, 13.0, 15.0, float("nan"), 17.0, 19.0, 20.0,
1396        float("nan")
1397    ]
1398    # Test the CPU implementation, which propagates diffs in case of NaN
1399    expected_input_backprop_tf_cpu = [
1400        float("nan"), 12.0, 13.0, 0.0, 15.0, float("nan"), 17.0, 0.0, 19.0,
1401        20.0, float("nan"), 0.0, 0.0, 0.0, 0.0, 0.0
1402    ]
1403    for v2 in [True, False]:
1404      self._testMaxPoolGradDirect(
1405          input_data,
1406          output_backprop,
1407          expected_input_backprop_tf_cpu,
1408          input_sizes=[1, 4, 4, 1],
1409          output_sizes=[1, 3, 3, 1],
1410          window_rows=2,
1411          window_cols=2,
1412          row_stride=1,
1413          col_stride=1,
1414          padding="VALID",
1415          use_gpu=False,
1416          v2=v2)
1417
1418    if not test.is_gpu_available():
1419      return
1420
1421    # Test the GPU implementation that uses cudnn for now.
1422    saved_nanprop = os.environ.get("TF_ENABLE_MAXPOOL_NANPROP")
1423    # Do not propagate the diff in cases of NaNs
1424    os.environ["TF_ENABLE_MAXPOOL_NANPROP"] = "0"
1425    expected_input_backprop_cudnn = [
1426        0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
1427        0.0, 0.0
1428    ]
1429
1430    for v2 in [True, False]:
1431      self._testMaxPoolGradDirect(
1432          input_data,
1433          output_backprop,
1434          expected_input_backprop_cudnn,
1435          input_sizes=[1, 4, 4, 1],
1436          output_sizes=[1, 3, 3, 1],
1437          window_rows=2,
1438          window_cols=2,
1439          row_stride=1,
1440          col_stride=1,
1441          padding="VALID",
1442          use_gpu=True,
1443          v2=v2)
1444
1445    # Propagate the diff in cases of NaNs
1446    os.environ["TF_ENABLE_MAXPOOL_NANPROP"] = "1"
1447    expected_input_backprop_cudnn = expected_input_backprop_tf_cpu
1448
1449    for v2 in [True, False]:
1450      self._testMaxPoolGradDirect(
1451          input_data,
1452          output_backprop,
1453          expected_input_backprop_cudnn,
1454          input_sizes=[1, 4, 4, 1],
1455          output_sizes=[1, 3, 3, 1],
1456          window_rows=2,
1457          window_cols=2,
1458          row_stride=1,
1459          col_stride=1,
1460          padding="VALID",
1461          use_gpu=True,
1462          v2=v2)
1463
1464    if saved_nanprop:
1465      os.environ["TF_ENABLE_MAXPOOL_NANPROP"] = saved_nanprop
1466    else:
1467      del os.environ["TF_ENABLE_MAXPOOL_NANPROP"]
1468
1469  def testMaxPoolGradDirect(self):
1470    self._testMaxPoolGradDirect1_1()
1471    self._testMaxPoolGradDirect1_2()
1472    self._testMaxPoolGradDirect1_3()
1473    self._testMaxPoolGradDirectWithNans2_1()
1474    self._testMaxPoolGradDirectWithNans2_2()
1475
1476  def _testMaxPoolGradGradValidPadding1_1(self, data_format, use_gpu):
1477    for pool_func in [gen_nn_ops._max_pool_v2, nn_ops.max_pool]:
1478      self._ConstructAndTestSecondGradient(
1479          pool_func,
1480          input_sizes=[1, 3, 3, 1],
1481          output_sizes=[1, 3, 3, 1],
1482          window_rows=1,
1483          window_cols=1,
1484          row_stride=1,
1485          col_stride=1,
1486          padding="VALID",
1487          data_format=data_format,
1488          use_gpu=use_gpu)
1489
1490  def _testMaxPoolGradGradValidPadding2_1_6(self, data_format, use_gpu):
1491    for pool_func in [gen_nn_ops._max_pool_v2, nn_ops.max_pool]:
1492      self._ConstructAndTestSecondGradient(
1493          pool_func,
1494          input_sizes=[2, 6, 6, 3],
1495          output_sizes=[2, 5, 5, 3],
1496          window_rows=2,
1497          window_cols=2,
1498          row_stride=1,
1499          col_stride=1,
1500          padding="VALID",
1501          data_format=data_format,
1502          use_gpu=use_gpu)
1503
1504  def _testMaxPoolGradGradValidPadding2_1_7(self, data_format, use_gpu):
1505    for pool_func in [gen_nn_ops._max_pool_v2, nn_ops.max_pool]:
1506      self._ConstructAndTestSecondGradient(
1507          pool_func,
1508          input_sizes=[2, 7, 7, 3],
1509          output_sizes=[2, 6, 6, 3],
1510          window_rows=2,
1511          window_cols=2,
1512          row_stride=1,
1513          col_stride=1,
1514          padding="VALID",
1515          data_format=data_format,
1516          use_gpu=use_gpu)
1517
1518  def _testMaxPoolGradGradValidPadding2_2(self, data_format, use_gpu):
1519    for pool_func in [gen_nn_ops._max_pool_v2, nn_ops.max_pool]:
1520      self._ConstructAndTestSecondGradient(
1521          pool_func,
1522          input_sizes=[2, 2, 2, 3],
1523          output_sizes=[2, 1, 1, 3],
1524          window_rows=2,
1525          window_cols=2,
1526          row_stride=2,
1527          col_stride=2,
1528          padding="VALID",
1529          data_format=data_format,
1530          use_gpu=use_gpu)
1531
1532  def _testMaxPoolGradGradSamePadding1_1(self, data_format, use_gpu):
1533    for pool_func in [gen_nn_ops._max_pool_v2, nn_ops.max_pool]:
1534      self._ConstructAndTestSecondGradient(
1535          pool_func,
1536          input_sizes=[2, 2, 4, 3],
1537          output_sizes=[2, 2, 4, 3],
1538          window_rows=1,
1539          window_cols=1,
1540          row_stride=1,
1541          col_stride=1,
1542          padding="SAME",
1543          data_format=data_format,
1544          use_gpu=use_gpu)
1545
1546  def _testMaxPoolGradGradSamePadding2_1(self, data_format, use_gpu):
1547    for pool_func in [gen_nn_ops._max_pool_v2, nn_ops.max_pool]:
1548      self._ConstructAndTestSecondGradient(
1549          pool_func,
1550          input_sizes=[2, 2, 4, 3],
1551          output_sizes=[2, 2, 4, 3],
1552          window_rows=2,
1553          window_cols=2,
1554          row_stride=1,
1555          col_stride=1,
1556          padding="SAME",
1557          data_format=data_format,
1558          use_gpu=use_gpu)
1559
1560  def _testMaxPoolGradGradSamePadding2_2(self, data_format, use_gpu):
1561    for pool_func in [gen_nn_ops._max_pool_v2, nn_ops.max_pool]:
1562      self._ConstructAndTestSecondGradient(
1563          pool_func,
1564          input_sizes=[2, 2, 4, 3],
1565          output_sizes=[2, 1, 2, 3],
1566          window_rows=2,
1567          window_cols=2,
1568          row_stride=2,
1569          col_stride=2,
1570          padding="SAME",
1571          data_format=data_format,
1572          use_gpu=use_gpu)
1573
1574  def _testMaxPoolGradGradSamePadding3_1(self, data_format, use_gpu):
1575    for pool_func in [gen_nn_ops._max_pool_v2, nn_ops.max_pool]:
1576      self._ConstructAndTestSecondGradient(
1577          pool_func,
1578          input_sizes=[1, 7, 7, 1],
1579          output_sizes=[1, 7, 7, 1],
1580          window_rows=3,
1581          window_cols=3,
1582          row_stride=1,
1583          col_stride=1,
1584          padding="SAME",
1585          data_format=data_format,
1586          use_gpu=use_gpu)
1587
1588  def testMaxPoolGradGrad(self):
1589    for (data_format, use_gpu) in GetTestConfigs():
1590      self._testMaxPoolGradGradValidPadding1_1(data_format, use_gpu)
1591      self._testMaxPoolGradGradValidPadding2_1_6(data_format, use_gpu)
1592      self._testMaxPoolGradGradValidPadding2_1_7(data_format, use_gpu)
1593      self._testMaxPoolGradGradValidPadding2_2(data_format, use_gpu)
1594      self._testMaxPoolGradGradSamePadding1_1(data_format, use_gpu)
1595      self._testMaxPoolGradGradSamePadding2_1(data_format, use_gpu)
1596      self._testMaxPoolGradGradSamePadding2_2(data_format, use_gpu)
1597      self._testMaxPoolGradGradSamePadding3_1(data_format, use_gpu)
1598
1599  def _MaxPoolGradGrad(self, orig_input, orig_output, grad, window_rows,
1600                       window_cols, row_stride, col_stride, padding):
1601    """Max Pooling Second-Order Gradient.
1602
1603    Args:
1604      orig_input: A float Tensor. The original input tensor.
1605      orig_output: A float Tensor. The original output tensor.
1606      grad: A float Tensor.
1607        The 4D (batch x out_rows x out_cols x depth) output backprop.
1608      window_rows: integer. Kernel size along rows dimension.
1609      window_cols: integer. Kernel size along cols dimension.
1610      row_stride: integer. Stride along rows dimension
1611      col_stride: integer. Stride along cols dimension
1612      padding: PoolingOpDef.Padding.  Padding type.
1613
1614    Returns:
1615      A Tensor.
1616    """
1617    return gen_nn_ops._max_pool_grad_grad(orig_input, orig_output, grad,
1618                                          [1, window_rows, window_cols,
1619                                           1], [1, row_stride, col_stride,
1620                                                1], padding)
1621
1622  def testAvgPoolGrad(self):
1623    for (data_format, use_gpu) in GetTestConfigs():
1624      self._testAvgPoolGradValidPadding1_1(data_format, use_gpu)
1625      self._testAvgPoolGradValidPadding1_2(data_format, use_gpu)
1626      self._testAvgPoolGradValidPadding2_1(data_format, use_gpu)
1627      self._testAvgPoolGradValidPadding2_2(data_format, use_gpu)
1628      self._testAvgPoolGradSamePadding1_1(data_format, use_gpu)
1629      self._testAvgPoolGradSamePadding1_2(data_format, use_gpu)
1630      self._testAvgPoolGradSamePadding2_1(data_format, use_gpu)
1631      self._testAvgPoolGradSamePadding2_2(data_format, use_gpu)
1632      self._testAvgPoolGradSamePadding3_1(data_format, use_gpu)
1633
1634  def _testAvgPoolGradValidPadding1_1(self, data_format, use_gpu):
1635    self._ConstructAndTestGradient(
1636        nn_ops.avg_pool,
1637        input_sizes=[2, 3, 3, 3],
1638        output_sizes=[2, 3, 3, 3],
1639        window_rows=1,
1640        window_cols=1,
1641        row_stride=1,
1642        col_stride=1,
1643        padding="VALID",
1644        data_format=data_format,
1645        use_gpu=use_gpu)
1646
1647  def _testAvgPoolGradValidPadding1_2(self, data_format, use_gpu):
1648    self._ConstructAndTestGradient(
1649        nn_ops.avg_pool,
1650        input_sizes=[2, 3, 3, 3],
1651        output_sizes=[2, 2, 2, 3],
1652        window_rows=1,
1653        window_cols=1,
1654        row_stride=2,
1655        col_stride=2,
1656        padding="VALID",
1657        data_format=data_format,
1658        use_gpu=use_gpu)
1659
1660  def _testAvgPoolGradValidPadding2_1(self, data_format, use_gpu):
1661    self._ConstructAndTestGradient(
1662        nn_ops.avg_pool,
1663        input_sizes=[2, 3, 3, 3],
1664        output_sizes=[2, 2, 2, 3],
1665        window_rows=2,
1666        window_cols=2,
1667        row_stride=1,
1668        col_stride=1,
1669        padding="VALID",
1670        data_format=data_format,
1671        use_gpu=use_gpu)
1672
1673  def _testAvgPoolGradValidPadding2_2(self, data_format, use_gpu):
1674    self._ConstructAndTestGradient(
1675        nn_ops.avg_pool,
1676        input_sizes=[2, 2, 2, 3],
1677        output_sizes=[2, 1, 1, 3],
1678        window_rows=2,
1679        window_cols=2,
1680        row_stride=2,
1681        col_stride=2,
1682        padding="VALID",
1683        data_format=data_format,
1684        use_gpu=use_gpu)
1685
1686  def _testAvgPoolGradSamePadding1_1(self, data_format, use_gpu):
1687    self._ConstructAndTestGradient(
1688        nn_ops.avg_pool,
1689        input_sizes=[2, 2, 4, 3],
1690        output_sizes=[2, 2, 4, 3],
1691        window_rows=1,
1692        window_cols=1,
1693        row_stride=1,
1694        col_stride=1,
1695        padding="SAME",
1696        data_format=data_format,
1697        use_gpu=use_gpu)
1698
1699  def _testAvgPoolGradSamePadding1_2(self, data_format, use_gpu):
1700    self._ConstructAndTestGradient(
1701        nn_ops.avg_pool,
1702        input_sizes=[2, 2, 4, 3],
1703        output_sizes=[2, 1, 2, 3],
1704        window_rows=1,
1705        window_cols=1,
1706        row_stride=2,
1707        col_stride=2,
1708        padding="SAME",
1709        data_format=data_format,
1710        use_gpu=use_gpu)
1711
1712  def _testAvgPoolGradSamePadding2_1(self, data_format, use_gpu):
1713    self._ConstructAndTestGradient(
1714        nn_ops.avg_pool,
1715        input_sizes=[2, 2, 4, 3],
1716        output_sizes=[2, 2, 4, 3],
1717        window_rows=2,
1718        window_cols=2,
1719        row_stride=1,
1720        col_stride=1,
1721        padding="SAME",
1722        data_format=data_format,
1723        use_gpu=use_gpu)
1724
1725  def _testAvgPoolGradSamePadding2_2(self, data_format, use_gpu):
1726    self._ConstructAndTestGradient(
1727        nn_ops.avg_pool,
1728        input_sizes=[2, 2, 4, 3],
1729        output_sizes=[2, 1, 2, 3],
1730        window_rows=2,
1731        window_cols=2,
1732        row_stride=2,
1733        col_stride=2,
1734        padding="SAME",
1735        data_format=data_format,
1736        use_gpu=use_gpu)
1737
1738  def _testAvgPoolGradSamePadding3_1(self, data_format, use_gpu):
1739    self._ConstructAndTestGradient(
1740        nn_ops.avg_pool,
1741        input_sizes=[1, 7, 7, 1],
1742        output_sizes=[1, 7, 7, 1],
1743        window_rows=3,
1744        window_cols=3,
1745        row_stride=1,
1746        col_stride=1,
1747        padding="SAME",
1748        data_format=data_format,
1749        use_gpu=use_gpu)
1750
1751  def testShapeFunctionEdgeCases(self):
1752    # All shapes unknown.
1753    for pool_func in [nn_ops.max_pool, nn_ops.avg_pool]:
1754      p = pool_func(
1755          array_ops.placeholder(dtypes.float32),
1756          ksize=[1, 1, 1, 1],
1757          strides=[1, 1, 1, 1],
1758          padding="SAME")
1759      self.assertEqual([None, None, None, None], p.get_shape().as_list())
1760    p, am = nn_ops.max_pool_with_argmax(
1761        array_ops.placeholder(dtypes.float32),
1762        ksize=[1, 1, 1, 1],
1763        strides=[1, 1, 1, 1],
1764        padding="SAME")
1765    self.assertEqual([None, None, None, None], p.get_shape().as_list())
1766    self.assertEqual([None, None, None, None], am.get_shape().as_list())
1767
1768    # Incorrect input shape.
1769    for pool_func in [
1770        nn_ops.max_pool, nn_ops.avg_pool, nn_ops.max_pool_with_argmax
1771    ]:
1772      with self.assertRaises(ValueError):
1773        pool_func(
1774            array_ops.placeholder(
1775                dtypes.float32, shape=[1, 3]),
1776            ksize=[1, 1, 1, 1],
1777            strides=[1, 1, 1, 1],
1778            padding="SAME")
1779
1780  def testOpEdgeCases(self):
1781    with self.test_session(use_gpu=test.is_gpu_available()) as sess:
1782      pool_funcs = [nn_ops.max_pool, nn_ops.avg_pool]
1783      if test.is_gpu_available():
1784        pool_funcs.append(nn_ops.max_pool_with_argmax)
1785      for pool_func in pool_funcs:
1786        # Illegal strides.
1787        with self.assertRaisesRegexp(
1788            errors_impl.UnimplementedError,
1789            "Pooling is not yet supported on the batch"):
1790          sess.run(
1791              pool_func(
1792                  array_ops.placeholder(dtypes.float32),
1793                  ksize=[1, 1, 1, 1],
1794                  strides=[2, 1, 1, 1],
1795                  padding="SAME"))
1796
1797        # Filter too large.
1798        with self.assertRaisesRegexp(ValueError, "Negative dimension size"):
1799          sess.run(
1800              pool_func(
1801                  array_ops.placeholder(
1802                      dtypes.float32, shape=[32, 20, 20, 3]),
1803                  ksize=[1, 20, 21, 1],
1804                  strides=[1, 1, 1, 1],
1805                  padding="VALID"))
1806        with self.assertRaisesRegexp(ValueError, "Negative dimension size"):
1807          pool_func(
1808              array_ops.placeholder(
1809                  dtypes.float32, shape=[32, 20, 20, 3]),
1810              ksize=[1, 21, 20, 1],
1811              strides=[1, 1, 1, 1],
1812              padding="VALID")
1813
1814
1815def GetMaxPoolFwdTest(input_size, filter_size, strides, padding):
1816
1817  def Test(self):
1818    # MaxPoolWithArgMax is implemented only on CUDA.
1819    if not test.is_gpu_available(cuda_only=True):
1820      return
1821    self._CompareMaxPoolingFwd(input_size, filter_size, strides, padding)
1822
1823  return Test
1824
1825
1826def GetMaxPoolGradTest(input_size, filter_size, output_size, strides, padding):
1827
1828  def Test(self):
1829    # MaxPoolWithArgMax is implemented only on CUDA.
1830    if not test.is_gpu_available(cuda_only=True):
1831      return
1832    self._CompareMaxPoolingBk(input_size, output_size, filter_size, strides,
1833                              padding)
1834
1835  return Test
1836
1837
1838def GetMaxPoolGradGradTest(input_size, filter_size, output_size, strides,
1839                           padding):
1840
1841  def Test(self):
1842    # MaxPoolWithArgMax is implemented only on CUDA.
1843    if not test.is_gpu_available(cuda_only=True):
1844      return
1845    self._CompareMaxPoolingGradBk(input_size, output_size, filter_size, strides,
1846                                  padding)
1847
1848  return Test
1849
1850
1851if __name__ == "__main__":
1852  for (name_, input_size_, filter_size_, output_size_, stride_,
1853       padding_) in GetShrunkInceptionMaxPoolShapes():
1854    setattr(PoolingTest, "testMaxPoolFwd_" + name_,
1855            GetMaxPoolFwdTest(input_size_, filter_size_, stride_, padding_))
1856    setattr(PoolingTest, "testMaxPoolGrad_" + name_,
1857            GetMaxPoolGradTest(input_size_, filter_size_, output_size_, stride_,
1858                               padding_))
1859    setattr(PoolingTest, "testMaxPoolGradGrad_" + name_,
1860            GetMaxPoolGradGradTest(input_size_, filter_size_, output_size_,
1861                                   stride_, padding_))
1862  test.main()
1863