From 3687ee1e7719436ff155a35911946b045903e8b6 Mon Sep 17 00:00:00 2001 From: Sang-Hoon Park Date: Wed, 24 Jun 2020 13:34:04 +0100 Subject: COMPMID-3539: Ignore align_corners for scaled size of 1 Scale kernels failed to validate when align_corners is true for scaled output size 1. Change this behavior to ignoring align_corners value to be aligned with expected behavior of higher-level frameworks. Also the minimum output size generated by the fixture for Scale kernels is changed to 1. Change-Id: Ib8e479af8bc43de3780005545f0c53fe195dc22e Signed-off-by: Sang-Hoon Park Reviewed-on: https://review.mlplatform.org/c/ml/ComputeLibrary/+/3478 Tested-by: Arm Jenkins Reviewed-by: Georgios Pinitas Comments-Addressed: Arm Jenkins --- Android.bp | 1 + SConscript | 1 + arm_compute/core/Utils.h | 21 ---------- src/core/CL/kernels/CLScaleKernel.cpp | 30 ++++---------- src/core/NEON/kernels/NEScaleKernel.cpp | 32 ++++++--------- src/core/Utils.cpp | 12 ------ src/core/utils/ScaleUtils.cpp | 44 +++++++++++++++++++++ src/core/utils/ScaleUtils.h | 67 ++++++++++++++++++++++++++++++++ src/runtime/NEON/functions/NEScale.cpp | 9 +++-- tests/validation/CL/Scale.cpp | 17 -------- tests/validation/NEON/Scale.cpp | 17 -------- tests/validation/fixtures/ScaleFixture.h | 7 +--- tests/validation/reference/Scale.cpp | 7 +++- 13 files changed, 145 insertions(+), 120 deletions(-) create mode 100644 src/core/utils/ScaleUtils.cpp create mode 100644 src/core/utils/ScaleUtils.h diff --git a/Android.bp b/Android.bp index e22aaea513..92c420a4dc 100644 --- a/Android.bp +++ b/Android.bp @@ -415,6 +415,7 @@ cc_library_static { "src/core/Utils.cpp", "src/core/Validate.cpp", "src/core/Version.cpp", + "src/core/utils/ScaleUtils.cpp", "src/core/utils/helpers/fft.cpp", "src/core/utils/helpers/tensor_transform.cpp", "src/core/utils/io/FileHandler.cpp", diff --git a/SConscript b/SConscript index 87571a3bf4..9428d10f45 100644 --- a/SConscript +++ b/SConscript @@ -178,6 +178,7 @@ arm_compute_env.Append(LIBS = ['dl']) core_files = Glob('src/core/*.cpp') core_files += Glob('src/core/CPP/*.cpp') core_files += Glob('src/core/CPP/kernels/*.cpp') +core_files += Glob('src/core/utils/*.cpp') core_files += Glob('src/core/utils/helpers/*.cpp') core_files += Glob('src/core/utils/io/*.cpp') core_files += Glob('src/core/utils/quantization/*.cpp') diff --git a/arm_compute/core/Utils.h b/arm_compute/core/Utils.h index 481dab3526..289df40890 100644 --- a/arm_compute/core/Utils.h +++ b/arm_compute/core/Utils.h @@ -981,27 +981,6 @@ 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); - -/** Returns if aligned corners are allowed for the given sampling policy - * - * @param[in] sampling_policy The sampling policy to consider - * - * @return True if aligned corners are allowed - */ -inline bool is_align_corners_allowed(SamplingPolicy sampling_policy) -{ - return sampling_policy != SamplingPolicy::CENTER; -} - /** Returns a pair of minimum and maximum values for a quantized activation * * @param[in] act_info The information for activation diff --git a/src/core/CL/kernels/CLScaleKernel.cpp b/src/core/CL/kernels/CLScaleKernel.cpp index 872ba5b6cc..f3acc3b31c 100644 --- a/src/core/CL/kernels/CLScaleKernel.cpp +++ b/src/core/CL/kernels/CLScaleKernel.cpp @@ -35,6 +35,8 @@ #include "arm_compute/core/TensorInfo.h" #include "support/StringSupport.h" +#include "src/core/utils/ScaleUtils.h" + #include #include @@ -54,8 +56,8 @@ inline std::pair calculate_scale_factors(const ITensorInfo &input, const unsigned int output_width = output.dimension(idx_width); const unsigned int output_height = output.dimension(idx_height); - float wr = arm_compute::calculate_resize_ratio(input_width, output_width, align_corners); - float hr = arm_compute::calculate_resize_ratio(input_height, output_height, align_corners); + float wr = arm_compute::scale_utils::calculate_resize_ratio(input_width, output_width, align_corners); + float hr = arm_compute::scale_utils::calculate_resize_ratio(input_height, output_height, align_corners); return std::make_pair(wr, hr); } @@ -68,29 +70,13 @@ Status validate_arguments(const ITensorInfo *input, const ITensorInfo *output, c ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_TYPES(input, output); ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_QUANTIZATION_INFO(input, output); ARM_COMPUTE_RETURN_ERROR_ON(output == input); - ARM_COMPUTE_RETURN_ERROR_ON(info.align_corners && !is_align_corners_allowed(info.sampling_policy)); + ARM_COMPUTE_RETURN_ERROR_ON(info.align_corners && !arm_compute::scale_utils::is_align_corners_allowed_sampling_policy(info.sampling_policy)); - if(info.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 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 input_width = input->dimension(width_index); - const auto input_height = input->dimension(height_index); - const auto output_width = output->dimension(width_index); - const auto output_height = output->dimension(height_index); - - ARM_COMPUTE_RETURN_ERROR_ON(input_width == 0 || input_height == 0 || output_width == 0 || output_height == 0); - ARM_COMPUTE_RETURN_ERROR_ON((output_width - 1 == 0) || (output_height - 1 == 0)); - } + const bool will_use_align_corners = info.align_corners && arm_compute::scale_utils::is_align_corners_allowed_output_shape(output->tensor_shape(), output->data_layout()); float wr = 0.f; float hr = 0.f; - std::tie(wr, hr) = calculate_scale_factors(*input, *output, info.align_corners); + std::tie(wr, hr) = calculate_scale_factors(*input, *output, will_use_align_corners); ARM_COMPUTE_RETURN_ERROR_ON(info.interpolation_policy == InterpolationPolicy::AREA && (wr > 1.f || hr > 1.f)); @@ -191,7 +177,7 @@ void CLScaleKernel::configure(const CLCompileContext &compile_context, const ICL _output = output; _interpolation_policy = info.interpolation_policy; _data_layout = input->info()->data_layout(); - _align_corners = info.align_corners; + _align_corners = info.align_corners && arm_compute::scale_utils::is_align_corners_allowed_output_shape(output->info()->tensor_shape(), _data_layout); float wr = 0.f; float hr = 0.f; diff --git a/src/core/NEON/kernels/NEScaleKernel.cpp b/src/core/NEON/kernels/NEScaleKernel.cpp index 857084ef7e..0f329a1c2c 100644 --- a/src/core/NEON/kernels/NEScaleKernel.cpp +++ b/src/core/NEON/kernels/NEScaleKernel.cpp @@ -30,6 +30,8 @@ #include "arm_compute/core/Window.h" #include "arm_compute/core/utils/misc/Utility.h" +#include "src/core/utils/ScaleUtils.h" + #include namespace arm_compute @@ -68,19 +70,7 @@ Status validate_arguments(const ITensorInfo *input, const ITensorInfo *dx, const ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(dy, 1, DataType::F32); } - ARM_COMPUTE_RETURN_ERROR_ON(info.align_corners && !is_align_corners_allowed(info.sampling_policy)); - - if(info.align_corners && is_align_corners_allowed(info.sampling_policy)) - { - // 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)); - } + ARM_COMPUTE_RETURN_ERROR_ON(info.align_corners && !arm_compute::scale_utils::is_align_corners_allowed_sampling_policy(info.sampling_policy)); if(info.interpolation_policy == InterpolationPolicy::AREA) { @@ -378,7 +368,7 @@ void NEScaleKernel::configure(const ITensor *input, const ITensor *dx, const ITe _border_mode = info.border_mode; _constant_border_value = info.constant_border_value; _use_padding = info.use_padding; - _align_corners = info.align_corners; + _align_corners = info.align_corners && arm_compute::scale_utils::is_align_corners_allowed_output_shape(output->info()->tensor_shape(), data_layout); if(info.sampling_policy == SamplingPolicy::CENTER) { @@ -386,8 +376,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 = 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); + const auto wr = arm_compute::scale_utils::calculate_resize_ratio(input->info()->dimension(idx_width), output->info()->dimension(idx_width), _align_corners); + const auto hr = arm_compute::scale_utils::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) @@ -437,7 +427,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 = arm_compute::calculate_resize_ratio(_input->info()->dimension(1), _output->info()->dimension(1), _align_corners); + const auto hr = arm_compute::scale_utils::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 @@ -670,7 +660,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::QASYMM8_SIGNED, DataType::S16, DataType::F16, DataType::F32); // Compute the ratio between source height and destination height - const auto hr = arm_compute::calculate_resize_ratio(_input->info()->dimension(1), _output->info()->dimension(1), _align_corners); + const auto hr = arm_compute::scale_utils::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 @@ -971,8 +961,8 @@ void NEScaleKernel::scale_area_nchw(const Window &window) Iterator in(_input, win_in); Iterator out(_output, window); - 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 wr = arm_compute::scale_utils::calculate_resize_ratio(_input->info()->dimension(0), _output->info()->dimension(0), _align_corners); + const auto hr = arm_compute::scale_utils::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]; @@ -1019,7 +1009,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 = arm_compute::calculate_resize_ratio(_input->info()->dimension(idx_height), _output->info()->dimension(idx_height), _align_corners); + const auto hr = arm_compute::scale_utils::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 diff --git a/src/core/Utils.cpp b/src/core/Utils.cpp index bdde082a1f..4d7e964695 100644 --- a/src/core/Utils.cpp +++ b/src/core/Utils.cpp @@ -456,18 +456,6 @@ 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); -} - std::pair arm_compute::get_quantized_activation_min_max(ActivationLayerInfo act_info, DataType data_type, UniformQuantizationInfo oq_info) { const bool is_qasymm8_signed = is_data_type_quantized_asymmetric_signed(data_type); diff --git a/src/core/utils/ScaleUtils.cpp b/src/core/utils/ScaleUtils.cpp new file mode 100644 index 0000000000..488b3dfaf5 --- /dev/null +++ b/src/core/utils/ScaleUtils.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "src/core/utils/ScaleUtils.h" +#include "arm_compute/core/Helpers.h" + +float arm_compute::scale_utils::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); +} + +bool arm_compute::scale_utils::is_align_corners_allowed_output_shape(const TensorShape &output_shape, DataLayout layout) +{ + const size_t idx_width = get_data_layout_dimension_index(layout, DataLayoutDimension::WIDTH); + const size_t idx_height = get_data_layout_dimension_index(layout, DataLayoutDimension::HEIGHT); + return (output_shape[idx_width] > 1) && (output_shape[idx_height] > 1); +} \ No newline at end of file diff --git a/src/core/utils/ScaleUtils.h b/src/core/utils/ScaleUtils.h new file mode 100644 index 0000000000..c3895d4ec0 --- /dev/null +++ b/src/core/utils/ScaleUtils.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2020 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef UTILS_CORE_SCALEUTILS_H +#define UTILS_CORE_SCALEUTILS_H + +#include "arm_compute/core/Types.h" + +#include +#include + +namespace arm_compute +{ +namespace scale_utils +{ +/** 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); + +/** Returns if aligned corners are allowed for the given sampling policy + * + * @param[in] sampling_policy The sampling policy to consider + * + * @return True if aligned corners are allowed + */ +inline bool is_align_corners_allowed_sampling_policy(SamplingPolicy sampling_policy) +{ + return sampling_policy != SamplingPolicy::CENTER; +} + +/** Returns if aligned corners are allowed for the given output shape + * + * @param[in] output_shape The shape of the scaled output tensor + * @param[in] layout The data layout of the output tensor + * + * @return True if aligned corners are allowed + */ +bool is_align_corners_allowed_output_shape(const TensorShape &output_shape, DataLayout layout); +} // namespace scale_utils +} // namespace arm_compute +#endif /* UTILS_CORE_SCALEUTILS_H */ \ No newline at end of file diff --git a/src/runtime/NEON/functions/NEScale.cpp b/src/runtime/NEON/functions/NEScale.cpp index 170b2ee3eb..28fbab4303 100644 --- a/src/runtime/NEON/functions/NEScale.cpp +++ b/src/runtime/NEON/functions/NEScale.cpp @@ -33,6 +33,8 @@ #include "arm_compute/runtime/NEON/NEScheduler.h" #include "arm_compute/runtime/TensorAllocator.h" +#include "src/core/utils/ScaleUtils.h" + #include #include #include @@ -107,7 +109,8 @@ void NEScale::configure(ITensor *input, ITensor *output, const ScaleKernelInfo & ARM_COMPUTE_ERROR_THROW_ON(NEScale::validate(input->info(), output->info(), info)); _use_padding = info.use_padding; - const bool is_align_corners_used = info.align_corners && is_align_corners_allowed(info.sampling_policy); + const bool is_align_corners_used = info.align_corners && arm_compute::scale_utils::is_align_corners_allowed_sampling_policy(info.sampling_policy) + && arm_compute::scale_utils::is_align_corners_allowed_output_shape(output->info()->tensor_shape(), output->info()->data_layout()); // Get data layout and width/height indices const DataLayout data_layout = input->info()->data_layout(); @@ -118,8 +121,8 @@ void NEScale::configure(ITensor *input, ITensor *output, const ScaleKernelInfo & 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 = arm_compute::calculate_resize_ratio(input->info()->dimension(idx_width), output->info()->dimension(idx_width), is_align_corners_used); - const auto hr = arm_compute::calculate_resize_ratio(input->info()->dimension(idx_height), output->info()->dimension(idx_height), is_align_corners_used); + const auto wr = arm_compute::scale_utils::calculate_resize_ratio(input->info()->dimension(idx_width), output->info()->dimension(idx_width), is_align_corners_used); + const auto hr = arm_compute::scale_utils::calculate_resize_ratio(input->info()->dimension(idx_height), output->info()->dimension(idx_height), is_align_corners_used); // Get the element size of the input image const size_t input_element_size = input->info()->element_size(); diff --git a/tests/validation/CL/Scale.cpp b/tests/validation/CL/Scale.cpp index 50c148dfba..8a010032a3 100644 --- a/tests/validation/CL/Scale.cpp +++ b/tests/validation/CL/Scale.cpp @@ -186,23 +186,6 @@ TEST_CASE(AlignedCornerNotSupported, framework::DatasetMode::ALL) ARM_COMPUTE_EXPECT(bool(result) == false, framework::LogLevel::ERRORS); } -TEST_CASE(InvalidAlignedCornerOutput, framework::DatasetMode::ALL) -{ - // Bilinear with aligned corners require at least 2x2 output to prevent overflow. - // Also, aligned corners require sampling policy to be TOP_LEFT. - constexpr auto interpolation_policy = InterpolationPolicy::BILINEAR; - constexpr bool align_corners = true; - constexpr auto sampling_policy = SamplingPolicy::TOP_LEFT; - const auto invalid_output_shape = TensorShape{ 1, 1, 3, 2 }; - - const auto input = TensorInfo{ default_input_shape, 1, default_data_type, default_data_layout }; - const auto output = TensorInfo{ invalid_output_shape, 1, default_data_type, default_data_layout }; - Status result{}; - - result = CLScale::validate(&input, &output, ScaleKernelInfo{ interpolation_policy, default_border_mode, PixelValue(), sampling_policy, default_use_padding, align_corners }); - ARM_COMPUTE_EXPECT(bool(result) == false, framework::LogLevel::ERRORS); -} - TEST_CASE(WindowShrink, framework::DatasetMode::ALL) { const auto input = TensorInfo{ TensorShape(37U, 37U, 2U), 1, DataType::F32 }; diff --git a/tests/validation/NEON/Scale.cpp b/tests/validation/NEON/Scale.cpp index f4a9b9df56..a7eb4b2d8d 100644 --- a/tests/validation/NEON/Scale.cpp +++ b/tests/validation/NEON/Scale.cpp @@ -244,23 +244,6 @@ TEST_CASE(AlignedCornerNotSupported, framework::DatasetMode::ALL) result = NEScale::validate(&input, &output, ScaleKernelInfo{ interpolation_policy, default_border_mode, PixelValue(), sampling_policy, default_use_padding, align_corners }); ARM_COMPUTE_EXPECT(bool(result) == false, framework::LogLevel::ERRORS); } - -TEST_CASE(InvalidAlignedCornerOutput, framework::DatasetMode::ALL) -{ - // Bilinear with aligned corners require at least 2x2 output to prevent overflow. - // Also, aligned corners require sampling policy to be TOP_LEFT. - constexpr auto interpolation_policy = InterpolationPolicy::BILINEAR; - constexpr bool align_corners = true; - constexpr auto sampling_policy = SamplingPolicy::TOP_LEFT; - const auto invalid_output_shape = TensorShape{ 1, 1, 3, 2 }; - - const auto input = TensorInfo{ input_shape, 1, default_data_type, default_data_layout }; - const auto output = TensorInfo{ invalid_output_shape, 1, default_data_type, default_data_layout }; - Status result{}; - - result = NEScale::validate(&input, &output, ScaleKernelInfo{ interpolation_policy, default_border_mode, PixelValue(), sampling_policy, default_use_padding, align_corners }); - ARM_COMPUTE_EXPECT(bool(result) == false, framework::LogLevel::ERRORS); -} TEST_SUITE_END() // Validate template diff --git a/tests/validation/fixtures/ScaleFixture.h b/tests/validation/fixtures/ScaleFixture.h index 12d9012ece..b7a821fad4 100644 --- a/tests/validation/fixtures/ScaleFixture.h +++ b/tests/validation/fixtures/ScaleFixture.h @@ -74,11 +74,8 @@ protected: constexpr float max_width{ 8192.0f }; constexpr float max_height{ 6384.0f }; - - const bool is_align_corners_used = _align_corners && arm_compute::is_align_corners_allowed(_sampling_policy); - - const float min_width = is_align_corners_used ? 2.f : 1.f; - const float min_height = is_align_corners_used ? 2.f : 1.f; + const float min_width{ 1.f }; + const float min_height{ 1.f }; std::mt19937 generator(library->seed()); std::uniform_real_distribution distribution_float(_min_scale, _max_scale); diff --git a/tests/validation/reference/Scale.cpp b/tests/validation/reference/Scale.cpp index cb4ad6f909..44beabb2d4 100644 --- a/tests/validation/reference/Scale.cpp +++ b/tests/validation/reference/Scale.cpp @@ -26,6 +26,7 @@ #include "Utils.h" #include "arm_compute/core/utils/misc/Utility.h" +#include "src/core/utils/ScaleUtils.h" namespace arm_compute { @@ -46,9 +47,11 @@ SimpleTensor scale_core(const SimpleTensor &in, float scale_x, float scale shape_scaled.set(1, (in.shape()[1] + round_value) * scale_y, /* apply_dim_correction = */ false); SimpleTensor out(shape_scaled, in.data_type()); + align_corners = align_corners && arm_compute::scale_utils::is_align_corners_allowed_output_shape(out.shape(), DataLayout::NCHW); + // Compute the ratio between source width/height and destination width/height - const auto wr = arm_compute::calculate_resize_ratio(in.shape()[0], out.shape()[0], align_corners); - const auto hr = arm_compute::calculate_resize_ratio(in.shape()[1], out.shape()[1], align_corners); + const auto wr = arm_compute::scale_utils::calculate_resize_ratio(in.shape()[0], out.shape()[0], align_corners); + const auto hr = arm_compute::scale_utils::calculate_resize_ratio(in.shape()[1], out.shape()[1], align_corners); const auto width = static_cast(in.shape().x()); const auto height = static_cast(in.shape().y()); -- cgit v1.2.1