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