|
17 | 17 | #include <executorch/test/utils/DeathTest.h> |
18 | 18 | #include <gtest/gtest.h> |
19 | 19 | #include <cmath> |
| 20 | +#include <numeric> |
| 21 | +#include <vector> |
20 | 22 |
|
21 | 23 | using namespace ::testing; |
22 | 24 | using executorch::aten::ArrayRef; |
@@ -291,6 +293,162 @@ TEST_F(OpMeanOutTest, BFloat16LargeDimAccumulatesInFloat) { |
291 | 293 | EXPECT_TENSOR_CLOSE(out, expected); |
292 | 294 | } |
293 | 295 |
|
| 296 | +TEST_F(OpMeanOutTest, ChannelsLastSpatialReduction) { |
| 297 | + TensorFactory<ScalarType::Float> tf; |
| 298 | + std::vector<float> data(120); |
| 299 | + std::iota(data.begin(), data.end(), 0.0f); |
| 300 | + Tensor x = tf.channels_last_like(tf.make({2, 3, 4, 5}, data)); |
| 301 | + Tensor out = tf.zeros({2, 3}); |
| 302 | + const int64_t dims[] = {2, 3}; |
| 303 | + |
| 304 | + op_mean_out(x, ArrayRef<int64_t>(dims), false, {}, out); |
| 305 | + |
| 306 | + EXPECT_TENSOR_CLOSE( |
| 307 | + out, tf.make({2, 3}, {9.5, 29.5, 49.5, 69.5, 89.5, 109.5})); |
| 308 | +} |
| 309 | + |
| 310 | +TEST_F(OpMeanOutTest, ChannelsLastReductionDimensions) { |
| 311 | + TensorFactory<ScalarType::Float> tf; |
| 312 | + std::vector<float> data(120); |
| 313 | + std::iota(data.begin(), data.end(), 0.0f); |
| 314 | + Tensor contiguous = tf.make({2, 3, 4, 5}, data); |
| 315 | + Tensor channels_last = tf.channels_last_like(contiguous); |
| 316 | + |
| 317 | + for (int mask = 0; mask < 16; ++mask) { |
| 318 | + SCOPED_TRACE(mask); |
| 319 | + std::vector<int64_t> dims; |
| 320 | + for (int d = 3; d >= 0; --d) { |
| 321 | + if (mask & (1 << d)) { |
| 322 | + dims.push_back(d - 4); |
| 323 | + } |
| 324 | + } |
| 325 | + const ArrayRef<int64_t> dim_list(dims.data(), dims.size()); |
| 326 | + for (bool keepdim : {false, true}) { |
| 327 | + SCOPED_TRACE(keepdim); |
| 328 | + std::vector<int32_t> sizes; |
| 329 | + for (int d = 0; d < 4; ++d) { |
| 330 | + if (mask == 0 || (mask & (1 << d))) { |
| 331 | + if (keepdim) { |
| 332 | + sizes.push_back(1); |
| 333 | + } |
| 334 | + } else { |
| 335 | + sizes.push_back(contiguous.size(d)); |
| 336 | + } |
| 337 | + } |
| 338 | + Tensor expected = tf.zeros(sizes); |
| 339 | + op_mean_out(contiguous, dim_list, keepdim, {}, expected); |
| 340 | + |
| 341 | + Tensor out = tf.zeros(sizes); |
| 342 | + op_mean_out(channels_last, dim_list, keepdim, {}, out); |
| 343 | + EXPECT_TENSOR_CLOSE(out, expected); |
| 344 | + |
| 345 | + if (keepdim) { |
| 346 | + Tensor expected_channels_last = tf.channels_last_like(expected); |
| 347 | + for (const Tensor& input : {contiguous, channels_last}) { |
| 348 | + Tensor out_channels_last = tf.zeros_channels_last(sizes); |
| 349 | + op_mean_out(input, dim_list, keepdim, {}, out_channels_last); |
| 350 | + EXPECT_TENSOR_CLOSE(out_channels_last, expected_channels_last); |
| 351 | + } |
| 352 | + } |
| 353 | + } |
| 354 | + } |
| 355 | +} |
| 356 | + |
| 357 | +TEST_F(OpMeanOutTest, ChannelsLastAllDimensions) { |
| 358 | + TensorFactory<ScalarType::Float> tf; |
| 359 | + Tensor x = |
| 360 | + tf.channels_last_like(tf.make({1, 2, 2, 2}, {0, 1, 2, 3, 4, 5, 6, 7})); |
| 361 | + Tensor out = tf.zeros({}); |
| 362 | + op_mean_out(x, {}, false, {}, out); |
| 363 | + EXPECT_TENSOR_CLOSE(out, tf.make({}, {3.5})); |
| 364 | + |
| 365 | + op_mean_dtype_out(x, {}, out); |
| 366 | + EXPECT_TENSOR_CLOSE(out, tf.make({}, {3.5})); |
| 367 | + |
| 368 | + Tensor out_keepdim = tf.zeros_channels_last({1, 1, 1, 1}); |
| 369 | + op_mean_out(x, {}, true, {}, out_keepdim); |
| 370 | + EXPECT_TENSOR_CLOSE(out_keepdim, tf.make_channels_last({1, 1, 1, 1}, {3.5})); |
| 371 | +} |
| 372 | + |
| 373 | +TEST_F(OpMeanOutTest, ChannelsLast3d) { |
| 374 | + TensorFactory<ScalarType::Float> tf; |
| 375 | + std::vector<float> data(48); |
| 376 | + std::iota(data.begin(), data.end(), 0.0f); |
| 377 | + Tensor x = tf.make_with_dimorder({2, 3, 2, 2, 2}, data, {0, 2, 3, 4, 1}); |
| 378 | + Tensor out = tf.zeros({2, 3}); |
| 379 | + const int64_t dims[] = {2, 3, 4}; |
| 380 | + op_mean_out(x, ArrayRef<int64_t>(dims), false, {}, out); |
| 381 | + EXPECT_TENSOR_CLOSE( |
| 382 | + out, tf.make({2, 3}, {10.5, 11.5, 12.5, 34.5, 35.5, 36.5})); |
| 383 | + |
| 384 | + Tensor out_keepdim = tf.make_with_dimorder( |
| 385 | + {1, 3, 2, 2, 2}, std::vector<float>(24), {0, 2, 3, 4, 1}); |
| 386 | + op_mean_out(x, ArrayRef<int64_t>{0}, true, {}, out_keepdim); |
| 387 | + std::vector<float> expected_data(24); |
| 388 | + std::iota(expected_data.begin(), expected_data.end(), 12.0f); |
| 389 | + EXPECT_TENSOR_CLOSE( |
| 390 | + out_keepdim, |
| 391 | + tf.make_with_dimorder({1, 3, 2, 2, 2}, expected_data, {0, 2, 3, 4, 1})); |
| 392 | + |
| 393 | + Tensor out_4d = tf.zeros_channels_last({2, 3, 2, 2}); |
| 394 | + op_mean_out(x, ArrayRef<int64_t>{-1}, false, {}, out_4d); |
| 395 | + EXPECT_TENSOR_CLOSE( |
| 396 | + out_4d, |
| 397 | + tf.make_channels_last( |
| 398 | + {2, 3, 2, 2}, {1.5, 2.5, 3.5, 7.5, 8.5, 9.5, 13.5, 14.5, |
| 399 | + 15.5, 19.5, 20.5, 21.5, 25.5, 26.5, 27.5, 31.5, |
| 400 | + 32.5, 33.5, 37.5, 38.5, 39.5, 43.5, 44.5, 45.5})); |
| 401 | +} |
| 402 | + |
| 403 | +TEST_F(OpMeanOutTest, ChannelsLastDTypeConversion) { |
| 404 | + TensorFactory<ScalarType::Int> tf_in; |
| 405 | + TensorFactory<ScalarType::Float> tf_out; |
| 406 | + Tensor x = tf_in.channels_last_like( |
| 407 | + tf_in.make({1, 2, 2, 2}, {0, 1, 2, 3, 4, 5, 6, 7})); |
| 408 | + Tensor out = tf_out.zeros_channels_last({1, 2, 2, 1}); |
| 409 | + op_mean_out(x, ArrayRef<int64_t>{3}, true, ScalarType::Float, out); |
| 410 | + EXPECT_TENSOR_CLOSE( |
| 411 | + out, |
| 412 | + tf_out.channels_last_like( |
| 413 | + tf_out.make({1, 2, 2, 1}, {0.5, 2.5, 4.5, 6.5}))); |
| 414 | +} |
| 415 | + |
| 416 | +TEST_F(OpMeanOutTest, ChannelsLastBFloat16AccumulatesInFloat) { |
| 417 | + TensorFactory<ScalarType::BFloat16> tf; |
| 418 | + Tensor x = tf.full_channels_last({1, 2, 16, 32}, 1); |
| 419 | + Tensor out = tf.zeros({1, 2}); |
| 420 | + const int64_t dims[] = {2, 3}; |
| 421 | + op_mean_out(x, ArrayRef<int64_t>(dims), false, {}, out); |
| 422 | + EXPECT_TENSOR_CLOSE(out, tf.ones({1, 2})); |
| 423 | +} |
| 424 | + |
| 425 | +TEST_F(OpMeanOutTest, ChannelsLastEmptyInput) { |
| 426 | + TensorFactory<ScalarType::Float> tf; |
| 427 | + Tensor x = tf.make_channels_last({2, 3, 0, 4}, {}); |
| 428 | + Tensor out = tf.zeros_channels_last({2, 3, 1, 4}); |
| 429 | + op_mean_out(x, ArrayRef<int64_t>{2}, true, {}, out); |
| 430 | + EXPECT_TENSOR_CLOSE(out, tf.full_channels_last({2, 3, 1, 4}, NAN)); |
| 431 | + |
| 432 | + Tensor empty_out = tf.make_channels_last({2, 3, 0, 1}, {}); |
| 433 | + op_mean_out(x, ArrayRef<int64_t>{3}, true, {}, empty_out); |
| 434 | + EXPECT_TENSOR_CLOSE(empty_out, tf.make_channels_last({2, 3, 0, 1}, {})); |
| 435 | + |
| 436 | + Tensor scalar_out = tf.zeros({}); |
| 437 | + op_mean_dtype_out(x, {}, scalar_out); |
| 438 | + EXPECT_TENSOR_CLOSE(scalar_out, tf.make({}, {NAN})); |
| 439 | +} |
| 440 | + |
| 441 | +TEST_F(OpMeanOutTest, ChannelsLastDynamicOutput) { |
| 442 | + TensorFactory<ScalarType::Float> tf; |
| 443 | + Tensor x = |
| 444 | + tf.channels_last_like(tf.make({1, 2, 2, 2}, {0, 1, 2, 3, 4, 5, 6, 7})); |
| 445 | + Tensor out = tf.zeros_channels_last( |
| 446 | + {2, 3, 4, 5}, torch::executor::TensorShapeDynamism::DYNAMIC_BOUND); |
| 447 | + op_mean_out(x, ArrayRef<int64_t>{3}, true, {}, out); |
| 448 | + EXPECT_TENSOR_CLOSE( |
| 449 | + out, tf.channels_last_like(tf.make({1, 2, 2, 1}, {0.5, 2.5, 4.5, 6.5}))); |
| 450 | +} |
| 451 | + |
294 | 452 | TEST_F(OpMeanOutTest, InvalidDimensionListDies) { |
295 | 453 | ET_SKIP_IF( |
296 | 454 | torch::executor::testing::SupportedFeatures::get()->is_aten, |
|
0 commit comments