From 5b7fd87b6ab73a7206a45d3621d484131c901143 Mon Sep 17 00:00:00 2001 From: Sang-Hoon Park Date: Thu, 9 Jan 2020 15:27:51 +0000 Subject: MLCE-139 add align_corners parameter handling to CLScale Change-Id: I9d6047c306d7928258d5168eb4bfb96b09d2608f Signed-off-by: Sang-Hoon Park Reviewed-on: https://review.mlplatform.org/c/2569 Reviewed-by: Pablo Marquez Comments-Addressed: Arm Jenkins Tested-by: Arm Jenkins --- arm_compute/core/CL/kernels/CLScaleKernel.h | 8 +++- arm_compute/runtime/CL/functions/CLScale.h | 4 +- src/core/CL/kernels/CLScaleKernel.cpp | 62 +++++++++++++++++++---------- src/runtime/CL/functions/CLScale.cpp | 8 ++-- tests/validation/CL/Scale.cpp | 1 + 5 files changed, 53 insertions(+), 30 deletions(-) diff --git a/arm_compute/core/CL/kernels/CLScaleKernel.h b/arm_compute/core/CL/kernels/CLScaleKernel.h index 7d9ed41305..f93286b07d 100644 --- a/arm_compute/core/CL/kernels/CLScaleKernel.h +++ b/arm_compute/core/CL/kernels/CLScaleKernel.h @@ -43,8 +43,9 @@ public: * @param[in] policy Interpolation type to use * @param[in] border_mode Selected border mode. * @param[in] sampling_policy (Optional) Sampling policy used by the interpolation. Defaults to @ref SamplingPolicy::CENTER + * @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 ICLTensor *input, ICLTensor *output, InterpolationPolicy policy, BorderMode border_mode, SamplingPolicy sampling_policy = SamplingPolicy::CENTER); + void configure(const ICLTensor *input, ICLTensor *output, InterpolationPolicy policy, BorderMode border_mode, SamplingPolicy sampling_policy = SamplingPolicy::CENTER, bool align_corners = false); /** Static function to check if given info will lead to a valid configuration of @ref CLScaleKernel * @@ -54,10 +55,12 @@ public: * @param[in] policy Interpolation type to use * @param[in] border_mode Selected border mode. * @param[in] sampling_policy (Optional) Sampling policy used by the interpolation. Defaults to @ref SamplingPolicy::CENTER + * @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, SamplingPolicy sampling_policy = SamplingPolicy::CENTER); + static Status validate(const ITensorInfo *input, const ITensorInfo *output, InterpolationPolicy policy, BorderMode border_mode, SamplingPolicy sampling_policy = SamplingPolicy::CENTER, + bool align_corners = false); /** Input tensor accessor. * * @return Pointer to input tensor. @@ -76,6 +79,7 @@ public: public: InterpolationPolicy _interpolationPolicy = InterpolationPolicy::BILINEAR; DataLayout _data_layout = DataLayout::UNKNOWN; + bool _align_corners = false; }; } // namespace arm_compute #endif /*ARM_COMPUTE_CLSCALEKERNEL_H */ diff --git a/arm_compute/runtime/CL/functions/CLScale.h b/arm_compute/runtime/CL/functions/CLScale.h index 9a201dc10f..c06c9b629a 100644 --- a/arm_compute/runtime/CL/functions/CLScale.h +++ b/arm_compute/runtime/CL/functions/CLScale.h @@ -47,7 +47,7 @@ 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. Defaults to false. + * @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(ICLTensor *input, ICLTensor *output, InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value = PixelValue(), SamplingPolicy sampling_policy = SamplingPolicy::CENTER, bool use_padding = true, bool align_corners = false); @@ -62,7 +62,7 @@ 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. Defaults to false. + * @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 */ diff --git a/src/core/CL/kernels/CLScaleKernel.cpp b/src/core/CL/kernels/CLScaleKernel.cpp index a427c79b65..38e07036d0 100644 --- a/src/core/CL/kernels/CLScaleKernel.cpp +++ b/src/core/CL/kernels/CLScaleKernel.cpp @@ -41,7 +41,7 @@ using namespace arm_compute; namespace { -inline std::pair calculate_scale_factors(const ITensorInfo &input, const ITensorInfo &output) +inline std::pair calculate_scale_factors(const ITensorInfo &input, const ITensorInfo &output, bool align_corners) { DataLayout data_layout = input.data_layout(); const int idx_width = get_data_layout_dimension_index(data_layout, DataLayoutDimension::WIDTH); @@ -53,13 +53,13 @@ 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 = static_cast(input_width) / static_cast(output_width); - float hr = static_cast(input_height) / static_cast(output_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); return std::make_pair(wr, hr); } -Status validate_arguments(const ITensorInfo *input, const ITensorInfo *output, InterpolationPolicy policy) +Status validate_arguments(const ITensorInfo *input, const ITensorInfo *output, InterpolationPolicy policy, bool align_corners) { ARM_COMPUTE_RETURN_ERROR_ON_F16_UNSUPPORTED(input); ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::QASYMM8, DataType::QASYMM8_SIGNED, DataType::U8, DataType::S16, DataType::F16, DataType::F32); @@ -68,9 +68,27 @@ Status validate_arguments(const ITensorInfo *input, const ITensorInfo *output, I ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_QUANTIZATION_INFO(input, output); ARM_COMPUTE_RETURN_ERROR_ON(output == input); + 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 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)); + } + float wr = 0.f; float hr = 0.f; - std::tie(wr, hr) = calculate_scale_factors(*input, *output); + std::tie(wr, hr) = calculate_scale_factors(*input, *output, align_corners); ARM_COMPUTE_RETURN_ERROR_ON(policy == InterpolationPolicy::AREA && (wr > 1.f || hr > 1.f)); @@ -139,10 +157,13 @@ BorderSize CLScaleKernel::border_size() const } Status CLScaleKernel::validate(const ITensorInfo *input, const ITensorInfo *output, InterpolationPolicy policy, - BorderMode border_mode, SamplingPolicy sampling_policy) + BorderMode border_mode, SamplingPolicy sampling_policy, bool align_corners) { - BorderSize border = BorderSize(1); - ARM_COMPUTE_RETURN_ON_ERROR(validate_arguments(input, output, policy)); + BorderSize border = BorderSize(1); + const bool is_align_corners = policy == InterpolationPolicy::BILINEAR + && sampling_policy == SamplingPolicy::TOP_LEFT + && align_corners; + ARM_COMPUTE_RETURN_ON_ERROR(validate_arguments(input, output, policy, is_align_corners)); ARM_COMPUTE_RETURN_ON_ERROR(validate_and_configure_window(input->clone().get(), output->clone().get(), policy, border_mode, sampling_policy, border).first); return Status{}; @@ -158,9 +179,13 @@ const ICLTensor *CLScaleKernel::output() const return _output; } -void CLScaleKernel::configure(const ICLTensor *input, ICLTensor *output, InterpolationPolicy policy, BorderMode border_mode, SamplingPolicy sampling_policy) +void CLScaleKernel::configure(const ICLTensor *input, ICLTensor *output, InterpolationPolicy policy, BorderMode border_mode, SamplingPolicy sampling_policy, bool align_corners) { - ARM_COMPUTE_ERROR_THROW_ON(validate_arguments(input->info(), output->info(), policy)); + _align_corners = policy == InterpolationPolicy::BILINEAR + && sampling_policy == SamplingPolicy::TOP_LEFT + && align_corners; + + ARM_COMPUTE_ERROR_THROW_ON(validate_arguments(input->info(), output->info(), policy, _align_corners)); _input = input; _output = output; @@ -169,7 +194,7 @@ void CLScaleKernel::configure(const ICLTensor *input, ICLTensor *output, Interpo float wr = 0.f; float hr = 0.f; - std::tie(wr, hr) = calculate_scale_factors(*input->info(), *output->info()); + std::tie(wr, hr) = calculate_scale_factors(*input->info(), *output->info(), _align_corners); const bool call_quantized_kernel = is_data_type_quantized_asymmetric(input->info()->data_type()) && policy == InterpolationPolicy::BILINEAR; @@ -177,12 +202,6 @@ void CLScaleKernel::configure(const ICLTensor *input, ICLTensor *output, Interpo const int idx_height = get_data_layout_dimension_index(_data_layout, DataLayoutDimension::HEIGHT); const bool is_nhwc = _data_layout == DataLayout::NHWC; - // Compute the ratio between source width/height and destination width/height - const unsigned int input_width = input->info()->dimension(idx_width); - const unsigned int input_height = input->info()->dimension(idx_height); - const unsigned int output_width = output->info()->dimension(idx_width); - const unsigned int output_height = output->info()->dimension(idx_height); - // Compute actual border size BorderSize border = border_size(); @@ -220,14 +239,13 @@ void CLScaleKernel::configure(const ICLTensor *input, ICLTensor *output, Interpo unsigned int idx = is_nhwc ? 2 * num_arguments_per_4D_tensor() : 2 * num_arguments_per_2D_tensor(); //Skip the input and output parameters - // Set static kernel arguments - const float scale_x = static_cast(input_width) / output_width; - const float scale_y = static_cast(input_height) / output_height; + const unsigned int input_width = input->info()->dimension(idx_width); + const unsigned int input_height = input->info()->dimension(idx_height); _kernel.setArg(idx++, input_width); _kernel.setArg(idx++, input_height); - _kernel.setArg(idx++, scale_x); - _kernel.setArg(idx++, scale_y); + _kernel.setArg(idx++, wr); + _kernel.setArg(idx++, hr); // Set config_id for enabling LWS tuning _config_id = "scale_"; diff --git a/src/runtime/CL/functions/CLScale.cpp b/src/runtime/CL/functions/CLScale.cpp index 39d992739c..a3559158a5 100644 --- a/src/runtime/CL/functions/CLScale.cpp +++ b/src/runtime/CL/functions/CLScale.cpp @@ -35,10 +35,10 @@ using namespace arm_compute; 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); + ARM_COMPUTE_UNUSED(use_padding); auto k = arm_compute::support::cpp14::make_unique(); k->set_target(CLScheduler::get().target()); - k->configure(input, output, policy, border_mode, sampling_policy); + k->configure(input, output, policy, border_mode, sampling_policy, align_corners); _kernel = std::move(k); // Tune kernels @@ -56,6 +56,6 @@ void CLScale::configure(ICLTensor *input, ICLTensor *output, InterpolationPolicy 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, use_padding, align_corners); - return CLScaleKernel::validate(input, output, policy, border_mode, sampling_policy); + ARM_COMPUTE_UNUSED(constant_border_value, use_padding); + return CLScaleKernel::validate(input, output, policy, border_mode, sampling_policy, align_corners); } diff --git a/tests/validation/CL/Scale.cpp b/tests/validation/CL/Scale.cpp index c03571ca02..848656a8d1 100644 --- a/tests/validation/CL/Scale.cpp +++ b/tests/validation/CL/Scale.cpp @@ -59,6 +59,7 @@ const auto ScaleDataTypes = framework::dataset::make("DataType", const auto AlignCorners = framework::dataset::make("AlignCorners", { false, + true, }); /** Tolerance */ -- cgit v1.2.1