Repository: chainer/chainer

Issue:
Error of max_pooling_2d on CPU
I gave a same value for the kernel size and stride on `average_pooling_2d` and `max_pooling_2d`, and I changed the value to be ranged from 1 to 99 for 100 x 100 x 3 images. Then, in the case of `average_pooling_2d`, there are no errors at all values, but in the case of `max_pooling_2d`, a numpy related error raised when the value is 6. The error doesn't come up on GPU. It happens only on CPU. (but I'm not sure in the case without cuDNN)

Test code:

```
import numpy
import chainer.functions as F
from chainer import Variable, cuda

x = numpy.random.rand(10, 3, 100, 100).astype(numpy.float32)

# when on GPU, there's no problem!
# cuda.init()
# x = cuda.to_gpu(x)

x = Variable(x)

# OK on both GPU and CPU
for i in range(1, 100):
    print('ave:', i,
          F.average_pooling_2d(x, ksize=i, stride=i, pad=0).data.shape)

# ERROR on CPU
for i in range(1, 100):
    print('max:', i,
          F.max_pooling_2d(x, ksize=i, stride=i, pad=0).data.shape)
```

Output (on CPU):

```
:
:
:
('ave:', 95, (10, 3, 1, 1))
('ave:', 96, (10, 3, 1, 1))
('ave:', 97, (10, 3, 1, 1))
('ave:', 98, (10, 3, 1, 1))
('ave:', 99, (10, 3, 1, 1))
('max:', 1, (10, 3, 100, 100))
('max:', 2, (10, 3, 50, 50))
('max:', 3, (10, 3, 34, 34))
('max:', 4, (10, 3, 25, 25))
('max:', 5, (10, 3, 20, 20))
Traceback (most recent call last):
  File "tests/test_pool.py", line 16, in <module>
    F.max_pooling_2d(x, ksize=i, stride=i, pad=0).data.shape)
  File "/home/ubuntu/anaconda/lib/python2.7/site-packages/chainer_cuda_deps-1.0.0-py2.7.egg/chainer/functions/pooling_2d.py", line 210, in max_pooling_2d
    return MaxPooling2D(ksize, stride, pad, cover_all, use_cudnn)(x)
  File "/home/ubuntu/anaconda/lib/python2.7/site-packages/chainer_cuda_deps-1.0.0-py2.7.egg/chainer/function.py", line 158, in __call__
    outputs = self.forward(in_data)
  File "/home/ubuntu/anaconda/lib/python2.7/site-packages/chainer_cuda_deps-1.0.0-py2.7.egg/chainer/function.py", line 195, in forward
    return self.forward_cpu(inputs)
  File "/home/ubuntu/anaconda/lib/python2.7/site-packages/chainer_cuda_deps-1.0.0-py2.7.egg/chainer/functions/pooling_2d.py", line 77, in forward_cpu
    y = self.indexes.choose(col)
ValueError: Need between 2 and (32) array objects (inclusive).
```

Error of max_pooling_2d on CPU
I gave a same value for the kernel size and stride on `average_pooling_2d` and `max_pooling_2d`, and I changed the value to be ranged from 1 to 99 for 100 x 100 x 3 images. Then, in the case of `average_pooling_2d`, there are no errors at all values, but in the case of `max_pooling_2d`, a numpy related error raised when the value is 6. The error doesn't come up on GPU. It happens only on CPU. (but I'm not sure in the case without cuDNN)

Test code:

```
import numpy
import chainer.functions as F
from chainer import Variable, cuda

x = numpy.random.rand(10, 3, 100, 100).astype(numpy.float32)

# when on GPU, there's no problem!
# cuda.init()
# x = cuda.to_gpu(x)

x = Variable(x)

# OK on both GPU and CPU
for i in range(1, 100):
    print('ave:', i,
          F.average_pooling_2d(x, ksize=i, stride=i, pad=0).data.shape)

# ERROR on CPU
for i in range(1, 100):
    print('max:', i,
          F.max_pooling_2d(x, ksize=i, stride=i, pad=0).data.shape)
```

Output (on CPU):

```
:
:
:
('ave:', 95, (10, 3, 1, 1))
('ave:', 96, (10, 3, 1, 1))
('ave:', 97, (10, 3, 1, 1))
('ave:', 98, (10, 3, 1, 1))
('ave:', 99, (10, 3, 1, 1))
('max:', 1, (10, 3, 100, 100))
('max:', 2, (10, 3, 50, 50))
('max:', 3, (10, 3, 34, 34))
('max:', 4, (10, 3, 25, 25))
('max:', 5, (10, 3, 20, 20))
Traceback (most recent call last):
  File "tests/test_pool.py", line 16, in <module>
    F.max_pooling_2d(x, ksize=i, stride=i, pad=0).data.shape)
  File "/home/ubuntu/anaconda/lib/python2.7/site-packages/chainer_cuda_deps-1.0.0-py2.7.egg/chainer/functions/pooling_2d.py", line 210, in max_pooling_2d
    return MaxPooling2D(ksize, stride, pad, cover_all, use_cudnn)(x)
  File "/home/ubuntu/anaconda/lib/python2.7/site-packages/chainer_cuda_deps-1.0.0-py2.7.egg/chainer/function.py", line 158, in __call__
    outputs = self.forward(in_data)
  File "/home/ubuntu/anaconda/lib/python2.7/site-packages/chainer_cuda_deps-1.0.0-py2.7.egg/chainer/function.py", line 195, in forward
    return self.forward_cpu(inputs)
  File "/home/ubuntu/anaconda/lib/python2.7/site-packages/chainer_cuda_deps-1.0.0-py2.7.egg/chainer/functions/pooling_2d.py", line 77, in forward_cpu
    y = self.indexes.choose(col)
ValueError: Need between 2 and (32) array objects (inclusive).
```



Discussion:
Thank you for reporting the bug. I succeeded to reproduce the bug. We will investigate the error.

Thank you for reporting the bug. I succeeded to reproduce the bug. We will investigate the error.


Resolving patch:
diff --git a/chainer/functions/pooling_2d.py b/chainer/functions/pooling_2d.py
--- a/chainer/functions/pooling_2d.py
+++ b/chainer/functions/pooling_2d.py
@@ -83,10 +83,12 @@ def forward_cpu(self, x):
             x[0], self.kh, self.kw, self.sy, self.sx, self.ph, self.pw,
             pval=-float('inf'), cover_all=self.cover_all)
         n, c, kh, kw, out_h, out_w = col.shape
-        col = numpy.rollaxis(col.reshape(n, c, kh * kw, out_h, out_w), 2)
+        col = col.reshape(n, c, kh * kw, out_h, out_w)
 
-        self.indexes = col.argmax(axis=0)
-        y = self.indexes.choose(col)
+        # We select maximum twice, since the implementation using numpy.choose
+        # hits its bug when kh * kw >= 32.
+        self.indexes = col.argmax(axis=2)
+        y = col.max(axis=2)
         return y,
 
     def forward_gpu(self, x):


Test patch:
diff --git a/tests/functions_tests/test_pooling_2d.py b/tests/functions_tests/test_pooling_2d.py
--- a/tests/functions_tests/test_pooling_2d.py
+++ b/tests/functions_tests/test_pooling_2d.py
@@ -56,6 +56,11 @@ def check_forward(self, x_data, use_cudnn=True):
     def test_forward_cpu(self):
         self.check_forward(self.x)
 
+    def test_forward_cpu_wide(self):  # see #120
+        x_data = numpy.random.rand(2, 3, 15, 15).astype(numpy.float32)
+        x = chainer.Variable(x_data)
+        functions.max_pooling_2d(x, 6, stride=6, pad=0)
+
     @attr.cudnn
     def test_forward_gpu(self):
         self.check_forward(cuda.to_gpu(self.x))