pooling_ops_test.py revision 9bedadceab3e126684494e6e6a8103ccab9d90c7
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
16"""Functional tests for pooling operations."""
17from __future__ import absolute_import
18from __future__ import division
19from __future__ import print_function
20
21import numpy as np
22import tensorflow as tf
23
24from tensorflow.python.framework import test_util
25from tensorflow.python.ops import gen_nn_ops
26
27
28def NHWCToNCHW(input_tensor):
29  """Convert the input from NHWC format to NCHW.
30
31  Args:
32    input_tensor:  a 4-D tensor, or a 4-element array representing the same.
33
34  Returns:
35    the converted tensor or a shape array
36  """
37  if isinstance(input_tensor, tf.Tensor):
38    return tf.transpose(input_tensor, [0, 3, 1, 2])
39  else:
40    return [input_tensor[0], input_tensor[3], input_tensor[1], input_tensor[2]]
41
42
43def NCHWToNHWC(input_tensor):
44  """Convert the input from NCHW format to NHWC.
45
46  Args:
47    input_tensor:  a 4-D tensor, or a 4-element array representing the same.
48
49  Returns:
50    the converted tensor or a shape array
51  """
52  if isinstance(input_tensor, tf.Tensor):
53    return tf.transpose(input_tensor, [0, 2, 3, 1])
54  else:
55    return [input_tensor[0], input_tensor[2], input_tensor[3], input_tensor[1]]
56
57
58def GetTestConfigs():
59  """Get all the valid tests configs to run.
60
61  Returns:
62    all the valid test configs as tuples of data_format and use_gpu.
63  """
64  test_configs = [("NHWC", False), ("NHWC", True)]
65  if test_util.IsGoogleCudaEnabled():
66    # "NCHW" format is not currently supported on CPU.
67    test_configs += [("NCHW", True)]
68  return test_configs
69
70
71def GetShrunkInceptionMaxPoolShapes(shrink=30):
72  """Iterator for some of the max pool ops in the Inception 2015 model.
73
74  Args:
75    shrink: Factor to shrink depth relative to Inception.
76
77  Yields:
78    Tuple (name, input_size, filter_size, out_size, strides, padding)
79  """
80  names = ["maxpool2", "maxpool3", "maxpool4", "maxpool5"]
81  input_sizes = [[32, 71, 71, 192],
82                 [32, 35, 35, 288], [32, 17, 17, 1248], [32, 8, 8, 2048]]
83  filter_sizes = [[1, 3, 3, 1], [1, 3, 3, 1],
84                  [1, 3, 3, 1], [1, 3, 3, 1]]
85  output_sizes = [[32, 35, 35, 192], [32, 17, 17, 288],
86                  [32, 8, 8, 1248], [32, 8, 8, 2048]]
87  strides = [[1, 2, 2, 1], [1, 2, 2, 1], [1, 2, 2, 1],
88             [1, 1, 1, 1]]
89  # Shrink each depth value
90  for i in input_sizes:
91    i[3] //= shrink
92  for o in output_sizes:
93    o[3] //= shrink
94  paddings = ["VALID", "VALID", "VALID", "SAME"]
95  for n, i, f, o, s, p in zip(names, input_sizes, filter_sizes, output_sizes,
96                              strides, paddings):
97    yield n, i, f, o, s, p
98
99
100class PoolingTest(tf.test.TestCase):
101
102  def _VerifyOneType(self, pool_func, input_sizes, ksize, strides, padding,
103                     data_format, data_type, expected, use_gpu):
104    """Verifies the output values of the pooling function.
105
106    Args:
107      pool_func: Function to be called, co.MaxPool, co.AvgPool,
108        or the Lua version.
109      input_sizes: Input tensor dimensions.
110      ksize: The kernel size dimensions
111      strides: The stride dimensions
112      padding: Padding type.
113      data_format: The data format we use to run the pooling operation.
114      data_type: The data type to use to run the pooling operation.
115      expected: An array containing the expected operation outputs.
116      use_gpu: Whether we are running on GPU.
117    """
118    total_size = 1
119    for s in input_sizes:
120      total_size *= s
121    # Initializes the input tensor with array containing incrementing
122    # numbers from 1.
123    x = [f * 1.0 for f in range(1, total_size + 1)]
124    with self.test_session(use_gpu=use_gpu) as sess:
125      t = tf.constant(x, shape=input_sizes, dtype=data_type)
126      if data_format == "NCHW":
127        t = NHWCToNCHW(t)
128        ksize = NHWCToNCHW(ksize)
129        strides = NHWCToNCHW(strides)
130      t = pool_func(t, ksize=ksize, strides=strides, padding=padding,
131                    data_format=data_format)
132      if data_format == "NCHW":
133        t = NCHWToNHWC(t)
134      actual = t.eval()
135      self.assertAllCloseAccordingToType(expected, actual.flatten())
136      self.assertShapeEqual(actual, t)
137
138  def _VerifyOneTest(self, pool_func, input_sizes, ksize, strides, padding,
139                     data_format, expected, use_gpu):
140    """Verifies the output values of the pooling function.
141
142    Args:
143      pool_func: Function to be called, co.MaxPool, co.AvgPool,
144        or the Lua version.
145      input_sizes: Input tensor dimensions.
146      ksize: The kernel size dimensions
147      strides: The stride dimensions
148      padding: Padding type.
149      data_format: The data format we use to run the pooling operation.
150      expected: An array containing the expected operation outputs.
151      use_gpu: Whether we are running on GPU.
152    """
153    self._VerifyOneType(pool_func, input_sizes, ksize, strides, padding,
154                        data_format, tf.float32, expected, use_gpu)
155
156    if not use_gpu or test_util.CudaSupportsHalfMatMulAndConv():
157      self._VerifyOneType(pool_func, input_sizes, ksize, strides, padding,
158                          data_format, tf.float16, expected, use_gpu)
159
160  def _VerifyValues(self, pool_func, input_sizes, ksize, strides, padding,
161                    expected, use_gpu):
162    """Verifies the output values of the pooling function.
163
164    Args:
165      pool_func: Function to be called, co.MaxPool, co.AvgPool,
166        or the Lua version.
167      input_sizes: Input tensor dimensions.
168      ksize: The kernel size dimensions
169      strides: The stride dimensions
170      padding: Padding type.
171      expected: An array containing the expected operation outputs.
172      use_gpu: Whether we are running on GPU.
173    """
174    for (data_format, use_gpu_2) in GetTestConfigs():
175      if use_gpu_2 == use_gpu:
176        self._VerifyOneTest(pool_func, input_sizes, ksize, strides, padding,
177                            data_format, expected, use_gpu)
178
179  def _testAvgPoolValidPadding(self, use_gpu):
180    expected_output = [7.0, 8.0, 9.0]
181    self._VerifyValues(tf.nn.avg_pool, input_sizes=[1, 3, 3, 3],
182                       ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1],
183                       padding="VALID",
184                       expected=expected_output, use_gpu=use_gpu)
185
186  def _testAvgPoolSamePadding(self, use_gpu):
187    expected_output = [8.5, 9.5, 10.5, 14.5, 15.5, 16.5]
188    self._VerifyValues(tf.nn.avg_pool, input_sizes=[1, 2, 4, 3],
189                       ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1],
190                       padding="SAME",
191                       expected=expected_output, use_gpu=use_gpu)
192
193  def _testAvgPoolSamePaddingNonSquareWindow(self, use_gpu):
194    # input is:
195    # [1.0, 2.0
196    #  3.0  4.0]
197    #
198    # Window of [x, x] should do:
199    #  [avg(1.0, 2.0), avg(2.0, padded0),
200    #   avg(3.0, 4.0), avg(4.0, padded0)]
201    self._VerifyValues(tf.nn.avg_pool, input_sizes=[1, 2, 2, 1],
202                       ksize=[1, 1, 2, 1], strides=[1, 1, 1, 1],
203                       padding="SAME",
204                       expected=[1.5, 2.0, 3.5, 4.0], use_gpu=use_gpu)
205
206    # Window of [x,
207    #            x] should do:
208    #  [avg(1.0, 3.0), avg(2.0, 4.0)
209    #   avg(3.0, padded0), avg(4.0, padded0)]
210    self._VerifyValues(tf.nn.avg_pool, input_sizes=[1, 2, 2, 1],
211                       ksize=[1, 2, 1, 1], strides=[1, 1, 1, 1],
212                       padding="SAME",
213                       expected=[2.0, 3.0, 3.0, 4.0], use_gpu=use_gpu)
214
215  def _testAvgPoolSamePaddingNonSquareWindowMultiBatch(self, use_gpu):
216    self._VerifyValues(tf.nn.avg_pool, input_sizes=[2, 2, 2, 2],
217                       ksize=[1, 1, 2, 1], strides=[1, 1, 1, 1],
218                       padding="SAME",
219                       expected=[2.0, 3.0, 3.0, 4.0,
220                                 6.0, 7.0, 7.0, 8.0,
221                                 10.0, 11.0, 11.0, 12.0,
222                                 14.0, 15.0, 15.0, 16.0],
223                       use_gpu=use_gpu)
224    self._VerifyValues(tf.nn.avg_pool, input_sizes=[2, 2, 2, 2],
225                       ksize=[1, 2, 1, 1], strides=[1, 1, 1, 1],
226                       padding="SAME",
227                       expected=[3.0, 4.0, 5.0, 6.0,
228                                 5.0, 6.0, 7.0, 8.0,
229                                 11.0, 12.0, 13.0, 14.0,
230                                 13.0, 14.0, 15.0, 16.0],
231                       use_gpu=use_gpu)
232
233  def _testAvgPoolValidPaddingUnevenStride(self, use_gpu):
234    self._VerifyValues(tf.nn.avg_pool, input_sizes=[1, 3, 3, 3],
235                       ksize=[1, 2, 2, 1], strides=[1, 1, 2, 1],
236                       padding="VALID",
237                       expected=[7.0, 8.0, 9.0, 16.0, 17.0, 18.0],
238                       use_gpu=use_gpu)
239    self._VerifyValues(tf.nn.avg_pool, input_sizes=[1, 3, 3, 3],
240                       ksize=[1, 2, 2, 1], strides=[1, 2, 1, 1],
241                       padding="VALID",
242                       expected=[7.0, 8.0, 9.0, 10.0, 11.0, 12.0],
243                       use_gpu=use_gpu)
244
245  def _testAvgPoolSamePadding4(self, use_gpu):
246    expected_output = [11.0, 12.0, 13.0, 14.0, 19.0, 20.0, 21.0, 22.0, 43.0,
247                       44.0, 45.0, 46.0, 51.0, 52.0, 53.0, 54.0]
248    self._VerifyValues(tf.nn.avg_pool, input_sizes=[1, 4, 4, 4],
249                       ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1],
250                       padding="SAME",
251                       expected=expected_output, use_gpu=use_gpu)
252
253  def _testAvgPoolSamePaddingPacket4(self, use_gpu):
254    expected_output = [21.0, 22.0, 23.0, 24.0, 27.0, 28.0, 29.0, 30.0,
255                       45.0, 46.0, 47.0, 48.0, 51.0, 52.0, 53.0, 54.0]
256    self._VerifyValues(tf.nn.avg_pool, input_sizes=[1, 4, 4, 4],
257                       ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1],
258                       padding="SAME",
259                       expected=expected_output, use_gpu=use_gpu)
260
261  def _testAvgPoolSamePaddingPacket8(self, use_gpu):
262    expected_output = [73.0, 74.0, 75.0, 76.0, 77.0, 78.0, 79.0, 80.0, 89.0,
263                       90.0, 91.0, 92.0, 93.0, 94.0, 95.0, 96.0, 105.0, 106.0,
264                       107.0, 108.0, 109.0, 110.0, 111.0, 112.0, 117.0, 118.0,
265                       119.0, 120.0, 121.0, 122.0, 123.0, 124.0, 201.0, 202.0,
266                       203.0, 204.0, 205.0, 206.0, 207.0, 208.0, 217.0, 218.0,
267                       219.0, 220.0, 221.0, 222.0, 223.0, 224.0, 233.0, 234.0,
268                       235.0, 236.0, 237.0, 238.0, 239.0, 240.0, 245.0, 246.0,
269                       247.0, 248.0, 249.0, 250.0, 251.0, 252.0, 329.0, 330.0,
270                       331.0, 332.0, 333.0, 334.0, 335.0, 336.0, 345.0, 346.0,
271                       347.0, 348.0, 349.0, 350.0, 351.0, 352.0, 361.0, 362.0,
272                       363.0, 364.0, 365.0, 366.0, 367.0, 368.0, 373.0, 374.0,
273                       375.0, 376.0, 377.0, 378.0, 379.0, 380.0, 425.0, 426.0,
274                       427.0, 428.0, 429.0, 430.0, 431.0, 432.0, 441.0, 442.0,
275                       443.0, 444.0, 445.0, 446.0, 447.0, 448.0, 457.0, 458.0,
276                       459.0, 460.0, 461.0, 462.0, 463.0, 464.0, 469.0, 470.0,
277                       471.0, 472.0, 473.0, 474.0, 475.0, 476.0]
278    self._VerifyValues(tf.nn.avg_pool, input_sizes=[1, 8, 8, 8],
279                       ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1],
280                       padding="SAME",
281                       expected=expected_output, use_gpu=use_gpu)
282
283  def testAvgPooling(self):
284    for use_gpu in True, False:
285      self._testAvgPoolValidPadding(use_gpu)
286      self._testAvgPoolSamePadding(use_gpu)
287      self._testAvgPoolSamePaddingNonSquareWindow(use_gpu)
288      self._testAvgPoolSamePaddingNonSquareWindowMultiBatch(use_gpu)
289      self._testAvgPoolValidPaddingUnevenStride(use_gpu)
290      self._testAvgPoolSamePadding4(use_gpu)
291      self._testAvgPoolSamePaddingPacket4(use_gpu)
292      self._testAvgPoolSamePaddingPacket8(use_gpu)
293
294  def _testMaxPoolValidPadding(self, use_gpu):
295    expected_output = [13.0, 14.0, 15.0]
296    self._VerifyValues(tf.nn.max_pool, input_sizes=[1, 3, 3, 3],
297                       ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1],
298                       padding="VALID",
299                       expected=expected_output, use_gpu=use_gpu)
300
301  def _testMaxPoolSamePadding(self, use_gpu):
302    expected_output = [13.0, 14.0, 15.0, 16.0, 17.0, 18.0]
303    self._VerifyValues(tf.nn.max_pool, input_sizes=[1, 2, 3, 3],
304                       ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1],
305                       padding="SAME",
306                       expected=expected_output, use_gpu=use_gpu)
307
308  def _testMaxPoolSamePaddingNonSquareWindow(self, use_gpu):
309    # input is:
310    # [1.0, 2.0
311    #  3.0  4.0]
312    #
313    # Window of [x, x] should do:
314    #
315    #  [max(1.0, 2.0), max(2.0, padded0),
316    #   max(3.0, 4.0), max(4.0, padded0)]
317    self._VerifyValues(tf.nn.max_pool, input_sizes=[1, 2, 2, 1],
318                       ksize=[1, 1, 2, 1], strides=[1, 1, 1, 1],
319                       padding="SAME",
320                       expected=[2.0, 2.0, 4.0, 4.0], use_gpu=use_gpu)
321
322  def _testMaxPoolValidPaddingUnevenStride(self, use_gpu):
323    self._VerifyValues(tf.nn.max_pool, input_sizes=[1, 4, 4, 1],
324                       ksize=[1, 2, 2, 1], strides=[1, 1, 2, 1],
325                       padding="VALID",
326                       expected=[6.0, 8.0, 10.0, 12.0, 14.0, 16.0],
327                       use_gpu=use_gpu)
328    self._VerifyValues(tf.nn.max_pool, input_sizes=[1, 4, 4, 1],
329                       ksize=[1, 2, 2, 1], strides=[1, 2, 1, 1],
330                       padding="VALID",
331                       expected=[6.0, 7.0, 8.0, 14.0, 15.0, 16.0],
332                       use_gpu=use_gpu)
333
334  def _testMaxPoolSamePaddingPacket4(self, use_gpu):
335    expected_output = [21.0, 22.0, 23.0, 24.0, 29.0, 30.0, 31.0, 32.0, 53.0,
336                       54.0, 55.0, 56.0, 61.0, 62.0, 63.0, 64.0]
337    self._VerifyValues(tf.nn.max_pool, input_sizes=[1, 4, 4, 4],
338                       ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1],
339                       padding="SAME",
340                       expected=expected_output, use_gpu=use_gpu)
341
342  def _testMaxPoolSamePaddingPacket8(self, use_gpu):
343    expected_output = [145.0, 146.0, 147.0, 148.0, 149.0, 150.0, 151.0, 152.0,
344                       161.0, 162.0, 163.0, 164.0, 165.0, 166.0, 167.0, 168.0,
345                       177.0, 178.0, 179.0, 180.0, 181.0, 182.0, 183.0, 184.0,
346                       185.0, 186.0, 187.0, 188.0, 189.0, 190.0, 191.0, 192.0,
347                       273.0, 274.0, 275.0, 276.0, 277.0, 278.0, 279.0, 280.0,
348                       289.0, 290.0, 291.0, 292.0, 293.0, 294.0, 295.0, 296.0,
349                       305.0, 306.0, 307.0, 308.0, 309.0, 310.0, 311.0, 312.0,
350                       313.0, 314.0, 315.0, 316.0, 317.0, 318.0, 319.0, 320.0,
351                       401.0, 402.0, 403.0, 404.0, 405.0, 406.0, 407.0, 408.0,
352                       417.0, 418.0, 419.0, 420.0, 421.0, 422.0, 423.0, 424.0,
353                       433.0, 434.0, 435.0, 436.0, 437.0, 438.0, 439.0, 440.0,
354                       441.0, 442.0, 443.0, 444.0, 445.0, 446.0, 447.0, 448.0,
355                       465.0, 466.0, 467.0, 468.0, 469.0, 470.0, 471.0, 472.0,
356                       481.0, 482.0, 483.0, 484.0, 485.0, 486.0, 487.0, 488.0,
357                       497.0, 498.0, 499.0, 500.0, 501.0, 502.0, 503.0, 504.0,
358                       505.0, 506.0, 507.0, 508.0, 509.0, 510.0, 511.0, 512.0]
359    self._VerifyValues(tf.nn.max_pool, input_sizes=[1, 8, 8, 8],
360                       ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1],
361                       padding="SAME",
362                       expected=expected_output, use_gpu=use_gpu)
363
364  def testMaxPooling(self):
365    for use_gpu in True, False:
366      self._testMaxPoolValidPadding(use_gpu)
367      self._testMaxPoolSamePadding(use_gpu)
368      self._testMaxPoolSamePaddingNonSquareWindow(use_gpu)
369      self._testMaxPoolValidPaddingUnevenStride(use_gpu)
370      self._testMaxPoolSamePaddingPacket4(use_gpu)
371      self._testMaxPoolSamePaddingPacket8(use_gpu)
372
373  # Tests for DepthwiseMaxPooling on CPU only.
374  def testDepthwiseMaxPool1x1DepthWindow1(self):
375    # input is:
376    # [1.0, ..., 10.0] along depth,
377    #
378    # We maxpool by depth in patches of 2.
379    self._VerifyValues(tf.nn.max_pool, input_sizes=[1, 1, 1, 10],
380                       ksize=[1, 1, 1, 2], strides=[1, 1, 1, 2],
381                       padding="SAME",
382                       expected=[2.0, 4.0, 6.0, 8.0, 10.0], use_gpu=False)
383
384  def testDepthwiseMaxPool2x2DepthWindow3(self):
385    # input is:
386    #
387    # a 2x2x6 cube, and we depthwise max across 3 to produce a 2x2x2
388    # output.  Each node has contiguous values, so the depthwise max
389    # should be multiples of 3.0.
390    self._VerifyValues(tf.nn.max_pool, input_sizes=[1, 2, 2, 6],
391                       ksize=[1, 1, 1, 3], strides=[1, 1, 1, 3],
392                       padding="SAME",
393                       expected=[3.0, 6.0, 9.0, 12.0, 15.0, 18.0, 21.0, 24.0],
394                       use_gpu=False)
395
396  def testKernelSmallerThanStrideValid(self):
397    for use_gpu in [True, False]:
398      self._VerifyValues(tf.nn.max_pool,
399                         input_sizes=[1, 7, 7, 1],
400                         ksize=[1, 2, 2, 1],
401                         strides=[1, 3, 3, 1],
402                         padding="VALID",
403                         expected=[9, 12, 30, 33],
404                         use_gpu=use_gpu)
405
406      self._VerifyValues(tf.nn.avg_pool,
407                         input_sizes=[1, 7, 7, 1],
408                         ksize=[1, 2, 2, 1],
409                         strides=[1, 3, 3, 1],
410                         padding="VALID",
411                         expected=[5, 8, 26, 29],
412                         use_gpu=use_gpu)
413
414  def testKernelSmallerThanStrideSame(self):
415    for use_gpu in [True, False]:
416      for pool_func in [tf.nn.max_pool, tf.nn.avg_pool]:
417        self._VerifyValues(pool_func,
418                           input_sizes=[1, 3, 3, 1],
419                           ksize=[1, 1, 1, 1],
420                           strides=[1, 2, 2, 1],
421                           padding="SAME",
422                           expected=[1, 3, 7, 9],
423                           use_gpu=use_gpu)
424
425        self._VerifyValues(pool_func,
426                           input_sizes=[1, 4, 4, 1],
427                           ksize=[1, 1, 1, 1],
428                           strides=[1, 2, 2, 1],
429                           padding="SAME",
430                           expected=[1, 3, 9, 11],
431                           use_gpu=use_gpu)
432
433  def _testDepthwiseMaxPoolInvalidConfig(self, in_size, ksize, strides,
434                                         error_msg, use_gpu=False):
435    t = tf.constant(1.0, shape=in_size)
436    with self.assertRaisesRegexp(ValueError, error_msg):
437      t = tf.nn.max_pool(t, ksize=ksize, strides=strides, padding="SAME")
438
439  def testDepthwiseMaxPoolInvalidConfigs(self):
440    self._testDepthwiseMaxPoolInvalidConfig(
441        [1, 2, 2, 4], [1, 2, 2, 2],
442        [1, 1, 1, 2], "exactly one of pooling across depth")
443    self._testDepthwiseMaxPoolInvalidConfig(
444        [1, 2, 2, 4], [1, 1, 1, 2],
445        [1, 1, 1, 1], "depth window to equal the depth stride")
446    self._testDepthwiseMaxPoolInvalidConfig(
447        [1, 2, 2, 4], [1, 1, 1, 3],
448        [1, 1, 1, 3], "evenly divide")
449    if tf.test.is_built_with_cuda():
450      with self.test_session(use_gpu=True):
451        t = tf.constant(1.0, shape=[1, 2, 2, 4])
452        with self.assertRaisesOpError("for CPU devices"):
453          tf.nn.max_pool(t, ksize=[1, 1, 1, 2], strides=[1, 1, 1, 2],
454                         padding="SAME").eval()
455
456  # The following are tests that verify that the CPU and GPU implementations
457  # produce the same resuts.
458  def _CompareMaxPoolingFwd(self, input_shape, ksize, strides, padding):
459    for dtype in np.float32, np.float16:
460      tensor_input = np.random.rand(*input_shape).astype(dtype)
461      with self.test_session(use_gpu=True):
462        t = tf.constant(tensor_input, shape=input_shape)
463        out_op, _ = tf.nn.max_pool_with_argmax(t, ksize, strides, padding)
464        gpu_val = out_op.eval()
465      with self.test_session(use_gpu=False):
466        t = tf.constant(tensor_input, shape=input_shape)
467        out_op = tf.nn.max_pool(t, ksize, strides, padding)
468        cpu_val = out_op.eval()
469      self.assertAllCloseAccordingToType(cpu_val, gpu_val)
470
471  def _CompareMaxPoolingBk(self, input_shape, output_shape, ksize, strides,
472                           padding):
473    for dtype in np.float32, np.float16:
474      # Generate numbers in a narrow range, so that there are many duplicates
475      # in the input.
476      tensor_input = np.random.random_integers(0, 3, input_shape).astype(dtype)
477      tensor_output = np.random.rand(*output_shape).astype(dtype)
478      with self.test_session(use_gpu=True):
479        t = tf.constant(tensor_input, shape=input_shape)
480        _, argmax_op = tf.nn.max_pool_with_argmax(t, ksize, strides, padding)
481        argmax = argmax_op.eval()
482        grad_in = tf.constant(tensor_output, shape=output_shape)
483        out_op = gen_nn_ops._max_pool_grad_with_argmax(t, grad_in, argmax,
484                                                       ksize, strides, padding)
485        gpu_val = out_op.eval()
486        self.assertShapeEqual(gpu_val, out_op)
487      with self.test_session(use_gpu=False):
488        t = tf.constant(tensor_input, shape=input_shape)
489        out_op = tf.nn.max_pool(t, ksize, strides, padding)
490        orig_out = out_op.eval()
491        grad_in = tf.constant(tensor_output, shape=output_shape)
492        out_op = gen_nn_ops._max_pool_grad(t, orig_out, grad_in, ksize, strides,
493                                           padding)
494        cpu_val = out_op.eval()
495        self.assertShapeEqual(cpu_val, out_op)
496      if dtype == np.float16:
497        # The CPU version accumulates its gradient on fp16, so it's less
498        # accurate than the GPU version that does the accumulation on fp32
499        self.assertAllClose(cpu_val, gpu_val, rtol=0.01, atol=0.01)
500      else:
501        self.assertAllClose(cpu_val, gpu_val)
502
503
504  def testMaxPoolingWithArgmax(self):
505    # MaxPoolWithArgMax is implemented only on GPU.
506    if not tf.test.is_built_with_cuda():
507      return
508    tensor_input = [1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0]
509    with self.test_session(use_gpu=True) as sess:
510      t = tf.constant(tensor_input, shape=[1, 3, 3, 1])
511      out_op, argmax_op = tf.nn.max_pool_with_argmax(t,
512                                                   ksize=[1, 2, 2, 1],
513                                                   strides=[1, 1, 1, 1],
514                                                   Targmax=tf.int64,
515                                                   padding="VALID")
516      out, argmax = sess.run([out_op, argmax_op])
517      self.assertShapeEqual(out, out_op)
518      self.assertShapeEqual(argmax, argmax_op)
519      self.assertAllClose(out.ravel(), [1.0, 1.0, 1.0, 1.0])
520      self.assertAllEqual(argmax.ravel(), [0, 1, 3, 5])
521
522  def testMaxPoolingGradWithArgmax(self):
523    # MaxPoolWithArgMax is implemented only on GPU.
524    if not tf.test.is_built_with_cuda():
525      return
526    orig_input = [1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0]
527    tensor_input = [11.0, 12.0, 13.0, 14.0]
528    tensor_argmax = list(np.array([0, 1, 3, 5], dtype=np.int64))
529    with self.test_session(use_gpu=True) as sess:
530      orig_in = tf.constant(orig_input, shape=[1, 3, 3, 1])
531      t = tf.constant(tensor_input, shape=[1, 2, 2, 1])
532      argmax = tf.constant(tensor_argmax, shape=[1, 2, 2, 1],
533                                    dtype=tf.int64)
534      out_op = gen_nn_ops._max_pool_grad_with_argmax(orig_in, t, argmax,
535                                                     ksize=[1, 2, 2, 1],
536                                                     strides=[1, 1, 1, 1],
537                                                     padding="VALID")
538      out = out_op.eval().flatten()
539      self.assertAllClose(out, [11.0, 12.0, 0.0, 13.0, 0.0,
540                                14.0, 0.0, 0.0, 0.0])
541
542  def _ConstructAndTestGradient(self, pool_func, input_sizes, output_sizes,
543                                window_rows, window_cols, row_stride,
544                                col_stride, padding, data_format, use_gpu,
545                                x_init_value=None):
546    """Verifies the gradients of the avg pooling function.
547
548    Args:
549      pool_func: Function to be called, co.MaxPool, co.AvgPool,
550        or the Lua version.
551      input_sizes: Input tensor dimensions.
552      output_sizes: Output tensor dimensions.
553      window_rows: kernel size in row dim
554      window_cols: kernel size in col dim
555      row_stride: Row Stride.
556      col_stride: Col Stride.
557      padding: Padding type.
558      data_format: Data format.
559      use_gpu: whether we are running on GPU
560      x_init_value: Values to be passed to the gradient checker.
561    """
562    assert input_sizes[0] == output_sizes[0]
563    assert input_sizes[3] == output_sizes[3]
564    total_size = 1
565    for s in input_sizes:
566      total_size *= s
567    # Initializes the input tensor with array containing incrementing
568    # numbers from 1.
569    x = [f * 1.0 for f in range(1, total_size + 1)]
570    with self.test_session(use_gpu=use_gpu):
571      input_tensor = tf.constant(x, shape=input_sizes, name="input")
572      if pool_func == tf.nn.avg_pool:
573        func_name = "avg_pool"
574        err_margin = 1e-4
575      else:
576        if x_init_value is None:
577          x_init_value = np.asfarray(
578              np.arange(1, total_size + 1),
579              dtype=np.float32).reshape(input_sizes)
580        func_name = "max_pool"
581        err_margin = 1e-3
582      if data_format == "NCHW":
583        ksize = [1, 1, window_rows, window_rows]
584        strides = [1, 1, row_stride, col_stride]
585        t = NHWCToNCHW(input_tensor)
586      else:
587        ksize = [1, window_rows, window_rows, 1]
588        strides = [1, row_stride, col_stride, 1]
589        t = input_tensor
590      t = pool_func(t, ksize=ksize, strides=strides, padding=padding,
591                    data_format=data_format, name=func_name)
592      if data_format == "NCHW":
593        t = NCHWToNHWC(t)
594
595      err = tf.test.compute_gradient_error(input_tensor,
596                                           input_sizes,
597                                           t,
598                                           output_sizes,
599                                           x_init_value=x_init_value,
600                                           delta=1e-2)
601    print("%s gradient error = " % func_name, err)
602    self.assertLess(err, err_margin)
603
604  def _testMaxPoolGradValidPadding1_1(self, data_format, use_gpu):
605    self._ConstructAndTestGradient(
606        tf.nn.max_pool, input_sizes=[1, 3, 3, 1],
607        output_sizes=[1, 3, 3, 1], window_rows=1, window_cols=1, row_stride=1,
608        col_stride=1, padding="VALID", data_format=data_format, use_gpu=use_gpu)
609
610  def _testMaxPoolGradValidPadding2_1_6(self, data_format, use_gpu):
611    self._ConstructAndTestGradient(
612        tf.nn.max_pool, input_sizes=[2, 6, 6, 3],
613        output_sizes=[2, 5, 5, 3], window_rows=2, window_cols=2, row_stride=1,
614        col_stride=1, padding="VALID", data_format=data_format, use_gpu=use_gpu)
615
616  def _testMaxPoolGradValidPadding2_1_7(self, data_format, use_gpu):
617    self._ConstructAndTestGradient(
618        tf.nn.max_pool, input_sizes=[2, 7, 7, 3],
619        output_sizes=[2, 6, 6, 3], window_rows=2, window_cols=2, row_stride=1,
620        col_stride=1, padding="VALID", data_format=data_format, use_gpu=use_gpu)
621
622  def _testMaxPoolGradValidPadding2_2(self, data_format, use_gpu):
623    self._ConstructAndTestGradient(
624        tf.nn.max_pool, input_sizes=[2, 2, 2, 3],
625        output_sizes=[2, 1, 1, 3], window_rows=2, window_cols=2, row_stride=2,
626        col_stride=2, padding="VALID", data_format=data_format, use_gpu=use_gpu)
627
628  def _testMaxPoolGradSamePadding1_1(self, data_format, use_gpu):
629    self._ConstructAndTestGradient(
630        tf.nn.max_pool, input_sizes=[2, 2, 4, 3],
631        output_sizes=[2, 2, 4, 3], window_rows=1, window_cols=1, row_stride=1,
632        col_stride=1, padding="SAME", data_format=data_format, use_gpu=use_gpu)
633
634  def _testMaxPoolGradSamePadding2_1(self, data_format, use_gpu):
635    self._ConstructAndTestGradient(
636        tf.nn.max_pool, input_sizes=[2, 2, 4, 3],
637        output_sizes=[2, 2, 4, 3], window_rows=2, window_cols=2, row_stride=1,
638        col_stride=1, padding="SAME", data_format=data_format, use_gpu=use_gpu)
639
640  def _testMaxPoolGradSamePadding2_2(self, data_format, use_gpu):
641    self._ConstructAndTestGradient(
642        tf.nn.max_pool, input_sizes=[2, 2, 4, 3],
643        output_sizes=[2, 1, 2, 3], window_rows=2, window_cols=2, row_stride=2,
644        col_stride=2, padding="SAME", data_format=data_format, use_gpu=use_gpu)
645
646  def _testMaxPoolGradSamePadding3_1(self, data_format, use_gpu):
647    self._ConstructAndTestGradient(
648        tf.nn.max_pool, input_sizes=[1, 7, 7, 1],
649        output_sizes=[1, 7, 7, 1], window_rows=3, window_cols=3, row_stride=1,
650        col_stride=1, padding="SAME", data_format=data_format, use_gpu=use_gpu)
651
652  def testMaxPoolGrad(self):
653    for (data_format, use_gpu) in GetTestConfigs():
654      self._testMaxPoolGradValidPadding1_1(data_format, use_gpu)
655      self._testMaxPoolGradValidPadding2_1_6(data_format, use_gpu)
656      self._testMaxPoolGradValidPadding2_1_7(data_format, use_gpu)
657      self._testMaxPoolGradValidPadding2_2(data_format, use_gpu)
658      self._testMaxPoolGradSamePadding1_1(data_format, use_gpu)
659      self._testMaxPoolGradSamePadding2_1(data_format, use_gpu)
660      self._testMaxPoolGradSamePadding2_2(data_format, use_gpu)
661      self._testMaxPoolGradSamePadding3_1(data_format, use_gpu)
662
663  def _MaxPoolGrad(self, orig_input, orig_output, grad, window_rows,
664                   window_cols, row_stride, col_stride, padding):
665    """Max Pooling Gradient.
666
667    Args:
668      orig_input: A float Tensor. The original input tensor.
669      orig_output: A float Tensor. The original output tensor.
670      grad: A float Tensor.
671        The 4D (batch x rows x cols x depth) output backprop.
672      window_rows: integer. Kernel size along rows dimension.
673      window_cols: integer. Kernel size along cols dimension.
674      row_stride: integer. Stride along rows dimension
675      col_stride: integer. Stride along cols dimension
676      padding: PoolingOpDef.Padding.  Padding type.
677
678    Returns:
679      A Tensor.
680    """
681    return gen_nn_ops._max_pool_grad(
682        orig_input, orig_output, grad,
683        [1, window_rows, window_cols, 1], [1, row_stride, col_stride, 1],
684        padding)
685
686  def _testMaxPoolGradDirect(self, input_data, output_backprop,
687                             expected_input_backprop, input_sizes, output_sizes,
688                             window_rows, window_cols, row_stride, col_stride,
689                             padding, use_gpu):
690    with self.test_session(use_gpu=use_gpu) as sess:
691      input_tensor = tf.constant(input_data, shape=input_sizes)
692      output_tensor = tf.nn.max_pool(
693          input_tensor, [1, window_rows, window_cols, 1],
694          [1, row_stride, col_stride, 1], padding)
695      output_backprop_tensor = tf.constant(output_backprop,
696                                                    shape=output_sizes)
697
698      input_backprop_tensor = self._MaxPoolGrad(
699          input_tensor, output_tensor, output_backprop_tensor,
700          window_rows, window_cols, row_stride, col_stride, padding)
701
702      actual_input_backprop = input_backprop_tensor.eval()
703      self.assertShapeEqual(actual_input_backprop, input_backprop_tensor)
704      actual_input_backprop = actual_input_backprop.flatten()
705      actual_input_backprop = self._GetNdArray(actual_input_backprop)
706
707      actual_output = output_tensor.eval().flatten()
708      actual_output = self._GetNdArray(actual_output)
709
710      self.assertAllClose(expected_input_backprop, actual_input_backprop,
711                          rtol=1e-6, atol=1e-6)
712
713  def _testMaxPoolGradDirect1_1(self):
714    input_data = [
715        1.0, 1.0, 1.0, 1.0,
716        1.0, 1.0, 1.0, 1.0,
717        1.0, 1.0, 1.0, 1.0,
718        1.0, 1.0, 1.0, 1.0]
719    output_backprop = [
720        11.0, 12.0, 13.0,
721        15.0, 16.0, 17.0,
722        19.0, 20.0, 21.0]
723    expected_input_backprop = [
724        11.0, 12.0, 13.0, 0.0,
725        15.0, 16.0, 17.0, 0.0,
726        19.0, 20.0, 21.0, 0.0,
727        0.0, 0.0, 0.0, 0.0]
728
729    for use_gpu in True, False:
730      self._testMaxPoolGradDirect(
731          input_data, output_backprop, expected_input_backprop,
732          input_sizes=[1, 4, 4, 1], output_sizes=[1, 3, 3, 1],
733          window_rows=2, window_cols=2, row_stride=1, col_stride=1,
734          padding="VALID", use_gpu=use_gpu)
735
736  def _testMaxPoolGradDirect1_2(self):
737    input_data = [
738        1.0, 0.0, 1.0, 0.0,
739        0.0, 1.0, 0.0, 1.0,
740        1.0, 0.0, 1.0, 0.0,
741        0.0, 1.0, 0.0, 1.0]
742    output_backprop = [
743        11.0, 12.0, 13.0,
744        15.0, 16.0, 17.0,
745        19.0, 20.0, 21.0]
746    expected_input_backprop = [
747        11.0, 0.0, 25.0, 0.0,
748        0.0, 31.0, 0.0, 17.0,
749        19.0, 0.0, 41.0, 0.0,
750        0.0, 0.0, 0.0, 0.0]
751
752    for use_gpu in True, False:
753      self._testMaxPoolGradDirect(
754          input_data, output_backprop, expected_input_backprop,
755          input_sizes=[1, 4, 4, 1], output_sizes=[1, 3, 3, 1],
756          window_rows=2, window_cols=2, row_stride=1, col_stride=1,
757          padding="VALID", use_gpu=use_gpu)
758
759  def _testMaxPoolGradDirect1_3(self):
760    input_data = [
761        1.0, 0.0, 1.0, 0.0,
762        0.0, 1.0, 0.0, 1.0,
763        1.0, 0.0, 1.0, 0.0,
764        0.0, 1.0, 0.0, 1.0,]
765    output_backprop = [
766        11.0, 12.0, 13.0, 14.0,
767        15.0, 16.0, 17.0, 18.0,
768        19.0, 20.0, 21.0, 22.0,
769        23.0, 24.0, 25.0, 26.0]
770    expected_input_backprop = [
771        54, 0.0, 62, 0.0,
772        0.0, 60, 0.0, 22.0,
773        47, 0.0, 51, 0.0,
774        0.0, 0.0, 0.0, 0.0,]
775
776    for use_gpu in True, False:
777      self._testMaxPoolGradDirect(
778          input_data, output_backprop, expected_input_backprop,
779          input_sizes=[1, 4, 4, 1], output_sizes=[1, 4, 4, 1],
780          window_rows=3, window_cols=3, row_stride=1, col_stride=1,
781          padding="SAME", use_gpu=use_gpu)
782
783  def _testMaxPoolGradDirectWithNans2_1(self):
784    input_data = [float("nan")] * 16
785    output_backprop = [
786        11.0, 12.0, 13.0,
787        15.0, 16.0, 17.0,
788        19.0, 20.0, 21.0]
789    # Test the CPU implementation, which propagates diffs in case of NaN
790    expected_input_backprop_tf_cpu = [
791        11.0, 12.0, 13.0, 0.0,
792        15.0, 16.0, 17.0, 0.0,
793        19.0, 20.0, 21.0, 0.0,
794        0.0, 0.0, 0.0, 0.0]
795    self._testMaxPoolGradDirect(
796        input_data, output_backprop, expected_input_backprop_tf_cpu,
797        input_sizes=[1, 4, 4, 1], output_sizes=[1, 3, 3, 1],
798        window_rows=2, window_cols=2, row_stride=1, col_stride=1,
799        padding="VALID", use_gpu=False)
800
801    if not tf.test.is_built_with_cuda():
802      return
803
804    # Test the GPU implementation that uses cudnn for now.
805    # It does not propagate the diff in cases of NaNs
806    expected_input_backprop_cudnn = [
807        0.0, 0.0, 0.0, 0.0,
808        0.0, 0.0, 0.0, 0.0,
809        0.0, 0.0, 0.0, 0.0,
810        0.0, 0.0, 0.0, 0.0]
811    self._testMaxPoolGradDirect(
812        input_data, output_backprop, expected_input_backprop_cudnn,
813        input_sizes=[1, 4, 4, 1], output_sizes=[1, 3, 3, 1],
814        window_rows=2, window_cols=2, row_stride=1, col_stride=1,
815        padding="VALID", use_gpu=True)
816
817  def _testMaxPoolGradDirectWithNans2_2(self):
818    input_data = [float("nan")] * 16
819    output_backprop = [
820        float("nan"), 12.0, 13.0,
821        15.0, float("nan"), 17.0,
822        19.0, 20.0, float("nan")]
823    # Test the CPU implementation, which propagates diffs in case of NaN
824    expected_input_backprop_tf_cpu = [
825        float("nan"), 12.0, 13.0, 0.0,
826        15.0, float("nan"), 17.0, 0.0,
827        19.0, 20.0, float("nan"), 0.0,
828        0.0, 0.0, 0.0, 0.0]
829    self._testMaxPoolGradDirect(
830        input_data, output_backprop, expected_input_backprop_tf_cpu,
831        input_sizes=[1, 4, 4, 1], output_sizes=[1, 3, 3, 1],
832        window_rows=2, window_cols=2, row_stride=1, col_stride=1,
833        padding="VALID", use_gpu=False)
834
835    if not tf.test.is_built_with_cuda():
836      return
837
838    # Test the GPU implementation that uses cudnn for now.
839    # It does not propagate the diff in cases of NaNs
840    expected_input_backprop_cudnn = [
841        0.0, 0.0, 0.0, 0.0,
842        0.0, 0.0, 0.0, 0.0,
843        0.0, 0.0, 0.0, 0.0,
844        0.0, 0.0, 0.0, 0.0]
845    self._testMaxPoolGradDirect(
846        input_data, output_backprop, expected_input_backprop_cudnn,
847        input_sizes=[1, 4, 4, 1], output_sizes=[1, 3, 3, 1],
848        window_rows=2, window_cols=2, row_stride=1, col_stride=1,
849        padding="VALID", use_gpu=True)
850
851  def testMaxPoolGradDirect(self):
852    self._testMaxPoolGradDirect1_1()
853    self._testMaxPoolGradDirect1_2()
854    self._testMaxPoolGradDirect1_3()
855    self._testMaxPoolGradDirectWithNans2_1()
856    self._testMaxPoolGradDirectWithNans2_2()
857
858  def testAvgPoolGrad(self):
859    for (data_format, use_gpu) in GetTestConfigs():
860      self._testAvgPoolGradValidPadding1_1(data_format, use_gpu)
861      self._testAvgPoolGradValidPadding2_1(data_format, use_gpu)
862      self._testAvgPoolGradValidPadding2_2(data_format, use_gpu)
863      self._testAvgPoolGradSamePadding1_1(data_format, use_gpu)
864      self._testAvgPoolGradSamePadding2_1(data_format, use_gpu)
865      self._testAvgPoolGradSamePadding2_2(data_format, use_gpu)
866      self._testAvgPoolGradSamePadding3_1(data_format, use_gpu)
867
868  def _testAvgPoolGradValidPadding1_1(self, data_format, use_gpu):
869    self._ConstructAndTestGradient(
870        tf.nn.avg_pool, input_sizes=[2, 3, 3, 3],
871        output_sizes=[2, 3, 3, 3], window_rows=1, window_cols=1, row_stride=1,
872        col_stride=1, padding="VALID", data_format=data_format, use_gpu=use_gpu)
873
874  def _testAvgPoolGradValidPadding2_1(self, data_format, use_gpu):
875    self._ConstructAndTestGradient(
876        tf.nn.avg_pool, input_sizes=[2, 3, 3, 3],
877        output_sizes=[2, 2, 2, 3], window_rows=2, window_cols=2, row_stride=1,
878        col_stride=1, padding="VALID", data_format=data_format, use_gpu=use_gpu)
879
880  def _testAvgPoolGradValidPadding2_2(self, data_format, use_gpu):
881    self._ConstructAndTestGradient(
882        tf.nn.avg_pool, input_sizes=[2, 2, 2, 3],
883        output_sizes=[2, 1, 1, 3], window_rows=2, window_cols=2, row_stride=2,
884        col_stride=2, padding="VALID", data_format=data_format, use_gpu=use_gpu)
885
886  def _testAvgPoolGradSamePadding1_1(self, data_format, use_gpu):
887    self._ConstructAndTestGradient(
888        tf.nn.avg_pool, input_sizes=[2, 2, 4, 3],
889        output_sizes=[2, 2, 4, 3], window_rows=1, window_cols=1, row_stride=1,
890        col_stride=1, padding="SAME", data_format=data_format, use_gpu=use_gpu)
891
892  def _testAvgPoolGradSamePadding2_1(self, data_format, use_gpu):
893    self._ConstructAndTestGradient(
894        tf.nn.avg_pool, input_sizes=[2, 2, 4, 3],
895        output_sizes=[2, 2, 4, 3], window_rows=2, window_cols=2, row_stride=1,
896        col_stride=1, padding="SAME", data_format=data_format, use_gpu=use_gpu)
897
898  def _testAvgPoolGradSamePadding2_2(self, data_format, use_gpu):
899    self._ConstructAndTestGradient(
900        tf.nn.avg_pool, input_sizes=[2, 2, 4, 3],
901        output_sizes=[2, 1, 2, 3], window_rows=2, window_cols=2, row_stride=2,
902        col_stride=2, padding="SAME", data_format=data_format, use_gpu=use_gpu)
903
904  def _testAvgPoolGradSamePadding3_1(self, data_format, use_gpu):
905    self._ConstructAndTestGradient(
906        tf.nn.avg_pool, input_sizes=[1, 7, 7, 1],
907        output_sizes=[1, 7, 7, 1], window_rows=3, window_cols=3, row_stride=1,
908        col_stride=1, padding="SAME", data_format=data_format, use_gpu=use_gpu)
909
910  def testShapeFunctionEdgeCases(self):
911    # All shapes unknown.
912    for pool_func in [tf.nn.max_pool, tf.nn.avg_pool]:
913      p = pool_func(tf.placeholder(tf.float32),
914                    ksize=[1, 1, 1, 1], strides=[1, 1, 1, 1],
915                    padding="SAME")
916      self.assertEqual([None, None, None, None], p.get_shape().as_list())
917    p, am = tf.nn.max_pool_with_argmax(
918        tf.placeholder(tf.float32),
919        ksize=[1, 1, 1, 1], strides=[1, 1, 1, 1],
920        padding="SAME")
921    self.assertEqual([None, None, None, None], p.get_shape().as_list())
922    self.assertEqual([None, None, None, None], am.get_shape().as_list())
923
924    # Incorrect input shape.
925    for pool_func in [tf.nn.max_pool, tf.nn.avg_pool,
926                      tf.nn.max_pool_with_argmax]:
927      with self.assertRaises(ValueError):
928        pool_func(tf.placeholder(tf.float32, shape=[1, 3]),
929                  ksize=[1, 1, 1, 1], strides=[1, 1, 1, 1], padding="SAME")
930
931    # Illegal strides.
932    for pool_func in [tf.nn.max_pool, tf.nn.avg_pool,
933                      tf.nn.max_pool_with_argmax]:
934      with self.assertRaisesRegexp(ValueError, "strides in the batch"):
935        pool_func(tf.placeholder(tf.float32),
936                  ksize=[1, 1, 1, 1], strides=[2, 1, 1, 1], padding="SAME")
937    with self.assertRaisesRegexp(ValueError, "strides in the batch and depth"):
938      tf.nn.avg_pool(tf.placeholder(tf.float32),
939                     ksize=[1, 1, 1, 1], strides=[1, 1, 1, 2], padding="SAME")
940
941    # Filter larger than input.
942    for pool_func in [tf.nn.max_pool, tf.nn.avg_pool,
943                      tf.nn.max_pool_with_argmax]:
944      with self.assertRaisesRegexp(ValueError,
945                                   "Filter must not be larger than the input"):
946        pool_func(tf.placeholder(tf.float32,
947                                        shape=[32, 20, 20, 3]),
948                  ksize=[1, 20, 21, 1], strides=[1, 1, 1, 1], padding="SAME")
949      with self.assertRaisesRegexp(ValueError,
950                                   "Filter must not be larger than the input"):
951        pool_func(tf.placeholder(tf.float32,
952                                        shape=[32, 20, 20, 3]),
953                  ksize=[1, 21, 20, 1], strides=[1, 1, 1, 1], padding="SAME")
954
955
956def GetMaxPoolFwdTest(input_size, filter_size, strides, padding):
957  def Test(self):
958    # MaxPoolWithArgMax is implemented only on GPU.
959    if not tf.test.is_built_with_cuda():
960      return
961    self._CompareMaxPoolingFwd(input_size, filter_size, strides, padding)
962  return Test
963
964
965def GetMaxPoolGradTest(input_size, filter_size, output_size, strides, padding):
966  def Test(self):
967    # MaxPoolWithArgMax is implemented only on GPU.
968    if not tf.test.is_built_with_cuda():
969      return
970    self._CompareMaxPoolingBk(input_size, output_size,
971                              filter_size, strides, padding)
972  return Test
973
974
975if __name__ == "__main__":
976  for (name_, input_size_, filter_size_, output_size_, stride_,
977       padding_) in GetShrunkInceptionMaxPoolShapes():
978    setattr(PoolingTest, "testMaxPoolFwd_" + name_,
979            GetMaxPoolFwdTest(input_size_, filter_size_, stride_, padding_))
980    setattr(PoolingTest, "testMaxPoolGrad_" + name_,
981            GetMaxPoolGradTest(input_size_, filter_size_, output_size_,
982                               stride_, padding_))
983  tf.test.main()
984