From cc1f6c94f1fc3b5d5ccbd5aa43e2a08487664f50 Mon Sep 17 00:00:00 2001 From: morgolock Date: Tue, 24 Mar 2020 09:26:48 +0000 Subject: MLCE-166: Add support for extracting indices in NEPoolingLayer 2x2 NCHW * Added initial support for pooling indices * Only supported for NCHW Poolsize 2 Change-Id: I92ce767e64fcc01aae89411064b4cb2be272a1e9 Signed-off-by: morgolock Reviewed-on: https://review.mlplatform.org/c/ml/ComputeLibrary/+/2927 Comments-Addressed: Arm Jenkins Reviewed-by: Georgios Pinitas Reviewed-by: Sang-Hoon Park Tested-by: Arm Jenkins --- tests/validation/NEON/PoolingLayer.cpp | 19 +++++++++++ tests/validation/fixtures/PoolingLayerFixture.h | 42 ++++++++++++++++++------- tests/validation/reference/PoolingLayer.cpp | 42 +++++++++++++++---------- tests/validation/reference/PoolingLayer.h | 4 +-- 4 files changed, 76 insertions(+), 31 deletions(-) (limited to 'tests') diff --git a/tests/validation/NEON/PoolingLayer.cpp b/tests/validation/NEON/PoolingLayer.cpp index 1012320b0d..a5876dcd0a 100644 --- a/tests/validation/NEON/PoolingLayer.cpp +++ b/tests/validation/NEON/PoolingLayer.cpp @@ -111,14 +111,33 @@ DATA_TEST_CASE(Validate, framework::DatasetMode::ALL, zip(zip(zip( // clang-format on // *INDENT-ON* +template +using NEPoolingLayerIndicesFixture = PoolingLayerIndicesValidationFixture; + template using NEPoolingLayerFixture = PoolingLayerValidationFixture; template using NESpecialPoolingLayerFixture = SpecialPoolingLayerValidationFixture; +const auto PoolingLayerIndicesDatasetFPSmall = combine(combine(combine(framework::dataset::make("PoolType", { PoolingType::MAX }), framework::dataset::make("PoolingSize", { Size2D(2, 2) })), + framework::dataset::make("PadStride", { PadStrideInfo(1, 1, 0, 0), PadStrideInfo(2, 1, 0, 0) })), + framework::dataset::make("ExcludePadding", { true, false })); + TEST_SUITE(Float) TEST_SUITE(FP32) +FIXTURE_DATA_TEST_CASE(RunIndices, NEPoolingLayerIndicesFixture, framework::DatasetMode::PRECOMMIT, combine(combine(datasets::SmallShapes(), combine(PoolingLayerIndicesDatasetFPSmall, + framework::dataset::make("DataType", + DataType::F32))), + framework::dataset::make("DataLayout", { DataLayout::NCHW }) + + )) +{ + // Validate output + validate(Accessor(_target), _reference, tolerance_f32); + validate(Accessor(_target_indices), _ref_indices); +} + FIXTURE_DATA_TEST_CASE(RunSpecial, NESpecialPoolingLayerFixture, framework::DatasetMode::ALL, datasets::PoolingLayerDatasetSpecial() * framework::dataset::make("DataType", DataType::F32)) { // Validate output diff --git a/tests/validation/fixtures/PoolingLayerFixture.h b/tests/validation/fixtures/PoolingLayerFixture.h index ec186564b7..7f2d7ac225 100644 --- a/tests/validation/fixtures/PoolingLayerFixture.h +++ b/tests/validation/fixtures/PoolingLayerFixture.h @@ -34,7 +34,6 @@ #include "tests/framework/Asserts.h" #include "tests/framework/Fixture.h" #include "tests/validation/reference/PoolingLayer.h" - #include namespace arm_compute @@ -48,7 +47,7 @@ class PoolingLayerValidationGenericFixture : public framework::Fixture { public: template - void setup(TensorShape shape, PoolingLayerInfo pool_info, DataType data_type, DataLayout data_layout) + void setup(TensorShape shape, PoolingLayerInfo pool_info, DataType data_type, DataLayout data_layout, bool indices = false) { std::mt19937 gen(library->seed()); std::uniform_int_distribution<> offset_dis(0, 20); @@ -59,8 +58,8 @@ public: const QuantizationInfo output_qinfo(scale, scale_out); _pool_info = pool_info; - _target = compute_target(shape, pool_info, data_type, data_layout, input_qinfo, output_qinfo); - _reference = compute_reference(shape, pool_info, data_type, input_qinfo, output_qinfo); + _target = compute_target(shape, pool_info, data_type, data_layout, input_qinfo, output_qinfo, indices); + _reference = compute_reference(shape, pool_info, data_type, input_qinfo, output_qinfo, indices); } protected: @@ -79,7 +78,9 @@ protected: } TensorType compute_target(TensorShape shape, PoolingLayerInfo info, - DataType data_type, DataLayout data_layout, QuantizationInfo input_qinfo, QuantizationInfo output_qinfo) + DataType data_type, DataLayout data_layout, + QuantizationInfo input_qinfo, QuantizationInfo output_qinfo, + bool indices) { // Change shape in case of NHWC. if(data_layout == DataLayout::NHWC) @@ -91,20 +92,24 @@ protected: TensorType src = create_tensor(shape, data_type, 1, input_qinfo, data_layout); const TensorShape dst_shape = misc::shape_calculator::compute_pool_shape(*(src.info()), info); TensorType dst = create_tensor(dst_shape, data_type, 1, output_qinfo, data_layout); + _target_indices = create_tensor(dst_shape, DataType::U32, 1); // Create and configure function FunctionType pool_layer; - pool_layer.configure(&src, &dst, info); + pool_layer.configure(&src, &dst, info, (indices) ? &_target_indices : nullptr); ARM_COMPUTE_EXPECT(src.info()->is_resizable(), framework::LogLevel::ERRORS); ARM_COMPUTE_EXPECT(dst.info()->is_resizable(), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(_target_indices.info()->is_resizable(), framework::LogLevel::ERRORS); // Allocate tensors src.allocator()->allocate(); dst.allocator()->allocate(); + _target_indices.allocator()->allocate(); ARM_COMPUTE_EXPECT(!src.info()->is_resizable(), framework::LogLevel::ERRORS); ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(!_target_indices.info()->is_resizable(), framework::LogLevel::ERRORS); // Fill tensors fill(AccessorType(src)); @@ -115,20 +120,33 @@ protected: return dst; } - SimpleTensor compute_reference(const TensorShape &shape, PoolingLayerInfo info, DataType data_type, QuantizationInfo input_qinfo, QuantizationInfo output_qinfo) + SimpleTensor compute_reference(const TensorShape &shape, PoolingLayerInfo info, DataType data_type, + QuantizationInfo input_qinfo, QuantizationInfo output_qinfo, bool indices) { // Create reference SimpleTensor src{ shape, data_type, 1, input_qinfo }; - // Fill reference fill(src); - return reference::pooling_layer(src, info, output_qinfo); + return reference::pooling_layer(src, info, output_qinfo, indices ? &_ref_indices : nullptr); } - TensorType _target{}; - SimpleTensor _reference{}; - PoolingLayerInfo _pool_info{}; + TensorType _target{}; + SimpleTensor _reference{}; + PoolingLayerInfo _pool_info{}; + TensorType _target_indices{}; + SimpleTensor _ref_indices{}; +}; +template +class PoolingLayerIndicesValidationFixture : public PoolingLayerValidationGenericFixture +{ +public: + template + void setup(TensorShape shape, PoolingType pool_type, Size2D pool_size, PadStrideInfo pad_stride_info, bool exclude_padding, DataType data_type, DataLayout data_layout) + { + PoolingLayerValidationGenericFixture::setup(shape, PoolingLayerInfo(pool_type, pool_size, data_layout, pad_stride_info, exclude_padding), + data_type, data_layout, true); + } }; template diff --git a/tests/validation/reference/PoolingLayer.cpp b/tests/validation/reference/PoolingLayer.cpp index ed2eb2c7ec..1a1aebd1b4 100644 --- a/tests/validation/reference/PoolingLayer.cpp +++ b/tests/validation/reference/PoolingLayer.cpp @@ -38,13 +38,15 @@ namespace reference using namespace arm_compute::misc::shape_calculator; template ::value, int>::type> -SimpleTensor pooling_layer_internal(const SimpleTensor &src, const PoolingLayerInfo &info) +SimpleTensor pooling_layer_internal(const SimpleTensor &src, const PoolingLayerInfo &info, SimpleTensor *indices) { ARM_COMPUTE_ERROR_ON(info.is_global_pooling && (src.shape().x() != src.shape().y())); - // Create reference SimpleTensor dst{ compute_pool_shape(TensorInfo(src.shape(), 1, src.data_type()), info), src.data_type(), 1 }; - + if(indices) + { + *indices = SimpleTensor { compute_pool_shape(TensorInfo(src.shape(), 1, src.data_type()), info), DataType::U32, 1 }; + } const int pool_size_x = info.is_global_pooling ? src.shape().x() : info.pool_size.width; const int pool_size_y = info.is_global_pooling ? src.shape().y() : info.pool_size.height; PoolingType type = info.pool_type; @@ -79,6 +81,7 @@ SimpleTensor pooling_layer_internal(const SimpleTensor &src, const Pooling hstart = std::max(hstart, 0); auto max_val = std::numeric_limits::lowest(); + int max_index{ 0 }; for(int y = hstart; y < hend; ++y) { for(int x = wstart; x < wend; ++x) @@ -86,12 +89,17 @@ SimpleTensor pooling_layer_internal(const SimpleTensor &src, const Pooling const auto val = static_cast(src[r * h_src * w_src + y * w_src + x]); if(val > max_val) { - max_val = val; + max_val = val; + max_index = coord2index(src.shape(), Coordinates(x, y, r)); } } } dst[r * h_dst * w_dst + h * w_dst + w] = static_cast(max_val); + if(indices) + { + (*indices)[r * h_dst * w_dst + h * w_dst + w] = max_index; + } } } } @@ -151,48 +159,48 @@ SimpleTensor pooling_layer_internal(const SimpleTensor &src, const Pooling return dst; } -template SimpleTensor pooling_layer_internal(const SimpleTensor &src, const PoolingLayerInfo &info); -template SimpleTensor pooling_layer_internal(const SimpleTensor &src, const PoolingLayerInfo &info); -template SimpleTensor pooling_layer_internal(const SimpleTensor &src, const PoolingLayerInfo &info); +template SimpleTensor pooling_layer_internal(const SimpleTensor &src, const PoolingLayerInfo &info, SimpleTensor *indices); +template SimpleTensor pooling_layer_internal(const SimpleTensor &src, const PoolingLayerInfo &info, SimpleTensor *indices); +template SimpleTensor pooling_layer_internal(const SimpleTensor &src, const PoolingLayerInfo &info, SimpleTensor *indices); template -SimpleTensor pooling_layer(const SimpleTensor &src, const PoolingLayerInfo &info, const QuantizationInfo &output_qinfo) +SimpleTensor pooling_layer(const SimpleTensor &src, const PoolingLayerInfo &info, const QuantizationInfo &output_qinfo, SimpleTensor *indices) { ARM_COMPUTE_UNUSED(output_qinfo); - return pooling_layer_internal(src, info); + return pooling_layer_internal(src, info, indices); } template <> -SimpleTensor pooling_layer(const SimpleTensor &src, const PoolingLayerInfo &info, const QuantizationInfo &output_qinfo) +SimpleTensor pooling_layer(const SimpleTensor &src, const PoolingLayerInfo &info, const QuantizationInfo &output_qinfo, SimpleTensor *indices) { SimpleTensor src_tmp = convert_from_asymmetric(src); - SimpleTensor dst_tmp = pooling_layer_internal(src_tmp, info); + SimpleTensor dst_tmp = pooling_layer_internal(src_tmp, info, indices); SimpleTensor dst = convert_to_asymmetric(dst_tmp, output_qinfo); return dst; } template <> -SimpleTensor pooling_layer(const SimpleTensor &src, const PoolingLayerInfo &info, const QuantizationInfo &output_qinfo) +SimpleTensor pooling_layer(const SimpleTensor &src, const PoolingLayerInfo &info, const QuantizationInfo &output_qinfo, SimpleTensor *indices) { SimpleTensor src_tmp = convert_from_asymmetric(src); - SimpleTensor dst_tmp = pooling_layer_internal(src_tmp, info); + SimpleTensor dst_tmp = pooling_layer_internal(src_tmp, info, indices); SimpleTensor dst = convert_to_asymmetric(dst_tmp, output_qinfo); return dst; } template <> -SimpleTensor pooling_layer(const SimpleTensor &src, const PoolingLayerInfo &info, const QuantizationInfo &output_qinfo) +SimpleTensor pooling_layer(const SimpleTensor &src, const PoolingLayerInfo &info, const QuantizationInfo &output_qinfo, SimpleTensor *indices) { ARM_COMPUTE_UNUSED(output_qinfo); if(src.data_type() == DataType::F16 && info.fp_mixed_precision) { - return pooling_layer_internal(src, info); + return pooling_layer_internal(src, info, indices); } - return pooling_layer_internal(src, info); + return pooling_layer_internal(src, info, indices); } -template SimpleTensor pooling_layer(const SimpleTensor &src, const PoolingLayerInfo &info, const QuantizationInfo &output_qinfo); +template SimpleTensor pooling_layer(const SimpleTensor &src, const PoolingLayerInfo &info, const QuantizationInfo &output_qinfo, SimpleTensor *indices); } // namespace reference } // namespace validation } // namespace test diff --git a/tests/validation/reference/PoolingLayer.h b/tests/validation/reference/PoolingLayer.h index 92d97d548e..3ca7f28d5a 100644 --- a/tests/validation/reference/PoolingLayer.h +++ b/tests/validation/reference/PoolingLayer.h @@ -36,9 +36,9 @@ namespace validation namespace reference { template ::value, int>::type = 0> -SimpleTensor pooling_layer_internal(const SimpleTensor &src, const PoolingLayerInfo &info); +SimpleTensor pooling_layer_internal(const SimpleTensor &src, const PoolingLayerInfo &info, SimpleTensor *indices); template -SimpleTensor pooling_layer(const SimpleTensor &src, const PoolingLayerInfo &info, const QuantizationInfo &output_qinfo); +SimpleTensor pooling_layer(const SimpleTensor &src, const PoolingLayerInfo &info, const QuantizationInfo &output_qinfo, SimpleTensor *indices); } // namespace reference } // namespace validation } // namespace test -- cgit v1.2.1