pooling_ops_test.py revision bed8383c27a0a7225e6fc7ff59a2cd6388fb4d09
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 numpy as np
22
23from tensorflow.python.framework import constant_op
24from tensorflow.python.framework import dtypes
25from tensorflow.python.framework import errors_impl
26from tensorflow.python.framework import ops
27from tensorflow.python.framework import test_util
28from tensorflow.python.ops import array_ops
29from tensorflow.python.ops import gen_nn_ops
30from tensorflow.python.ops import gradient_checker
31from tensorflow.python.ops import nn_ops
32import tensorflow.python.ops.nn_grad  # pylint: disable=unused-import
33from tensorflow.python.platform import test
34
35
36def NHWCToNCHW(input_tensor):
37  """Convert the input from NHWC format to NCHW.
38
39  Args:
40    input_tensor:  a 4-D tensor, or a 4-element array representing the same.
41
42  Returns:
43    the converted tensor or a shape array
44  """
45  if isinstance(input_tensor, ops.Tensor):
46    return array_ops.transpose(input_tensor, [0, 3, 1, 2])
47  else:
48    return [input_tensor[0], input_tensor[3], input_tensor[1], input_tensor[2]]
49
50
51def NCHWToNHWC(input_tensor):
52  """Convert the input from NCHW format to NHWC.
53
54  Args:
55    input_tensor:  a 4-D tensor, or a 4-element array representing the same.
56
57  Returns:
58    the converted tensor or a shape array
59  """
60  if isinstance(input_tensor, ops.Tensor):
61    return array_ops.transpose(input_tensor, [0, 2, 3, 1])
62  else:
63    return [input_tensor[0], input_tensor[2], input_tensor[3], input_tensor[1]]
64
65
66def GetTestConfigs():
67  """Get all the valid tests configs to run.
68
69  Returns:
70    all the valid test configs as tuples of data_format and use_gpu.
71  """
72  test_configs = [("NHWC", False), ("NHWC", True)]
73  if test.is_gpu_available(cuda_only=True):
74    # "NCHW" format is currently supported exclusively on CUDA GPUs.
75    test_configs += [("NCHW", True)]
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):
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    # Initializes the input tensor with array containing incrementing
128    # numbers from 1.
129    x = [f * 1.0 for f in range(1, total_size + 1)]
130    with self.test_session(use_gpu=use_gpu) as sess:
131      t = constant_op.constant(x, shape=input_sizes, dtype=data_type)
132      if data_format == "NCHW":
133        t = NHWCToNCHW(t)
134        ksize = NHWCToNCHW(ksize)
135        strides = NHWCToNCHW(strides)
136      t = pool_func(
137          t,
138          ksize=ksize,
139          strides=strides,
140          padding=padding,
141          data_format=data_format)
142      if data_format == "NCHW":
143        t = NCHWToNHWC(t)
144      actual = t.eval()
145      self.assertAllCloseAccordingToType(expected, actual.flatten())
146      self.assertShapeEqual(actual, t)
147
148  def _VerifyOneTest(self, pool_func, input_sizes, ksize, strides, padding,
149                     data_format, expected, use_gpu):
150    """Verifies the output values of the pooling function.
151
152    Args:
153      pool_func: Function to be called, co.MaxPool, co.AvgPool,
154        or the Lua version.
155      input_sizes: Input tensor dimensions.
156      ksize: The kernel size dimensions
157      strides: The stride dimensions
158      padding: Padding type.
159      data_format: The data format we use to run the pooling operation.
160      expected: An array containing the expected operation outputs.
161      use_gpu: Whether we are running on GPU.
162    """
163    self._VerifyOneType(pool_func, input_sizes, ksize, strides, padding,
164                        data_format, dtypes.float32, expected, use_gpu)
165
166    if not use_gpu or test_util.CudaSupportsHalfMatMulAndConv():
167      self._VerifyOneType(pool_func, input_sizes, ksize, strides, padding,
168                          data_format, dtypes.float16, expected, use_gpu)
169
170  def _VerifyValues(self, pool_func, input_sizes, ksize, strides, padding,
171                    expected, use_gpu):
172    """Verifies the output values of the pooling function.
173
174    Args:
175      pool_func: Function to be called, co.MaxPool, co.AvgPool,
176        or the Lua version.
177      input_sizes: Input tensor dimensions.
178      ksize: The kernel size dimensions
179      strides: The stride dimensions
180      padding: Padding type.
181      expected: An array containing the expected operation outputs.
182      use_gpu: Whether we are running on GPU.
183    """
184    for (data_format, use_gpu_2) in GetTestConfigs():
185      if use_gpu_2 == use_gpu:
186        self._VerifyOneTest(pool_func, input_sizes, ksize, strides, padding,
187                            data_format, expected, use_gpu)
188
189  def _testAvgPoolValidPadding(self, use_gpu):
190    expected_output = [7.0, 8.0, 9.0]
191    self._VerifyValues(
192        nn_ops.avg_pool,
193        input_sizes=[1, 3, 3, 3],
194        ksize=[1, 2, 2, 1],
195        strides=[1, 2, 2, 1],
196        padding="VALID",
197        expected=expected_output,
198        use_gpu=use_gpu)
199
200  def _testAvgPoolSamePadding(self, use_gpu):
201    expected_output = [8.5, 9.5, 10.5, 14.5, 15.5, 16.5]
202    self._VerifyValues(
203        nn_ops.avg_pool,
204        input_sizes=[1, 2, 4, 3],
205        ksize=[1, 2, 2, 1],
206        strides=[1, 2, 2, 1],
207        padding="SAME",
208        expected=expected_output,
209        use_gpu=use_gpu)
210
211  def _testAvgPoolSamePaddingNonSquareWindow(self, use_gpu):
212    # input is:
213    # [1.0, 2.0
214    #  3.0  4.0]
215    #
216    # Window of [x, x] should do:
217    #  [avg(1.0, 2.0), avg(2.0, padded0),
218    #   avg(3.0, 4.0), avg(4.0, padded0)]
219    self._VerifyValues(
220        nn_ops.avg_pool,
221        input_sizes=[1, 2, 2, 1],
222        ksize=[1, 1, 2, 1],
223        strides=[1, 1, 1, 1],
224        padding="SAME",
225        expected=[1.5, 2.0, 3.5, 4.0],
226        use_gpu=use_gpu)
227
228    # Window of [x,
229    #            x] should do:
230    #  [avg(1.0, 3.0), avg(2.0, 4.0)
231    #   avg(3.0, padded0), avg(4.0, padded0)]
232    self._VerifyValues(
233        nn_ops.avg_pool,
234        input_sizes=[1, 2, 2, 1],
235        ksize=[1, 2, 1, 1],
236        strides=[1, 1, 1, 1],
237        padding="SAME",
238        expected=[2.0, 3.0, 3.0, 4.0],
239        use_gpu=use_gpu)
240
241  def _testAvgPoolSamePaddingNonSquareWindowMultiBatch(self, use_gpu):
242    self._VerifyValues(
243        nn_ops.avg_pool,
244        input_sizes=[2, 2, 2, 2],
245        ksize=[1, 1, 2, 1],
246        strides=[1, 1, 1, 1],
247        padding="SAME",
248        expected=[
249            2.0, 3.0, 3.0, 4.0, 6.0, 7.0, 7.0, 8.0, 10.0, 11.0, 11.0, 12.0,
250            14.0, 15.0, 15.0, 16.0
251        ],
252        use_gpu=use_gpu)
253    self._VerifyValues(
254        nn_ops.avg_pool,
255        input_sizes=[2, 2, 2, 2],
256        ksize=[1, 2, 1, 1],
257        strides=[1, 1, 1, 1],
258        padding="SAME",
259        expected=[
260            3.0, 4.0, 5.0, 6.0, 5.0, 6.0, 7.0, 8.0, 11.0, 12.0, 13.0, 14.0,
261            13.0, 14.0, 15.0, 16.0
262        ],
263        use_gpu=use_gpu)
264
265  def _testAvgPoolValidPaddingUnevenStride(self, use_gpu):
266    self._VerifyValues(
267        nn_ops.avg_pool,
268        input_sizes=[1, 3, 3, 3],
269        ksize=[1, 2, 2, 1],
270        strides=[1, 1, 2, 1],
271        padding="VALID",
272        expected=[7.0, 8.0, 9.0, 16.0, 17.0, 18.0],
273        use_gpu=use_gpu)
274    self._VerifyValues(
275        nn_ops.avg_pool,
276        input_sizes=[1, 3, 3, 3],
277        ksize=[1, 2, 2, 1],
278        strides=[1, 2, 1, 1],
279        padding="VALID",
280        expected=[7.0, 8.0, 9.0, 10.0, 11.0, 12.0],
281        use_gpu=use_gpu)
282
283  def _testAvgPoolSamePadding4(self, use_gpu):
284    expected_output = [
285        11.0, 12.0, 13.0, 14.0, 19.0, 20.0, 21.0, 22.0, 43.0, 44.0, 45.0, 46.0,
286        51.0, 52.0, 53.0, 54.0
287    ]
288    self._VerifyValues(
289        nn_ops.avg_pool,
290        input_sizes=[1, 4, 4, 4],
291        ksize=[1, 2, 2, 1],
292        strides=[1, 2, 2, 1],
293        padding="SAME",
294        expected=expected_output,
295        use_gpu=use_gpu)
296
297  def _testAvgPoolSamePaddingPacket4(self, use_gpu):
298    expected_output = [
299        21.0, 22.0, 23.0, 24.0, 27.0, 28.0, 29.0, 30.0, 45.0, 46.0, 47.0, 48.0,
300        51.0, 52.0, 53.0, 54.0
301    ]
302    self._VerifyValues(
303        nn_ops.avg_pool,
304        input_sizes=[1, 4, 4, 4],
305        ksize=[1, 3, 3, 1],
306        strides=[1, 2, 2, 1],
307        padding="SAME",
308        expected=expected_output,
309        use_gpu=use_gpu)
310
311  def _testAvgPoolSamePaddingPacket8(self, use_gpu):
312    expected_output = [
313        73.0, 74.0, 75.0, 76.0, 77.0, 78.0, 79.0, 80.0, 89.0, 90.0, 91.0, 92.0,
314        93.0, 94.0, 95.0, 96.0, 105.0, 106.0, 107.0, 108.0, 109.0, 110.0, 111.0,
315        112.0, 117.0, 118.0, 119.0, 120.0, 121.0, 122.0, 123.0, 124.0, 201.0,
316        202.0, 203.0, 204.0, 205.0, 206.0, 207.0, 208.0, 217.0, 218.0, 219.0,
317        220.0, 221.0, 222.0, 223.0, 224.0, 233.0, 234.0, 235.0, 236.0, 237.0,
318        238.0, 239.0, 240.0, 245.0, 246.0, 247.0, 248.0, 249.0, 250.0, 251.0,
319        252.0, 329.0, 330.0, 331.0, 332.0, 333.0, 334.0, 335.0, 336.0, 345.0,
320        346.0, 347.0, 348.0, 349.0, 350.0, 351.0, 352.0, 361.0, 362.0, 363.0,
321        364.0, 365.0, 366.0, 367.0, 368.0, 373.0, 374.0, 375.0, 376.0, 377.0,
322        378.0, 379.0, 380.0, 425.0, 426.0, 427.0, 428.0, 429.0, 430.0, 431.0,
323        432.0, 441.0, 442.0, 443.0, 444.0, 445.0, 446.0, 447.0, 448.0, 457.0,
324        458.0, 459.0, 460.0, 461.0, 462.0, 463.0, 464.0, 469.0, 470.0, 471.0,
325        472.0, 473.0, 474.0, 475.0, 476.0
326    ]
327    self._VerifyValues(
328        nn_ops.avg_pool,
329        input_sizes=[1, 8, 8, 8],
330        ksize=[1, 3, 3, 1],
331        strides=[1, 2, 2, 1],
332        padding="SAME",
333        expected=expected_output,
334        use_gpu=use_gpu)
335
336  def testAvgPooling(self):
337    for use_gpu in True, False:
338      self._testAvgPoolValidPadding(use_gpu)
339      self._testAvgPoolSamePadding(use_gpu)
340      self._testAvgPoolSamePaddingNonSquareWindow(use_gpu)
341      self._testAvgPoolSamePaddingNonSquareWindowMultiBatch(use_gpu)
342      self._testAvgPoolValidPaddingUnevenStride(use_gpu)
343      self._testAvgPoolSamePadding4(use_gpu)
344      self._testAvgPoolSamePaddingPacket4(use_gpu)
345      self._testAvgPoolSamePaddingPacket8(use_gpu)
346
347  def _testMaxPoolValidPadding(self, use_gpu):
348    expected_output = [13.0, 14.0, 15.0]
349    self._VerifyValues(
350        nn_ops.max_pool,
351        input_sizes=[1, 3, 3, 3],
352        ksize=[1, 2, 2, 1],
353        strides=[1, 2, 2, 1],
354        padding="VALID",
355        expected=expected_output,
356        use_gpu=use_gpu)
357
358  def _testMaxPoolSamePadding(self, use_gpu):
359    expected_output = [13.0, 14.0, 15.0, 16.0, 17.0, 18.0]
360    self._VerifyValues(
361        nn_ops.max_pool,
362        input_sizes=[1, 2, 3, 3],
363        ksize=[1, 2, 2, 1],
364        strides=[1, 2, 2, 1],
365        padding="SAME",
366        expected=expected_output,
367        use_gpu=use_gpu)
368
369  def _testMaxPoolSamePaddingNonSquareWindow(self, use_gpu):
370    # input is:
371    # [1.0, 2.0
372    #  3.0  4.0]
373    #
374    # Window of [x, x] should do:
375    #
376    #  [max(1.0, 2.0), max(2.0, padded0),
377    #   max(3.0, 4.0), max(4.0, padded0)]
378    self._VerifyValues(
379        nn_ops.max_pool,
380        input_sizes=[1, 2, 2, 1],
381        ksize=[1, 1, 2, 1],
382        strides=[1, 1, 1, 1],
383        padding="SAME",
384        expected=[2.0, 2.0, 4.0, 4.0],
385        use_gpu=use_gpu)
386
387  def _testMaxPoolValidPaddingUnevenStride(self, use_gpu):
388    self._VerifyValues(
389        nn_ops.max_pool,
390        input_sizes=[1, 4, 4, 1],
391        ksize=[1, 2, 2, 1],
392        strides=[1, 1, 2, 1],
393        padding="VALID",
394        expected=[6.0, 8.0, 10.0, 12.0, 14.0, 16.0],
395        use_gpu=use_gpu)
396    self._VerifyValues(
397        nn_ops.max_pool,
398        input_sizes=[1, 4, 4, 1],
399        ksize=[1, 2, 2, 1],
400        strides=[1, 2, 1, 1],
401        padding="VALID",
402        expected=[6.0, 7.0, 8.0, 14.0, 15.0, 16.0],
403        use_gpu=use_gpu)
404
405  def _testMaxPoolSamePaddingPacket4(self, use_gpu):
406    expected_output = [
407        21.0, 22.0, 23.0, 24.0, 29.0, 30.0, 31.0, 32.0, 53.0, 54.0, 55.0, 56.0,
408        61.0, 62.0, 63.0, 64.0
409    ]
410    self._VerifyValues(
411        nn_ops.max_pool,
412        input_sizes=[1, 4, 4, 4],
413        ksize=[1, 2, 2, 1],
414        strides=[1, 2, 2, 1],
415        padding="SAME",
416        expected=expected_output,
417        use_gpu=use_gpu)
418
419  def _testMaxPoolSamePaddingPacket8(self, use_gpu):
420    expected_output = [
421        145.0, 146.0, 147.0, 148.0, 149.0, 150.0, 151.0, 152.0, 161.0, 162.0,
422        163.0, 164.0, 165.0, 166.0, 167.0, 168.0, 177.0, 178.0, 179.0, 180.0,
423        181.0, 182.0, 183.0, 184.0, 185.0, 186.0, 187.0, 188.0, 189.0, 190.0,
424        191.0, 192.0, 273.0, 274.0, 275.0, 276.0, 277.0, 278.0, 279.0, 280.0,
425        289.0, 290.0, 291.0, 292.0, 293.0, 294.0, 295.0, 296.0, 305.0, 306.0,
426        307.0, 308.0, 309.0, 310.0, 311.0, 312.0, 313.0, 314.0, 315.0, 316.0,
427        317.0, 318.0, 319.0, 320.0, 401.0, 402.0, 403.0, 404.0, 405.0, 406.0,
428        407.0, 408.0, 417.0, 418.0, 419.0, 420.0, 421.0, 422.0, 423.0, 424.0,
429        433.0, 434.0, 435.0, 436.0, 437.0, 438.0, 439.0, 440.0, 441.0, 442.0,
430        443.0, 444.0, 445.0, 446.0, 447.0, 448.0, 465.0, 466.0, 467.0, 468.0,
431        469.0, 470.0, 471.0, 472.0, 481.0, 482.0, 483.0, 484.0, 485.0, 486.0,
432        487.0, 488.0, 497.0, 498.0, 499.0, 500.0, 501.0, 502.0, 503.0, 504.0,
433        505.0, 506.0, 507.0, 508.0, 509.0, 510.0, 511.0, 512.0
434    ]
435    self._VerifyValues(
436        nn_ops.max_pool,
437        input_sizes=[1, 8, 8, 8],
438        ksize=[1, 3, 3, 1],
439        strides=[1, 2, 2, 1],
440        padding="SAME",
441        expected=expected_output,
442        use_gpu=use_gpu)
443
444  def testMaxPooling(self):
445    for use_gpu in True, False:
446      self._testMaxPoolValidPadding(use_gpu)
447      self._testMaxPoolSamePadding(use_gpu)
448      self._testMaxPoolSamePaddingNonSquareWindow(use_gpu)
449      self._testMaxPoolValidPaddingUnevenStride(use_gpu)
450      self._testMaxPoolSamePaddingPacket4(use_gpu)
451      self._testMaxPoolSamePaddingPacket8(use_gpu)
452
453  # Tests for DepthwiseMaxPooling on CPU only.
454  def testDepthwiseMaxPool1x1DepthWindow1(self):
455    # input is:
456    # [1.0, ..., 10.0] along depth,
457    #
458    # We maxpool by depth in patches of 2.
459    self._VerifyValues(
460        nn_ops.max_pool,
461        input_sizes=[1, 1, 1, 10],
462        ksize=[1, 1, 1, 2],
463        strides=[1, 1, 1, 2],
464        padding="SAME",
465        expected=[2.0, 4.0, 6.0, 8.0, 10.0],
466        use_gpu=False)
467
468  def testDepthwiseMaxPool2x2DepthWindow3(self):
469    # input is:
470    #
471    # a 2x2x6 cube, and we depthwise max across 3 to produce a 2x2x2
472    # output.  Each node has contiguous values, so the depthwise max
473    # should be multiples of 3.0.
474    self._VerifyValues(
475        nn_ops.max_pool,
476        input_sizes=[1, 2, 2, 6],
477        ksize=[1, 1, 1, 3],
478        strides=[1, 1, 1, 3],
479        padding="SAME",
480        expected=[3.0, 6.0, 9.0, 12.0, 15.0, 18.0, 21.0, 24.0],
481        use_gpu=False)
482
483  def testKernelSmallerThanStrideValid(self):
484    for use_gpu in [True, False]:
485      self._VerifyValues(
486          nn_ops.max_pool,
487          input_sizes=[1, 7, 7, 1],
488          ksize=[1, 2, 2, 1],
489          strides=[1, 3, 3, 1],
490          padding="VALID",
491          expected=[9, 12, 30, 33],
492          use_gpu=use_gpu)
493
494      self._VerifyValues(
495          nn_ops.avg_pool,
496          input_sizes=[1, 7, 7, 1],
497          ksize=[1, 2, 2, 1],
498          strides=[1, 3, 3, 1],
499          padding="VALID",
500          expected=[5, 8, 26, 29],
501          use_gpu=use_gpu)
502
503  def testKernelSmallerThanStrideSame(self):
504    for use_gpu in [True, False]:
505      for pool_func in [nn_ops.max_pool, nn_ops.avg_pool]:
506        self._VerifyValues(
507            pool_func,
508            input_sizes=[1, 3, 3, 1],
509            ksize=[1, 1, 1, 1],
510            strides=[1, 2, 2, 1],
511            padding="SAME",
512            expected=[1, 3, 7, 9],
513            use_gpu=use_gpu)
514
515        self._VerifyValues(
516            pool_func,
517            input_sizes=[1, 4, 4, 1],
518            ksize=[1, 1, 1, 1],
519            strides=[1, 2, 2, 1],
520            padding="SAME",
521            expected=[1, 3, 9, 11],
522            use_gpu=use_gpu)
523
524  def _testDepthwiseMaxPoolInvalidConfig(self,
525                                         in_size,
526                                         ksize,
527                                         strides,
528                                         error_msg,
529                                         use_gpu=False):
530    with self.test_session(use_gpu=use_gpu) as sess:
531      t = constant_op.constant(1.0, shape=in_size)
532      with self.assertRaisesRegexp(errors_impl.UnimplementedError, error_msg):
533        t = nn_ops.max_pool(
534            t, ksize=ksize, strides=strides, padding="SAME").eval()
535
536  def testDepthwiseMaxPoolInvalidConfigs(self):
537    self._testDepthwiseMaxPoolInvalidConfig(
538        [1, 2, 2, 4], [1, 2, 2, 2], [1, 1, 1, 2],
539        "exactly one of pooling across depth")
540    self._testDepthwiseMaxPoolInvalidConfig(
541        [1, 2, 2, 4], [1, 1, 1, 2], [1, 1, 1, 1],
542        "depth window to equal the depth stride")
543    self._testDepthwiseMaxPoolInvalidConfig([1, 2, 2, 4], [1, 1, 1, 3],
544                                            [1, 1, 1, 3], "evenly divide")
545    if test.is_gpu_available():
546      with self.test_session(use_gpu=True):
547        t = constant_op.constant(1.0, shape=[1, 2, 2, 4])
548        with self.assertRaisesOpError("for CPU devices"):
549          nn_ops.max_pool(
550              t, ksize=[1, 1, 1, 2], strides=[1, 1, 1, 2],
551              padding="SAME").eval()
552
553  # The following are tests that verify that the CPU and GPU implementations
554  # produce the same resuts.
555  def _CompareMaxPoolingFwd(self, input_shape, ksize, strides, padding):
556    for dtype in np.float32, np.float16:
557      tensor_input = np.random.rand(*input_shape).astype(dtype)
558      with self.test_session(use_gpu=True):
559        t = constant_op.constant(tensor_input, shape=input_shape)
560        out_op, _ = nn_ops.max_pool_with_argmax(t, ksize, strides, padding)
561        gpu_val = out_op.eval()
562      with self.test_session(use_gpu=False):
563        t = constant_op.constant(tensor_input, shape=input_shape)
564        out_op = nn_ops.max_pool(t, ksize, strides, padding)
565        cpu_val = out_op.eval()
566      self.assertAllCloseAccordingToType(cpu_val, gpu_val)
567
568  def _CompareMaxPoolingBk(self, input_shape, output_shape, ksize, strides,
569                           padding):
570    for dtype in np.float32, np.float16:
571      # Generate numbers in a narrow range, so that there are many duplicates
572      # in the input.
573      tensor_input = np.random.random_integers(0, 3, input_shape).astype(dtype)
574      tensor_output = np.random.rand(*output_shape).astype(dtype)
575      with self.test_session(use_gpu=True):
576        t = constant_op.constant(tensor_input, shape=input_shape)
577        _, argmax_op = nn_ops.max_pool_with_argmax(t, ksize, strides, padding)
578        argmax = argmax_op.eval()
579        grad_in = constant_op.constant(tensor_output, shape=output_shape)
580        out_op = gen_nn_ops._max_pool_grad_with_argmax(t, grad_in, argmax,
581                                                       ksize, strides, padding)
582        gpu_val = out_op.eval()
583        self.assertShapeEqual(gpu_val, out_op)
584      with self.test_session(use_gpu=False):
585        t = constant_op.constant(tensor_input, shape=input_shape)
586        out_op = nn_ops.max_pool(t, ksize, strides, padding)
587        orig_out = out_op.eval()
588        grad_in = constant_op.constant(tensor_output, shape=output_shape)
589        out_op = gen_nn_ops._max_pool_grad(t, orig_out, grad_in, ksize, strides,
590                                           padding)
591        cpu_val = out_op.eval()
592        self.assertShapeEqual(cpu_val, out_op)
593      if dtype == np.float16:
594        # The CPU version accumulates its gradient on fp16, so it's less
595        # accurate than the GPU version that does the accumulation on fp32
596        self.assertAllClose(cpu_val, gpu_val, rtol=0.01, atol=0.01)
597      else:
598        self.assertAllClose(cpu_val, gpu_val)
599
600  def testMaxPoolingWithArgmax(self):
601    # MaxPoolWithArgMax is implemented only on CUDA.
602    if not test.is_gpu_available(cuda_only=True):
603      return
604    tensor_input = [1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0]
605    with self.test_session(use_gpu=True) as sess:
606      t = constant_op.constant(tensor_input, shape=[1, 3, 3, 1])
607      out_op, argmax_op = nn_ops.max_pool_with_argmax(
608          t,
609          ksize=[1, 2, 2, 1],
610          strides=[1, 1, 1, 1],
611          Targmax=dtypes.int64,
612          padding="VALID")
613      out, argmax = sess.run([out_op, argmax_op])
614      self.assertShapeEqual(out, out_op)
615      self.assertShapeEqual(argmax, argmax_op)
616      self.assertAllClose(out.ravel(), [1.0, 1.0, 1.0, 1.0])
617      self.assertAllEqual(argmax.ravel(), [0, 1, 3, 5])
618
619  def testMaxPoolingGradWithArgmax(self):
620    # MaxPoolWithArgMax is implemented only on CUDA.
621    if not test.is_gpu_available(cuda_only=True):
622      return
623    orig_input = [1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0]
624    tensor_input = [11.0, 12.0, 13.0, 14.0]
625    tensor_argmax = list(np.array([0, 1, 3, 5], dtype=np.int64))
626    with self.test_session(use_gpu=True) as sess:
627      orig_in = constant_op.constant(orig_input, shape=[1, 3, 3, 1])
628      t = constant_op.constant(tensor_input, shape=[1, 2, 2, 1])
629      argmax = constant_op.constant(
630          tensor_argmax, shape=[1, 2, 2, 1], dtype=dtypes.int64)
631      out_op = gen_nn_ops._max_pool_grad_with_argmax(
632          orig_in,
633          t,
634          argmax,
635          ksize=[1, 2, 2, 1],
636          strides=[1, 1, 1, 1],
637          padding="VALID")
638      out = out_op.eval().flatten()
639      self.assertAllClose(out,
640                          [11.0, 12.0, 0.0, 13.0, 0.0, 14.0, 0.0, 0.0, 0.0])
641
642  def _ConstructAndTestGradient(self,
643                                pool_func,
644                                input_sizes,
645                                output_sizes,
646                                window_rows,
647                                window_cols,
648                                row_stride,
649                                col_stride,
650                                padding,
651                                data_format,
652                                use_gpu,
653                                x_init_value=None):
654    """Verifies the gradients of the avg pooling function.
655
656    Args:
657      pool_func: Function to be called, co.MaxPool, co.AvgPool,
658        or the Lua version.
659      input_sizes: Input tensor dimensions.
660      output_sizes: Output tensor dimensions.
661      window_rows: kernel size in row dim
662      window_cols: kernel size in col dim
663      row_stride: Row Stride.
664      col_stride: Col Stride.
665      padding: Padding type.
666      data_format: Data format.
667      use_gpu: whether we are running on GPU
668      x_init_value: Values to be passed to the gradient checker.
669    """
670    assert input_sizes[0] == output_sizes[0]
671    assert input_sizes[3] == output_sizes[3]
672    total_size = 1
673    for s in input_sizes:
674      total_size *= s
675    # Initializes the input tensor with array containing incrementing
676    # numbers from 1.
677    x = [f * 1.0 for f in range(1, total_size + 1)]
678    with self.test_session(use_gpu=use_gpu):
679      input_tensor = constant_op.constant(x, shape=input_sizes, name="input")
680      if pool_func == nn_ops.avg_pool:
681        func_name = "avg_pool"
682        err_margin = 1e-4
683      else:
684        if x_init_value is None:
685          x_init_value = np.asfarray(
686              np.arange(1, total_size + 1),
687              dtype=np.float32).reshape(input_sizes)
688        func_name = "max_pool"
689        err_margin = 1e-3
690      if data_format == "NCHW":
691        ksize = [1, 1, window_rows, window_rows]
692        strides = [1, 1, row_stride, col_stride]
693        t = NHWCToNCHW(input_tensor)
694      else:
695        ksize = [1, window_rows, window_rows, 1]
696        strides = [1, row_stride, col_stride, 1]
697        t = input_tensor
698      t = pool_func(
699          t,
700          ksize=ksize,
701          strides=strides,
702          padding=padding,
703          data_format=data_format,
704          name=func_name)
705      if data_format == "NCHW":
706        t = NCHWToNHWC(t)
707
708      err = gradient_checker.compute_gradient_error(
709          input_tensor,
710          input_sizes,
711          t,
712          output_sizes,
713          x_init_value=x_init_value,
714          delta=1e-2)
715    print("%s gradient error = " % func_name, err)
716    self.assertLess(err, err_margin)
717
718  def _testMaxPoolGradValidPadding1_1(self, data_format, use_gpu):
719    self._ConstructAndTestGradient(
720        nn_ops.max_pool,
721        input_sizes=[1, 3, 3, 1],
722        output_sizes=[1, 3, 3, 1],
723        window_rows=1,
724        window_cols=1,
725        row_stride=1,
726        col_stride=1,
727        padding="VALID",
728        data_format=data_format,
729        use_gpu=use_gpu)
730
731  def _testMaxPoolGradValidPadding2_1_6(self, data_format, use_gpu):
732    self._ConstructAndTestGradient(
733        nn_ops.max_pool,
734        input_sizes=[2, 6, 6, 3],
735        output_sizes=[2, 5, 5, 3],
736        window_rows=2,
737        window_cols=2,
738        row_stride=1,
739        col_stride=1,
740        padding="VALID",
741        data_format=data_format,
742        use_gpu=use_gpu)
743
744  def _testMaxPoolGradValidPadding2_1_7(self, data_format, use_gpu):
745    self._ConstructAndTestGradient(
746        nn_ops.max_pool,
747        input_sizes=[2, 7, 7, 3],
748        output_sizes=[2, 6, 6, 3],
749        window_rows=2,
750        window_cols=2,
751        row_stride=1,
752        col_stride=1,
753        padding="VALID",
754        data_format=data_format,
755        use_gpu=use_gpu)
756
757  def _testMaxPoolGradValidPadding2_2(self, data_format, use_gpu):
758    self._ConstructAndTestGradient(
759        nn_ops.max_pool,
760        input_sizes=[2, 2, 2, 3],
761        output_sizes=[2, 1, 1, 3],
762        window_rows=2,
763        window_cols=2,
764        row_stride=2,
765        col_stride=2,
766        padding="VALID",
767        data_format=data_format,
768        use_gpu=use_gpu)
769
770  def _testMaxPoolGradSamePadding1_1(self, data_format, use_gpu):
771    self._ConstructAndTestGradient(
772        nn_ops.max_pool,
773        input_sizes=[2, 2, 4, 3],
774        output_sizes=[2, 2, 4, 3],
775        window_rows=1,
776        window_cols=1,
777        row_stride=1,
778        col_stride=1,
779        padding="SAME",
780        data_format=data_format,
781        use_gpu=use_gpu)
782
783  def _testMaxPoolGradSamePadding2_1(self, data_format, use_gpu):
784    self._ConstructAndTestGradient(
785        nn_ops.max_pool,
786        input_sizes=[2, 2, 4, 3],
787        output_sizes=[2, 2, 4, 3],
788        window_rows=2,
789        window_cols=2,
790        row_stride=1,
791        col_stride=1,
792        padding="SAME",
793        data_format=data_format,
794        use_gpu=use_gpu)
795
796  def _testMaxPoolGradSamePadding2_2(self, data_format, use_gpu):
797    self._ConstructAndTestGradient(
798        nn_ops.max_pool,
799        input_sizes=[2, 2, 4, 3],
800        output_sizes=[2, 1, 2, 3],
801        window_rows=2,
802        window_cols=2,
803        row_stride=2,
804        col_stride=2,
805        padding="SAME",
806        data_format=data_format,
807        use_gpu=use_gpu)
808
809  def _testMaxPoolGradSamePadding3_1(self, data_format, use_gpu):
810    self._ConstructAndTestGradient(
811        nn_ops.max_pool,
812        input_sizes=[1, 7, 7, 1],
813        output_sizes=[1, 7, 7, 1],
814        window_rows=3,
815        window_cols=3,
816        row_stride=1,
817        col_stride=1,
818        padding="SAME",
819        data_format=data_format,
820        use_gpu=use_gpu)
821
822  def testMaxPoolGrad(self):
823    for (data_format, use_gpu) in GetTestConfigs():
824      self._testMaxPoolGradValidPadding1_1(data_format, use_gpu)
825      self._testMaxPoolGradValidPadding2_1_6(data_format, use_gpu)
826      self._testMaxPoolGradValidPadding2_1_7(data_format, use_gpu)
827      self._testMaxPoolGradValidPadding2_2(data_format, use_gpu)
828      self._testMaxPoolGradSamePadding1_1(data_format, use_gpu)
829      self._testMaxPoolGradSamePadding2_1(data_format, use_gpu)
830      self._testMaxPoolGradSamePadding2_2(data_format, use_gpu)
831      self._testMaxPoolGradSamePadding3_1(data_format, use_gpu)
832
833  def _MaxPoolGrad(self, orig_input, orig_output, grad, window_rows,
834                   window_cols, row_stride, col_stride, padding):
835    """Max Pooling Gradient.
836
837    Args:
838      orig_input: A float Tensor. The original input tensor.
839      orig_output: A float Tensor. The original output tensor.
840      grad: A float Tensor.
841        The 4D (batch x rows x cols x depth) output backprop.
842      window_rows: integer. Kernel size along rows dimension.
843      window_cols: integer. Kernel size along cols dimension.
844      row_stride: integer. Stride along rows dimension
845      col_stride: integer. Stride along cols dimension
846      padding: PoolingOpDef.Padding.  Padding type.
847
848    Returns:
849      A Tensor.
850    """
851    return gen_nn_ops._max_pool_grad(orig_input, orig_output, grad,
852                                     [1, window_rows, window_cols, 1],
853                                     [1, row_stride, col_stride, 1], padding)
854
855  def _testMaxPoolGradDirect(self, input_data, output_backprop,
856                             expected_input_backprop, input_sizes, output_sizes,
857                             window_rows, window_cols, row_stride, col_stride,
858                             padding, use_gpu):
859    with self.test_session(use_gpu=use_gpu) as sess:
860      input_tensor = constant_op.constant(input_data, shape=input_sizes)
861      output_tensor = nn_ops.max_pool(input_tensor,
862                                      [1, window_rows, window_cols, 1],
863                                      [1, row_stride, col_stride, 1], padding)
864      output_backprop_tensor = constant_op.constant(
865          output_backprop, shape=output_sizes)
866
867      input_backprop_tensor = self._MaxPoolGrad(input_tensor, output_tensor,
868                                                output_backprop_tensor,
869                                                window_rows, window_cols,
870                                                row_stride, col_stride, padding)
871
872      actual_input_backprop = input_backprop_tensor.eval()
873      self.assertShapeEqual(actual_input_backprop, input_backprop_tensor)
874      actual_input_backprop = actual_input_backprop.flatten()
875      actual_input_backprop = self._GetNdArray(actual_input_backprop)
876
877      actual_output = output_tensor.eval().flatten()
878      actual_output = self._GetNdArray(actual_output)
879
880      self.assertAllClose(
881          expected_input_backprop, actual_input_backprop, rtol=1e-6, atol=1e-6)
882
883  def _testMaxPoolGradDirect1_1(self):
884    input_data = [
885        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,
886        1.0, 1.0
887    ]
888    output_backprop = [11.0, 12.0, 13.0, 15.0, 16.0, 17.0, 19.0, 20.0, 21.0]
889    expected_input_backprop = [
890        11.0, 12.0, 13.0, 0.0, 15.0, 16.0, 17.0, 0.0, 19.0, 20.0, 21.0, 0.0,
891        0.0, 0.0, 0.0, 0.0
892    ]
893
894    for use_gpu in True, False:
895      self._testMaxPoolGradDirect(
896          input_data,
897          output_backprop,
898          expected_input_backprop,
899          input_sizes=[1, 4, 4, 1],
900          output_sizes=[1, 3, 3, 1],
901          window_rows=2,
902          window_cols=2,
903          row_stride=1,
904          col_stride=1,
905          padding="VALID",
906          use_gpu=use_gpu)
907
908  def _testMaxPoolGradDirect1_2(self):
909    input_data = [
910        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,
911        0.0, 1.0
912    ]
913    output_backprop = [11.0, 12.0, 13.0, 15.0, 16.0, 17.0, 19.0, 20.0, 21.0]
914    expected_input_backprop = [
915        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,
916        0.0, 0.0, 0.0
917    ]
918
919    for use_gpu in True, False:
920      self._testMaxPoolGradDirect(
921          input_data,
922          output_backprop,
923          expected_input_backprop,
924          input_sizes=[1, 4, 4, 1],
925          output_sizes=[1, 3, 3, 1],
926          window_rows=2,
927          window_cols=2,
928          row_stride=1,
929          col_stride=1,
930          padding="VALID",
931          use_gpu=use_gpu)
932
933  def _testMaxPoolGradDirect1_3(self):
934    input_data = [
935        1.0,
936        0.0,
937        1.0,
938        0.0,
939        0.0,
940        1.0,
941        0.0,
942        1.0,
943        1.0,
944        0.0,
945        1.0,
946        0.0,
947        0.0,
948        1.0,
949        0.0,
950        1.0,
951    ]
952    output_backprop = [
953        11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0,
954        23.0, 24.0, 25.0, 26.0
955    ]
956    expected_input_backprop = [
957        54,
958        0.0,
959        62,
960        0.0,
961        0.0,
962        60,
963        0.0,
964        22.0,
965        47,
966        0.0,
967        51,
968        0.0,
969        0.0,
970        0.0,
971        0.0,
972        0.0,
973    ]
974
975    for use_gpu in True, False:
976      self._testMaxPoolGradDirect(
977          input_data,
978          output_backprop,
979          expected_input_backprop,
980          input_sizes=[1, 4, 4, 1],
981          output_sizes=[1, 4, 4, 1],
982          window_rows=3,
983          window_cols=3,
984          row_stride=1,
985          col_stride=1,
986          padding="SAME",
987          use_gpu=use_gpu)
988
989  def _testMaxPoolGradDirectWithNans2_1(self):
990    input_data = [float("nan")] * 16
991    output_backprop = [11.0, 12.0, 13.0, 15.0, 16.0, 17.0, 19.0, 20.0, 21.0]
992    # Test the CPU implementation, which propagates diffs in case of NaN
993    expected_input_backprop_tf_cpu = [
994        11.0, 12.0, 13.0, 0.0, 15.0, 16.0, 17.0, 0.0, 19.0, 20.0, 21.0, 0.0,
995        0.0, 0.0, 0.0, 0.0
996    ]
997    self._testMaxPoolGradDirect(
998        input_data,
999        output_backprop,
1000        expected_input_backprop_tf_cpu,
1001        input_sizes=[1, 4, 4, 1],
1002        output_sizes=[1, 3, 3, 1],
1003        window_rows=2,
1004        window_cols=2,
1005        row_stride=1,
1006        col_stride=1,
1007        padding="VALID",
1008        use_gpu=False)
1009
1010    if not test.is_gpu_available():
1011      return
1012
1013    # Test the GPU implementation that uses cudnn for now.
1014    # It does not propagate the diff in cases of NaNs
1015    expected_input_backprop_cudnn = [
1016        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,
1017        0.0, 0.0
1018    ]
1019    self._testMaxPoolGradDirect(
1020        input_data,
1021        output_backprop,
1022        expected_input_backprop_cudnn,
1023        input_sizes=[1, 4, 4, 1],
1024        output_sizes=[1, 3, 3, 1],
1025        window_rows=2,
1026        window_cols=2,
1027        row_stride=1,
1028        col_stride=1,
1029        padding="VALID",
1030        use_gpu=True)
1031
1032  def _testMaxPoolGradDirectWithNans2_2(self):
1033    input_data = [float("nan")] * 16
1034    output_backprop = [
1035        float("nan"), 12.0, 13.0, 15.0, float("nan"), 17.0, 19.0, 20.0,
1036        float("nan")
1037    ]
1038    # Test the CPU implementation, which propagates diffs in case of NaN
1039    expected_input_backprop_tf_cpu = [
1040        float("nan"), 12.0, 13.0, 0.0, 15.0, float("nan"), 17.0, 0.0, 19.0,
1041        20.0, float("nan"), 0.0, 0.0, 0.0, 0.0, 0.0
1042    ]
1043    self._testMaxPoolGradDirect(
1044        input_data,
1045        output_backprop,
1046        expected_input_backprop_tf_cpu,
1047        input_sizes=[1, 4, 4, 1],
1048        output_sizes=[1, 3, 3, 1],
1049        window_rows=2,
1050        window_cols=2,
1051        row_stride=1,
1052        col_stride=1,
1053        padding="VALID",
1054        use_gpu=False)
1055
1056    if not test.is_gpu_available():
1057      return
1058
1059    # Test the GPU implementation that uses cudnn for now.
1060    # It does not propagate the diff in cases of NaNs
1061    expected_input_backprop_cudnn = [
1062        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,
1063        0.0, 0.0
1064    ]
1065    self._testMaxPoolGradDirect(
1066        input_data,
1067        output_backprop,
1068        expected_input_backprop_cudnn,
1069        input_sizes=[1, 4, 4, 1],
1070        output_sizes=[1, 3, 3, 1],
1071        window_rows=2,
1072        window_cols=2,
1073        row_stride=1,
1074        col_stride=1,
1075        padding="VALID",
1076        use_gpu=True)
1077
1078  def testMaxPoolGradDirect(self):
1079    self._testMaxPoolGradDirect1_1()
1080    self._testMaxPoolGradDirect1_2()
1081    self._testMaxPoolGradDirect1_3()
1082    self._testMaxPoolGradDirectWithNans2_1()
1083    self._testMaxPoolGradDirectWithNans2_2()
1084
1085  def testAvgPoolGrad(self):
1086    for (data_format, use_gpu) in GetTestConfigs():
1087      self._testAvgPoolGradValidPadding1_1(data_format, use_gpu)
1088      self._testAvgPoolGradValidPadding2_1(data_format, use_gpu)
1089      self._testAvgPoolGradValidPadding2_2(data_format, use_gpu)
1090      self._testAvgPoolGradSamePadding1_1(data_format, use_gpu)
1091      self._testAvgPoolGradSamePadding2_1(data_format, use_gpu)
1092      self._testAvgPoolGradSamePadding2_2(data_format, use_gpu)
1093      self._testAvgPoolGradSamePadding3_1(data_format, use_gpu)
1094
1095  def _testAvgPoolGradValidPadding1_1(self, data_format, use_gpu):
1096    self._ConstructAndTestGradient(
1097        nn_ops.avg_pool,
1098        input_sizes=[2, 3, 3, 3],
1099        output_sizes=[2, 3, 3, 3],
1100        window_rows=1,
1101        window_cols=1,
1102        row_stride=1,
1103        col_stride=1,
1104        padding="VALID",
1105        data_format=data_format,
1106        use_gpu=use_gpu)
1107
1108  def _testAvgPoolGradValidPadding2_1(self, data_format, use_gpu):
1109    self._ConstructAndTestGradient(
1110        nn_ops.avg_pool,
1111        input_sizes=[2, 3, 3, 3],
1112        output_sizes=[2, 2, 2, 3],
1113        window_rows=2,
1114        window_cols=2,
1115        row_stride=1,
1116        col_stride=1,
1117        padding="VALID",
1118        data_format=data_format,
1119        use_gpu=use_gpu)
1120
1121  def _testAvgPoolGradValidPadding2_2(self, data_format, use_gpu):
1122    self._ConstructAndTestGradient(
1123        nn_ops.avg_pool,
1124        input_sizes=[2, 2, 2, 3],
1125        output_sizes=[2, 1, 1, 3],
1126        window_rows=2,
1127        window_cols=2,
1128        row_stride=2,
1129        col_stride=2,
1130        padding="VALID",
1131        data_format=data_format,
1132        use_gpu=use_gpu)
1133
1134  def _testAvgPoolGradSamePadding1_1(self, data_format, use_gpu):
1135    self._ConstructAndTestGradient(
1136        nn_ops.avg_pool,
1137        input_sizes=[2, 2, 4, 3],
1138        output_sizes=[2, 2, 4, 3],
1139        window_rows=1,
1140        window_cols=1,
1141        row_stride=1,
1142        col_stride=1,
1143        padding="SAME",
1144        data_format=data_format,
1145        use_gpu=use_gpu)
1146
1147  def _testAvgPoolGradSamePadding2_1(self, data_format, use_gpu):
1148    self._ConstructAndTestGradient(
1149        nn_ops.avg_pool,
1150        input_sizes=[2, 2, 4, 3],
1151        output_sizes=[2, 2, 4, 3],
1152        window_rows=2,
1153        window_cols=2,
1154        row_stride=1,
1155        col_stride=1,
1156        padding="SAME",
1157        data_format=data_format,
1158        use_gpu=use_gpu)
1159
1160  def _testAvgPoolGradSamePadding2_2(self, data_format, use_gpu):
1161    self._ConstructAndTestGradient(
1162        nn_ops.avg_pool,
1163        input_sizes=[2, 2, 4, 3],
1164        output_sizes=[2, 1, 2, 3],
1165        window_rows=2,
1166        window_cols=2,
1167        row_stride=2,
1168        col_stride=2,
1169        padding="SAME",
1170        data_format=data_format,
1171        use_gpu=use_gpu)
1172
1173  def _testAvgPoolGradSamePadding3_1(self, data_format, use_gpu):
1174    self._ConstructAndTestGradient(
1175        nn_ops.avg_pool,
1176        input_sizes=[1, 7, 7, 1],
1177        output_sizes=[1, 7, 7, 1],
1178        window_rows=3,
1179        window_cols=3,
1180        row_stride=1,
1181        col_stride=1,
1182        padding="SAME",
1183        data_format=data_format,
1184        use_gpu=use_gpu)
1185
1186  def testShapeFunctionEdgeCases(self):
1187    # All shapes unknown.
1188    for pool_func in [nn_ops.max_pool, nn_ops.avg_pool]:
1189      p = pool_func(
1190          array_ops.placeholder(dtypes.float32),
1191          ksize=[1, 1, 1, 1],
1192          strides=[1, 1, 1, 1],
1193          padding="SAME")
1194      self.assertEqual([None, None, None, None], p.get_shape().as_list())
1195    p, am = nn_ops.max_pool_with_argmax(
1196        array_ops.placeholder(dtypes.float32),
1197        ksize=[1, 1, 1, 1],
1198        strides=[1, 1, 1, 1],
1199        padding="SAME")
1200    self.assertEqual([None, None, None, None], p.get_shape().as_list())
1201    self.assertEqual([None, None, None, None], am.get_shape().as_list())
1202
1203    # Incorrect input shape.
1204    for pool_func in [
1205        nn_ops.max_pool, nn_ops.avg_pool, nn_ops.max_pool_with_argmax
1206    ]:
1207      with self.assertRaises(ValueError):
1208        pool_func(
1209            array_ops.placeholder(
1210                dtypes.float32, shape=[1, 3]),
1211            ksize=[1, 1, 1, 1],
1212            strides=[1, 1, 1, 1],
1213            padding="SAME")
1214
1215  def testOpEdgeCases(self):
1216    with self.test_session() as sess:
1217      pool_funcs = [nn_ops.max_pool, nn_ops.avg_pool]
1218      if test.is_gpu_available():
1219        pool_funcs.append(nn_ops.max_pool_with_argmax)
1220      for pool_func in pool_funcs:
1221        # Illegal strides.
1222        with self.assertRaisesRegexp(
1223            errors_impl.UnimplementedError,
1224            "Pooling is not yet supported on the batch"):
1225          sess.run(
1226              pool_func(
1227                  array_ops.placeholder(dtypes.float32),
1228                  ksize=[1, 1, 1, 1],
1229                  strides=[2, 1, 1, 1],
1230                  padding="SAME"))
1231
1232        # Filter too large.
1233        with self.assertRaisesRegexp(ValueError, "Negative dimension size"):
1234          sess.run(
1235              pool_func(
1236                  array_ops.placeholder(
1237                      dtypes.float32, shape=[32, 20, 20, 3]),
1238                  ksize=[1, 20, 21, 1],
1239                  strides=[1, 1, 1, 1],
1240                  padding="VALID"))
1241        with self.assertRaisesRegexp(ValueError, "Negative dimension size"):
1242          pool_func(
1243              array_ops.placeholder(
1244                  dtypes.float32, shape=[32, 20, 20, 3]),
1245              ksize=[1, 21, 20, 1],
1246              strides=[1, 1, 1, 1],
1247              padding="VALID")
1248
1249
1250def GetMaxPoolFwdTest(input_size, filter_size, strides, padding):
1251
1252  def Test(self):
1253    # MaxPoolWithArgMax is implemented only on CUDA.
1254    if not test.is_gpu_available(cuda_only=True):
1255      return
1256    self._CompareMaxPoolingFwd(input_size, filter_size, strides, padding)
1257
1258  return Test
1259
1260
1261def GetMaxPoolGradTest(input_size, filter_size, output_size, strides, padding):
1262
1263  def Test(self):
1264    # MaxPoolWithArgMax is implemented only on CUDA.
1265    if not test.is_gpu_available(cuda_only=True):
1266      return
1267    self._CompareMaxPoolingBk(input_size, output_size, filter_size, strides,
1268                              padding)
1269
1270  return Test
1271
1272
1273if __name__ == "__main__":
1274  for (name_, input_size_, filter_size_, output_size_, stride_,
1275       padding_) in GetShrunkInceptionMaxPoolShapes():
1276    setattr(PoolingTest, "testMaxPoolFwd_" + name_,
1277            GetMaxPoolFwdTest(input_size_, filter_size_, stride_, padding_))
1278    setattr(PoolingTest, "testMaxPoolGrad_" + name_,
1279            GetMaxPoolGradTest(input_size_, filter_size_, output_size_, stride_,
1280                               padding_))
1281  test.main()
1282