1 // This file is part of Eigen, a lightweight C++ template library 2 // for linear algebra. 3 // 4 // Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog (at) gmail.com> 5 // 6 // This Source Code Form is subject to the terms of the Mozilla 7 // Public License v. 2.0. If a copy of the MPL was not distributed 8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 9 10 #include "main.h" 11 12 #include <Eigen/CXX11/Tensor> 13 14 using Eigen::Tensor; 15 16 void test_simple_patch() 17 { 18 Tensor<float, 4> tensor(2,3,5,7); 19 tensor.setRandom(); 20 Tensor<float, 4, RowMajor> tensor_row_major = tensor.swap_layout(); 21 VERIFY_IS_EQUAL(tensor.dimension(0), tensor_row_major.dimension(3)); 22 VERIFY_IS_EQUAL(tensor.dimension(1), tensor_row_major.dimension(2)); 23 VERIFY_IS_EQUAL(tensor.dimension(2), tensor_row_major.dimension(1)); 24 VERIFY_IS_EQUAL(tensor.dimension(3), tensor_row_major.dimension(0)); 25 26 // Single pixel patch: ColMajor 27 Tensor<float, 5> single_pixel_patch; 28 single_pixel_patch = tensor.extract_image_patches(1, 1); 29 VERIFY_IS_EQUAL(single_pixel_patch.dimension(0), 2); 30 VERIFY_IS_EQUAL(single_pixel_patch.dimension(1), 1); 31 VERIFY_IS_EQUAL(single_pixel_patch.dimension(2), 1); 32 VERIFY_IS_EQUAL(single_pixel_patch.dimension(3), 3*5); 33 VERIFY_IS_EQUAL(single_pixel_patch.dimension(4), 7); 34 35 // Single pixel patch: RowMajor 36 Tensor<float, 5, RowMajor> single_pixel_patch_row_major; 37 single_pixel_patch_row_major = tensor_row_major.extract_image_patches(1, 1); 38 VERIFY_IS_EQUAL(single_pixel_patch_row_major.dimension(0), 7); 39 VERIFY_IS_EQUAL(single_pixel_patch_row_major.dimension(1), 3*5); 40 VERIFY_IS_EQUAL(single_pixel_patch_row_major.dimension(2), 1); 41 VERIFY_IS_EQUAL(single_pixel_patch_row_major.dimension(3), 1); 42 VERIFY_IS_EQUAL(single_pixel_patch_row_major.dimension(4), 2); 43 44 for (int i = 0; i < tensor.size(); ++i) { 45 // ColMajor 46 if (tensor.data()[i] != single_pixel_patch.data()[i]) { 47 std::cout << "Mismatch detected at index " << i << " : " 48 << tensor.data()[i] << " vs " << single_pixel_patch.data()[i] 49 << std::endl; 50 } 51 VERIFY_IS_EQUAL(single_pixel_patch.data()[i], tensor.data()[i]); 52 // RowMajor 53 if (tensor_row_major.data()[i] != single_pixel_patch_row_major.data()[i]) { 54 std::cout << "Mismatch detected at index " << i << " : " 55 << tensor.data()[i] << " vs " 56 << single_pixel_patch_row_major.data()[i] << std::endl; 57 } 58 VERIFY_IS_EQUAL(single_pixel_patch_row_major.data()[i], 59 tensor_row_major.data()[i]); 60 VERIFY_IS_EQUAL(tensor.data()[i], tensor_row_major.data()[i]); 61 VERIFY_IS_EQUAL(single_pixel_patch.data()[i], 62 single_pixel_patch_row_major.data()[i]); 63 } 64 65 // Entire image patch: ColMajor 66 Tensor<float, 5> entire_image_patch; 67 entire_image_patch = tensor.extract_image_patches(3, 5); 68 VERIFY_IS_EQUAL(entire_image_patch.dimension(0), 2); 69 VERIFY_IS_EQUAL(entire_image_patch.dimension(1), 3); 70 VERIFY_IS_EQUAL(entire_image_patch.dimension(2), 5); 71 VERIFY_IS_EQUAL(entire_image_patch.dimension(3), 3*5); 72 VERIFY_IS_EQUAL(entire_image_patch.dimension(4), 7); 73 74 // Entire image patch: RowMajor 75 Tensor<float, 5, RowMajor> entire_image_patch_row_major; 76 entire_image_patch_row_major = tensor_row_major.extract_image_patches(3, 5); 77 VERIFY_IS_EQUAL(entire_image_patch_row_major.dimension(0), 7); 78 VERIFY_IS_EQUAL(entire_image_patch_row_major.dimension(1), 3*5); 79 VERIFY_IS_EQUAL(entire_image_patch_row_major.dimension(2), 5); 80 VERIFY_IS_EQUAL(entire_image_patch_row_major.dimension(3), 3); 81 VERIFY_IS_EQUAL(entire_image_patch_row_major.dimension(4), 2); 82 83 for (int i = 0; i < 3; ++i) { 84 for (int j = 0; j < 5; ++j) { 85 int patchId = i+3*j; 86 for (int r = 0; r < 3; ++r) { 87 for (int c = 0; c < 5; ++c) { 88 for (int d = 0; d < 2; ++d) { 89 for (int b = 0; b < 7; ++b) { 90 float expected = 0.0f; 91 float expected_row_major = 0.0f; 92 if (r-1+i >= 0 && c-2+j >= 0 && r-1+i < 3 && c-2+j < 5) { 93 expected = tensor(d, r-1+i, c-2+j, b); 94 expected_row_major = tensor_row_major(b, c-2+j, r-1+i, d); 95 } 96 // ColMajor 97 if (entire_image_patch(d, r, c, patchId, b) != expected) { 98 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl; 99 } 100 VERIFY_IS_EQUAL(entire_image_patch(d, r, c, patchId, b), expected); 101 // RowMajor 102 if (entire_image_patch_row_major(b, patchId, c, r, d) != 103 expected_row_major) { 104 std::cout << "Mismatch detected at index i=" << i << " j=" << j 105 << " r=" << r << " c=" << c << " d=" << d << " b=" << b 106 << std::endl; 107 } 108 VERIFY_IS_EQUAL(entire_image_patch_row_major(b, patchId, c, r, d), 109 expected_row_major); 110 // Check that ColMajor and RowMajor agree. 111 VERIFY_IS_EQUAL(expected, expected_row_major); 112 } 113 } 114 } 115 } 116 } 117 } 118 119 // 2D patch: ColMajor 120 Tensor<float, 5> twod_patch; 121 twod_patch = tensor.extract_image_patches(2, 2); 122 VERIFY_IS_EQUAL(twod_patch.dimension(0), 2); 123 VERIFY_IS_EQUAL(twod_patch.dimension(1), 2); 124 VERIFY_IS_EQUAL(twod_patch.dimension(2), 2); 125 VERIFY_IS_EQUAL(twod_patch.dimension(3), 3*5); 126 VERIFY_IS_EQUAL(twod_patch.dimension(4), 7); 127 128 // 2D patch: RowMajor 129 Tensor<float, 5, RowMajor> twod_patch_row_major; 130 twod_patch_row_major = tensor_row_major.extract_image_patches(2, 2); 131 VERIFY_IS_EQUAL(twod_patch_row_major.dimension(0), 7); 132 VERIFY_IS_EQUAL(twod_patch_row_major.dimension(1), 3*5); 133 VERIFY_IS_EQUAL(twod_patch_row_major.dimension(2), 2); 134 VERIFY_IS_EQUAL(twod_patch_row_major.dimension(3), 2); 135 VERIFY_IS_EQUAL(twod_patch_row_major.dimension(4), 2); 136 137 138 // Based on the calculation described in TensorTraits.h, padding happens to be 0. 139 int row_padding = 0; 140 int col_padding = 0; 141 int stride = 1; 142 143 for (int i = 0; i < 3; ++i) { 144 for (int j = 0; j < 5; ++j) { 145 int patchId = i+3*j; 146 for (int r = 0; r < 2; ++r) { 147 for (int c = 0; c < 2; ++c) { 148 for (int d = 0; d < 2; ++d) { 149 for (int b = 0; b < 7; ++b) { 150 float expected = 0.0f; 151 float expected_row_major = 0.0f; 152 int row_offset = r*stride + i - row_padding; 153 int col_offset = c*stride + j - col_padding; 154 // ColMajor 155 if (row_offset >= 0 && col_offset >= 0 && row_offset < tensor.dimension(1) && col_offset < tensor.dimension(2)) { 156 expected = tensor(d, row_offset, col_offset, b); 157 } 158 if (twod_patch(d, r, c, patchId, b) != expected) { 159 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl; 160 } 161 VERIFY_IS_EQUAL(twod_patch(d, r, c, patchId, b), expected); 162 163 // RowMajor 164 if (row_offset >= 0 && col_offset >= 0 && row_offset < tensor_row_major.dimension(2) && col_offset < tensor_row_major.dimension(1)) { 165 expected_row_major = tensor_row_major(b, col_offset, row_offset, d); 166 167 } 168 if (twod_patch_row_major(b, patchId, c, r, d) != expected_row_major) { 169 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl; 170 } 171 VERIFY_IS_EQUAL(twod_patch_row_major(b, patchId, c, r, d), expected_row_major); 172 // Check that ColMajor and RowMajor agree. 173 VERIFY_IS_EQUAL(expected, expected_row_major); 174 } 175 } 176 } 177 } 178 } 179 } 180 } 181 182 // Verifies VALID padding (no padding) with incrementing values. 183 void test_patch_padding_valid() 184 { 185 int input_depth = 3; 186 int input_rows = 3; 187 int input_cols = 3; 188 int input_batches = 1; 189 int ksize = 2; // Corresponds to the Rows and Cols for tensor.extract_image_patches<>. 190 int stride = 2; // Only same stride is supported. 191 Tensor<float, 4> tensor(input_depth, input_rows, input_cols, input_batches); 192 // Initializes tensor with incrementing numbers. 193 for (int i = 0; i < tensor.size(); ++i) { 194 tensor.data()[i] = i + 1; 195 } 196 // ColMajor 197 Tensor<float, 5> result = tensor.extract_image_patches(ksize, ksize, stride, stride, 1, 1, PADDING_VALID); 198 199 VERIFY_IS_EQUAL(result.dimension(0), input_depth); // depth 200 VERIFY_IS_EQUAL(result.dimension(1), ksize); // kernel rows 201 VERIFY_IS_EQUAL(result.dimension(2), ksize); // kernel cols 202 VERIFY_IS_EQUAL(result.dimension(3), 1); // number of patches 203 VERIFY_IS_EQUAL(result.dimension(4), input_batches); // number of batches 204 205 // RowMajor 206 Tensor<float, 4, RowMajor> tensor_row_major = tensor.swap_layout(); 207 VERIFY_IS_EQUAL(tensor.dimension(0), tensor_row_major.dimension(3)); 208 VERIFY_IS_EQUAL(tensor.dimension(1), tensor_row_major.dimension(2)); 209 VERIFY_IS_EQUAL(tensor.dimension(2), tensor_row_major.dimension(1)); 210 VERIFY_IS_EQUAL(tensor.dimension(3), tensor_row_major.dimension(0)); 211 212 Tensor<float, 5, RowMajor> result_row_major = tensor_row_major.extract_image_patches(ksize, ksize, stride, stride, 1, 1, PADDING_VALID); 213 VERIFY_IS_EQUAL(result.dimension(0), result_row_major.dimension(4)); 214 VERIFY_IS_EQUAL(result.dimension(1), result_row_major.dimension(3)); 215 VERIFY_IS_EQUAL(result.dimension(2), result_row_major.dimension(2)); 216 VERIFY_IS_EQUAL(result.dimension(3), result_row_major.dimension(1)); 217 VERIFY_IS_EQUAL(result.dimension(4), result_row_major.dimension(0)); 218 219 // No padding is carried out. 220 int row_padding = 0; 221 int col_padding = 0; 222 223 for (int i = 0; (i+stride+ksize-1) < input_rows; i += stride) { // input rows 224 for (int j = 0; (j+stride+ksize-1) < input_cols; j += stride) { // input cols 225 int patchId = i+input_rows*j; 226 for (int r = 0; r < ksize; ++r) { // patch rows 227 for (int c = 0; c < ksize; ++c) { // patch cols 228 for (int d = 0; d < input_depth; ++d) { // depth 229 for (int b = 0; b < input_batches; ++b) { // batch 230 float expected = 0.0f; 231 float expected_row_major = 0.0f; 232 int row_offset = r + i - row_padding; 233 int col_offset = c + j - col_padding; 234 if (row_offset >= 0 && col_offset >= 0 && row_offset < input_rows && col_offset < input_cols) { 235 expected = tensor(d, row_offset, col_offset, b); 236 expected_row_major = tensor_row_major(b, col_offset, row_offset, d); 237 } 238 // ColMajor 239 if (result(d, r, c, patchId, b) != expected) { 240 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl; 241 } 242 VERIFY_IS_EQUAL(result(d, r, c, patchId, b), expected); 243 // RowMajor 244 if (result_row_major(b, patchId, c, r, d) != expected_row_major) { 245 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl; 246 } 247 VERIFY_IS_EQUAL(result_row_major(b, patchId, c, r, d), expected_row_major); 248 // Check that ColMajor and RowMajor agree. 249 VERIFY_IS_EQUAL(expected, expected_row_major); 250 } 251 } 252 } 253 } 254 } 255 } 256 } 257 258 // Verifies VALID padding (no padding) with the same value. 259 void test_patch_padding_valid_same_value() 260 { 261 int input_depth = 1; 262 int input_rows = 5; 263 int input_cols = 5; 264 int input_batches = 2; 265 int ksize = 3; // Corresponds to the Rows and Cols for tensor.extract_image_patches<>. 266 int stride = 2; // Only same stride is supported. 267 // ColMajor 268 Tensor<float, 4> tensor(input_depth, input_rows, input_cols, input_batches); 269 tensor = tensor.constant(11.0f); 270 Tensor<float, 5> result = tensor.extract_image_patches(ksize, ksize, stride, stride, 1, 1, PADDING_VALID); 271 272 VERIFY_IS_EQUAL(result.dimension(0), input_depth); // depth 273 VERIFY_IS_EQUAL(result.dimension(1), ksize); // kernel rows 274 VERIFY_IS_EQUAL(result.dimension(2), ksize); // kernel cols 275 VERIFY_IS_EQUAL(result.dimension(3), 4); // number of patches 276 VERIFY_IS_EQUAL(result.dimension(4), input_batches); // number of batches 277 278 // RowMajor 279 Tensor<float, 4, RowMajor> tensor_row_major = tensor.swap_layout(); 280 VERIFY_IS_EQUAL(tensor.dimension(0), tensor_row_major.dimension(3)); 281 VERIFY_IS_EQUAL(tensor.dimension(1), tensor_row_major.dimension(2)); 282 VERIFY_IS_EQUAL(tensor.dimension(2), tensor_row_major.dimension(1)); 283 VERIFY_IS_EQUAL(tensor.dimension(3), tensor_row_major.dimension(0)); 284 285 Tensor<float, 5, RowMajor> result_row_major = tensor_row_major.extract_image_patches(ksize, ksize, stride, stride, 1, 1, PADDING_VALID); 286 VERIFY_IS_EQUAL(result.dimension(0), result_row_major.dimension(4)); 287 VERIFY_IS_EQUAL(result.dimension(1), result_row_major.dimension(3)); 288 VERIFY_IS_EQUAL(result.dimension(2), result_row_major.dimension(2)); 289 VERIFY_IS_EQUAL(result.dimension(3), result_row_major.dimension(1)); 290 VERIFY_IS_EQUAL(result.dimension(4), result_row_major.dimension(0)); 291 292 // No padding is carried out. 293 int row_padding = 0; 294 int col_padding = 0; 295 296 for (int i = 0; (i+stride+ksize-1) <= input_rows; i += stride) { // input rows 297 for (int j = 0; (j+stride+ksize-1) <= input_cols; j += stride) { // input cols 298 int patchId = i+input_rows*j; 299 for (int r = 0; r < ksize; ++r) { // patch rows 300 for (int c = 0; c < ksize; ++c) { // patch cols 301 for (int d = 0; d < input_depth; ++d) { // depth 302 for (int b = 0; b < input_batches; ++b) { // batch 303 float expected = 0.0f; 304 float expected_row_major = 0.0f; 305 int row_offset = r + i - row_padding; 306 int col_offset = c + j - col_padding; 307 if (row_offset >= 0 && col_offset >= 0 && row_offset < input_rows && col_offset < input_cols) { 308 expected = tensor(d, row_offset, col_offset, b); 309 expected_row_major = tensor_row_major(b, col_offset, row_offset, d); 310 } 311 // ColMajor 312 if (result(d, r, c, patchId, b) != expected) { 313 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl; 314 } 315 VERIFY_IS_EQUAL(result(d, r, c, patchId, b), expected); 316 // RowMajor 317 if (result_row_major(b, patchId, c, r, d) != expected_row_major) { 318 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl; 319 } 320 VERIFY_IS_EQUAL(result_row_major(b, patchId, c, r, d), expected_row_major); 321 // Check that ColMajor and RowMajor agree. 322 VERIFY_IS_EQUAL(expected, expected_row_major); 323 } 324 } 325 } 326 } 327 } 328 } 329 } 330 331 // Verifies SAME padding. 332 void test_patch_padding_same() 333 { 334 int input_depth = 3; 335 int input_rows = 4; 336 int input_cols = 2; 337 int input_batches = 1; 338 int ksize = 2; // Corresponds to the Rows and Cols for tensor.extract_image_patches<>. 339 int stride = 2; // Only same stride is supported. 340 // ColMajor 341 Tensor<float, 4> tensor(input_depth, input_rows, input_cols, input_batches); 342 // Initializes tensor with incrementing numbers. 343 for (int i = 0; i < tensor.size(); ++i) { 344 tensor.data()[i] = i + 1; 345 } 346 Tensor<float, 5> result = tensor.extract_image_patches(ksize, ksize, stride, stride, PADDING_SAME); 347 348 VERIFY_IS_EQUAL(result.dimension(0), input_depth); // depth 349 VERIFY_IS_EQUAL(result.dimension(1), ksize); // kernel rows 350 VERIFY_IS_EQUAL(result.dimension(2), ksize); // kernel cols 351 VERIFY_IS_EQUAL(result.dimension(3), 2); // number of patches 352 VERIFY_IS_EQUAL(result.dimension(4), input_batches); // number of batches 353 354 // RowMajor 355 Tensor<float, 4, RowMajor> tensor_row_major = tensor.swap_layout(); 356 VERIFY_IS_EQUAL(tensor.dimension(0), tensor_row_major.dimension(3)); 357 VERIFY_IS_EQUAL(tensor.dimension(1), tensor_row_major.dimension(2)); 358 VERIFY_IS_EQUAL(tensor.dimension(2), tensor_row_major.dimension(1)); 359 VERIFY_IS_EQUAL(tensor.dimension(3), tensor_row_major.dimension(0)); 360 361 Tensor<float, 5, RowMajor> result_row_major = tensor_row_major.extract_image_patches(ksize, ksize, stride, stride, PADDING_SAME); 362 VERIFY_IS_EQUAL(result.dimension(0), result_row_major.dimension(4)); 363 VERIFY_IS_EQUAL(result.dimension(1), result_row_major.dimension(3)); 364 VERIFY_IS_EQUAL(result.dimension(2), result_row_major.dimension(2)); 365 VERIFY_IS_EQUAL(result.dimension(3), result_row_major.dimension(1)); 366 VERIFY_IS_EQUAL(result.dimension(4), result_row_major.dimension(0)); 367 368 // Based on the calculation described in TensorTraits.h, padding happens to be 369 // 0. 370 int row_padding = 0; 371 int col_padding = 0; 372 373 for (int i = 0; (i+stride+ksize-1) <= input_rows; i += stride) { // input rows 374 for (int j = 0; (j+stride+ksize-1) <= input_cols; j += stride) { // input cols 375 int patchId = i+input_rows*j; 376 for (int r = 0; r < ksize; ++r) { // patch rows 377 for (int c = 0; c < ksize; ++c) { // patch cols 378 for (int d = 0; d < input_depth; ++d) { // depth 379 for (int b = 0; b < input_batches; ++b) { // batch 380 float expected = 0.0f; 381 float expected_row_major = 0.0f; 382 int row_offset = r*stride + i - row_padding; 383 int col_offset = c*stride + j - col_padding; 384 if (row_offset >= 0 && col_offset >= 0 && row_offset < input_rows && col_offset < input_cols) { 385 expected = tensor(d, row_offset, col_offset, b); 386 expected_row_major = tensor_row_major(b, col_offset, row_offset, d); 387 } 388 // ColMajor 389 if (result(d, r, c, patchId, b) != expected) { 390 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl; 391 } 392 VERIFY_IS_EQUAL(result(d, r, c, patchId, b), expected); 393 // RowMajor 394 if (result_row_major(b, patchId, c, r, d) != expected_row_major) { 395 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl; 396 } 397 VERIFY_IS_EQUAL(result_row_major(b, patchId, c, r, d), expected_row_major); 398 // Check that ColMajor and RowMajor agree. 399 VERIFY_IS_EQUAL(expected, expected_row_major); 400 } 401 } 402 } 403 } 404 } 405 } 406 } 407 408 void test_patch_no_extra_dim() 409 { 410 Tensor<float, 3> tensor(2,3,5); 411 tensor.setRandom(); 412 Tensor<float, 3, RowMajor> tensor_row_major = tensor.swap_layout(); 413 VERIFY_IS_EQUAL(tensor.dimension(0), tensor_row_major.dimension(2)); 414 VERIFY_IS_EQUAL(tensor.dimension(1), tensor_row_major.dimension(1)); 415 VERIFY_IS_EQUAL(tensor.dimension(2), tensor_row_major.dimension(0)); 416 417 // Single pixel patch: ColMajor 418 Tensor<float, 4> single_pixel_patch; 419 single_pixel_patch = tensor.extract_image_patches(1, 1); 420 VERIFY_IS_EQUAL(single_pixel_patch.dimension(0), 2); 421 VERIFY_IS_EQUAL(single_pixel_patch.dimension(1), 1); 422 VERIFY_IS_EQUAL(single_pixel_patch.dimension(2), 1); 423 VERIFY_IS_EQUAL(single_pixel_patch.dimension(3), 3*5); 424 425 // Single pixel patch: RowMajor 426 Tensor<float, 4, RowMajor> single_pixel_patch_row_major; 427 single_pixel_patch_row_major = tensor_row_major.extract_image_patches(1, 1); 428 VERIFY_IS_EQUAL(single_pixel_patch_row_major.dimension(0), 3*5); 429 VERIFY_IS_EQUAL(single_pixel_patch_row_major.dimension(1), 1); 430 VERIFY_IS_EQUAL(single_pixel_patch_row_major.dimension(2), 1); 431 VERIFY_IS_EQUAL(single_pixel_patch_row_major.dimension(3), 2); 432 433 for (int i = 0; i < tensor.size(); ++i) { 434 // ColMajor 435 if (tensor.data()[i] != single_pixel_patch.data()[i]) { 436 std::cout << "Mismatch detected at index " << i << " : " << tensor.data()[i] << " vs " << single_pixel_patch.data()[i] << std::endl; 437 } 438 VERIFY_IS_EQUAL(single_pixel_patch.data()[i], tensor.data()[i]); 439 // RowMajor 440 if (tensor_row_major.data()[i] != single_pixel_patch_row_major.data()[i]) { 441 std::cout << "Mismatch detected at index " << i << " : " 442 << tensor.data()[i] << " vs " 443 << single_pixel_patch_row_major.data()[i] << std::endl; 444 } 445 VERIFY_IS_EQUAL(single_pixel_patch_row_major.data()[i], 446 tensor_row_major.data()[i]); 447 VERIFY_IS_EQUAL(tensor.data()[i], tensor_row_major.data()[i]); 448 VERIFY_IS_EQUAL(single_pixel_patch.data()[i], 449 single_pixel_patch_row_major.data()[i]); 450 } 451 452 // Entire image patch: ColMajor 453 Tensor<float, 4> entire_image_patch; 454 entire_image_patch = tensor.extract_image_patches(3, 5); 455 VERIFY_IS_EQUAL(entire_image_patch.dimension(0), 2); 456 VERIFY_IS_EQUAL(entire_image_patch.dimension(1), 3); 457 VERIFY_IS_EQUAL(entire_image_patch.dimension(2), 5); 458 VERIFY_IS_EQUAL(entire_image_patch.dimension(3), 3*5); 459 460 // Entire image patch: RowMajor 461 Tensor<float, 4, RowMajor> entire_image_patch_row_major; 462 entire_image_patch_row_major = tensor_row_major.extract_image_patches(3, 5); 463 VERIFY_IS_EQUAL(entire_image_patch_row_major.dimension(0), 3*5); 464 VERIFY_IS_EQUAL(entire_image_patch_row_major.dimension(1), 5); 465 VERIFY_IS_EQUAL(entire_image_patch_row_major.dimension(2), 3); 466 VERIFY_IS_EQUAL(entire_image_patch_row_major.dimension(3), 2); 467 468 for (int i = 0; i < 3; ++i) { 469 for (int j = 0; j < 5; ++j) { 470 int patchId = i+3*j; 471 for (int r = 0; r < 3; ++r) { 472 for (int c = 0; c < 5; ++c) { 473 for (int d = 0; d < 2; ++d) { 474 float expected = 0.0f; 475 float expected_row_major = 0.0f; 476 if (r-1+i >= 0 && c-2+j >= 0 && r-1+i < 3 && c-2+j < 5) { 477 expected = tensor(d, r-1+i, c-2+j); 478 expected_row_major = tensor_row_major(c-2+j, r-1+i, d); 479 } 480 // ColMajor 481 if (entire_image_patch(d, r, c, patchId) != expected) { 482 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << std::endl; 483 } 484 VERIFY_IS_EQUAL(entire_image_patch(d, r, c, patchId), expected); 485 // RowMajor 486 if (entire_image_patch_row_major(patchId, c, r, d) != 487 expected_row_major) { 488 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << std::endl; 489 } 490 VERIFY_IS_EQUAL(entire_image_patch_row_major(patchId, c, r, d), 491 expected_row_major); 492 // Check that ColMajor and RowMajor agree. 493 VERIFY_IS_EQUAL(expected, expected_row_major); 494 } 495 } 496 } 497 } 498 } 499 500 // 2D patch: ColMajor 501 Tensor<float, 4> twod_patch; 502 twod_patch = tensor.extract_image_patches(2, 2); 503 VERIFY_IS_EQUAL(twod_patch.dimension(0), 2); 504 VERIFY_IS_EQUAL(twod_patch.dimension(1), 2); 505 VERIFY_IS_EQUAL(twod_patch.dimension(2), 2); 506 VERIFY_IS_EQUAL(twod_patch.dimension(3), 3*5); 507 508 // 2D patch: RowMajor 509 Tensor<float, 4, RowMajor> twod_patch_row_major; 510 twod_patch_row_major = tensor_row_major.extract_image_patches(2, 2); 511 VERIFY_IS_EQUAL(twod_patch_row_major.dimension(0), 3*5); 512 VERIFY_IS_EQUAL(twod_patch_row_major.dimension(1), 2); 513 VERIFY_IS_EQUAL(twod_patch_row_major.dimension(2), 2); 514 VERIFY_IS_EQUAL(twod_patch_row_major.dimension(3), 2); 515 516 // Based on the calculation described in TensorTraits.h, padding happens to be 0. 517 int row_padding = 0; 518 int col_padding = 0; 519 int stride = 1; 520 521 for (int i = 0; i < 3; ++i) { 522 for (int j = 0; j < 5; ++j) { 523 int patchId = i+3*j; 524 for (int r = 0; r < 2; ++r) { 525 for (int c = 0; c < 2; ++c) { 526 for (int d = 0; d < 2; ++d) { 527 float expected = 0.0f; 528 float expected_row_major = 0.0f; 529 int row_offset = r*stride + i - row_padding; 530 int col_offset = c*stride + j - col_padding; 531 // ColMajor 532 if (row_offset >= 0 && col_offset >= 0 && row_offset < tensor.dimension(1) && col_offset < tensor.dimension(2)) { 533 expected = tensor(d, row_offset, col_offset); 534 } 535 if (twod_patch(d, r, c, patchId) != expected) { 536 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << std::endl; 537 } 538 VERIFY_IS_EQUAL(twod_patch(d, r, c, patchId), expected); 539 // RowMajor 540 if (row_offset >= 0 && col_offset >= 0 && row_offset < tensor_row_major.dimension(1) && col_offset < tensor_row_major.dimension(0)) { 541 expected_row_major = tensor_row_major(col_offset, row_offset, d); 542 } 543 if (twod_patch_row_major(patchId, c, r, d) != expected_row_major) { 544 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << std::endl; 545 } 546 VERIFY_IS_EQUAL(twod_patch_row_major(patchId, c, r, d), expected_row_major); 547 // Check that ColMajor and RowMajor agree. 548 VERIFY_IS_EQUAL(expected, expected_row_major); 549 } 550 } 551 } 552 } 553 } 554 } 555 556 void test_imagenet_patches() 557 { 558 // Test the code on typical configurations used by the 'imagenet' benchmarks at 559 // https://github.com/soumith/convnet-benchmarks 560 // ColMajor 561 Tensor<float, 4> l_in(3, 128, 128, 16); 562 l_in.setRandom(); 563 Tensor<float, 5> l_out = l_in.extract_image_patches(11, 11); 564 VERIFY_IS_EQUAL(l_out.dimension(0), 3); 565 VERIFY_IS_EQUAL(l_out.dimension(1), 11); 566 VERIFY_IS_EQUAL(l_out.dimension(2), 11); 567 VERIFY_IS_EQUAL(l_out.dimension(3), 128*128); 568 VERIFY_IS_EQUAL(l_out.dimension(4), 16); 569 570 // RowMajor 571 Tensor<float, 5, RowMajor> l_out_row_major = l_in.swap_layout().extract_image_patches(11, 11); 572 VERIFY_IS_EQUAL(l_out_row_major.dimension(0), 16); 573 VERIFY_IS_EQUAL(l_out_row_major.dimension(1), 128*128); 574 VERIFY_IS_EQUAL(l_out_row_major.dimension(2), 11); 575 VERIFY_IS_EQUAL(l_out_row_major.dimension(3), 11); 576 VERIFY_IS_EQUAL(l_out_row_major.dimension(4), 3); 577 578 for (int b = 0; b < 16; ++b) { 579 for (int i = 0; i < 128; ++i) { 580 for (int j = 0; j < 128; ++j) { 581 int patchId = i+128*j; 582 for (int c = 0; c < 11; ++c) { 583 for (int r = 0; r < 11; ++r) { 584 for (int d = 0; d < 3; ++d) { 585 float expected = 0.0f; 586 if (r-5+i >= 0 && c-5+j >= 0 && r-5+i < 128 && c-5+j < 128) { 587 expected = l_in(d, r-5+i, c-5+j, b); 588 } 589 // ColMajor 590 if (l_out(d, r, c, patchId, b) != expected) { 591 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl; 592 } 593 VERIFY_IS_EQUAL(l_out(d, r, c, patchId, b), expected); 594 // RowMajor 595 if (l_out_row_major(b, patchId, c, r, d) != 596 expected) { 597 std::cout << "Mismatch detected at index i=" << i << " j=" << j 598 << " r=" << r << " c=" << c << " d=" << d << " b=" << b 599 << std::endl; 600 } 601 VERIFY_IS_EQUAL(l_out_row_major(b, patchId, c, r, d), 602 expected); 603 } 604 } 605 } 606 } 607 } 608 } 609 610 // ColMajor 611 l_in.resize(16, 64, 64, 32); 612 l_in.setRandom(); 613 l_out = l_in.extract_image_patches(9, 9); 614 VERIFY_IS_EQUAL(l_out.dimension(0), 16); 615 VERIFY_IS_EQUAL(l_out.dimension(1), 9); 616 VERIFY_IS_EQUAL(l_out.dimension(2), 9); 617 VERIFY_IS_EQUAL(l_out.dimension(3), 64*64); 618 VERIFY_IS_EQUAL(l_out.dimension(4), 32); 619 620 // RowMajor 621 l_out_row_major = l_in.swap_layout().extract_image_patches(9, 9); 622 VERIFY_IS_EQUAL(l_out_row_major.dimension(0), 32); 623 VERIFY_IS_EQUAL(l_out_row_major.dimension(1), 64*64); 624 VERIFY_IS_EQUAL(l_out_row_major.dimension(2), 9); 625 VERIFY_IS_EQUAL(l_out_row_major.dimension(3), 9); 626 VERIFY_IS_EQUAL(l_out_row_major.dimension(4), 16); 627 628 for (int b = 0; b < 32; ++b) { 629 for (int i = 0; i < 64; ++i) { 630 for (int j = 0; j < 64; ++j) { 631 int patchId = i+64*j; 632 for (int c = 0; c < 9; ++c) { 633 for (int r = 0; r < 9; ++r) { 634 for (int d = 0; d < 16; ++d) { 635 float expected = 0.0f; 636 if (r-4+i >= 0 && c-4+j >= 0 && r-4+i < 64 && c-4+j < 64) { 637 expected = l_in(d, r-4+i, c-4+j, b); 638 } 639 // ColMajor 640 if (l_out(d, r, c, patchId, b) != expected) { 641 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl; 642 } 643 VERIFY_IS_EQUAL(l_out(d, r, c, patchId, b), expected); 644 // RowMajor 645 if (l_out_row_major(b, patchId, c, r, d) != expected) { 646 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl; 647 } 648 VERIFY_IS_EQUAL(l_out_row_major(b, patchId, c, r, d), expected); 649 } 650 } 651 } 652 } 653 } 654 } 655 656 // ColMajor 657 l_in.resize(32, 16, 16, 32); 658 l_in.setRandom(); 659 l_out = l_in.extract_image_patches(7, 7); 660 VERIFY_IS_EQUAL(l_out.dimension(0), 32); 661 VERIFY_IS_EQUAL(l_out.dimension(1), 7); 662 VERIFY_IS_EQUAL(l_out.dimension(2), 7); 663 VERIFY_IS_EQUAL(l_out.dimension(3), 16*16); 664 VERIFY_IS_EQUAL(l_out.dimension(4), 32); 665 666 // RowMajor 667 l_out_row_major = l_in.swap_layout().extract_image_patches(7, 7); 668 VERIFY_IS_EQUAL(l_out_row_major.dimension(0), 32); 669 VERIFY_IS_EQUAL(l_out_row_major.dimension(1), 16*16); 670 VERIFY_IS_EQUAL(l_out_row_major.dimension(2), 7); 671 VERIFY_IS_EQUAL(l_out_row_major.dimension(3), 7); 672 VERIFY_IS_EQUAL(l_out_row_major.dimension(4), 32); 673 674 for (int b = 0; b < 32; ++b) { 675 for (int i = 0; i < 16; ++i) { 676 for (int j = 0; j < 16; ++j) { 677 int patchId = i+16*j; 678 for (int c = 0; c < 7; ++c) { 679 for (int r = 0; r < 7; ++r) { 680 for (int d = 0; d < 32; ++d) { 681 float expected = 0.0f; 682 if (r-3+i >= 0 && c-3+j >= 0 && r-3+i < 16 && c-3+j < 16) { 683 expected = l_in(d, r-3+i, c-3+j, b); 684 } 685 // ColMajor 686 if (l_out(d, r, c, patchId, b) != expected) { 687 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl; 688 } 689 VERIFY_IS_EQUAL(l_out(d, r, c, patchId, b), expected); 690 // RowMajor 691 if (l_out_row_major(b, patchId, c, r, d) != expected) { 692 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl; 693 } 694 VERIFY_IS_EQUAL(l_out_row_major(b, patchId, c, r, d), expected); 695 } 696 } 697 } 698 } 699 } 700 } 701 702 // ColMajor 703 l_in.resize(64, 13, 13, 32); 704 l_in.setRandom(); 705 l_out = l_in.extract_image_patches(3, 3); 706 VERIFY_IS_EQUAL(l_out.dimension(0), 64); 707 VERIFY_IS_EQUAL(l_out.dimension(1), 3); 708 VERIFY_IS_EQUAL(l_out.dimension(2), 3); 709 VERIFY_IS_EQUAL(l_out.dimension(3), 13*13); 710 VERIFY_IS_EQUAL(l_out.dimension(4), 32); 711 712 // RowMajor 713 l_out_row_major = l_in.swap_layout().extract_image_patches(3, 3); 714 VERIFY_IS_EQUAL(l_out_row_major.dimension(0), 32); 715 VERIFY_IS_EQUAL(l_out_row_major.dimension(1), 13*13); 716 VERIFY_IS_EQUAL(l_out_row_major.dimension(2), 3); 717 VERIFY_IS_EQUAL(l_out_row_major.dimension(3), 3); 718 VERIFY_IS_EQUAL(l_out_row_major.dimension(4), 64); 719 720 for (int b = 0; b < 32; ++b) { 721 for (int i = 0; i < 13; ++i) { 722 for (int j = 0; j < 13; ++j) { 723 int patchId = i+13*j; 724 for (int c = 0; c < 3; ++c) { 725 for (int r = 0; r < 3; ++r) { 726 for (int d = 0; d < 64; ++d) { 727 float expected = 0.0f; 728 if (r-1+i >= 0 && c-1+j >= 0 && r-1+i < 13 && c-1+j < 13) { 729 expected = l_in(d, r-1+i, c-1+j, b); 730 } 731 // ColMajor 732 if (l_out(d, r, c, patchId, b) != expected) { 733 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl; 734 } 735 VERIFY_IS_EQUAL(l_out(d, r, c, patchId, b), expected); 736 // RowMajor 737 if (l_out_row_major(b, patchId, c, r, d) != expected) { 738 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl; 739 } 740 VERIFY_IS_EQUAL(l_out_row_major(b, patchId, c, r, d), expected); 741 } 742 } 743 } 744 } 745 } 746 } 747 } 748 749 void test_cxx11_tensor_image_patch() 750 { 751 CALL_SUBTEST_1(test_simple_patch()); 752 CALL_SUBTEST_2(test_patch_no_extra_dim()); 753 CALL_SUBTEST_3(test_patch_padding_valid()); 754 CALL_SUBTEST_4(test_patch_padding_valid_same_value()); 755 CALL_SUBTEST_5(test_patch_padding_same()); 756 CALL_SUBTEST_6(test_imagenet_patches()); 757 } 758