From bb123bd6f64444141161562aad06cb406762d47a Mon Sep 17 00:00:00 2001 From: Sang-Hoon Park Date: Fri, 3 Jan 2020 10:57:30 +0000 Subject: MLCE-139 add align_corners parameter to NEScale Change-Id: I497ceb54c5fd8af1af8c529f90fd5a00a45263c8 Signed-off-by: Sang-Hoon Park Reviewed-on: https://review.mlplatform.org/c/2538 Comments-Addressed: Arm Jenkins Tested-by: Arm Jenkins Reviewed-by: Michele Di Giorgio Reviewed-by: Pablo Marquez --- arm_compute/core/NEON/kernels/NEScaleKernel.h | 9 ++- arm_compute/core/Utils.h | 12 ++- arm_compute/runtime/CL/functions/CLScale.h | 10 ++- .../runtime/GLES_COMPUTE/functions/GCScale.h | 6 +- arm_compute/runtime/NEON/functions/NEScale.h | 11 ++- src/core/NEON/kernels/NEScaleKernel.cpp | 52 +++++++++---- src/core/Utils.cpp | 14 +++- src/runtime/CL/functions/CLScale.cpp | 11 ++- src/runtime/GLES_COMPUTE/functions/GCScale.cpp | 6 +- src/runtime/NEON/functions/NEScale.cpp | 23 +++--- tests/validation/CL/Scale.cpp | 86 +++++++++++++--------- tests/validation/GLES_COMPUTE/Scale.cpp | 26 ++++--- tests/validation/NEON/Scale.cpp | 82 ++++++++++++--------- tests/validation/fixtures/ScaleFixture.h | 22 ++++-- tests/validation/reference/Scale.cpp | 28 ++++--- tests/validation/reference/Scale.h | 4 +- 16 files changed, 258 insertions(+), 144 deletions(-) diff --git a/arm_compute/core/NEON/kernels/NEScaleKernel.h b/arm_compute/core/NEON/kernels/NEScaleKernel.h index b720288c5c..e6790371a6 100644 --- a/arm_compute/core/NEON/kernels/NEScaleKernel.h +++ b/arm_compute/core/NEON/kernels/NEScaleKernel.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2019 ARM Limited. + * Copyright (c) 2016-2020 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -67,10 +67,11 @@ public: * @param[in] constant_border_value (Optional) Constant value to use for borders if border_mode is set to CONSTANT and use_padding is set to false. * @param[in] sampling_policy (Optional) Sampling policy used by the interpolation. Defaults to @ref SamplingPolicy::CENTER * @param[in] use_padding (Optional) Is padding in use or not. Defaults to true. + * @param[in] align_corners (Optional) Align corners of input and output, only affecting bilinear policy with TOP_LEFT sampling policy. Defaults to false. */ void configure(const ITensor *input, const ITensor *dx, const ITensor *dy, const ITensor *offsets, ITensor *output, InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value = PixelValue(), - SamplingPolicy sampling_policy = SamplingPolicy::CENTER, bool use_padding = true); + SamplingPolicy sampling_policy = SamplingPolicy::CENTER, bool use_padding = true, bool align_corners = false); /** Static function to check if given info will lead to a valid configuration of @ref NEScaleKernel * * @note dx, dy and offsets have the same dimensions (width and height) of the output tensor @@ -86,10 +87,11 @@ public: * @param[in] constant_border_value (Optional) Constant value to use for borders if border_mode is set to CONSTANT and use_padding is set to false. * @param[in] sampling_policy (Optional) Sampling policy used by the interpolation. Defaults to @ref SamplingPolicy::CENTER * @param[in] use_padding (Optional) Is padding in use or not. Defaults to true. + * @param[in] align_corners (Optional) Align corners of input and output, only affecting bilinear policy with TOP_LEFT sampling policy. Defaults to false. */ static Status validate(const ITensorInfo *input, const ITensorInfo *dx, const ITensorInfo *dy, const ITensorInfo *offsets, ITensorInfo *output, InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value = PixelValue(), - SamplingPolicy sampling_policy = SamplingPolicy::CENTER, bool use_padding = true); + SamplingPolicy sampling_policy = SamplingPolicy::CENTER, bool use_padding = true, bool align_corners = false); // Inherited methods overridden: void run(const Window &window, const ThreadInfo &info) override; @@ -121,6 +123,7 @@ private: PixelValue _constant_border_value; float _sampling_offset; bool _use_padding; + bool _align_corners; }; } // namespace arm_compute #endif /*ARM_COMPUTE_NESCALEKERNEL_H */ diff --git a/arm_compute/core/Utils.h b/arm_compute/core/Utils.h index 0a7eeefded..3a8f6b319f 100644 --- a/arm_compute/core/Utils.h +++ b/arm_compute/core/Utils.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2019 ARM Limited. + * Copyright (c) 2016-2020 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -967,6 +967,16 @@ bool needs_serialized_reduction(ReductionOperation op, DataType dt, unsigned int */ QuantizationInfo get_softmax_output_quantization_info(DataType input_type, bool is_log); +/** Returns resize ratio between input and output with consideration of aligned corners + * + * @param[in] input_size The input size + * @param[in] output_size the output size + * @param[in] align_corners True to align corners of input and output. Defaults to false. + * + * @return The ratio between input and output (i.e., the input size divided by the output size) + */ +float calculate_resize_ratio(size_t input_size, size_t output_size, bool align_corners = false); + /** Convert a tensor format into a string. * * @param[in] format @ref Format to be translated to string. diff --git a/arm_compute/runtime/CL/functions/CLScale.h b/arm_compute/runtime/CL/functions/CLScale.h index 6a638e9f3a..2bef54e352 100644 --- a/arm_compute/runtime/CL/functions/CLScale.h +++ b/arm_compute/runtime/CL/functions/CLScale.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2019 ARM Limited. + * Copyright (c) 2016-2020 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -46,9 +46,11 @@ public: * @param[in] border_mode Strategy to use for borders. * @param[in] constant_border_value (Optional) Constant value to use for borders if border_mode is set to CONSTANT. * @param[in] sampling_policy (Optional) Sampling policy used by the interpolation. Defaults to @ref SamplingPolicy::CENTER + * @param[in] use_padding (Optional) Is padding in use or not. Defaults to true. + * @param[in] align_corners (Optional) Align corners of input and output, only affecting bilinear policy. Defaults to false. */ void configure(ICLTensor *input, ICLTensor *output, InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value = PixelValue(), - SamplingPolicy sampling_policy = SamplingPolicy::CENTER); + SamplingPolicy sampling_policy = SamplingPolicy::CENTER, bool use_padding = true, bool align_corners = false); /** Static function to check if given info will lead to a valid configuration of @ref CLScale * @@ -59,11 +61,13 @@ public: * @param[in] border_mode Strategy to use for borders. * @param[in] constant_border_value (Optional) Constant value to use for borders if border_mode is set to CONSTANT. * @param[in] sampling_policy (Optional) Sampling policy used by the interpolation. Defaults to @ref SamplingPolicy::CENTER + * @param[in] use_padding (Optional) Is padding in use or not. Defaults to true. + * @param[in] align_corners (Optional) Align corners of input and output, only affecting bilinear policy. Defaults to false. * * @return a status */ static Status validate(const ITensorInfo *input, const ITensorInfo *output, InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value = PixelValue(), - SamplingPolicy sampling_policy = SamplingPolicy::CENTER); + SamplingPolicy sampling_policy = SamplingPolicy::CENTER, bool use_padding = true, bool align_corners = false); }; } #endif /*ARM_COMPUTE_CLSCALE_H */ diff --git a/arm_compute/runtime/GLES_COMPUTE/functions/GCScale.h b/arm_compute/runtime/GLES_COMPUTE/functions/GCScale.h index 72d9b3c3e8..d4295d57fa 100644 --- a/arm_compute/runtime/GLES_COMPUTE/functions/GCScale.h +++ b/arm_compute/runtime/GLES_COMPUTE/functions/GCScale.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2019 ARM Limited. + * Copyright (c) 2016-2020 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -46,9 +46,11 @@ public: * @param[in] border_mode Strategy to use for borders. * @param[in] constant_border_value (Optional) Constant value to use for borders if border_mode is set to CONSTANT. * @param[in] sampling_policy (Optional) Sampling policy used by the interpolation. Defaults to @ref SamplingPolicy::CENTER + * @param[in] use_padding (Optional) Is padding in use or not. Defaults to true. + * @param[in] align_corners (Optional) Align corners of input and output, only affecting bilinear policy with TOP_LEFT sampling policy. Defaults to false. */ void configure(IGCTensor *input, IGCTensor *output, InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value = PixelValue(), - SamplingPolicy sampling_policy = SamplingPolicy::CENTER); + SamplingPolicy sampling_policy = SamplingPolicy::CENTER, bool use_padding = true, bool align_corners = false); }; } #endif /*ARM_COMPUTE_GCSCALE_H */ diff --git a/arm_compute/runtime/NEON/functions/NEScale.h b/arm_compute/runtime/NEON/functions/NEScale.h index 69698a47a9..75acb96b55 100644 --- a/arm_compute/runtime/NEON/functions/NEScale.h +++ b/arm_compute/runtime/NEON/functions/NEScale.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2019 ARM Limited. + * Copyright (c) 2016-2020 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -54,9 +54,10 @@ public: * @param[in] constant_border_value (Optional) Constant value to use for borders if border_mode is set to CONSTANT. * @param[in] sampling_policy (Optional) Sampling policy used by the interpolation. Defaults to @ref SamplingPolicy::CENTER * @param[in] use_padding (Optional) Is padding in use or not. Defaults to true. + * @param[in] align_corners (Optional) Align corners of input and output, only affecting bilinear policy with TOP_LEFT sampling policy. Defaults to false. */ void configure(ITensor *input, ITensor *output, InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value = PixelValue(), - SamplingPolicy sampling_policy = SamplingPolicy::CENTER, bool use_padding = true); + SamplingPolicy sampling_policy = SamplingPolicy::CENTER, bool use_padding = true, bool align_corners = false); /** Static function to check if given info will lead to a valid configuration of @ref NEScale * * @param[in] input Source tensor. Data type supported: U8/S16/F16/F32. (Written to only for @p border_mode != UNDEFINED) @@ -66,11 +67,12 @@ public: * @param[in] constant_border_value (Optional) Constant value to use for borders if border_mode is set to CONSTANT. * @param[in] sampling_policy (Optional) Sampling policy used by the interpolation. Defaults to @ref SamplingPolicy::CENTER * @param[in] use_padding (Optional) Is padding in use or not. Defaults to true. + * @param[in] align_corners (Optional) Align corners of input and output, only affecting bilinear policy with TOP_LEFT sampling policy. Defaults to false. * * @return a status */ static Status validate(const ITensorInfo *input, const ITensorInfo *output, InterpolationPolicy policy, BorderMode border_mode, - PixelValue constant_border_value = PixelValue(), SamplingPolicy sampling_policy = SamplingPolicy::CENTER, bool use_padding = true); + PixelValue constant_border_value = PixelValue(), SamplingPolicy sampling_policy = SamplingPolicy::CENTER, bool use_padding = true, bool align_corners = false); // Inherited methods overridden: void run() override; @@ -82,6 +84,7 @@ private: NEScaleKernel _scale_kernel; /**< Kernel to perform the scaling */ NEFillBorderKernel _border_handler; /**< kernel to handle tensor borders */ bool _use_padding; /**< Is padding used on the tensors */ + bool _align_corners; /**< Align corners of input and output */ }; -} +} // namespace arm_compute #endif /*ARM_COMPUTE_NESCALEIMAGE_H */ diff --git a/src/core/NEON/kernels/NEScaleKernel.cpp b/src/core/NEON/kernels/NEScaleKernel.cpp index 1cea8c6714..66408ab94c 100644 --- a/src/core/NEON/kernels/NEScaleKernel.cpp +++ b/src/core/NEON/kernels/NEScaleKernel.cpp @@ -31,6 +31,7 @@ #include "arm_compute/core/ITensor.h" #include "arm_compute/core/NEON/wrapper/wrapper.h" #include "arm_compute/core/TensorInfo.h" +#include "arm_compute/core/Utils.h" #include "arm_compute/core/Validate.h" #include "arm_compute/core/Window.h" #include "arm_compute/core/utils/misc/Utility.h" @@ -45,7 +46,7 @@ namespace { Status validate_arguments(const ITensorInfo *input, const ITensorInfo *dx, const ITensorInfo *dy, const ITensorInfo *offsets, ITensorInfo *output, InterpolationPolicy policy, - BorderMode border_mode, PixelValue constant_border_value, SamplingPolicy sampling_policy, bool use_padding) + BorderMode border_mode, PixelValue constant_border_value, SamplingPolicy sampling_policy, bool use_padding, bool align_corners) { ARM_COMPUTE_RETURN_ERROR_ON_CPU_F16_UNSUPPORTED(input); ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::U8, DataType::S16, DataType::F16, DataType::F32, DataType::QASYMM8); @@ -56,9 +57,13 @@ Status validate_arguments(const ITensorInfo *input, const ITensorInfo *dx, const ARM_COMPUTE_RETURN_ERROR_ON(!use_padding && border_mode != BorderMode::CONSTANT); ARM_COMPUTE_UNUSED(constant_border_value); - const DataLayout data_layout = input->data_layout(); - ARM_COMPUTE_RETURN_ERROR_ON(output->dimension(get_data_layout_dimension_index(data_layout, DataLayoutDimension::WIDTH)) == 0); - ARM_COMPUTE_RETURN_ERROR_ON(output->dimension(get_data_layout_dimension_index(data_layout, DataLayoutDimension::HEIGHT)) == 0); + const DataLayout data_layout = input->data_layout(); + const auto width_index = get_data_layout_dimension_index(data_layout, DataLayoutDimension::WIDTH); + const auto height_index = get_data_layout_dimension_index(data_layout, DataLayoutDimension::HEIGHT); + const auto output_width = output->dimension(width_index); + const auto output_height = output->dimension(height_index); + ARM_COMPUTE_RETURN_ERROR_ON(output_width == 0); + ARM_COMPUTE_RETURN_ERROR_ON(output_height == 0); if(policy == InterpolationPolicy::NEAREST_NEIGHBOR) { @@ -70,6 +75,18 @@ Status validate_arguments(const ITensorInfo *input, const ITensorInfo *dx, const ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(offsets, 1, DataType::S32); ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(dx, 1, DataType::F32); ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(dy, 1, DataType::F32); + + if(align_corners) + { + // For bilinear method with aligned corners, the resize ratio will + // be calculated by (input_size - 1)/(output_size - 1). Belows are + // checking possible overflows. + const auto input_width = input->dimension(width_index); + const auto input_height = input->dimension(height_index); + + ARM_COMPUTE_RETURN_ERROR_ON(input_width == 0 || input_height == 0); + ARM_COMPUTE_RETURN_ERROR_ON((output_width - 1 == 0) || (output_height - 1 == 0)); + } } if(policy == InterpolationPolicy::AREA) @@ -327,7 +344,7 @@ inline void scale_bilinear_nhwc_core(const ITensor *input, const ITensor *offset NEScaleKernel::NEScaleKernel() : _func(nullptr), _offsets(nullptr), _dx(nullptr), _dy(nullptr), _input(nullptr), _output(nullptr), _policy(), _border_size(1), _border_mode(), _constant_border_value(PixelValue()), - _sampling_offset(0), _use_padding(true) + _sampling_offset(0), _use_padding(true), _align_corners(false) { } @@ -338,7 +355,7 @@ BorderSize NEScaleKernel::border_size() const void NEScaleKernel::configure(const ITensor *input, const ITensor *dx, const ITensor *dy, const ITensor *offsets, ITensor *output, InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value, SamplingPolicy sampling_policy, - bool use_padding) + bool use_padding, bool align_corners) { ARM_COMPUTE_ERROR_ON_NULLPTR(input, output); // Perform validation step @@ -347,7 +364,7 @@ void NEScaleKernel::configure(const ITensor *input, const ITensor *dx, const ITe dy != nullptr ? dy->info() : nullptr, offsets != nullptr ? offsets->info() : nullptr, output->info(), - policy, border_mode, constant_border_value, sampling_policy, use_padding)); + policy, border_mode, constant_border_value, sampling_policy, use_padding, align_corners)); // Get data layout and width/height indices const DataLayout data_layout = input->info()->data_layout(); @@ -364,6 +381,9 @@ void NEScaleKernel::configure(const ITensor *input, const ITensor *dx, const ITe _border_mode = border_mode; _constant_border_value = constant_border_value; _use_padding = use_padding; + _align_corners = _policy == InterpolationPolicy::BILINEAR + && sampling_policy == SamplingPolicy::TOP_LEFT + && align_corners; if(sampling_policy == SamplingPolicy::CENTER) { @@ -371,8 +391,8 @@ void NEScaleKernel::configure(const ITensor *input, const ITensor *dx, const ITe } // Compute the ratio between source width/height and destination width/height - const auto wr = static_cast(input->info()->dimension(idx_width)) / static_cast(output->info()->dimension(idx_width)); - const auto hr = static_cast(input->info()->dimension(idx_height)) / static_cast(output->info()->dimension(idx_height)); + const auto wr = arm_compute::calculate_resize_ratio(input->info()->dimension(idx_width), output->info()->dimension(idx_width), _align_corners); + const auto hr = arm_compute::calculate_resize_ratio(input->info()->dimension(idx_height), output->info()->dimension(idx_height), _align_corners); // Add constant border only on top in case of NHWC layout if(data_layout == DataLayout::NHWC) @@ -425,7 +445,7 @@ void NEScaleKernel::scale_nearest_nchw(const Window &window) const size_t input_stride = _input->info()->strides_in_bytes()[1]; // Compute the ratio between source height and destination height - const auto hr = static_cast(_input->info()->dimension(1)) / static_cast(_output->info()->dimension(1)); + const auto hr = arm_compute::calculate_resize_ratio(_input->info()->dimension(1), _output->info()->dimension(1), _align_corners); // Don't increment in X and Y direction for the input tensor // A pointer to the start of this plane is needed as base for the precomputed offsets @@ -622,7 +642,7 @@ void NEScaleKernel::scale_bilinear_nchw(const Window &window) ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(_input, 1, DataType::U8, DataType::QASYMM8, DataType::S16, DataType::F16, DataType::F32); // Compute the ratio between source height and destination height - const auto hr = static_cast(_input->info()->dimension(1)) / static_cast(_output->info()->dimension(1)); + const auto hr = arm_compute::calculate_resize_ratio(_input->info()->dimension(1), _output->info()->dimension(1), _align_corners); // Don't increment in X and Y direction for the input tensor // A pointer to the start of this plane is needed as base for the precomputed offsets @@ -871,8 +891,8 @@ void NEScaleKernel::scale_area_nchw(const Window &window) Iterator in(_input, win_in); Iterator out(_output, window); - const auto wr = static_cast(_input->info()->dimension(0)) / static_cast(_output->info()->dimension(0)); - const auto hr = static_cast(_input->info()->dimension(1)) / static_cast(_output->info()->dimension(1)); + const auto wr = arm_compute::calculate_resize_ratio(_input->info()->dimension(0), _output->info()->dimension(0), _align_corners); + const auto hr = arm_compute::calculate_resize_ratio(_input->info()->dimension(1), _output->info()->dimension(1), _align_corners); const auto w = _input->info()->dimension(0); const auto h = _input->info()->dimension(1); const size_t in_stride = _input->info()->strides_in_bytes()[1]; @@ -919,7 +939,7 @@ void NEScaleKernel::scale_nhwc(const Window &window) const size_t input_stride_c = _input->info()->strides_in_bytes()[idx_channels]; // Compute the ratio between source height and destination height - const auto hr = static_cast(_input->info()->dimension(idx_height)) / static_cast(_output->info()->dimension(idx_height)); + const auto hr = arm_compute::calculate_resize_ratio(_input->info()->dimension(idx_height), _output->info()->dimension(idx_height), _align_corners); // Don't increment in width/height/channels for the input tensor // A pointer to the start of this plane is needed as base for the precomputed offsets @@ -994,7 +1014,7 @@ void NEScaleKernel::scale_nhwc(const Window &window) Status NEScaleKernel::validate(const ITensorInfo *input, const ITensorInfo *dx, const ITensorInfo *dy, const ITensorInfo *offsets, ITensorInfo *output, InterpolationPolicy policy, - BorderMode border_mode, PixelValue constant_border_value, SamplingPolicy sampling_policy, bool use_padding) + BorderMode border_mode, PixelValue constant_border_value, SamplingPolicy sampling_policy, bool use_padding, bool align_corners) { BorderSize border_size(1); if(input->data_layout() == DataLayout::NHWC) @@ -1002,7 +1022,7 @@ Status NEScaleKernel::validate(const ITensorInfo *input, const ITensorInfo *dx, border_size = (border_mode == BorderMode::CONSTANT && policy == InterpolationPolicy::BILINEAR) ? BorderSize(1, 0, 0, 0) : BorderSize(0); } - ARM_COMPUTE_RETURN_ON_ERROR(validate_arguments(input, dx, dy, offsets, output, policy, border_mode, constant_border_value, sampling_policy, use_padding)); + ARM_COMPUTE_RETURN_ON_ERROR(validate_arguments(input, dx, dy, offsets, output, policy, border_mode, constant_border_value, sampling_policy, use_padding, align_corners)); ARM_COMPUTE_RETURN_ON_ERROR(validate_and_configure_window(input->clone().get(), dx != nullptr ? dx->clone().get() : nullptr, dy != nullptr ? dy->clone().get() : nullptr, diff --git a/src/core/Utils.cpp b/src/core/Utils.cpp index 7e7dea5e34..30e5b66540 100644 --- a/src/core/Utils.cpp +++ b/src/core/Utils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2019 ARM Limited. + * Copyright (c) 2016-2020 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -459,6 +459,18 @@ QuantizationInfo arm_compute::get_softmax_output_quantization_info(DataType inpu return QuantizationInfo(1.f / 256, 0); } +float arm_compute::calculate_resize_ratio(size_t input_size, size_t output_size, bool align_corners) +{ + const size_t offset = align_corners ? 1 : 0; + const auto in = input_size - offset; + const auto out = output_size - offset; + + ARM_COMPUTE_ERROR_ON((input_size == 0 || output_size == 0) && offset == 1); + ARM_COMPUTE_ERROR_ON(out == 0); + + return static_cast(in) / static_cast(out); +} + #ifdef ARM_COMPUTE_ASSERTS_ENABLED void arm_compute::print_consecutive_elements(std::ostream &s, DataType dt, const uint8_t *ptr, unsigned int n, int stream_width, const std::string &element_delim) { diff --git a/src/runtime/CL/functions/CLScale.cpp b/src/runtime/CL/functions/CLScale.cpp index f204e644a6..39d992739c 100644 --- a/src/runtime/CL/functions/CLScale.cpp +++ b/src/runtime/CL/functions/CLScale.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018 ARM Limited. + * Copyright (c) 2016-2020 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -32,8 +32,10 @@ using namespace arm_compute; -void CLScale::configure(ICLTensor *input, ICLTensor *output, InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value, SamplingPolicy sampling_policy) +void CLScale::configure(ICLTensor *input, ICLTensor *output, InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value, SamplingPolicy sampling_policy, bool use_padding, + bool align_corners) { + ARM_COMPUTE_UNUSED(use_padding, align_corners); auto k = arm_compute::support::cpp14::make_unique(); k->set_target(CLScheduler::get().target()); k->configure(input, output, policy, border_mode, sampling_policy); @@ -51,8 +53,9 @@ void CLScale::configure(ICLTensor *input, ICLTensor *output, InterpolationPolicy _border_handler.configure(input, _kernel->border_size(), border_mode, constant_border_value); } -Status CLScale::validate(const ITensorInfo *input, const ITensorInfo *output, InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value, SamplingPolicy sampling_policy) +Status CLScale::validate(const ITensorInfo *input, const ITensorInfo *output, InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value, SamplingPolicy sampling_policy, + bool use_padding, bool align_corners) { - ARM_COMPUTE_UNUSED(constant_border_value); + ARM_COMPUTE_UNUSED(constant_border_value, use_padding, align_corners); return CLScaleKernel::validate(input, output, policy, border_mode, sampling_policy); } diff --git a/src/runtime/GLES_COMPUTE/functions/GCScale.cpp b/src/runtime/GLES_COMPUTE/functions/GCScale.cpp index cfe65a30d4..3b56ea120d 100644 --- a/src/runtime/GLES_COMPUTE/functions/GCScale.cpp +++ b/src/runtime/GLES_COMPUTE/functions/GCScale.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017 ARM Limited. + * Copyright (c) 2016-2020 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -31,8 +31,10 @@ using namespace arm_compute; -void GCScale::configure(IGCTensor *input, IGCTensor *output, InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value, SamplingPolicy sampling_policy) +void GCScale::configure(IGCTensor *input, IGCTensor *output, InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value, SamplingPolicy sampling_policy, bool use_padding, + bool align_corners) { + ARM_COMPUTE_UNUSED(use_padding, align_corners); auto k = arm_compute::support::cpp14::make_unique(); k->configure(input, output, policy, border_mode == BorderMode::UNDEFINED, sampling_policy); _kernel = std::move(k); diff --git a/src/runtime/NEON/functions/NEScale.cpp b/src/runtime/NEON/functions/NEScale.cpp index be643b3757..27c057592c 100644 --- a/src/runtime/NEON/functions/NEScale.cpp +++ b/src/runtime/NEON/functions/NEScale.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2019 ARM Limited. + * Copyright (c) 2016-2020 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -98,16 +98,21 @@ NEScale::NEScale() // NOLINT _dy(), _scale_kernel(), _border_handler(), - _use_padding(true) + _use_padding(true), + _align_corners(false) { } -void NEScale::configure(ITensor *input, ITensor *output, InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value, SamplingPolicy sampling_policy, bool use_padding) +void NEScale::configure(ITensor *input, ITensor *output, InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value, SamplingPolicy sampling_policy, bool use_padding, + bool align_corners) { ARM_COMPUTE_ERROR_ON_NULLPTR(input, output); ARM_COMPUTE_ERROR_THROW_ON(NEScale::validate(input->info(), output->info(), policy, border_mode, constant_border_value, sampling_policy, use_padding)); - _use_padding = use_padding; + _use_padding = use_padding; + _align_corners = policy == InterpolationPolicy::BILINEAR + && sampling_policy == SamplingPolicy::TOP_LEFT + && align_corners; // Get data layout and width/height indices const DataLayout data_layout = input->info()->data_layout(); @@ -118,8 +123,8 @@ void NEScale::configure(ITensor *input, ITensor *output, InterpolationPolicy pol const TensorShape shape(output->info()->dimension(idx_width), output->info()->dimension(idx_height)); // Compute the ratio between source width/height and destination width/height - const auto wr = static_cast(input->info()->dimension(idx_width)) / static_cast(output->info()->dimension(idx_width)); - const auto hr = static_cast(input->info()->dimension(idx_height)) / static_cast(output->info()->dimension(idx_height)); + const auto wr = arm_compute::calculate_resize_ratio(input->info()->dimension(idx_width), output->info()->dimension(idx_width), _align_corners); + const auto hr = arm_compute::calculate_resize_ratio(input->info()->dimension(idx_height), output->info()->dimension(idx_height), _align_corners); // Get the element size of the input image const size_t input_element_size = input->info()->element_size(); @@ -155,7 +160,7 @@ void NEScale::configure(ITensor *input, ITensor *output, InterpolationPolicy pol _dx.allocator()->init(tensor_info_dxdy); _dy.allocator()->init(tensor_info_dxdy); - _scale_kernel.configure(input, &_dx, &_dy, &_offsets, output, policy, border_mode, constant_border_value, sampling_policy, use_padding); + _scale_kernel.configure(input, &_dx, &_dy, &_offsets, output, policy, border_mode, constant_border_value, sampling_policy, use_padding, align_corners); // Allocate once the configure methods have been called _offsets.allocator()->allocate(); @@ -181,7 +186,7 @@ void NEScale::configure(ITensor *input, ITensor *output, InterpolationPolicy pol } Status NEScale::validate(const ITensorInfo *input, const ITensorInfo *output, InterpolationPolicy policy, - BorderMode border_mode, PixelValue constant_border_value, SamplingPolicy sampling_policy, bool use_padding) + BorderMode border_mode, PixelValue constant_border_value, SamplingPolicy sampling_policy, bool use_padding, bool align_corners) { ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input, output); ARM_COMPUTE_RETURN_ERROR_ON(sampling_policy != SamplingPolicy::CENTER && sampling_policy != SamplingPolicy::TOP_LEFT); @@ -218,7 +223,7 @@ Status NEScale::validate(const ITensorInfo *input, const ITensorInfo *output, In } ARM_COMPUTE_RETURN_ON_ERROR(NEScaleKernel::validate(input->clone().get(), dx, dy, offsets, output->clone().get(), - policy, border_mode, constant_border_value, sampling_policy, use_padding)); + policy, border_mode, constant_border_value, sampling_policy, use_padding, align_corners)); return Status{}; } diff --git a/tests/validation/CL/Scale.cpp b/tests/validation/CL/Scale.cpp index 93cf26802d..d04e10fe14 100644 --- a/tests/validation/CL/Scale.cpp +++ b/tests/validation/CL/Scale.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 ARM Limited. + * Copyright (c) 2017-2020 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -55,6 +55,12 @@ const auto ScaleDataTypes = framework::dataset::make("DataType", DataType::F32, }); +/** Align corners, this functionality is supported only by NEON */ +const auto AlignCorners = framework::dataset::make("AlignCorners", +{ + false, +}); + /** Tolerance */ constexpr AbsoluteTolerance tolerance_u8(1); constexpr AbsoluteTolerance tolerance_s16(1); @@ -165,12 +171,13 @@ using CLScaleFixture = ScaleValidationFixture; TEST_SUITE(Float) TEST_SUITE(FP32) -FIXTURE_DATA_TEST_CASE(RunSmall, CLScaleFixture, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(datasets::Tiny4DShapes(), framework::dataset::make("DataType", +FIXTURE_DATA_TEST_CASE(RunSmall, CLScaleFixture, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(combine(datasets::Tiny4DShapes(), framework::dataset::make("DataType", DataType::F32)), framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })), - framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), - datasets::BorderModes()), - datasets::SamplingPolicies())) + framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), + datasets::BorderModes()), + datasets::SamplingPolicies()), + AlignCorners)) { //Create valid region TensorInfo src_info(_shape, 1, _data_type); @@ -179,12 +186,13 @@ FIXTURE_DATA_TEST_CASE(RunSmall, CLScaleFixture, framework::DatasetMode:: // Validate output validate(CLAccessor(_target), _reference, valid_region, tolerance_f32, tolerance_num_f32, tolerance_f32_absolute); } -FIXTURE_DATA_TEST_CASE(RunLarge, CLScaleFixture, framework::DatasetMode::NIGHTLY, combine(combine(combine(combine(combine(datasets::LargeShapes(), framework::dataset::make("DataType", +FIXTURE_DATA_TEST_CASE(RunLarge, CLScaleFixture, framework::DatasetMode::NIGHTLY, combine(combine(combine(combine(combine(combine(datasets::LargeShapes(), framework::dataset::make("DataType", DataType::F32)), framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })), framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), - datasets::BorderModes()), - datasets::SamplingPolicies())) + datasets::BorderModes()), + datasets::SamplingPolicies()), + AlignCorners)) { //Create valid region TensorInfo src_info(_shape, 1, _data_type); @@ -195,12 +203,13 @@ FIXTURE_DATA_TEST_CASE(RunLarge, CLScaleFixture, framework::DatasetMode:: } TEST_SUITE_END() // FP32 TEST_SUITE(FP16) -FIXTURE_DATA_TEST_CASE(RunSmall, CLScaleFixture, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(datasets::Tiny4DShapes(), framework::dataset::make("DataType", +FIXTURE_DATA_TEST_CASE(RunSmall, CLScaleFixture, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(combine(datasets::Tiny4DShapes(), framework::dataset::make("DataType", DataType::F16)), framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })), - framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), - datasets::BorderModes()), - datasets::SamplingPolicies())) + framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), + datasets::BorderModes()), + datasets::SamplingPolicies()), + AlignCorners)) { //Create valid region TensorInfo src_info(_shape, 1, _data_type); @@ -209,12 +218,13 @@ FIXTURE_DATA_TEST_CASE(RunSmall, CLScaleFixture, framework::DatasetMode::A // Validate output validate(CLAccessor(_target), _reference, valid_region, tolerance_f16); } -FIXTURE_DATA_TEST_CASE(RunLarge, CLScaleFixture, framework::DatasetMode::NIGHTLY, combine(combine(combine(combine(combine(datasets::LargeShapes(), framework::dataset::make("DataType", +FIXTURE_DATA_TEST_CASE(RunLarge, CLScaleFixture, framework::DatasetMode::NIGHTLY, combine(combine(combine(combine(combine(combine(datasets::LargeShapes(), framework::dataset::make("DataType", DataType::F16)), framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })), - framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), - datasets::BorderModes()), - datasets::SamplingPolicies())) + framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), + datasets::BorderModes()), + datasets::SamplingPolicies()), + AlignCorners)) { //Create valid region TensorInfo src_info(_shape, 1, _data_type); @@ -228,12 +238,13 @@ TEST_SUITE_END() // Float TEST_SUITE(Integer) TEST_SUITE(U8) -FIXTURE_DATA_TEST_CASE(RunSmall, CLScaleFixture, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(datasets::Tiny4DShapes(), framework::dataset::make("DataType", +FIXTURE_DATA_TEST_CASE(RunSmall, CLScaleFixture, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(combine(datasets::Tiny4DShapes(), framework::dataset::make("DataType", DataType::U8)), framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })), - framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), - datasets::BorderModes()), - datasets::SamplingPolicies())) + framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), + datasets::BorderModes()), + datasets::SamplingPolicies()), + AlignCorners)) { //Create valid region TensorInfo src_info(_shape, 1, _data_type); @@ -242,12 +253,13 @@ FIXTURE_DATA_TEST_CASE(RunSmall, CLScaleFixture, framework::DatasetMode // Validate output validate(CLAccessor(_target), _reference, valid_region, tolerance_u8); } -FIXTURE_DATA_TEST_CASE(RunLarge, CLScaleFixture, framework::DatasetMode::NIGHTLY, combine(combine(combine(combine(combine(datasets::LargeShapes(), framework::dataset::make("DataType", +FIXTURE_DATA_TEST_CASE(RunLarge, CLScaleFixture, framework::DatasetMode::NIGHTLY, combine(combine(combine(combine(combine(combine(datasets::LargeShapes(), framework::dataset::make("DataType", DataType::U8)), framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })), framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), - datasets::BorderModes()), - datasets::SamplingPolicies())) + datasets::BorderModes()), + datasets::SamplingPolicies()), + AlignCorners)) { //Create valid region TensorInfo src_info(_shape, 1, _data_type); @@ -258,12 +270,13 @@ FIXTURE_DATA_TEST_CASE(RunLarge, CLScaleFixture, framework::DatasetMode } TEST_SUITE_END() // U8 TEST_SUITE(S16) -FIXTURE_DATA_TEST_CASE(RunSmall, CLScaleFixture, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(datasets::Tiny4DShapes(), framework::dataset::make("DataType", +FIXTURE_DATA_TEST_CASE(RunSmall, CLScaleFixture, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(combine(datasets::Tiny4DShapes(), framework::dataset::make("DataType", DataType::S16)), framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })), - framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), - datasets::BorderModes()), - datasets::SamplingPolicies())) + framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), + datasets::BorderModes()), + datasets::SamplingPolicies()), + AlignCorners)) { //Create valid region TensorInfo src_info(_shape, 1, _data_type); @@ -272,12 +285,13 @@ FIXTURE_DATA_TEST_CASE(RunSmall, CLScaleFixture, framework::DatasetMode // Validate output validate(CLAccessor(_target), _reference, valid_region, tolerance_s16); } -FIXTURE_DATA_TEST_CASE(RunLarge, CLScaleFixture, framework::DatasetMode::NIGHTLY, combine(combine(combine(combine(combine(datasets::LargeShapes(), framework::dataset::make("DataType", +FIXTURE_DATA_TEST_CASE(RunLarge, CLScaleFixture, framework::DatasetMode::NIGHTLY, combine(combine(combine(combine(combine(combine(datasets::LargeShapes(), framework::dataset::make("DataType", DataType::S16)), framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })), framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), - datasets::BorderModes()), - datasets::SamplingPolicies())) + datasets::BorderModes()), + datasets::SamplingPolicies()), + AlignCorners)) { //Create valid region TensorInfo src_info(_shape, 1, _data_type); @@ -293,14 +307,15 @@ template using CLScaleQuantizedFixture = ScaleValidationQuantizedFixture; TEST_SUITE(Quantized) TEST_SUITE(QASYMM8) -FIXTURE_DATA_TEST_CASE(RunSmall, CLScaleQuantizedFixture, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(combine(datasets::Tiny4DShapes(), +FIXTURE_DATA_TEST_CASE(RunSmall, CLScaleQuantizedFixture, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(combine(combine(datasets::Tiny4DShapes(), framework::dataset::make("DataType", DataType::QASYMM8)), framework::dataset::make("QuantizationInfo", { QuantizationInfo(0.5f, -1) })), framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })), framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), - datasets::BorderModes()), - datasets::SamplingPolicies())) + datasets::BorderModes()), + datasets::SamplingPolicies()), + AlignCorners)) { //Create valid region TensorInfo src_info(_shape, 1, _data_type); @@ -309,14 +324,15 @@ FIXTURE_DATA_TEST_CASE(RunSmall, CLScaleQuantizedFixture, framework::Da // Validate output validate(CLAccessor(_target), _reference, valid_region, tolerance_u8); } -FIXTURE_DATA_TEST_CASE(RunLarge, CLScaleQuantizedFixture, framework::DatasetMode::NIGHTLY, combine(combine(combine(combine(combine(combine(datasets::LargeShapes(), +FIXTURE_DATA_TEST_CASE(RunLarge, CLScaleQuantizedFixture, framework::DatasetMode::NIGHTLY, combine(combine(combine(combine(combine(combine(combine(datasets::LargeShapes(), framework::dataset::make("DataType", DataType::QASYMM8)), framework::dataset::make("QuantizationInfo", { QuantizationInfo(0.5f, -1) })), framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })), framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), datasets::BorderModes()), - datasets::SamplingPolicies())) + datasets::SamplingPolicies()), + AlignCorners)) { //Create valid region TensorInfo src_info(_shape, 1, _data_type); diff --git a/tests/validation/GLES_COMPUTE/Scale.cpp b/tests/validation/GLES_COMPUTE/Scale.cpp index 4bfa08f060..e6526b8445 100644 --- a/tests/validation/GLES_COMPUTE/Scale.cpp +++ b/tests/validation/GLES_COMPUTE/Scale.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018 ARM Limited. + * Copyright (c) 2017-2020 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -52,6 +52,12 @@ const auto ScaleDataTypes = framework::dataset::make("DataType", DataType::F16, }); +/** Align corners, this functionality is supported only by NEON */ +const auto AlignCorners = framework::dataset::make("AlignCorners", +{ + false, +}); + /** Tolerance */ RelativeTolerance tolerance_f16(half(0.1)); } // namespace @@ -108,12 +114,13 @@ using GCScaleFixture = ScaleValidationFixture; TEST_SUITE(Float) TEST_SUITE(FP16) -FIXTURE_DATA_TEST_CASE(RunSmall, GCScaleFixture, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(datasets::SmallShapes(), framework::dataset::make("DataType", +FIXTURE_DATA_TEST_CASE(RunSmall, GCScaleFixture, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(combine(datasets::SmallShapes(), framework::dataset::make("DataType", DataType::F16)), framework::dataset::make("DataLayout", { DataLayout::NCHW })), - framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR })), - datasets::BorderModes()), - datasets::SamplingPolicies())) + framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR })), + datasets::BorderModes()), + datasets::SamplingPolicies()), + AlignCorners)) { //Create valid region TensorInfo src_info(_shape, 1, _data_type); @@ -122,12 +129,13 @@ FIXTURE_DATA_TEST_CASE(RunSmall, GCScaleFixture, framework::DatasetMode::A // Validate output validate(GCAccessor(_target), _reference, valid_region, tolerance_f16); } -FIXTURE_DATA_TEST_CASE(RunLarge, GCScaleFixture, framework::DatasetMode::NIGHTLY, combine(combine(combine(combine(combine(datasets::LargeShapes(), framework::dataset::make("DataType", +FIXTURE_DATA_TEST_CASE(RunLarge, GCScaleFixture, framework::DatasetMode::NIGHTLY, combine(combine(combine(combine(combine(combine(datasets::LargeShapes(), framework::dataset::make("DataType", DataType::F16)), framework::dataset::make("DataLayout", { DataLayout::NCHW })), - framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR })), - datasets::BorderModes()), - datasets::SamplingPolicies())) + framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR })), + datasets::BorderModes()), + datasets::SamplingPolicies()), + AlignCorners)) { //Create valid region TensorInfo src_info(_shape, 1, _data_type); diff --git a/tests/validation/NEON/Scale.cpp b/tests/validation/NEON/Scale.cpp index d419c62651..ce1b249f88 100644 --- a/tests/validation/NEON/Scale.cpp +++ b/tests/validation/NEON/Scale.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 ARM Limited. + * Copyright (c) 2017-2020 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -62,6 +62,13 @@ const auto ScaleDataLayouts = framework::dataset::make("DataLayout", DataLayout::NHWC, }); +/** Align corners */ +const auto AlignCorners = framework::dataset::make("AlignCorners", +{ + false, + true, +}); + /** Tolerance */ constexpr AbsoluteTolerance tolerance_u8(1); constexpr AbsoluteTolerance tolerance_s16(1); @@ -200,12 +207,13 @@ using NEScaleQuantizedFixture = ScaleValidationQuantizedFixture, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(datasets::SmallShapes(), framework::dataset::make("DataType", +FIXTURE_DATA_TEST_CASE(RunSmall, NEScaleFixture, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(combine(datasets::SmallShapes(), framework::dataset::make("DataType", DataType::F32)), framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })), - framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), - datasets::BorderModes()), - framework::dataset::make("SamplingPolicy", { SamplingPolicy::TOP_LEFT, SamplingPolicy::CENTER }))) + framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), + datasets::BorderModes()), + framework::dataset::make("SamplingPolicy", { SamplingPolicy::TOP_LEFT, SamplingPolicy::CENTER })), + AlignCorners)) { //Create valid region TensorInfo src_info(_shape, 1, _data_type); @@ -214,12 +222,13 @@ FIXTURE_DATA_TEST_CASE(RunSmall, NEScaleFixture, framework::DatasetMode:: // Validate output validate(Accessor(_target), _reference, valid_region, tolerance_f32, tolerance_num_f32); } -FIXTURE_DATA_TEST_CASE(RunLarge, NEScaleFixture, framework::DatasetMode::NIGHTLY, combine(combine(combine(combine(combine(datasets::LargeShapes(), framework::dataset::make("DataType", +FIXTURE_DATA_TEST_CASE(RunLarge, NEScaleFixture, framework::DatasetMode::NIGHTLY, combine(combine(combine(combine(combine(combine(datasets::LargeShapes(), framework::dataset::make("DataType", DataType::F32)), framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })), framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), - datasets::BorderModes()), - framework::dataset::make("SamplingPolicy", { SamplingPolicy::TOP_LEFT, SamplingPolicy::CENTER }))) + datasets::BorderModes()), + framework::dataset::make("SamplingPolicy", { SamplingPolicy::TOP_LEFT, SamplingPolicy::CENTER })), + AlignCorners)) { //Create valid region TensorInfo src_info(_shape, 1, _data_type); @@ -231,12 +240,13 @@ FIXTURE_DATA_TEST_CASE(RunLarge, NEScaleFixture, framework::DatasetMode:: TEST_SUITE_END() // FP32 #ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC TEST_SUITE(FP16) -FIXTURE_DATA_TEST_CASE(RunSmall, NEScaleFixture, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(datasets::SmallShapes(), framework::dataset::make("DataType", +FIXTURE_DATA_TEST_CASE(RunSmall, NEScaleFixture, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(combine(datasets::SmallShapes(), framework::dataset::make("DataType", DataType::F16)), framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })), - framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), - datasets::BorderModes()), - framework::dataset::make("SamplingPolicy", { SamplingPolicy::TOP_LEFT, SamplingPolicy::CENTER }))) + framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), + datasets::BorderModes()), + framework::dataset::make("SamplingPolicy", { SamplingPolicy::TOP_LEFT, SamplingPolicy::CENTER })), + AlignCorners)) { //Create valid region TensorInfo src_info(_shape, 1, _data_type); @@ -245,12 +255,13 @@ FIXTURE_DATA_TEST_CASE(RunSmall, NEScaleFixture, framework::DatasetMode::A // Validate output validate(Accessor(_target), _reference, valid_region, tolerance_f16); } -FIXTURE_DATA_TEST_CASE(RunLarge, NEScaleFixture, framework::DatasetMode::NIGHTLY, combine(combine(combine(combine(combine(datasets::LargeShapes(), framework::dataset::make("DataType", +FIXTURE_DATA_TEST_CASE(RunLarge, NEScaleFixture, framework::DatasetMode::NIGHTLY, combine(combine(combine(combine(combine(combine(datasets::LargeShapes(), framework::dataset::make("DataType", DataType::F16)), framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })), - framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), - datasets::BorderModes()), - framework::dataset::make("SamplingPolicy", { SamplingPolicy::TOP_LEFT, SamplingPolicy::CENTER }))) + framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), + datasets::BorderModes()), + framework::dataset::make("SamplingPolicy", { SamplingPolicy::TOP_LEFT, SamplingPolicy::CENTER })), + AlignCorners)) { //Create valid region TensorInfo src_info(_shape, 1, _data_type); @@ -265,12 +276,13 @@ TEST_SUITE_END() // Float TEST_SUITE(Integer) TEST_SUITE(U8) -FIXTURE_DATA_TEST_CASE(RunSmall, NEScaleFixture, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(datasets::SmallShapes(), framework::dataset::make("DataType", +FIXTURE_DATA_TEST_CASE(RunSmall, NEScaleFixture, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(combine(datasets::SmallShapes(), framework::dataset::make("DataType", DataType::U8)), framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })), - framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), - datasets::BorderModes()), - framework::dataset::make("SamplingPolicy", { SamplingPolicy::TOP_LEFT, SamplingPolicy::CENTER }))) + framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), + datasets::BorderModes()), + framework::dataset::make("SamplingPolicy", { SamplingPolicy::TOP_LEFT, SamplingPolicy::CENTER })), + AlignCorners)) { //Create valid region TensorInfo src_info(_shape, 1, _data_type); @@ -279,12 +291,13 @@ FIXTURE_DATA_TEST_CASE(RunSmall, NEScaleFixture, framework::DatasetMode // Validate output validate(Accessor(_target), _reference, valid_region, tolerance_u8); } -FIXTURE_DATA_TEST_CASE(RunLarge, NEScaleFixture, framework::DatasetMode::NIGHTLY, combine(combine(combine(combine(combine(datasets::LargeShapes(), framework::dataset::make("DataType", +FIXTURE_DATA_TEST_CASE(RunLarge, NEScaleFixture, framework::DatasetMode::NIGHTLY, combine(combine(combine(combine(combine(combine(datasets::LargeShapes(), framework::dataset::make("DataType", DataType::U8)), framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })), framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), - datasets::BorderModes()), - framework::dataset::make("SamplingPolicy", { SamplingPolicy::TOP_LEFT, SamplingPolicy::CENTER }))) + datasets::BorderModes()), + framework::dataset::make("SamplingPolicy", { SamplingPolicy::TOP_LEFT, SamplingPolicy::CENTER })), + AlignCorners)) { //Create valid region TensorInfo src_info(_shape, 1, _data_type); @@ -295,12 +308,13 @@ FIXTURE_DATA_TEST_CASE(RunLarge, NEScaleFixture, framework::DatasetMode } TEST_SUITE_END() // U8 TEST_SUITE(S16) -FIXTURE_DATA_TEST_CASE(RunSmall, NEScaleFixture, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(datasets::SmallShapes(), framework::dataset::make("DataType", +FIXTURE_DATA_TEST_CASE(RunSmall, NEScaleFixture, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(combine(datasets::SmallShapes(), framework::dataset::make("DataType", DataType::S16)), framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })), - framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), - datasets::BorderModes()), - framework::dataset::make("SamplingPolicy", { SamplingPolicy::TOP_LEFT, SamplingPolicy::CENTER }))) + framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), + datasets::BorderModes()), + framework::dataset::make("SamplingPolicy", { SamplingPolicy::TOP_LEFT, SamplingPolicy::CENTER })), + AlignCorners)) { //Create valid region TensorInfo src_info(_shape, 1, _data_type); @@ -309,12 +323,13 @@ FIXTURE_DATA_TEST_CASE(RunSmall, NEScaleFixture, framework::DatasetMode // Validate output validate(Accessor(_target), _reference, valid_region, tolerance_s16, tolerance_num_s16); } -FIXTURE_DATA_TEST_CASE(RunLarge, NEScaleFixture, framework::DatasetMode::NIGHTLY, combine(combine(combine(combine(combine(datasets::LargeShapes(), framework::dataset::make("DataType", +FIXTURE_DATA_TEST_CASE(RunLarge, NEScaleFixture, framework::DatasetMode::NIGHTLY, combine(combine(combine(combine(combine(combine(datasets::LargeShapes(), framework::dataset::make("DataType", DataType::S16)), framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })), framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), - datasets::BorderModes()), - framework::dataset::make("SamplingPolicy", { SamplingPolicy::TOP_LEFT, SamplingPolicy::CENTER }))) + datasets::BorderModes()), + framework::dataset::make("SamplingPolicy", { SamplingPolicy::TOP_LEFT, SamplingPolicy::CENTER })), + AlignCorners)) { //Create valid region TensorInfo src_info(_shape, 1, _data_type); @@ -328,13 +343,14 @@ TEST_SUITE_END() // Integer TEST_SUITE(Quantized) TEST_SUITE(QASYMM8) -FIXTURE_DATA_TEST_CASE(RunSmall, NEScaleQuantizedFixture, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(combine(datasets::SmallShapes(), +FIXTURE_DATA_TEST_CASE(RunSmall, NEScaleQuantizedFixture, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(combine(combine(datasets::SmallShapes(), framework::dataset::make("DataType", DataType::QASYMM8)), framework::dataset::make("QuantizationInfo", { QuantizationInfo(0.5f, -10) })), framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })), framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), - datasets::BorderModes()), - framework::dataset::make("SamplingPolicy", { SamplingPolicy::TOP_LEFT, SamplingPolicy::CENTER }))) + datasets::BorderModes()), + framework::dataset::make("SamplingPolicy", { SamplingPolicy::TOP_LEFT, SamplingPolicy::CENTER })), + AlignCorners)) { //Create valid region TensorInfo src_info(_shape, 1, _data_type); diff --git a/tests/validation/fixtures/ScaleFixture.h b/tests/validation/fixtures/ScaleFixture.h index 2be02ec4d6..8d851ce574 100644 --- a/tests/validation/fixtures/ScaleFixture.h +++ b/tests/validation/fixtures/ScaleFixture.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018 ARM Limited. + * Copyright (c) 2017-2020 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -45,7 +45,8 @@ class ScaleValidationGenericFixture : public framework::Fixture { public: template - void setup(TensorShape shape, DataType data_type, QuantizationInfo quantization_info, DataLayout data_layout, InterpolationPolicy policy, BorderMode border_mode, SamplingPolicy sampling_policy) + void setup(TensorShape shape, DataType data_type, QuantizationInfo quantization_info, DataLayout data_layout, InterpolationPolicy policy, BorderMode border_mode, SamplingPolicy sampling_policy, + bool align_corners) { constexpr float max_width = 8192.0f; constexpr float max_height = 6384.0f; @@ -56,6 +57,7 @@ public: _sampling_policy = sampling_policy; _data_type = data_type; _quantization_info = quantization_info; + _align_corners = align_corners; std::mt19937 generator(library->seed()); std::uniform_real_distribution distribution_float(0.25, 3); @@ -120,7 +122,7 @@ protected: // Create and configure function FunctionType scale; - scale.configure(&src, &dst, policy, border_mode, constant_border_value, sampling_policy); + scale.configure(&src, &dst, policy, border_mode, constant_border_value, sampling_policy, /* use_padding */ true, _align_corners); ARM_COMPUTE_EXPECT(src.info()->is_resizable(), framework::LogLevel::ERRORS); ARM_COMPUTE_EXPECT(dst.info()->is_resizable(), framework::LogLevel::ERRORS); @@ -150,7 +152,7 @@ protected: // Fill reference fill(src); - return reference::scale(src, scale_x, scale_y, policy, border_mode, constant_border_value, sampling_policy); + return reference::scale(src, scale_x, scale_y, policy, border_mode, constant_border_value, sampling_policy, /* ceil_policy_scale */ false, _align_corners); } TensorType _target{}; @@ -161,6 +163,7 @@ protected: SamplingPolicy _sampling_policy{}; DataType _data_type{}; QuantizationInfo _quantization_info{}; + bool _align_corners{ false }; }; template @@ -168,7 +171,8 @@ class ScaleValidationQuantizedFixture : public ScaleValidationGenericFixture - void setup(TensorShape shape, DataType data_type, QuantizationInfo quantization_info, DataLayout data_layout, InterpolationPolicy policy, BorderMode border_mode, SamplingPolicy sampling_policy) + void setup(TensorShape shape, DataType data_type, QuantizationInfo quantization_info, DataLayout data_layout, InterpolationPolicy policy, BorderMode border_mode, SamplingPolicy sampling_policy, + bool align_corners) { ScaleValidationGenericFixture::setup(shape, data_type, @@ -176,7 +180,8 @@ public: data_layout, policy, border_mode, - sampling_policy); + sampling_policy, + align_corners); } }; template @@ -184,7 +189,7 @@ class ScaleValidationFixture : public ScaleValidationGenericFixture - void setup(TensorShape shape, DataType data_type, DataLayout data_layout, InterpolationPolicy policy, BorderMode border_mode, SamplingPolicy sampling_policy) + void setup(TensorShape shape, DataType data_type, DataLayout data_layout, InterpolationPolicy policy, BorderMode border_mode, SamplingPolicy sampling_policy, bool align_corners) { ScaleValidationGenericFixture::setup(shape, data_type, @@ -192,7 +197,8 @@ public: data_layout, policy, border_mode, - sampling_policy); + sampling_policy, + align_corners); } }; } // namespace validation diff --git a/tests/validation/reference/Scale.cpp b/tests/validation/reference/Scale.cpp index 7962459ce8..4e5189ee66 100644 --- a/tests/validation/reference/Scale.cpp +++ b/tests/validation/reference/Scale.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 ARM Limited. + * Copyright (c) 2017-2020 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -38,7 +38,7 @@ namespace reference { template SimpleTensor scale_core(const SimpleTensor &in, float scale_x, float scale_y, InterpolationPolicy policy, BorderMode border_mode, T constant_border_value, - SamplingPolicy sampling_policy, bool ceil_policy_scale) + SamplingPolicy sampling_policy, bool ceil_policy_scale, bool align_corners) { // Add 1 if ceil_policy_scale is true const size_t round_value = ceil_policy_scale ? 1U : 0U; @@ -47,9 +47,13 @@ SimpleTensor scale_core(const SimpleTensor &in, float scale_x, float scale shape_scaled.set(1, (in.shape()[1] + round_value) * scale_y); SimpleTensor out(shape_scaled, in.data_type()); + const auto needs_align_corners = policy == InterpolationPolicy::BILINEAR + && sampling_policy == SamplingPolicy::TOP_LEFT + && align_corners; + // Compute the ratio between source width/height and destination width/height - const auto wr = static_cast(in.shape()[0]) / static_cast(out.shape()[0]); - const auto hr = static_cast(in.shape()[1]) / static_cast(out.shape()[1]); + const auto wr = arm_compute::calculate_resize_ratio(in.shape()[0], out.shape()[0], needs_align_corners); + const auto hr = arm_compute::calculate_resize_ratio(in.shape()[1], out.shape()[1], needs_align_corners); const auto width = static_cast(in.shape().x()); const auto height = static_cast(in.shape().y()); @@ -182,36 +186,36 @@ SimpleTensor scale_core(const SimpleTensor &in, float scale_x, float scale template SimpleTensor scale(const SimpleTensor &src, float scale_x, float scale_y, InterpolationPolicy policy, BorderMode border_mode, T constant_border_value, - SamplingPolicy sampling_policy, bool ceil_policy_scale) + SamplingPolicy sampling_policy, bool ceil_policy_scale, bool align_corners) { - return scale_core(src, scale_x, scale_y, policy, border_mode, constant_border_value, sampling_policy, ceil_policy_scale); + return scale_core(src, scale_x, scale_y, policy, border_mode, constant_border_value, sampling_policy, ceil_policy_scale, align_corners); } template <> SimpleTensor scale(const SimpleTensor &src, float scale_x, float scale_y, InterpolationPolicy policy, BorderMode border_mode, uint8_t constant_border_value, - SamplingPolicy sampling_policy, bool ceil_policy_scale) + SamplingPolicy sampling_policy, bool ceil_policy_scale, bool align_corners) { SimpleTensor dst; if(src.quantization_info().uniform().scale != 0.f) { SimpleTensor src_tmp = convert_from_asymmetric(src); float constant_border_value_f = dequantize_qasymm8(constant_border_value, src.quantization_info()); - SimpleTensor dst_tmp = scale_core(src_tmp, scale_x, scale_y, policy, border_mode, constant_border_value_f, sampling_policy, ceil_policy_scale); + SimpleTensor dst_tmp = scale_core(src_tmp, scale_x, scale_y, policy, border_mode, constant_border_value_f, sampling_policy, ceil_policy_scale, align_corners); dst = convert_to_asymmetric(dst_tmp, src.quantization_info()); } else { - dst = scale_core(src, scale_x, scale_y, policy, border_mode, constant_border_value, sampling_policy, ceil_policy_scale); + dst = scale_core(src, scale_x, scale_y, policy, border_mode, constant_border_value, sampling_policy, ceil_policy_scale, align_corners); } return dst; } template SimpleTensor scale(const SimpleTensor &src, float scale_x, float scale_y, InterpolationPolicy policy, BorderMode border_mode, int16_t constant_border_value, - SamplingPolicy sampling_policy, bool ceil_policy_scale); + SamplingPolicy sampling_policy, bool ceil_policy_scale, bool align_corners); template SimpleTensor scale(const SimpleTensor &src, float scale_x, float scale_y, InterpolationPolicy policy, BorderMode border_mode, half constant_border_value, - SamplingPolicy sampling_policy, bool ceil_policy_scale); + SamplingPolicy sampling_policy, bool ceil_policy_scale, bool align_corners); template SimpleTensor scale(const SimpleTensor &src, float scale_x, float scale_y, InterpolationPolicy policy, BorderMode border_mode, float constant_border_value, - SamplingPolicy sampling_policy, bool ceil_policy_scale); + SamplingPolicy sampling_policy, bool ceil_policy_scale, bool align_corners); } // namespace reference } // namespace validation } // namespace test diff --git a/tests/validation/reference/Scale.h b/tests/validation/reference/Scale.h index 8fbf6eb131..65cecbb6d5 100644 --- a/tests/validation/reference/Scale.h +++ b/tests/validation/reference/Scale.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 ARM Limited. + * Copyright (c) 2017-2020 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -37,7 +37,7 @@ namespace reference { template SimpleTensor scale(const SimpleTensor &src, float scale_x, float scale_y, InterpolationPolicy policy, BorderMode border_mode, T constant_border_value = 0, - SamplingPolicy sampling_policy = SamplingPolicy::CENTER, bool ceil_policy_scale = false); + SamplingPolicy sampling_policy = SamplingPolicy::CENTER, bool ceil_policy_scale = false, bool align_corners = false); } // namespace reference } // namespace validation } // namespace test -- cgit v1.2.1