From 20b4313365ea2ed31f59fd757f68f791f076e6bc Mon Sep 17 00:00:00 2001 From: Georgios Pinitas Date: Mon, 14 May 2018 16:05:23 +0100 Subject: COMPMID-814: Add validate method to scale. Change-Id: I5004c79ac7b10f988f25e14847f1ea2be01629da Reviewed-on: https://eu-gerrit-1.euhpc.arm.com/131143 Tested-by: Jenkins Reviewed-by: Anthony Barbier --- arm_compute/core/NEON/kernels/NEScaleKernel.h | 15 ++ arm_compute/runtime/NEON/functions/NEScale.h | 17 ++- src/core/NEON/kernels/NEScaleKernel.cpp | 202 +++++++++++++++++--------- src/runtime/NEON/functions/NEScale.cpp | 47 +++++- tests/validation/NEON/Scale.cpp | 51 +++++++ 5 files changed, 260 insertions(+), 72 deletions(-) diff --git a/arm_compute/core/NEON/kernels/NEScaleKernel.h b/arm_compute/core/NEON/kernels/NEScaleKernel.h index 0a3a952537..575814b84c 100644 --- a/arm_compute/core/NEON/kernels/NEScaleKernel.h +++ b/arm_compute/core/NEON/kernels/NEScaleKernel.h @@ -67,6 +67,21 @@ public: */ void configure(const ITensor *input, const ITensor *dx, const ITensor *dy, const ITensor *offsets, ITensor *output, InterpolationPolicy policy, BorderMode border_mode, SamplingPolicy sampling_policy = SamplingPolicy::CENTER); + /** 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 + * + * @param[in] input Source tensor. Data types supported: U8/S16/F32. + * @param[in] dx Pixel's distance between the X real coordinate and the smallest X following integer. Data type supported: F32 + * @param[in] dy Pixel's distance between the Y real coordinate and the smallest Y following integer. Data type supported: F32 + * @param[in] offsets Offset to access the pixel with NEAREST interpolation or the top-left pixel with BILINEAR interpolation in the input tensor. Data type supported: S32. + * @param[in] output Destination tensor. Data types supported: Same as @p input. All but the lowest two dimensions must be the same size as in the input tensor, i.e. scaling is only performed within the XY-plane. + * @param[in] policy Interpolation type to use + * @param[in] border_mode Border mode policy + * @param[in] sampling_policy (Optional) Sampling policy used by the interpolation. Defaults to @ref SamplingPolicy::CENTER + */ + static Status validate(const ITensorInfo *input, const ITensorInfo *dx, const ITensorInfo *dy, const ITensorInfo *offsets, ITensorInfo *output, + InterpolationPolicy policy, BorderMode border_mode, SamplingPolicy sampling_policy = SamplingPolicy::CENTER); // Inherited methods overridden: void run(const Window &window, const ThreadInfo &info) override; diff --git a/arm_compute/runtime/NEON/functions/NEScale.h b/arm_compute/runtime/NEON/functions/NEScale.h index 1d96db3ffc..9b5a12bece 100644 --- a/arm_compute/runtime/NEON/functions/NEScale.h +++ b/arm_compute/runtime/NEON/functions/NEScale.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017 ARM Limited. + * Copyright (c) 2016-2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -47,7 +47,7 @@ public: NEScale(); /** Initialize the function's source, destination, interpolation type and border_mode. * - * @param[in, out] input Source tensor. Data type supported: U8/F32. (Written to only for @p border_mode != UNDEFINED) + * @param[in, out] input Source tensor. Data type supported: U8/S16/F32. (Written to only for @p border_mode != UNDEFINED) * @param[out] output Destination tensor. Data type supported: Same as @p input. All but the lowest two dimensions must be the same size as in the input tensor, i.e. scaling is only performed within the XY-plane. * @param[in] policy The interpolation type. * @param[in] border_mode Strategy to use for borders. @@ -56,6 +56,19 @@ public: */ void configure(ITensor *input, ITensor *output, InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value = PixelValue(), SamplingPolicy sampling_policy = SamplingPolicy::CENTER); + /** 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/F32. (Written to only for @p border_mode != UNDEFINED) + * @param[in] output Destination tensor. Data type supported: Same as @p input. All but the lowest two dimensions must be the same size as in the input tensor, i.e. scaling is only performed within the XY-plane. + * @param[in] policy The interpolation type. + * @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 + * + * @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); // Inherited methods overridden: void run() override; diff --git a/src/core/NEON/kernels/NEScaleKernel.cpp b/src/core/NEON/kernels/NEScaleKernel.cpp index 311c807009..3f57ffba5c 100644 --- a/src/core/NEON/kernels/NEScaleKernel.cpp +++ b/src/core/NEON/kernels/NEScaleKernel.cpp @@ -42,52 +42,122 @@ namespace arm_compute { namespace { -Window configure_nchw(const ITensor *input, const ITensor *dx, const ITensor *dy, const ITensor *offsets, ITensor *output, - InterpolationPolicy policy, bool border_undefined, SamplingPolicy sampling_policy, BorderSize border_size) +Status validate_arguments(const ITensorInfo *input, const ITensorInfo *dx, const ITensorInfo *dy, + const ITensorInfo *offsets, ITensorInfo *output, InterpolationPolicy policy, + BorderMode border_mode, SamplingPolicy sampling_policy) { + ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::U8, DataType::S16, DataType::F32); + ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(output); + ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_TYPES(input, output); + ARM_COMPUTE_RETURN_ERROR_ON(output == input); + ARM_COMPUTE_RETURN_ERROR_ON(sampling_policy != SamplingPolicy::CENTER); + ARM_COMPUTE_UNUSED(border_mode); + + 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); + + if(policy == InterpolationPolicy::NEAREST_NEIGHBOR) + { + ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(offsets, 1, DataType::S32); + } + + if(policy == InterpolationPolicy::BILINEAR) + { + 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(policy == InterpolationPolicy::AREA) + { + ARM_COMPUTE_RETURN_ERROR_ON(data_layout != DataLayout::NCHW); + } + + return Status{}; +} + +std::pair validate_and_configure_window_nchw(ITensorInfo *input, ITensorInfo *dx, ITensorInfo *dy, ITensorInfo *offsets, ITensorInfo *output, + InterpolationPolicy policy, bool border_undefined, SamplingPolicy sampling_policy, BorderSize border_size) +{ + bool window_changed{ false }; + Window win{}; + constexpr unsigned int num_elems_processed_per_iteration = 16; // Configure kernel window - Window win = calculate_max_window(*output->info(), Steps(num_elems_processed_per_iteration)); + win = calculate_max_window(*output, Steps(num_elems_processed_per_iteration)); + + const ValidRegion &input_valid_region = input->valid_region(); - const ValidRegion &input_valid_region = input->info()->valid_region(); + if(offsets != nullptr) + { + AccessWindowHorizontal offsets_access(offsets, 0, num_elems_processed_per_iteration); + window_changed = window_changed || update_window_and_padding(win, offsets_access); + } + if(dx != nullptr && dy != nullptr) + { + AccessWindowHorizontal dx_access(dx, 0, num_elems_processed_per_iteration); + AccessWindowHorizontal dy_access(dy, 0, num_elems_processed_per_iteration); + window_changed = window_changed || update_window_and_padding(win, dx_access, dy_access); + } // Reads can occur within the valid region of the input - AccessWindowStatic input_access(input->info(), input_valid_region.anchor[0] - border_size.left, + AccessWindowStatic input_access(input, input_valid_region.anchor[0] - border_size.left, input_valid_region.anchor[1] - border_size.top, input_valid_region.anchor[0] + input_valid_region.shape[0] + border_size.right, input_valid_region.anchor[1] + input_valid_region.shape[1] + border_size.bottom); - AccessWindowHorizontal offsets_access(offsets == nullptr ? nullptr : offsets->info(), 0, - num_elems_processed_per_iteration); - AccessWindowHorizontal dx_access(dx == nullptr ? nullptr : dx->info(), 0, num_elems_processed_per_iteration); - AccessWindowHorizontal dy_access(dy == nullptr ? nullptr : dy->info(), 0, num_elems_processed_per_iteration); - AccessWindowHorizontal output_access(output->info(), 0, num_elems_processed_per_iteration); - - update_window_and_padding(win, input_access, offsets_access, dx_access, dy_access, output_access); - - output_access.set_valid_region(win, calculate_valid_region_scale(*(input->info()), output->info()->tensor_shape(), + AccessWindowHorizontal output_access(output, 0, num_elems_processed_per_iteration); + window_changed = window_changed || update_window_and_padding(win, input_access, output_access); + output_access.set_valid_region(win, calculate_valid_region_scale(*input, output->tensor_shape(), policy, sampling_policy, border_undefined)); - return win; + Status err = (window_changed) ? ARM_COMPUTE_CREATE_ERROR(ErrorCode::RUNTIME_ERROR, "Insufficient Padding!") : Status{}; + return std::make_pair(err, win); } -Window configure_nhwc(const ITensor *input, ITensor *output, - InterpolationPolicy policy, bool border_undefined, SamplingPolicy sampling_policy, BorderSize border_size) + +std::pair validate_and_configure_window_nhwc(ITensorInfo *input, ITensorInfo *output, + InterpolationPolicy policy, bool border_undefined, + SamplingPolicy sampling_policy, BorderSize border_size) { - unsigned int num_elems_processed_per_iteration = (policy == InterpolationPolicy::NEAREST_NEIGHBOR) ? 16 / input->info()->element_size() : 1; + bool window_changed{ false }; + Window win{}; + + const unsigned int num_elems_processed_per_iteration = (policy == InterpolationPolicy::NEAREST_NEIGHBOR) ? 16 / input->element_size() : 1; // Configure kernel window - Window win = calculate_max_window(*output->info(), Steps(num_elems_processed_per_iteration)); + win = calculate_max_window(*output, Steps(num_elems_processed_per_iteration)); + + AccessWindowStatic input_access(input, 0, -border_size.top, + ceil_to_multiple(input->tensor_shape()[0], num_elems_processed_per_iteration), + input->tensor_shape()[1]); + AccessWindowHorizontal output_access(output, 0, num_elems_processed_per_iteration); - AccessWindowStatic input_access(input->info(), 0, -border_size.top, - ceil_to_multiple(input->info()->tensor_shape()[0], num_elems_processed_per_iteration), - input->info()->tensor_shape()[1]); - AccessWindowHorizontal output_access(output->info(), 0, num_elems_processed_per_iteration); + window_changed = update_window_and_padding(win, input_access, output_access); + output->set_valid_region(calculate_valid_region_scale(*input, output->tensor_shape(), + policy, sampling_policy, border_undefined)); - update_window_and_padding(win, input_access, output_access); - output->info()->set_valid_region(calculate_valid_region_scale(*(input->info()), output->info()->tensor_shape(), - policy, sampling_policy, border_undefined)); + Status err = (window_changed) ? ARM_COMPUTE_CREATE_ERROR(ErrorCode::RUNTIME_ERROR, "Insufficient Padding!") : Status{}; + return std::make_pair(err, win); +} + +std::pair validate_and_configure_window(ITensorInfo *input, ITensorInfo *dx, ITensorInfo *dy, ITensorInfo *offsets, ITensorInfo *output, + InterpolationPolicy policy, bool border_undefined, SamplingPolicy sampling_policy, BorderSize border_size) +{ + std::pair win_config; + switch(input->data_layout()) + { + case DataLayout::NCHW: + win_config = validate_and_configure_window_nchw(input, dx, dy, offsets, output, policy, border_undefined, sampling_policy, border_size); + break; + case DataLayout::NHWC: + win_config = validate_and_configure_window_nhwc(input, output, policy, border_undefined, sampling_policy, border_size); + break; + default: + win_config = std::make_pair(ARM_COMPUTE_CREATE_ERROR(ErrorCode::RUNTIME_ERROR, "Unsupported data layout!"), Window{}); + } - return win; + return win_config; } template @@ -197,33 +267,21 @@ 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, SamplingPolicy sampling_policy) { - ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::U8, DataType::S16, DataType::F32); - ARM_COMPUTE_ERROR_ON_NULLPTR(output); - ARM_COMPUTE_ERROR_ON_MISMATCHING_DATA_TYPES(input, output); - ARM_COMPUTE_ERROR_ON(output == input); - ARM_COMPUTE_ERROR_ON(sampling_policy != SamplingPolicy::CENTER); - ARM_COMPUTE_UNUSED(sampling_policy); + ARM_COMPUTE_ERROR_ON_NULLPTR(input, output); - if(policy == InterpolationPolicy::NEAREST_NEIGHBOR) - { - ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(offsets, 1, DataType::S32); - } - - if(policy == InterpolationPolicy::BILINEAR) - { - ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(offsets, 1, DataType::S32); - ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(dx, 1, DataType::F32); - ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(dy, 1, DataType::F32); - } + // Perform validation step + ARM_COMPUTE_ERROR_THROW_ON(validate_arguments(input->info(), + dx != nullptr ? dx->info() : nullptr, + dy != nullptr ? dy->info() : nullptr, + offsets != nullptr ? offsets->info() : nullptr, + output->info(), + policy, border_mode, sampling_policy)); // Get data layout and width/height indices const DataLayout data_layout = input->info()->data_layout(); const int idx_width = get_data_layout_dimension_index(data_layout, DataLayoutDimension::WIDTH); const int idx_height = get_data_layout_dimension_index(data_layout, DataLayoutDimension::HEIGHT); - ARM_COMPUTE_ERROR_ON(output->info()->dimension(idx_width) == 0); - ARM_COMPUTE_ERROR_ON(output->info()->dimension(idx_height) == 0); - _input = input; _output = output; _offsets = offsets; @@ -259,16 +317,11 @@ void NEScaleKernel::configure(const ITensor *input, const ITensor *dx, const ITe } case InterpolationPolicy::BILINEAR: { - ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(_dx, 1, DataType::F32); - ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(_dy, 1, DataType::F32); - _func = (data_layout == DataLayout::NCHW) ? &NEScaleKernel::scale_bilinear_nchw : &NEScaleKernel::scale_nhwc; break; } case InterpolationPolicy::AREA: { - ARM_COMPUTE_ERROR_ON(data_layout != DataLayout::NCHW); - _func = &NEScaleKernel::scale_area_nchw; break; } @@ -277,19 +330,14 @@ void NEScaleKernel::configure(const ITensor *input, const ITensor *dx, const ITe } // Configure window - Window win{}; - switch(data_layout) - { - case DataLayout::NCHW: - win = configure_nchw(input, dx, dy, offsets, output, policy, border_mode == BorderMode::UNDEFINED, sampling_policy, border_size()); - break; - case DataLayout::NHWC: - win = configure_nhwc(input, output, policy, border_mode == BorderMode::UNDEFINED, sampling_policy, border_size()); - break; - default: - ARM_COMPUTE_ERROR("Unsupported data layout"); - } - INEKernel::configure(win); + std::pair win_config = validate_and_configure_window(input->info(), + dx != nullptr ? dx->info() : nullptr, + dy != nullptr ? dy->info() : nullptr, + offsets != nullptr ? offsets->info() : nullptr, + output->info(), + policy, border_mode == BorderMode::UNDEFINED, sampling_policy, border_size()); + ARM_COMPUTE_ERROR_THROW_ON(win_config.first); + INEKernel::configure(win_config.second); } void NEScaleKernel::scale_nearest_nchw(const Window &window) @@ -663,8 +711,6 @@ void NEScaleKernel::scale_area_nchw(const Window &window) void NEScaleKernel::scale_nhwc(const Window &window) { - ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(_input, 1, DataType::U8, DataType::S16, DataType::F32); - // Get data layout and width/height indices const DataLayout data_layout = _input->info()->data_layout(); const int idx_channels = get_data_layout_dimension_index(data_layout, DataLayoutDimension::CHANNEL); @@ -732,6 +778,28 @@ 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, SamplingPolicy sampling_policy) +{ + BorderSize border_size(1); + if(input->data_layout() == DataLayout::NHWC) + { + 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, sampling_policy)); + ARM_COMPUTE_RETURN_ON_ERROR(validate_and_configure_window(input->clone().get(), + dx != nullptr ? dx->clone().get() : nullptr, + dy != nullptr ? dy->clone().get() : nullptr, + offsets != nullptr ? offsets->clone().get() : nullptr, + output->clone().get(), + policy, border_mode == BorderMode::UNDEFINED, sampling_policy, border_size) + .first); + + return Status{}; +} + void NEScaleKernel::run(const Window &window, const ThreadInfo &info) { ARM_COMPUTE_UNUSED(info); diff --git a/src/runtime/NEON/functions/NEScale.cpp b/src/runtime/NEON/functions/NEScale.cpp index 43ef6199ba..9407273c1f 100644 --- a/src/runtime/NEON/functions/NEScale.cpp +++ b/src/runtime/NEON/functions/NEScale.cpp @@ -45,7 +45,6 @@ namespace void precompute_dx_dy_offsets(ITensor *dx, ITensor *dy, ITensor *offsets, float wr, float hr, size_t input_element_size, SamplingPolicy sampling_policy) { ARM_COMPUTE_ERROR_ON(nullptr == offsets); - ARM_COMPUTE_ERROR_ON(sampling_policy != SamplingPolicy::CENTER); ARM_COMPUTE_UNUSED(sampling_policy); Window win; @@ -99,8 +98,8 @@ NEScale::NEScale() // NOLINT void NEScale::configure(ITensor *input, ITensor *output, InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value, SamplingPolicy sampling_policy) { - ARM_COMPUTE_ERROR_ON(nullptr == input); - ARM_COMPUTE_ERROR_ON(nullptr == output); + 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)); // Get data layout and width/height indices const DataLayout data_layout = input->info()->data_layout(); @@ -171,6 +170,48 @@ void NEScale::configure(ITensor *input, ITensor *output, InterpolationPolicy pol _border_handler.configure(input, _scale_kernel.border_size(), border_mode, PixelValue(constant_border_value)); } +Status NEScale::validate(const ITensorInfo *input, const ITensorInfo *output, InterpolationPolicy policy, + BorderMode border_mode, PixelValue constant_border_value, SamplingPolicy sampling_policy) +{ + ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input, output); + ARM_COMPUTE_RETURN_ERROR_ON(sampling_policy != SamplingPolicy::CENTER); + ARM_COMPUTE_UNUSED(border_mode, constant_border_value); + + ITensorInfo *offsets = nullptr; + ITensorInfo *dx = nullptr; + ITensorInfo *dy = nullptr; + + // Get data layout and width/height indices + const DataLayout data_layout = input->data_layout(); + const int idx_width = get_data_layout_dimension_index(data_layout, DataLayoutDimension::WIDTH); + const int idx_height = get_data_layout_dimension_index(data_layout, DataLayoutDimension::HEIGHT); + + // Get the tensor shape of auxilary buffers + const TensorShape shape(output->dimension(idx_width), output->dimension(idx_height)); + + TensorInfo tensor_info_offsets(shape, Format::S32); + TensorInfo tensor_info_dx(shape, Format::F32); + TensorInfo tensor_info_dy(shape, Format::F32); + + switch(policy) + { + case InterpolationPolicy::NEAREST_NEIGHBOR: + offsets = &tensor_info_offsets; + break; + case InterpolationPolicy::BILINEAR: + offsets = &tensor_info_offsets; + dx = &tensor_info_dx; + dy = &tensor_info_dy; + break; + default: + break; + } + + ARM_COMPUTE_RETURN_ON_ERROR(NEScaleKernel::validate(input->clone().get(), dx, dy, offsets, output->clone().get(), + policy, border_mode, sampling_policy)); + return Status{}; +} + void NEScale::run() { NEScheduler::get().schedule(&_border_handler, Window::DimZ); diff --git a/tests/validation/NEON/Scale.cpp b/tests/validation/NEON/Scale.cpp index b21affd9d3..8940259f13 100644 --- a/tests/validation/NEON/Scale.cpp +++ b/tests/validation/NEON/Scale.cpp @@ -74,6 +74,57 @@ constexpr float tolerance_num_f32 = 0.01f; TEST_SUITE(NEON) TEST_SUITE(Scale) +// *INDENT-OFF* +// clang-format off +DATA_TEST_CASE(Validate, framework::DatasetMode::ALL, zip(zip(zip(zip(zip(zip( + framework::dataset::make("InputInfo", { TensorInfo(TensorShape(27U, 13U, 2U), 1, DataType::U8, 0), // Mismatching data type + TensorInfo(TensorShape(27U, 13U, 2U), 1, DataType::F32, 0), // Unsupported sampling point + TensorInfo(TensorShape(4U, 27U, 13U), 1, DataType::F32, 0), // Invalid policy + TensorInfo(TensorShape(27U, 13U, 2U), 1, DataType::F32, 0), // Insufficient padding + TensorInfo(TensorShape(4U, 27U, 13U), 1, DataType::F32, 0), + }), + framework::dataset::make("OutputInfo",{ TensorInfo(TensorShape(132U, 25U, 2U), 1, DataType::F32, 0), + TensorInfo(TensorShape(132U, 25U, 2U), 1, DataType::F32, 0), + TensorInfo(TensorShape(4U, 132U, 25U), 1, DataType::F32, 0), + TensorInfo(TensorShape(132U, 25U, 2U), 1, DataType::F32, 0), + TensorInfo(TensorShape(4U, 132U, 25U), 1, DataType::F32, 0), + })), + framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, + InterpolationPolicy::NEAREST_NEIGHBOR, + InterpolationPolicy::AREA, + InterpolationPolicy::AREA, + InterpolationPolicy::NEAREST_NEIGHBOR, + })), + framework::dataset::make("BorderMode", { BorderMode::UNDEFINED, + BorderMode::UNDEFINED, + BorderMode::UNDEFINED, + BorderMode::UNDEFINED, + BorderMode::REPLICATE, + })), + framework::dataset::make("SamplingPolicy", { SamplingPolicy::CENTER, + SamplingPolicy::TOP_LEFT, + SamplingPolicy::CENTER, + SamplingPolicy::CENTER, + SamplingPolicy::CENTER, + })), + framework::dataset::make("DataLayout", { DataLayout::NCHW, + DataLayout::NCHW, + DataLayout::NHWC, + DataLayout::NCHW, + DataLayout::NHWC, + })), + framework::dataset::make("Expected", { false, false, false, false ,true })), + input_info, output_info, policy,border_mode, sampling_policy, data_layout, expected) +{ + const PixelValue constant_border(5); + Status status = NEScale::validate(&input_info.clone()->set_is_resizable(false).set_data_layout(data_layout), + &output_info.clone()->set_is_resizable(false).set_data_layout(data_layout), + policy, border_mode, constant_border, sampling_policy); + ARM_COMPUTE_EXPECT(bool(status) == expected, framework::LogLevel::ERRORS); +} +// clang-format on +// *INDENT-ON* + DATA_TEST_CASE(Configuration, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(concat(datasets::SmallShapes(), datasets::LargeShapes()), ScaleDataTypes), ScaleDataLayouts), framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })), datasets::BorderModes()), -- cgit v1.2.1