Home | History | Annotate | Download | only in kernels
      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 #include "tensorflow/core/kernels/eigen_pooling.h"
     17 #include "tensorflow/core/framework/types.h"
     18 #include "tensorflow/core/platform/test.h"
     19 
     20 namespace Eigen {
     21 
     22 namespace {
     23 void EigenApprox(float a, float b) {
     24   ASSERT_TRUE(std::abs(a - b) <= std::min(std::abs(a), std::abs(b)) * 1e-3);
     25 }
     26 }  // namespace
     27 
     28 TEST(EigenPoolingTest, Simple) {
     29   const int depth = 10;
     30   const int input_rows = 5;
     31   const int input_cols = 5;
     32   const int num_batches = 13;
     33   const int patch_rows = 4;
     34   const int patch_cols = 4;
     35   const int output_rows = 2;
     36   const int output_cols = 2;
     37 
     38   Tensor<float, 4> input(depth, input_rows, input_cols, num_batches);
     39   Tensor<float, 4> result(depth, output_rows, output_cols, num_batches);
     40   input = input.constant(11.0f) + input.random();
     41   result.setRandom();
     42   result = result.constant(-1000.f);
     43 
     44   // Max pooling using a 4x4 window and a stride of 1.
     45   const int stride = 1;
     46   result = SpatialMaxPooling(input, patch_rows, patch_cols, stride, stride,
     47                              PADDING_VALID);
     48 
     49   EXPECT_EQ(result.dimension(0), depth);
     50   EXPECT_EQ(result.dimension(1), output_rows);
     51   EXPECT_EQ(result.dimension(2), output_cols);
     52   EXPECT_EQ(result.dimension(3), num_batches);
     53 
     54   for (int b = 0; b < num_batches; ++b) {
     55     for (int d = 0; d < depth; ++d) {
     56       for (int i = 0; i < output_rows; ++i) {
     57         for (int j = 0; j < output_cols; ++j) {
     58           float expected = -10000.f;
     59           for (int r = 0; r < patch_rows; ++r) {
     60             for (int c = 0; c < patch_cols; ++c) {
     61               expected = (std::max)(expected, input(d, r + i, c + j, b));
     62             }
     63           }
     64           if (result(d, i, j, b) != expected) {
     65             std::cout << "at d=" << d << " b=" << b << " i=" << i << " j=" << j
     66                       << " " << result(d, i, j, b) << " vs " << expected
     67                       << std::endl;
     68           }
     69           EigenApprox(result(d, i, j, b), expected);
     70         }
     71       }
     72     }
     73   }
     74 }
     75 
     76 TEST(EigenPoolingTest, SimpleRowMajor) {
     77   const int depth = 10;
     78   const int input_rows = 5;
     79   const int input_cols = 5;
     80   const int num_batches = 13;
     81   const int patch_rows = 4;
     82   const int patch_cols = 4;
     83   const int output_rows = 2;
     84   const int output_cols = 2;
     85 
     86   Tensor<float, 4, RowMajor> input(num_batches, input_cols, input_rows, depth);
     87   Tensor<float, 4, RowMajor> result(num_batches, output_cols, output_rows,
     88                                     depth);
     89   input = input.constant(11.0f) + input.random();
     90   result.setRandom();
     91   result = result.constant(-1000.f);
     92 
     93   // Max pooling using a 4x4 window and a stride of 1.
     94   const int stride = 1;
     95   result = SpatialMaxPooling(input, patch_rows, patch_cols, stride, stride,
     96                              PADDING_VALID);
     97 
     98   EXPECT_EQ(result.dimension(3), depth);
     99   EXPECT_EQ(result.dimension(2), output_rows);
    100   EXPECT_EQ(result.dimension(1), output_cols);
    101   EXPECT_EQ(result.dimension(0), num_batches);
    102 
    103   for (int b = 0; b < num_batches; ++b) {
    104     for (int d = 0; d < depth; ++d) {
    105       for (int i = 0; i < output_rows; ++i) {
    106         for (int j = 0; j < output_cols; ++j) {
    107           float expected = -10000.f;
    108           for (int r = 0; r < patch_rows; ++r) {
    109             for (int c = 0; c < patch_cols; ++c) {
    110               expected = (std::max)(expected, input(b, c + j, r + i, d));
    111             }
    112           }
    113           if (result(b, j, i, d) != expected) {
    114             std::cout << "at d=" << d << " b=" << b << " i=" << i << " j=" << j
    115                       << " " << result(b, j, i, d) << " vs " << expected
    116                       << std::endl;
    117           }
    118           EigenApprox(result(b, j, i, d), expected);
    119         }
    120       }
    121     }
    122   }
    123 }
    124 
    125 TEST(EigenPoolingTest, Cuboid) {
    126   const int channels = 10;
    127   const int input_planes = 5;
    128   const int input_rows = 5;
    129   const int input_cols = 5;
    130   const int num_batches = 13;
    131   const int patch_rows = 4;
    132   const int patch_cols = 3;
    133   const int patch_planes = 2;
    134   const int output_rows = 2;
    135   const int output_cols = 3;
    136   const int output_planes = 4;
    137 
    138   Tensor<float, 5> input(channels, input_planes, input_rows, input_cols,
    139                          num_batches);
    140   Tensor<float, 5> result(channels, output_planes, output_rows, output_cols,
    141                           num_batches);
    142   input = input.constant(11.0f) + input.random();
    143   result.setRandom();
    144   result = result.constant(-1000.0f);
    145 
    146   // Max pooling using a 4x3x2 window and a stride of 1.
    147   const int stride = 1;
    148   result = CuboidMaxPooling(input, patch_planes, patch_rows, patch_cols, stride,
    149                             stride, stride, PADDING_VALID);
    150 
    151   EXPECT_EQ(result.dimension(0), channels);
    152   EXPECT_EQ(result.dimension(1), output_planes);
    153   EXPECT_EQ(result.dimension(2), output_rows);
    154   EXPECT_EQ(result.dimension(3), output_cols);
    155   EXPECT_EQ(result.dimension(4), num_batches);
    156 
    157   for (int b = 0; b < num_batches; ++b) {
    158     for (int d = 0; d < channels; ++d) {
    159       for (int i = 0; i < output_planes; ++i) {
    160         for (int j = 0; j < output_rows; ++j) {
    161           for (int k = 0; k < output_cols; ++k) {
    162             float expected = -10000.f;
    163             for (int p = 0; p < patch_planes; ++p) {
    164               for (int r = 0; r < patch_rows; ++r) {
    165                 for (int c = 0; c < patch_cols; ++c) {
    166                   expected =
    167                       (std::max)(expected, input(d, p + i, r + j, c + k, b));
    168                 }
    169               }
    170             }
    171             if (result(d, i, j, k, b) != expected) {
    172               std::cout << "at d=" << d << " b=" << b << " i=" << i
    173                         << " j=" << j << " k=" << k << " "
    174                         << result(d, i, j, k, b) << " vs " << expected
    175                         << std::endl;
    176             }
    177             EigenApprox(result(d, i, j, k, b), expected);
    178           }
    179         }
    180       }
    181     }
    182   }
    183 }
    184 
    185 TEST(EigenPoolingTest, CuboidRowMajor) {
    186   const int channels = 10;
    187   const int input_planes = 5;
    188   const int input_rows = 5;
    189   const int input_cols = 5;
    190   const int num_batches = 13;
    191   const int patch_rows = 4;
    192   const int patch_cols = 3;
    193   const int patch_planes = 2;
    194   const int output_rows = 2;
    195   const int output_cols = 3;
    196   const int output_planes = 4;
    197 
    198   Tensor<float, 5, RowMajor> input(num_batches, input_cols, input_rows,
    199                                    input_planes, channels);
    200   Tensor<float, 5, RowMajor> result(num_batches, output_cols, output_rows,
    201                                     output_planes, channels);
    202   input = input.constant(11.0f) + input.random();
    203   result.setRandom();
    204   result = result.constant(-1000.0f);
    205 
    206   // Max pooling using a 4x3x2 window and a stride of 1.
    207   const int stride = 1;
    208   result = CuboidMaxPooling(input, patch_planes, patch_rows, patch_cols, stride,
    209                             stride, stride, PADDING_VALID);
    210 
    211   EXPECT_EQ(result.dimension(4), channels);
    212   EXPECT_EQ(result.dimension(3), output_planes);
    213   EXPECT_EQ(result.dimension(2), output_rows);
    214   EXPECT_EQ(result.dimension(1), output_cols);
    215   EXPECT_EQ(result.dimension(0), num_batches);
    216 
    217   for (int b = 0; b < num_batches; ++b) {
    218     for (int d = 0; d < channels; ++d) {
    219       for (int i = 0; i < output_planes; ++i) {
    220         for (int j = 0; j < output_rows; ++j) {
    221           for (int k = 0; k < output_cols; ++k) {
    222             float expected = -10000.f;
    223             for (int p = 0; p < patch_planes; ++p) {
    224               for (int r = 0; r < patch_rows; ++r) {
    225                 for (int c = 0; c < patch_cols; ++c) {
    226                   expected =
    227                       (std::max)(expected, input(b, c + k, r + j, p + i, d));
    228                 }
    229               }
    230             }
    231             if (result(b, k, j, i, d) != expected) {
    232               std::cout << "at d=" << d << " b=" << b << " i=" << i
    233                         << " j=" << j << " k=" << k << " "
    234                         << result(b, k, j, i, d) << " vs " << expected
    235                         << std::endl;
    236             }
    237             EigenApprox(result(b, k, j, i, d), expected);
    238           }
    239         }
    240       }
    241     }
    242   }
    243 }
    244 
    245 TEST(EigenPoolingTest, ValidCuboid) {
    246   const int channels = 10;
    247   const int input_planes = 5;
    248   const int input_rows = 5;
    249   const int input_cols = 5;
    250   const int num_batches = 13;
    251   const int patch_rows = 4;
    252   const int patch_cols = 3;
    253   const int patch_planes = 2;
    254   const int output_rows = 2;
    255   const int output_cols = 3;
    256   const int output_planes = 4;
    257 
    258   Tensor<float, 5> input(channels, input_planes, input_rows, input_cols,
    259                          num_batches);
    260   Tensor<float, 5> result(channels, output_planes, output_rows, output_cols,
    261                           num_batches);
    262   input = input.constant(11.0f) + input.random();
    263   result.setRandom();
    264   result = result.constant(-1000.0f);
    265 
    266   // Max pooling using a 4x3x2 window and a stride of 1.
    267   const int stride = 1;
    268   result = CuboidAvgPooling(input, patch_planes, patch_rows, patch_cols, stride,
    269                             stride, stride, PADDING_VALID);
    270 
    271   EXPECT_EQ(result.dimension(0), channels);
    272   EXPECT_EQ(result.dimension(1), output_planes);
    273   EXPECT_EQ(result.dimension(2), output_rows);
    274   EXPECT_EQ(result.dimension(3), output_cols);
    275   EXPECT_EQ(result.dimension(4), num_batches);
    276 
    277   for (int b = 0; b < num_batches; ++b) {
    278     for (int d = 0; d < channels; ++d) {
    279       for (int i = 0; i < output_planes; ++i) {
    280         for (int j = 0; j < output_rows; ++j) {
    281           for (int k = 0; k < output_cols; ++k) {
    282             float expected_sum = 0.0f;
    283             int expected_count = 0;
    284             for (int p = 0; p < patch_planes; ++p) {
    285               for (int r = 0; r < patch_rows; ++r) {
    286                 for (int c = 0; c < patch_cols; ++c) {
    287                   expected_sum += input(d, p + i, r + j, c + k, b);
    288                   expected_count++;
    289                 }
    290               }
    291             }
    292             const float expected = expected_sum / expected_count;
    293             if (result(d, i, j, k, b) != expected) {
    294               std::cout << "at d=" << d << " b=" << b << " i=" << i
    295                         << " j=" << j << " k=" << k << " "
    296                         << result(d, i, j, k, b) << " vs " << expected
    297                         << std::endl;
    298             }
    299             EigenApprox(result(d, i, j, k, b), expected);
    300           }
    301         }
    302       }
    303     }
    304   }
    305 }
    306 
    307 TEST(EigenPoolingTest, ValidCuboidRowMajor) {
    308   const int channels = 10;
    309   const int input_planes = 5;
    310   const int input_rows = 5;
    311   const int input_cols = 5;
    312   const int num_batches = 13;
    313   const int patch_rows = 4;
    314   const int patch_cols = 3;
    315   const int patch_planes = 2;
    316   const int output_rows = 2;
    317   const int output_cols = 3;
    318   const int output_planes = 4;
    319 
    320   Tensor<float, 5, RowMajor> input(num_batches, input_cols, input_rows,
    321                                    input_planes, channels);
    322   Tensor<float, 5, RowMajor> result(num_batches, output_cols, output_rows,
    323                                     output_planes, channels);
    324   input = input.constant(11.0f) + input.random();
    325   result.setRandom();
    326   result = result.constant(-1000.0f);
    327 
    328   // Max pooling using a 4x3x2 window and a stride of 1.
    329   const int stride = 1;
    330   result = CuboidAvgPooling(input, patch_planes, patch_rows, patch_cols, stride,
    331                             stride, stride, PADDING_VALID);
    332 
    333   EXPECT_EQ(result.dimension(4), channels);
    334   EXPECT_EQ(result.dimension(3), output_planes);
    335   EXPECT_EQ(result.dimension(2), output_rows);
    336   EXPECT_EQ(result.dimension(1), output_cols);
    337   EXPECT_EQ(result.dimension(0), num_batches);
    338 
    339   for (int b = 0; b < num_batches; ++b) {
    340     for (int d = 0; d < channels; ++d) {
    341       for (int i = 0; i < output_planes; ++i) {
    342         for (int j = 0; j < output_rows; ++j) {
    343           for (int k = 0; k < output_cols; ++k) {
    344             float expected_sum = 0.0f;
    345             int expected_count = 0;
    346             for (int p = 0; p < patch_planes; ++p) {
    347               for (int r = 0; r < patch_rows; ++r) {
    348                 for (int c = 0; c < patch_cols; ++c) {
    349                   expected_sum += input(b, c + k, r + j, p + i, d);
    350                   expected_count++;
    351                 }
    352               }
    353             }
    354             const float expected = expected_sum / expected_count;
    355             if (result(b, k, j, i, d) != expected) {
    356               std::cout << "at d=" << d << " b=" << b << " i=" << i
    357                         << " j=" << j << " k=" << k << " "
    358                         << result(b, k, j, i, d) << " vs " << expected
    359                         << std::endl;
    360             }
    361             EigenApprox(result(b, k, j, i, d), expected);
    362           }
    363         }
    364       }
    365     }
    366   }
    367 }
    368 
    369 TEST(EigenPoolingTest, SameCuboid) {
    370   const int channels = 10;
    371   const int input_planes = 5;
    372   const int input_rows = 5;
    373   const int input_cols = 5;
    374   const int num_batches = 13;
    375   const int patch_rows = 4;
    376   const int patch_cols = 3;
    377   const int patch_planes = 2;
    378   const int output_rows = input_rows;
    379   const int output_cols = input_cols;
    380   const int output_planes = input_planes;
    381 
    382   Tensor<float, 5> input(channels, input_planes, input_rows, input_cols,
    383                          num_batches);
    384   Tensor<float, 5> result(channels, output_planes, output_rows, output_cols,
    385                           num_batches);
    386   input = input.constant(11.0f) + input.random();
    387   result.setRandom();
    388   result = result.constant(-1000.0f);
    389 
    390   // Max pooling using a 4x3x2 window and a stride of 1.
    391   const int stride = 1;
    392   result = CuboidAvgPooling(input, patch_planes, patch_rows, patch_cols, stride,
    393                             stride, stride, PADDING_SAME);
    394 
    395   EXPECT_EQ(result.dimension(0), channels);
    396   EXPECT_EQ(result.dimension(1), output_planes);
    397   EXPECT_EQ(result.dimension(2), output_rows);
    398   EXPECT_EQ(result.dimension(3), output_cols);
    399   EXPECT_EQ(result.dimension(4), num_batches);
    400 
    401   const int pad_p = output_planes - input_planes + patch_planes - 1;
    402   const int pad_r = output_rows - input_rows + patch_rows - 1;
    403   const int pad_c = output_cols - input_cols + patch_cols - 1;
    404 
    405   // Number of pixels the input is extended with at the lower end in every
    406   // dimension.
    407   const int dp = pad_p / 2;
    408   const int dr = pad_r / 2;
    409   const int dc = pad_c / 2;
    410 
    411   for (int b = 0; b < num_batches; ++b) {
    412     for (int d = 0; d < channels; ++d) {
    413       for (int i = 0; i < output_planes; ++i) {
    414         for (int j = 0; j < output_rows; ++j) {
    415           for (int k = 0; k < output_cols; ++k) {
    416             float expected_sum = 0.0f;
    417             int expected_count = 0;
    418             for (int p = 0; p < patch_planes; ++p) {
    419               for (int r = 0; r < patch_rows; ++r) {
    420                 for (int c = 0; c < patch_cols; ++c) {
    421                   const int in_p = p + i - dp;
    422                   const int in_r = r + j - dr;
    423                   const int in_c = c + k - dc;
    424                   if (in_p >= 0 && in_p < input_planes && in_r >= 0 &&
    425                       in_r < input_rows && in_c >= 0 && in_c < input_cols) {
    426                     expected_sum += input(d, in_p, in_r, in_c, b);
    427                     expected_count++;
    428                   }
    429                 }
    430               }
    431             }
    432             const float expected = expected_sum / expected_count;
    433             if (result(d, i, j, k, b) != expected) {
    434               std::cout << "at d=" << d << " b=" << b << " i=" << i
    435                         << " j=" << j << " k=" << k << " "
    436                         << result(d, i, j, k, b) << " vs " << expected
    437                         << std::endl;
    438             }
    439             EigenApprox(result(d, i, j, k, b), expected);
    440           }
    441         }
    442       }
    443     }
    444   }
    445 }
    446 
    447 TEST(EigenPoolingTest, SameCuboidRowMajor) {
    448   const int channels = 10;
    449   const int input_planes = 5;
    450   const int input_rows = 5;
    451   const int input_cols = 5;
    452   const int num_batches = 13;
    453   const int patch_rows = 4;
    454   const int patch_cols = 3;
    455   const int patch_planes = 2;
    456   const int output_rows = input_rows;
    457   const int output_cols = input_cols;
    458   const int output_planes = input_planes;
    459 
    460   Tensor<float, 5, RowMajor> input(num_batches, input_cols, input_rows,
    461                                    input_planes, channels);
    462   Tensor<float, 5, RowMajor> result(num_batches, output_cols, output_rows,
    463                                     output_planes, channels);
    464   input = input.constant(11.0f) + input.random();
    465   result.setRandom();
    466   result = result.constant(-1000.0f);
    467 
    468   // Max pooling using a 4x3x2 window and a stride of 1.
    469   const int stride = 1;
    470   result = CuboidAvgPooling(input, patch_planes, patch_rows, patch_cols, stride,
    471                             stride, stride, PADDING_SAME);
    472 
    473   EXPECT_EQ(result.dimension(4), channels);
    474   EXPECT_EQ(result.dimension(3), output_planes);
    475   EXPECT_EQ(result.dimension(2), output_rows);
    476   EXPECT_EQ(result.dimension(1), output_cols);
    477   EXPECT_EQ(result.dimension(0), num_batches);
    478 
    479   const int pad_p = output_planes - input_planes + patch_planes - 1;
    480   const int pad_r = output_rows - input_rows + patch_rows - 1;
    481   const int pad_c = output_cols - input_cols + patch_cols - 1;
    482 
    483   // Number of pixels the input is extended with at the lower end in every
    484   // dimension.
    485   const int dp = pad_p / 2;
    486   const int dr = pad_r / 2;
    487   const int dc = pad_c / 2;
    488 
    489   for (int b = 0; b < num_batches; ++b) {
    490     for (int d = 0; d < channels; ++d) {
    491       for (int i = 0; i < output_planes; ++i) {
    492         for (int j = 0; j < output_rows; ++j) {
    493           for (int k = 0; k < output_cols; ++k) {
    494             float expected_sum = 0.0f;
    495             int expected_count = 0;
    496             for (int p = 0; p < patch_planes; ++p) {
    497               for (int r = 0; r < patch_rows; ++r) {
    498                 for (int c = 0; c < patch_cols; ++c) {
    499                   const int in_p = p + i - dp;
    500                   const int in_r = r + j - dr;
    501                   const int in_c = c + k - dc;
    502                   if (in_p >= 0 && in_p < input_planes && in_r >= 0 &&
    503                       in_r < input_rows && in_c >= 0 && in_c < input_cols) {
    504                     expected_sum += input(b, in_c, in_r, in_p, d);
    505                     expected_count++;
    506                   }
    507                 }
    508               }
    509             }
    510             const float expected = expected_sum / expected_count;
    511             if (result(b, k, j, i, d) != expected) {
    512               std::cout << "at d=" << d << " b=" << b << " i=" << i
    513                         << " j=" << j << " k=" << k << " "
    514                         << result(b, k, j, i, d) << " vs " << expected
    515                         << std::endl;
    516             }
    517             EigenApprox(result(b, k, j, i, d), expected);
    518           }
    519         }
    520       }
    521     }
    522   }
    523 }
    524 
    525 TEST(EigenPoolingTest, Strided) {
    526   const int depth = 10;
    527   const int input_rows = 5;
    528   const int input_cols = 5;
    529   const int num_batches = 13;
    530   const int patch_rows = 3;
    531   const int patch_cols = 3;
    532   const int output_rows = 2;
    533   const int output_cols = 2;
    534 
    535   Tensor<float, 4> input(depth, input_rows, input_cols, num_batches);
    536   Tensor<float, 4> result(depth, output_rows, output_cols, num_batches);
    537   input = input.constant(11.0f) + input.random();
    538   result.setRandom();
    539 
    540   // Max pooling using a 3x3 window and a stride of 2.
    541   int stride = 2;
    542   result = SpatialMaxPooling(input, patch_rows, patch_cols, stride, stride,
    543                              PADDING_VALID);
    544 
    545   EXPECT_EQ(result.dimension(0), depth);
    546   EXPECT_EQ(result.dimension(1), output_rows);
    547   EXPECT_EQ(result.dimension(2), output_cols);
    548   EXPECT_EQ(result.dimension(3), num_batches);
    549 
    550   for (int b = 0; b < num_batches; ++b) {
    551     for (int d = 0; d < depth; ++d) {
    552       for (int i = 0; i < output_rows; ++i) {
    553         for (int j = 0; j < output_cols; ++j) {
    554           float expected = -10000.f;
    555           for (int r = 0; r < patch_rows; ++r) {
    556             for (int c = 0; c < patch_cols; ++c) {
    557               expected = (std::max)(
    558                   expected, input(d, r + stride * i, c + stride * j, b));
    559             }
    560           }
    561           if (result(d, i, j, b) != expected) {
    562             std::cout << "at d=" << d << " b=" << b << " i=" << i << " j=" << j
    563                       << " " << result(d, i, j, b) << " vs " << expected
    564                       << std::endl;
    565           }
    566           EigenApprox(result(d, i, j, b), expected);
    567         }
    568       }
    569     }
    570   }
    571 }
    572 
    573 TEST(EigenPoolingTest, StridedRowMajor) {
    574   const int depth = 10;
    575   const int input_rows = 5;
    576   const int input_cols = 5;
    577   const int num_batches = 13;
    578   const int patch_rows = 3;
    579   const int patch_cols = 3;
    580   const int output_rows = 2;
    581   const int output_cols = 2;
    582 
    583   Tensor<float, 4, RowMajor> input(num_batches, input_cols, input_rows, depth);
    584   Tensor<float, 4, RowMajor> result(num_batches, output_cols, output_rows,
    585                                     depth);
    586   input = input.constant(11.0f) + input.random();
    587   result.setRandom();
    588 
    589   // Max pooling using a 3x3 window and a stride of 2.
    590   int stride = 2;
    591   result = SpatialMaxPooling(input, patch_rows, patch_cols, stride, stride,
    592                              PADDING_VALID);
    593 
    594   EXPECT_EQ(result.dimension(3), depth);
    595   EXPECT_EQ(result.dimension(2), output_rows);
    596   EXPECT_EQ(result.dimension(1), output_cols);
    597   EXPECT_EQ(result.dimension(0), num_batches);
    598 
    599   for (int b = 0; b < num_batches; ++b) {
    600     for (int d = 0; d < depth; ++d) {
    601       for (int i = 0; i < output_rows; ++i) {
    602         for (int j = 0; j < output_cols; ++j) {
    603           float expected = -10000.f;
    604           for (int r = 0; r < patch_rows; ++r) {
    605             for (int c = 0; c < patch_cols; ++c) {
    606               expected = (std::max)(
    607                   expected, input(b, c + stride * j, r + stride * i, d));
    608             }
    609           }
    610           if (result(b, j, i, d) != expected) {
    611             std::cout << "at d=" << d << " b=" << b << " i=" << i << " j=" << j
    612                       << " " << result(b, j, i, d) << " vs " << expected
    613                       << std::endl;
    614           }
    615           EigenApprox(result(b, j, i, d), expected);
    616         }
    617       }
    618     }
    619   }
    620 }
    621 
    622 TEST(EigenPoolingTest, StridedCuboid) {
    623   const int channels = 10;
    624   const int input_planes = 5;
    625   const int input_rows = 5;
    626   const int input_cols = 5;
    627   const int num_batches = 13;
    628   const int patch_planes = 3;
    629   const int patch_rows = 3;
    630   const int patch_cols = 3;
    631   const int output_planes = 2;
    632   const int output_rows = 2;
    633   const int output_cols = 2;
    634 
    635   Tensor<float, 5> input(channels, input_planes, input_rows, input_cols,
    636                          num_batches);
    637   Tensor<float, 5> result(channels, output_planes, output_rows, output_cols,
    638                           num_batches);
    639   input = input.constant(11.0f) + input.random();
    640   result.setRandom();
    641 
    642   // Max pooling using a 3x3x3 window and a stride of 2.
    643   int stride = 2;
    644   result = CuboidMaxPooling(input, patch_planes, patch_rows, patch_cols, stride,
    645                             stride, stride, PADDING_VALID);
    646 
    647   EXPECT_EQ(result.dimension(0), channels);
    648   EXPECT_EQ(result.dimension(1), output_planes);
    649   EXPECT_EQ(result.dimension(2), output_rows);
    650   EXPECT_EQ(result.dimension(3), output_cols);
    651   EXPECT_EQ(result.dimension(4), num_batches);
    652 
    653   for (int b = 0; b < num_batches; ++b) {
    654     for (int d = 0; d < channels; ++d) {
    655       for (int i = 0; i < output_planes; ++i) {
    656         for (int j = 0; j < output_rows; ++j) {
    657           for (int k = 0; k < output_cols; ++k) {
    658             float expected = -10000.f;
    659             for (int p = 0; p < patch_planes; ++p) {
    660               for (int r = 0; r < patch_rows; ++r) {
    661                 for (int c = 0; c < patch_cols; ++c) {
    662                   expected = (std::max)(expected,
    663                                         input(d, p + stride * i, r + stride * j,
    664                                               c + stride * k, b));
    665                 }
    666               }
    667             }
    668             if (result(d, i, j, k, b) != expected) {
    669               std::cout << "at d=" << d << " b=" << b << " i=" << i
    670                         << " j=" << j << " " << k << " "
    671                         << result(d, i, j, k, b) << " vs " << expected
    672                         << std::endl;
    673             }
    674             EigenApprox(result(d, i, j, k, b), expected);
    675           }
    676         }
    677       }
    678     }
    679   }
    680 }
    681 
    682 TEST(EigenPoolingTest, StridedCuboidRowMajor) {
    683   const int channels = 10;
    684   const int input_planes = 5;
    685   const int input_rows = 5;
    686   const int input_cols = 5;
    687   const int num_batches = 13;
    688   const int patch_planes = 3;
    689   const int patch_rows = 3;
    690   const int patch_cols = 3;
    691   const int output_planes = 2;
    692   const int output_rows = 2;
    693   const int output_cols = 2;
    694 
    695   Tensor<float, 5, RowMajor> input(num_batches, input_cols, input_rows,
    696                                    input_planes, channels);
    697   Tensor<float, 5, RowMajor> result(num_batches, output_cols, output_rows,
    698                                     output_planes, channels);
    699   input = input.constant(11.0f) + input.random();
    700   result.setRandom();
    701 
    702   // Max pooling using a 3x3x3 window and a stride of 2.
    703   int stride = 2;
    704   result = CuboidMaxPooling(input, patch_planes, patch_rows, patch_cols, stride,
    705                             stride, stride, PADDING_VALID);
    706 
    707   EXPECT_EQ(result.dimension(4), channels);
    708   EXPECT_EQ(result.dimension(3), output_planes);
    709   EXPECT_EQ(result.dimension(2), output_rows);
    710   EXPECT_EQ(result.dimension(1), output_cols);
    711   EXPECT_EQ(result.dimension(0), num_batches);
    712 
    713   for (int b = 0; b < num_batches; ++b) {
    714     for (int d = 0; d < channels; ++d) {
    715       for (int i = 0; i < output_planes; ++i) {
    716         for (int j = 0; j < output_rows; ++j) {
    717           for (int k = 0; k < output_cols; ++k) {
    718             float expected = -10000.f;
    719             for (int p = 0; p < patch_planes; ++p) {
    720               for (int r = 0; r < patch_rows; ++r) {
    721                 for (int c = 0; c < patch_cols; ++c) {
    722                   expected = (std::max)(expected,
    723                                         input(b, c + stride * k, r + stride * j,
    724                                               p + stride * i, d));
    725                 }
    726               }
    727             }
    728             if (result(b, k, j, i, d) != expected) {
    729               std::cout << "at d=" << d << " b=" << b << " i=" << i
    730                         << " j=" << j << " " << k << " "
    731                         << result(b, k, j, i, d) << " vs " << expected
    732                         << std::endl;
    733             }
    734             EigenApprox(result(b, k, j, i, d), expected);
    735           }
    736         }
    737       }
    738     }
    739   }
    740 }
    741 
    742 }  // namespace Eigen
    743