aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSang-Hoon Park <sang-hoon.park@arm.com>2020-05-27 13:03:18 +0100
committerSang-Hoon Park <sang-hoon.park@arm.com>2020-06-01 21:01:19 +0000
commitc72dabc9ad572493c12c1d9052ec201732b9201e (patch)
tree289072de7acd4d1f27af772ba542569a5dbd9efc
parent6d76e4d4b6e7d5e44d2cc9368d53a996d10672e4 (diff)
downloadComputeLibrary-c72dabc9ad572493c12c1d9052ec201732b9201e.tar.gz
COMPMID-3363: Test improvement of Scale on NEON
- Create shape dataset for scale kernel, focusing on smaller shapes to be more sensitive to aligned corners - Remove redundant configuration tests - Remove nightly tests - Create new suite for validate() testing - Code cleanup by const variables - Fix fixture issue at computation of minimum scaled size for aligned corners - Extract logic determining scale values for testing. Change-Id: Ifeef354a4d74ed9e6a4e514eded4298e595becbf Signed-off-by: Sang-Hoon Park <sang-hoon.park@arm.com> Reviewed-on: https://review.mlplatform.org/c/ml/ComputeLibrary/+/3273 Tested-by: Arm Jenkins <bsgcomp@arm.com> Reviewed-by: Georgios Pinitas <georgios.pinitas@arm.com> Comments-Addressed: Arm Jenkins <bsgcomp@arm.com>
-rw-r--r--tests/validation/NEON/Scale.cpp484
-rw-r--r--tests/validation/fixtures/ScaleFixture.h87
2 files changed, 322 insertions, 249 deletions
diff --git a/tests/validation/NEON/Scale.cpp b/tests/validation/NEON/Scale.cpp
index b7d7b00cb6..82ab666d4a 100644
--- a/tests/validation/NEON/Scale.cpp
+++ b/tests/validation/NEON/Scale.cpp
@@ -47,6 +47,105 @@ namespace validation
{
namespace
{
+using test::datasets::ShapeDataset;
+
+/** Class to generate boundary values for the given template parameters
+ * including shapes with large differences between width and height
+ */
+template <uint32_t channel, uint32_t batch, uint32_t element_per_vector, uint32_t vector_size>
+class ScaleShapesBaseDataSet : public ShapeDataset
+{
+ static constexpr auto boundary_minus_one = element_per_vector * vector_size - 1;
+ static constexpr auto boundary_plus_one = element_per_vector * vector_size + 1;
+ static constexpr auto small_size = 3;
+
+public:
+ // These tensor shapes are NCHW layout, fixture will convert to NHWC.
+ ScaleShapesBaseDataSet()
+ : ShapeDataset("Shape",
+ {
+ TensorShape{ small_size, boundary_minus_one, channel, batch },
+ TensorShape{ small_size, boundary_plus_one, channel, batch },
+ TensorShape{ boundary_minus_one, small_size, channel, batch },
+ TensorShape{ boundary_plus_one, small_size, channel, batch },
+ TensorShape{ boundary_minus_one, boundary_plus_one, channel, batch },
+ TensorShape{ boundary_plus_one, boundary_minus_one, channel, batch },
+ })
+ {
+ }
+};
+
+/** For the single vector, only larger value (+1) than boundary
+ * since smaller value (-1) could cause some invalid shapes like
+ * - invalid zero size
+ * - size 1 which isn't compatible with scale with aligned corners.
+ */
+template <uint32_t channel, uint32_t batch, uint32_t element_per_vector>
+class ScaleShapesBaseDataSet<channel, batch, element_per_vector, 1> : public ShapeDataset
+{
+ static constexpr auto small_size = 3;
+ static constexpr auto boundary_plus_one = element_per_vector + 1;
+
+public:
+ // These tensor shapes are NCHW layout, fixture will convert to NHWC.
+ ScaleShapesBaseDataSet()
+ : ShapeDataset("Shape",
+ {
+ TensorShape{ small_size, boundary_plus_one, channel, batch },
+ TensorShape{ boundary_plus_one, small_size, channel, batch },
+ })
+ {
+ }
+};
+
+/** For the shapes smaller than one vector, only pre-defined tiny shapes
+ * are tested (3x2, 2x3) as smaller shapes are more likely to cause
+ * issues and easier to debug.
+ */
+template <uint32_t channel, uint32_t batch, uint32_t element_per_vector>
+class ScaleShapesBaseDataSet<channel, batch, element_per_vector, 0> : public ShapeDataset
+{
+ static constexpr auto small_size = 3;
+ static constexpr auto zero_vector_boundary_value = 2;
+
+public:
+ // These tensor shapes are NCHW layout, fixture will convert to NHWC.
+ ScaleShapesBaseDataSet()
+ : ShapeDataset("Shape",
+ {
+ TensorShape{ small_size, zero_vector_boundary_value, channel, batch },
+ TensorShape{ zero_vector_boundary_value, small_size, channel, batch },
+ })
+ {
+ }
+};
+
+/** Generated shaeps
+ * - 2D shapes with 0, 1, 2 vector iterations
+ * - 3D shapes with 0, 1 vector iterations
+ * - 4D shapes with 0 vector iterations
+ */
+#define SCALE_SHAPE_DATASET(element_per_vector) \
+ concat(concat(concat(concat(concat(ScaleShapesBaseDataSet<1, 1, (element_per_vector), 0>(), \
+ ScaleShapesBaseDataSet<1, 1, (element_per_vector), 1>()), \
+ ScaleShapesBaseDataSet<1, 1, (element_per_vector), 2>()), \
+ ScaleShapesBaseDataSet<3, 3, (element_per_vector), 0>()), \
+ ScaleShapesBaseDataSet<3, 3, (element_per_vector), 1>()), \
+ ScaleShapesBaseDataSet<3, 7, (element_per_vector), 0>())
+
+/** We consider vector size in byte 64 since the maximum size of
+ * a vector used by @ref ScaleKernelInfo is currently 64-byte (float32x4x4).
+ * There are possibility to reduce test time further by using
+ * smaller vector sizes for different data types where applicable.
+ */
+constexpr uint32_t vector_byte = 64;
+
+template <typename T>
+constexpr uint32_t num_elements_per_vector()
+{
+ return vector_byte / sizeof(T);
+}
+
/** Scale data types */
const auto ScaleDataTypes = framework::dataset::make("DataType",
{
@@ -55,6 +154,13 @@ const auto ScaleDataTypes = framework::dataset::make("DataType",
DataType::F32,
});
+/** Interpolation policy test set */
+const auto InterpolationPolicySet = framework::dataset::make("InterpolationPolicy",
+{
+ InterpolationPolicy::NEAREST_NEIGHBOR,
+ InterpolationPolicy::BILINEAR,
+});
+
/** Scale data types */
const auto ScaleDataLayouts = framework::dataset::make("DataLayout",
{
@@ -62,6 +168,13 @@ const auto ScaleDataLayouts = framework::dataset::make("DataLayout",
DataLayout::NHWC,
});
+/** Sampling policy data set */
+const auto SamplingPolicySet = framework::dataset::make("SamplingPolicy",
+{
+ SamplingPolicy::TOP_LEFT,
+ SamplingPolicy::CENTER,
+});
+
/** Align corners */
const auto AlignCorners = framework::dataset::make("AlignCorners",
{
@@ -69,6 +182,30 @@ const auto AlignCorners = framework::dataset::make("AlignCorners",
true,
});
+/** Generating dataset for non-quantized data tyeps with the given shapes */
+#define ASSEMBLE_DATASET(shape) \
+ combine(combine(combine(combine(combine((shape), ScaleDataLayouts), \
+ InterpolationPolicySet), \
+ datasets::BorderModes()), \
+ SamplingPolicySet), \
+ AlignCorners)
+
+/** Quantization information data set */
+const auto QuantizationInfoSet = framework::dataset::make("QuantizationInfo",
+{
+ QuantizationInfo(0.5f, -10),
+});
+
+/** Generating dataset for quantized data tyeps with the given shapes */
+#define ASSEMBLE_QUANTIZED_DATASET(shape) \
+ combine(combine(combine(combine(combine(combine(shape, \
+ QuantizationInfoSet), \
+ ScaleDataLayouts), \
+ InterpolationPolicySet), \
+ datasets::BorderModes()), \
+ SamplingPolicySet), \
+ AlignCorners)
+
/** Tolerance */
constexpr AbsoluteTolerance<uint8_t> tolerance_u8(1);
constexpr AbsoluteTolerance<int16_t> tolerance_s16(1);
@@ -83,123 +220,151 @@ constexpr float tolerance_num_f32 = 0.01f;
TEST_SUITE(NEON)
TEST_SUITE(Scale)
+TEST_SUITE(Validate)
+
+/** Validate test suite is to test ARM_COMPUTE_RETURN_ON_* macros
+ * we use to check the validity of given arguments in @ref NEScale
+ * and subsequent call to @ref NEScaleKernel.
+ * Since this is using validate() of @ref NEScale, which pre-adjust
+ * arguments for @ref NEScaleKernel, the following conditions in
+ * the kernel are not currently tested.
+ * - The same input and output
+ * - Data type of offset, dx and dy
+ */
-// *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), // Mismatching data type
- TensorInfo(TensorShape(4U, 27U, 13U), 1, DataType::F32), // Invalid policy
- TensorInfo(TensorShape(27U, 13U, 2U), 1, DataType::F32), // Insufficient padding
- TensorInfo(TensorShape(4U, 27U, 13U), 1, DataType::F32),
- }),
- framework::dataset::make("OutputInfo",{ TensorInfo(TensorShape(132U, 25U, 2U), 1, DataType::F32),
- TensorInfo(TensorShape(4U, 132U, 25U), 1, DataType::F32),
- TensorInfo(TensorShape(132U, 25U, 2U), 1, DataType::F32),
- TensorInfo(TensorShape(4U, 132U, 25U), 1, DataType::F32),
- })),
- framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR,
- InterpolationPolicy::AREA,
- InterpolationPolicy::AREA,
- InterpolationPolicy::NEAREST_NEIGHBOR,
- })),
- framework::dataset::make("BorderMode", { BorderMode::UNDEFINED,
- BorderMode::UNDEFINED,
- BorderMode::UNDEFINED,
- BorderMode::REPLICATE,
- })),
- framework::dataset::make("SamplingPolicy", { SamplingPolicy::CENTER,
- SamplingPolicy::CENTER,
- SamplingPolicy::CENTER,
- SamplingPolicy::CENTER,
- })),
- framework::dataset::make("DataLayout", { DataLayout::NCHW,
- DataLayout::NHWC,
- DataLayout::NCHW,
- DataLayout::NHWC,
- })),
- framework::dataset::make("Expected", { false, false, false ,true })),
- input_info, output_info, policy,border_mode, sampling_policy, data_layout, expected)
+const auto input_shape = TensorShape{ 2, 3, 3, 2 };
+const auto output_shape = TensorShape{ 4, 6, 3, 2 };
+
+constexpr auto default_data_type = DataType::U8;
+constexpr auto default_data_layout = DataLayout::NHWC;
+constexpr auto default_interpolation_policy = InterpolationPolicy::NEAREST_NEIGHBOR;
+constexpr auto default_border_mode = BorderMode::UNDEFINED;
+constexpr auto default_sampling_policy = SamplingPolicy::CENTER;
+constexpr bool default_use_padding = false;
+
+TEST_CASE(NullPtr, framework::DatasetMode::ALL)
{
- 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);
+ const auto input = TensorInfo{ input_shape, 1, default_data_type, default_data_layout };
+ const auto output = TensorInfo{ output_shape, 1, default_data_type, default_data_layout };
+ Status result{};
+
+ // nullptr is given as input
+ result = NEScale::validate(nullptr, &output, default_interpolation_policy, default_border_mode);
+ ARM_COMPUTE_EXPECT(bool(result) == false, framework::LogLevel::ERRORS);
+
+ // nullptr is given as output
+ result = NEScale::validate(&input, nullptr, default_interpolation_policy, default_border_mode);
+ ARM_COMPUTE_EXPECT(bool(result) == false, framework::LogLevel::ERRORS);
}
-// clang-format on
-// *INDENT-ON*
-
-DATA_TEST_CASE(Configuration, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(datasets::SmallShapes(), ScaleDataTypes), ScaleDataLayouts),
- framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })),
- datasets::BorderModes()),
- framework::dataset::make("SamplingPolicy", { SamplingPolicy::CENTER })),
- shape, data_type, data_layout, policy, border_mode, sampling_policy)
+
+TEST_CASE(SupportDataType, framework::DatasetMode::ALL)
{
- std::mt19937 generator(library->seed());
- std::uniform_real_distribution<float> distribution_float(0.25, 2);
- const float scale_x = distribution_float(generator);
- const float scale_y = distribution_float(generator);
- uint8_t constant_border_value = 0;
- TensorShape src_shape = shape;
- if(border_mode == BorderMode::CONSTANT)
+ const std::map<DataType, bool> supported_data_types =
{
- std::uniform_int_distribution<uint8_t> distribution_u8(0, 255);
- constant_border_value = distribution_u8(generator);
- }
-
- // Get width/height indices depending on 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);
-
- // Change shape in case of NHWC.
- if(data_layout == DataLayout::NHWC)
+ { DataType::U8, true },
+ { DataType::S8, false },
+ { DataType::QSYMM8, false },
+ { DataType::QASYMM8, true },
+ { DataType::QASYMM8_SIGNED, true },
+ { DataType::QSYMM8_PER_CHANNEL, false },
+ { DataType::U16, false },
+ { DataType::S16, true },
+ { DataType::QSYMM16, false },
+ { DataType::QASYMM16, false },
+ { DataType::U32, false },
+ { DataType::S32, false },
+ { DataType::U64, false },
+ { DataType::S64, false },
+ { DataType::BFLOAT16, false },
+#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
+ { DataType::F16, true },
+#else // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
+ { DataType::F16, false },
+#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
+ { DataType::F32, true },
+ { DataType::F64, false },
+ { DataType::SIZET, false },
+ };
+ Status result{};
+ for(auto &kv : supported_data_types)
{
- permute(src_shape, PermutationVector(2U, 0U, 1U));
+ const auto input = TensorInfo{ input_shape, 1, kv.first, default_data_layout };
+ const auto output = TensorInfo{ output_shape, 1, kv.first, default_data_layout };
+ result = NEScale::validate(&input, &output, default_interpolation_policy, default_border_mode);
+ ARM_COMPUTE_EXPECT(bool(result) == kv.second, framework::LogLevel::ERRORS);
}
+}
- // Calculate scaled shape
- TensorShape shape_scaled(src_shape);
- shape_scaled.set(idx_width, src_shape[idx_width] * scale_x);
- shape_scaled.set(idx_height, src_shape[idx_height] * scale_y);
+TEST_CASE(MissmatchingDataType, framework::DatasetMode::ALL)
+{
+ constexpr auto non_default_data_type = DataType::F32;
- // Create tensors
- Tensor src = create_tensor<Tensor>(src_shape, data_type, 1, QuantizationInfo(), data_layout);
- Tensor dst = create_tensor<Tensor>(shape_scaled, data_type, 1, QuantizationInfo(), data_layout);
+ const auto input = TensorInfo{ input_shape, 1, default_data_type, default_data_layout };
+ const auto output = TensorInfo{ output_shape, 1, non_default_data_type, default_data_layout };
+ Status result{};
+ result = NEScale::validate(&input, &output, default_interpolation_policy, default_border_mode);
+ ARM_COMPUTE_EXPECT(bool(result) == false, framework::LogLevel::ERRORS);
+}
- ARM_COMPUTE_EXPECT(src.info()->is_resizable(), framework::LogLevel::ERRORS);
- ARM_COMPUTE_EXPECT(dst.info()->is_resizable(), framework::LogLevel::ERRORS);
+TEST_CASE(UsePadding, framework::DatasetMode::ALL)
+{
+ const auto input = TensorInfo{ input_shape, 1, default_data_type, default_data_layout };
+ const auto output = TensorInfo{ output_shape, 1, default_data_type, default_data_layout };
+ Status result{};
- // Create and configure function
- NEScale nescale;
- nescale.configure(&src, &dst, policy, border_mode, constant_border_value, sampling_policy);
+ // When use padding is false, border mode should be constant
+ constexpr auto border_mode = BorderMode::UNDEFINED;
+ constexpr bool use_padding = false;
- // Validate valid region
- const ValidRegion dst_valid_region = calculate_valid_region_scale(*(src.info()), shape_scaled, policy, sampling_policy, (border_mode == BorderMode::UNDEFINED));
- validate(dst.info()->valid_region(), dst_valid_region);
+ result = NEScale::validate(&input, &output, default_interpolation_policy, border_mode, PixelValue(), default_sampling_policy, use_padding);
+ ARM_COMPUTE_EXPECT(bool(result) == false, framework::LogLevel::ERRORS);
+}
- // Validate padding
- int num_elements_processed_x = 16;
- if(data_layout == DataLayout::NHWC)
- {
- num_elements_processed_x = (policy == InterpolationPolicy::BILINEAR) ? 1 : 16 / src.info()->element_size();
- }
- PaddingCalculator calculator(shape_scaled.x(), num_elements_processed_x);
- calculator.set_border_mode(border_mode);
+TEST_CASE(AreaWithNHWC, framework::DatasetMode::ALL)
+{
+ // InterpolationPolicy::AREA is not supported for NHWC
+ constexpr auto interpolation_policy = InterpolationPolicy::AREA;
+ constexpr auto data_layout = DataLayout::NHWC;
+
+ const auto input = TensorInfo{ input_shape, 1, default_data_type, data_layout };
+ const auto output = TensorInfo{ output_shape, 1, default_data_type, data_layout };
+ Status result{};
+ result = NEScale::validate(&input, &output, interpolation_policy, default_border_mode);
+ ARM_COMPUTE_EXPECT(bool(result) == false, framework::LogLevel::ERRORS);
+}
- PaddingSize read_padding(1);
- if(data_layout == DataLayout::NHWC)
- {
- read_padding = calculator.required_padding(PaddingCalculator::Option::EXCLUDE_BORDER);
- if(border_mode != BorderMode::REPLICATE && policy == InterpolationPolicy::BILINEAR)
- {
- read_padding.top = 1;
- }
- }
- const PaddingSize write_padding = calculator.required_padding(PaddingCalculator::Option::EXCLUDE_BORDER);
- validate(src.info()->padding(), read_padding);
- validate(dst.info()->padding(), write_padding);
+TEST_CASE(AreaWithNonU8, framework::DatasetMode::ALL)
+{
+ // InterpolationPolicy::AREA only supports U8
+ constexpr auto interpolation_policy = InterpolationPolicy::AREA;
+ constexpr auto data_type = DataType::F32;
+ constexpr auto data_layout = DataLayout::NCHW;
+
+ const auto input = TensorInfo{ input_shape, 1, data_type, data_layout };
+ const auto output = TensorInfo{ output_shape, 1, data_type, data_layout };
+ Status result{};
+ result = NEScale::validate(&input, &output, interpolation_policy, default_border_mode);
+ 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, 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 <typename T>
using NEScaleFixture = ScaleValidationFixture<Tensor, Accessor, NEScale, T>;
template <typename T>
@@ -207,28 +372,8 @@ using NEScaleQuantizedFixture = ScaleValidationQuantizedFixture<Tensor, Accessor
TEST_SUITE(Float)
TEST_SUITE(FP32)
-FIXTURE_DATA_TEST_CASE(RunSmall, NEScaleFixture<float>, 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 })),
- AlignCorners))
-{
- //Create valid region
- TensorInfo src_info(_shape, 1, _data_type);
- ValidRegion valid_region = calculate_valid_region_scale(src_info, _reference.shape(), _policy, _sampling_policy, (_border_mode == BorderMode::UNDEFINED));
-
- // Validate output
- validate(Accessor(_target), _reference, valid_region, tolerance_f32, tolerance_num_f32);
-}
-FIXTURE_DATA_TEST_CASE(RunLarge, NEScaleFixture<float>, 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 })),
- AlignCorners))
+const auto f32_shape = combine((SCALE_SHAPE_DATASET(num_elements_per_vector<float>())), framework::dataset::make("DataType", DataType::F32));
+FIXTURE_DATA_TEST_CASE(RunSmall, NEScaleFixture<float>, framework::DatasetMode::ALL, ASSEMBLE_DATASET(f32_shape))
{
//Create valid region
TensorInfo src_info(_shape, 1, _data_type);
@@ -240,28 +385,8 @@ FIXTURE_DATA_TEST_CASE(RunLarge, NEScaleFixture<float>, framework::DatasetMode::
TEST_SUITE_END() // FP32
#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
TEST_SUITE(FP16)
-FIXTURE_DATA_TEST_CASE(RunSmall, NEScaleFixture<half>, 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 })),
- AlignCorners))
-{
- //Create valid region
- TensorInfo src_info(_shape, 1, _data_type);
- const ValidRegion valid_region = calculate_valid_region_scale(src_info, _reference.shape(), _policy, _sampling_policy, (_border_mode == BorderMode::UNDEFINED));
-
- // Validate output
- validate(Accessor(_target), _reference, valid_region, tolerance_f16);
-}
-FIXTURE_DATA_TEST_CASE(RunLarge, NEScaleFixture<half>, 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 })),
- AlignCorners))
+const auto f16_shape = combine((SCALE_SHAPE_DATASET(num_elements_per_vector<half>())), framework::dataset::make("DataType", DataType::F16));
+FIXTURE_DATA_TEST_CASE(RunSmall, NEScaleFixture<half>, framework::DatasetMode::ALL, ASSEMBLE_DATASET(f16_shape))
{
//Create valid region
TensorInfo src_info(_shape, 1, _data_type);
@@ -276,28 +401,8 @@ TEST_SUITE_END() // Float
TEST_SUITE(Integer)
TEST_SUITE(U8)
-FIXTURE_DATA_TEST_CASE(RunSmall, NEScaleFixture<uint8_t>, 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 })),
- AlignCorners))
-{
- //Create valid region
- TensorInfo src_info(_shape, 1, _data_type);
- ValidRegion valid_region = calculate_valid_region_scale(src_info, _reference.shape(), _policy, _sampling_policy, (_border_mode == BorderMode::UNDEFINED));
-
- // Validate output
- validate(Accessor(_target), _reference, valid_region, tolerance_u8);
-}
-FIXTURE_DATA_TEST_CASE(RunLarge, NEScaleFixture<uint8_t>, 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 })),
- AlignCorners))
+const auto u8_shape = combine((SCALE_SHAPE_DATASET(num_elements_per_vector<uint8_t>())), framework::dataset::make("DataType", DataType::U8));
+FIXTURE_DATA_TEST_CASE(RunSmall, NEScaleFixture<uint8_t>, framework::DatasetMode::ALL, ASSEMBLE_DATASET(u8_shape))
{
//Create valid region
TensorInfo src_info(_shape, 1, _data_type);
@@ -308,28 +413,8 @@ FIXTURE_DATA_TEST_CASE(RunLarge, NEScaleFixture<uint8_t>, framework::DatasetMode
}
TEST_SUITE_END() // U8
TEST_SUITE(S16)
-FIXTURE_DATA_TEST_CASE(RunSmall, NEScaleFixture<int16_t>, 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 })),
- AlignCorners))
-{
- //Create valid region
- TensorInfo src_info(_shape, 1, _data_type);
- ValidRegion valid_region = calculate_valid_region_scale(src_info, _reference.shape(), _policy, _sampling_policy, (_border_mode == BorderMode::UNDEFINED));
-
- // Validate output
- validate(Accessor(_target), _reference, valid_region, tolerance_s16, tolerance_num_s16);
-}
-FIXTURE_DATA_TEST_CASE(RunLarge, NEScaleFixture<int16_t>, 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 })),
- AlignCorners))
+const auto s16_shape = combine((SCALE_SHAPE_DATASET(num_elements_per_vector<int16_t>())), framework::dataset::make("DataType", DataType::S16));
+FIXTURE_DATA_TEST_CASE(RunSmall, NEScaleFixture<int16_t>, framework::DatasetMode::ALL, ASSEMBLE_DATASET(s16_shape))
{
//Create valid region
TensorInfo src_info(_shape, 1, _data_type);
@@ -343,14 +428,8 @@ TEST_SUITE_END() // Integer
TEST_SUITE(Quantized)
TEST_SUITE(QASYMM8)
-FIXTURE_DATA_TEST_CASE(RunSmall, NEScaleQuantizedFixture<uint8_t>, 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 })),
- AlignCorners))
+const auto qasymm8_shape = combine((SCALE_SHAPE_DATASET(num_elements_per_vector<uint8_t>())), framework::dataset::make("DataType", DataType::QASYMM8));
+FIXTURE_DATA_TEST_CASE(RunSmall, NEScaleQuantizedFixture<uint8_t>, framework::DatasetMode::ALL, ASSEMBLE_QUANTIZED_DATASET(qasymm8_shape))
{
//Create valid region
TensorInfo src_info(_shape, 1, _data_type);
@@ -360,16 +439,9 @@ FIXTURE_DATA_TEST_CASE(RunSmall, NEScaleQuantizedFixture<uint8_t>, framework::Da
validate(Accessor(_target), _reference, valid_region, tolerance_u8);
}
TEST_SUITE_END() // QASYMM8
-
TEST_SUITE(QASYMM8_SIGNED)
-FIXTURE_DATA_TEST_CASE(RunSmall, NEScaleQuantizedFixture<int8_t>, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(combine(combine(datasets::SmallShapes(),
- framework::dataset::make("DataType", DataType::QASYMM8_SIGNED)),
- 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 })),
- AlignCorners))
+const auto qasymm8_signed_shape = combine((SCALE_SHAPE_DATASET(num_elements_per_vector<int8_t>())), framework::dataset::make("DataType", DataType::QASYMM8_SIGNED));
+FIXTURE_DATA_TEST_CASE(RunSmall, NEScaleQuantizedFixture<int8_t>, framework::DatasetMode::ALL, ASSEMBLE_QUANTIZED_DATASET(qasymm8_signed_shape))
{
//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 e3846eda67..cf3c5c818f 100644
--- a/tests/validation/fixtures/ScaleFixture.h
+++ b/tests/validation/fixtures/ScaleFixture.h
@@ -48,52 +48,54 @@ public:
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;
-
_shape = shape;
_policy = policy;
_border_mode = border_mode;
_sampling_policy = sampling_policy;
_data_type = data_type;
_quantization_info = quantization_info;
- _align_corners = align_corners;
+ _align_corners = align_corners && _policy == InterpolationPolicy::BILINEAR && _sampling_policy == SamplingPolicy::TOP_LEFT;
- std::mt19937 generator(library->seed());
- std::uniform_real_distribution<float> distribution_float(0.25, 3);
- float scale_x = distribution_float(generator);
- float scale_y = distribution_float(generator);
+ generate_scale(shape);
- 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);
+ std::mt19937 generator(library->seed());
+ std::uniform_int_distribution<uint8_t> distribution_u8(0, 255);
+ _constant_border_value = static_cast<T>(distribution_u8(generator));
- scale_x = ((shape[idx_width] * scale_x) > max_width) ? (max_width / shape[idx_width]) : scale_x;
- scale_y = ((shape[idx_height] * scale_y) > max_height) ? (max_height / shape[idx_height]) : scale_y;
+ _target = compute_target(shape, data_layout);
+ _reference = compute_reference(shape);
+ }
- const bool align_corners_a = policy == InterpolationPolicy::BILINEAR
- && sampling_policy == SamplingPolicy::TOP_LEFT
- && align_corners;
+protected:
+ void generate_scale(const TensorShape &shape)
+ {
+ static constexpr float _min_scale{ 0.25f };
+ static constexpr float _max_scale{ 3.f };
- if(align_corners_a)
+ constexpr float max_width{ 8192.0f };
+ constexpr float max_height{ 6384.0f };
+
+ const float min_width = _align_corners ? 2.f : 1.f;
+ const float min_height = _align_corners ? 2.f : 1.f;
+
+ std::mt19937 generator(library->seed());
+ std::uniform_real_distribution<float> distribution_float(_min_scale, _max_scale);
+
+ auto generate = [&](size_t input_size, float min_output, float max_output) -> float
{
- /* When align_corners = true is used for bilinear, both width and height
- * of output should be > 1 to avoid overflow during computation otherwise
- * it fails while checking argument values.
- */
- constexpr float min_width = 2.f;
- constexpr float min_height = 2.f;
- scale_x = ((shape[idx_width] * scale_x) < min_width) ? (min_width / shape[idx_width]) : scale_x;
- scale_y = ((shape[idx_height] * scale_y) < min_height) ? (min_height / shape[idx_height]) : scale_y;
- }
+ const float generated_scale = distribution_float(generator);
+ const float output_size = utility::clamp(static_cast<float>(input_size) * generated_scale, min_output, max_output);
+ return output_size / input_size;
+ };
- std::uniform_int_distribution<uint8_t> distribution_u8(0, 255);
- T constant_border_value = static_cast<T>(distribution_u8(generator));
+ // Input shape is always given in NCHW layout. NHWC is dealt by permute in compute_target()
+ const int idx_width = get_data_layout_dimension_index(DataLayout::NCHW, DataLayoutDimension::WIDTH);
+ const int idx_height = get_data_layout_dimension_index(DataLayout::NCHW, DataLayoutDimension::HEIGHT);
- _target = compute_target(shape, data_layout, scale_x, scale_y, policy, border_mode, constant_border_value, sampling_policy, quantization_info);
- _reference = compute_reference(shape, scale_x, scale_y, policy, border_mode, constant_border_value, sampling_policy, quantization_info);
+ _scale_x = generate(shape[idx_width], min_width, max_width);
+ _scale_y = generate(shape[idx_height], min_height, max_height);
}
-protected:
template <typename U>
void fill(U &&tensor)
{
@@ -114,9 +116,7 @@ protected:
}
}
- TensorType compute_target(TensorShape shape, DataLayout data_layout, const float scale_x, const float scale_y,
- InterpolationPolicy policy, BorderMode border_mode, T constant_border_value, SamplingPolicy sampling_policy,
- QuantizationInfo quantization_info)
+ TensorType compute_target(TensorShape shape, DataLayout data_layout)
{
// Change shape in case of NHWC.
if(data_layout == DataLayout::NHWC)
@@ -125,20 +125,20 @@ protected:
}
// Create tensors
- TensorType src = create_tensor<TensorType>(shape, _data_type, 1, quantization_info, data_layout);
+ TensorType src = create_tensor<TensorType>(shape, _data_type, 1, _quantization_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);
TensorShape shape_scaled(shape);
- shape_scaled.set(idx_width, shape[idx_width] * scale_x);
- shape_scaled.set(idx_height, shape[idx_height] * scale_y);
- TensorType dst = create_tensor<TensorType>(shape_scaled, _data_type, 1, quantization_info, data_layout);
+ shape_scaled.set(idx_width, shape[idx_width] * _scale_x);
+ shape_scaled.set(idx_height, shape[idx_height] * _scale_y);
+ TensorType dst = create_tensor<TensorType>(shape_scaled, _data_type, 1, _quantization_info, data_layout);
// Create and configure function
FunctionType scale;
- scale.configure(&src, &dst, policy, border_mode, constant_border_value, sampling_policy, /* use_padding */ true, _align_corners);
+ 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);
@@ -158,17 +158,15 @@ protected:
return dst;
}
- SimpleTensor<T> compute_reference(const TensorShape &shape, const float scale_x, const float scale_y,
- InterpolationPolicy policy, BorderMode border_mode, T constant_border_value, SamplingPolicy sampling_policy,
- QuantizationInfo quantization_info)
+ SimpleTensor<T> compute_reference(const TensorShape &shape)
{
// Create reference
- SimpleTensor<T> src{ shape, _data_type, 1, quantization_info };
+ SimpleTensor<T> src{ shape, _data_type, 1, _quantization_info };
// Fill reference
fill(src);
- return reference::scale<T>(src, scale_x, scale_y, policy, border_mode, constant_border_value, sampling_policy, /* ceil_policy_scale */ false, _align_corners);
+ return reference::scale<T>(src, _scale_x, _scale_y, _policy, _border_mode, _constant_border_value, _sampling_policy, /* ceil_policy_scale */ false, _align_corners);
}
TensorType _target{};
@@ -176,10 +174,13 @@ protected:
TensorShape _shape{};
InterpolationPolicy _policy{};
BorderMode _border_mode{};
+ T _constant_border_value{};
SamplingPolicy _sampling_policy{};
DataType _data_type{};
QuantizationInfo _quantization_info{};
bool _align_corners{ false };
+ float _scale_x{ 1.f };
+ float _scale_y{ 1.f };
};
template <typename TensorType, typename AccessorType, typename FunctionType, typename T>