diff options
Diffstat (limited to 'tests/validation/NEON/ActivationLayer.cpp')
-rw-r--r-- | tests/validation/NEON/ActivationLayer.cpp | 266 |
1 files changed, 210 insertions, 56 deletions
diff --git a/tests/validation/NEON/ActivationLayer.cpp b/tests/validation/NEON/ActivationLayer.cpp index 063bfaa2cd..73f5de68ac 100644 --- a/tests/validation/NEON/ActivationLayer.cpp +++ b/tests/validation/NEON/ActivationLayer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2020 ARM Limited. + * Copyright (c) 2017-2023 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -22,10 +22,14 @@ * SOFTWARE. */ #include "arm_compute/core/Types.h" +#include "arm_compute/core/utils/misc/Traits.h" +#include "arm_compute/core/utils/StringUtils.h" #include "arm_compute/runtime/NEON/functions/NEActivationLayer.h" #include "arm_compute/runtime/RuntimeContext.h" #include "arm_compute/runtime/Tensor.h" #include "arm_compute/runtime/TensorAllocator.h" +#include "src/common/cpuinfo/CpuIsaInfo.h" +#include "src/cpu/kernels/CpuActivationKernel.h" #include "tests/NEON/Accessor.h" #include "tests/PaddingCalculator.h" #include "tests/datasets/ActivationFunctionsDataset.h" @@ -36,6 +40,9 @@ #include "tests/validation/Validation.h" #include "tests/validation/fixtures/ActivationLayerFixture.h" +#include "arm_compute/Acl.hpp" +#include "support/AclRequires.h" + namespace arm_compute { namespace test @@ -44,6 +51,8 @@ namespace validation { namespace { +RelativeTolerance<float> tolerance_float_sqrt(0.0001f); + /** Define relative tolerance of the activation layer. * * @param[in] data_type The data type used. @@ -56,17 +65,35 @@ RelativeTolerance<float> relative_tolerance(DataType data_type, ActivationLayerI switch(activation) { case ActivationLayerInfo::ActivationFunction::LOGISTIC: - case ActivationLayerInfo::ActivationFunction::SOFT_RELU: case ActivationLayerInfo::ActivationFunction::ELU: case ActivationLayerInfo::ActivationFunction::SQRT: case ActivationLayerInfo::ActivationFunction::TANH: + case ActivationLayerInfo::ActivationFunction::HARD_SWISH: + case ActivationLayerInfo::ActivationFunction::SWISH: + case ActivationLayerInfo::ActivationFunction::GELU: switch(data_type) { case DataType::F16: +#if defined(ENABLE_SVE) + return RelativeTolerance<float>(0.25f); +#else // !defined(ENABLE_SVE) return RelativeTolerance<float>(0.1f); +#endif // defined(ENABLE_SVE) default: return RelativeTolerance<float>(0.05f); } + case ActivationLayerInfo::ActivationFunction::SOFT_RELU: + switch(data_type) + { + case DataType::F16: +#if defined(ENABLE_SVE) + return RelativeTolerance<float>(0.9f); +#else // !defined(ENABLE_SVE) + return RelativeTolerance<float>(0.01f); +#endif // defined(ENABLE_SVE) + default: + return RelativeTolerance<float>(0.00001f); + } default: return RelativeTolerance<float>(0.f); } @@ -84,13 +111,30 @@ AbsoluteTolerance<float> absolute_tolerance(DataType data_type, ActivationLayerI switch(activation) { case ActivationLayerInfo::ActivationFunction::LOGISTIC: - case ActivationLayerInfo::ActivationFunction::SOFT_RELU: case ActivationLayerInfo::ActivationFunction::SQRT: case ActivationLayerInfo::ActivationFunction::TANH: + case ActivationLayerInfo::ActivationFunction::SWISH: + case ActivationLayerInfo::ActivationFunction::HARD_SWISH: switch(data_type) { case DataType::F16: +#if defined(ENABLE_SVE) + return AbsoluteTolerance<float>(0.25f); +#else // !defined(ENABLE_SVE) return AbsoluteTolerance<float>(0.01f); +#endif // defined(ENABLE_SVE) + default: + return AbsoluteTolerance<float>(0.00001f); + } + case ActivationLayerInfo::ActivationFunction::SOFT_RELU: + switch(data_type) + { + case DataType::F16: +#if defined(ENABLE_SVE) + return AbsoluteTolerance<float>(0.9f); +#else // !defined(ENABLE_SVE) + return AbsoluteTolerance<float>(0.01f); +#endif // defined(ENABLE_SVE) default: return AbsoluteTolerance<float>(0.00001f); } @@ -99,12 +143,27 @@ AbsoluteTolerance<float> absolute_tolerance(DataType data_type, ActivationLayerI } } -/** Tolerance for quantized asymmetric operations */ -#if defined(__aarch64__) -constexpr AbsoluteTolerance<uint8_t> tolerance_qasymm8(0); -#else // defined(__aarch64__) -constexpr AbsoluteTolerance<uint8_t> tolerance_qasymm8(1); -#endif // defined(__aarch64__) +/** Define absolute tolerance of the activation layer for qasymm8. + * + * @param[in] activation The activation function used. + * + * @return Absolute tolerance depending on the activation function. + */ +AbsoluteTolerance<uint8_t> tolerance_qasymm8(ActivationLayerInfo::ActivationFunction activation) +{ + switch(activation) + { + case ActivationLayerInfo::ActivationFunction::LOGISTIC: + case ActivationLayerInfo::ActivationFunction::SQRT: + case ActivationLayerInfo::ActivationFunction::TANH: + case ActivationLayerInfo::ActivationFunction::HARD_SWISH: + case ActivationLayerInfo::ActivationFunction::SOFT_RELU: + case ActivationLayerInfo::ActivationFunction::LEAKY_RELU: + return AbsoluteTolerance<uint8_t>(1); + default: + return AbsoluteTolerance<uint8_t>(0); + } +} constexpr AbsoluteTolerance<int16_t> tolerance_qsymm16(1); @@ -117,55 +176,93 @@ const auto CNNDataTypes = framework::dataset::make("DataType", DataType::F32, }); -const auto NeonActivationFunctionsDataset = concat(datasets::ActivationFunctions(), framework::dataset::make("ActivationFunction", ActivationLayerInfo::ActivationFunction::HARD_SWISH)); +const auto NeonActivationFunctionsDataset = concat(datasets::ActivationFunctions(), + framework::dataset::make("ActivationFunction", { ActivationLayerInfo::ActivationFunction::HARD_SWISH, ActivationLayerInfo::ActivationFunction::SWISH })); /** Input data sets. */ const auto ActivationDataset = combine(combine(framework::dataset::make("InPlace", { false, true }), NeonActivationFunctionsDataset), framework::dataset::make("AlphaBeta", { 0.5f, 1.f })); + +template <typename T, ARM_COMPUTE_REQUIRES_TA(arm_compute::utils::traits::is_floating_point<T>::value)> +void test_float_sqrt_boundary_value() +{ + constexpr auto vector_size = uint32_t{ 16 }; + + auto data_type = DataType::F32; +#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC + data_type = std::is_same<T, half>::value ? DataType::F16 : data_type; +#endif /* __ARM_FEATURE_FP16_VECTOR_ARITHMETIC */ + + const auto boundary_value_vector = std::vector<T> + { + std::numeric_limits<T>::min(), + T(0), + std::numeric_limits<T>::epsilon(), + std::numeric_limits<T>::max(), + }; + + // the following size ensures that the whole logic (vector + left-over) to be tested + // using all boundary values iff boundary_value_vecotr.size() is smaller than vector_size. + auto shape = TensorShape{ vector_size + boundary_value_vector.size() }; + auto info = ActivationLayerInfo{ ActivationLayerInfo::ActivationFunction::SQRT }; + auto src = create_tensor<Tensor>(shape, data_type); + + auto act = NEActivationLayer{}; + act.configure(&src, nullptr, info); + src.allocator()->allocate(); + library->fill_static_values(Accessor(src), boundary_value_vector); + act.run(); + + auto reference_src = SimpleTensor<T> { shape, data_type }; + library->fill_static_values(reference_src, boundary_value_vector); + auto reference_dst = reference::activation_layer<T>(reference_src, info); + + validate(Accessor(src), reference_dst, tolerance_float_sqrt); +} } // namespace TEST_SUITE(NEON) TEST_SUITE(ActivationLayer) -DATA_TEST_CASE(Configuration, framework::DatasetMode::ALL, combine(combine(datasets::SmallShapes(), CNNDataTypes), framework::dataset::make("InPlace", { false, true })), - shape, data_type, in_place) +/** Test case for memory injection in @ref cpu::CpuWinogradConv2d. + * + * Configure the operator once and inject memory at run-time in multiple executions. + * + * Checks performed in order: + * - Both runs compute the same output + */ +TEST_CASE(ActivationAPI, framework::DatasetMode::ALL) { - // Create tensors - Tensor src = create_tensor<Tensor>(shape, data_type, 1); - Tensor dst = create_tensor<Tensor>(shape, data_type, 1); + acl::StatusCode err = acl::StatusCode::Success; - ARM_COMPUTE_EXPECT(src.info()->is_resizable(), framework::LogLevel::ERRORS); - ARM_COMPUTE_EXPECT(dst.info()->is_resizable(), framework::LogLevel::ERRORS); + // Create context & Queue + acl::Context ctx(acl::Target::Cpu, &err); + ARM_COMPUTE_ASSERT(err == acl::StatusCode::Success); - // Create context - RuntimeContext ctx; + acl::Queue queue(ctx, &err); + ARM_COMPUTE_ASSERT(err == acl::StatusCode::Success); - // Create and configure function - NEActivationLayer act_layer(&ctx); + // Create activation operator + acl::TensorDescriptor src_info({ 2, 3 }, acl::DataType::Float32); + acl::TensorDescriptor dst_info({ 2, 3 }, acl::DataType::Float32); + acl::ActivationDesc desc{ AclRelu, 6.f, 0.f, false }; - if(in_place) - { - act_layer.configure(&src, nullptr, ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::ABS)); - } - else - { - act_layer.configure(&src, &dst, ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::ABS)); - } + acl::Activation act(ctx, src_info, dst_info, desc, &err); + ARM_COMPUTE_ASSERT(err == acl::StatusCode::Success); - // Validate valid region - const ValidRegion valid_region = shape_to_valid_region(shape); - validate(src.info()->valid_region(), valid_region); + // Create tensors and feed + acl::Tensor src(ctx, src_info, &err); + ARM_COMPUTE_ASSERT(err == acl::StatusCode::Success); + acl::Tensor dst(ctx, dst_info, &err); + ARM_COMPUTE_ASSERT(err == acl::StatusCode::Success); - if(!in_place) - { - validate(dst.info()->valid_region(), valid_region); - } + acl::TensorPack pack(ctx); + err = pack.add(src, ACL_SRC); + err = pack.add(dst, ACL_DST); + ARM_COMPUTE_ASSERT(err == acl::StatusCode::Success); - // Validate padding - validate(src.info()->padding(), PaddingSize()); - if(!in_place) - { - validate(dst.info()->padding(), PaddingSize()); - } + // Execute operator + err = act.run(queue, pack); + ARM_COMPUTE_ASSERT(err == acl::StatusCode::Success); } // *INDENT-OFF* @@ -189,6 +286,49 @@ DATA_TEST_CASE(Validate, framework::DatasetMode::ALL, zip(zip(zip( bool is_valid = bool(NEActivationLayer::validate(&input_info.clone()->set_is_resizable(false), &output_info.clone()->set_is_resizable(false), act_info)); ARM_COMPUTE_EXPECT(is_valid == expected, framework::LogLevel::ERRORS); } + +DATA_TEST_CASE(KernelSelection, framework::DatasetMode::ALL, concat(concat( + combine(framework::dataset::make("CpuExt", std::string("NEON")), + framework::dataset::make("DataType", { DataType::F32, + DataType::F16, + DataType::QASYMM8, + DataType::QASYMM8_SIGNED, + DataType::QSYMM16 + })), + combine(framework::dataset::make("CpuExt", std::string("SVE")), + framework::dataset::make("DataType", { DataType::F32, + DataType::F16, + }))), + combine(framework::dataset::make("CpuExt", std::string("SVE2")), + framework::dataset::make("DataType", { DataType::QASYMM8, + DataType::QASYMM8_SIGNED, + DataType::QSYMM16 + }))), + cpu_ext, data_type) +{ + using namespace cpu::kernels; + + cpuinfo::CpuIsaInfo cpu_isa{}; + cpu_isa.neon = (cpu_ext == "NEON"); + cpu_isa.sve = (cpu_ext == "SVE"); + cpu_isa.sve2 = (cpu_ext == "SVE2"); + cpu_isa.fp16 = (data_type == DataType::F16); + + const auto *selected_impl = CpuActivationKernel::get_implementation(ActivationDataTypeISASelectorData{data_type, CPUModel::GENERIC, cpu_isa,ActivationLayerInfo::ActivationFunction::BOUNDED_RELU}, cpu::KernelSelectionType::Preferred); + + ARM_COMPUTE_ERROR_ON_NULLPTR(selected_impl); + std::string expected = lower_string(cpu_ext) + "_" + cpu_impl_dt(data_type) + "_activation"; + if( data_type == DataType::QASYMM8 || data_type == DataType::QASYMM8_SIGNED) + { +#ifdef __aarch64__ + expected = "neon_q8_activation_lut"; +#else // __aarch64__ + expected = lower_string(cpu_ext) + "_" + cpu_impl_dt(data_type) + "_activation"; +#endif // __aarch64__ + } + std::string actual = selected_impl->name; + ARM_COMPUTE_EXPECT_EQUAL(expected, actual, framework::LogLevel::ERRORS); +} // clang-format on // *INDENT-ON* @@ -198,6 +338,10 @@ using NEActivationLayerFixture = ActivationValidationFixture<Tensor, Accessor, N TEST_SUITE(Float) #ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC TEST_SUITE(FP16) +TEST_CASE(SqrtBoundaryValue, framework::DatasetMode::ALL) +{ + test_float_sqrt_boundary_value<half>(); +} FIXTURE_DATA_TEST_CASE(RunSmall, NEActivationLayerFixture<half>, framework::DatasetMode::ALL, combine(combine(datasets::SmallShapes(), ActivationDataset), framework::dataset::make("DataType", DataType::F16))) @@ -205,10 +349,14 @@ FIXTURE_DATA_TEST_CASE(RunSmall, NEActivationLayerFixture<half>, framework::Data // Validate output validate(Accessor(_target), _reference, relative_tolerance(_data_type, _function), 0.f, absolute_tolerance(_data_type, _function)); } -TEST_SUITE_END() -#endif /* __ARM_FEATURE_FP16_VECTOR_ARITHMETIC */ +TEST_SUITE_END() // FP16 +#endif /* __ARM_FEATURE_FP16_VECTOR_ARITHMETIC */ TEST_SUITE(FP32) +TEST_CASE(SqrtBoundaryValue, framework::DatasetMode::ALL) +{ + test_float_sqrt_boundary_value<float>(); +} FIXTURE_DATA_TEST_CASE(RunSmall, NEActivationLayerFixture<float>, framework::DatasetMode::ALL, combine(combine(datasets::SmallShapes(), ActivationDataset), framework::dataset::make("DataType", DataType::F32))) @@ -223,12 +371,15 @@ template <typename T> using NEActivationLayerQuantizedFixture = ActivationValidationQuantizedFixture<Tensor, Accessor, NEActivationLayer, T>; /** Input data sets. */ -const auto QuantizedActivationFunctionsDataset = framework::dataset::make("ActivationFunction", { ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, - ActivationLayerInfo::ActivationFunction::RELU, - ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, - ActivationLayerInfo::ActivationFunction::LOGISTIC, - ActivationLayerInfo::ActivationFunction::TANH - }); +const auto QuantizedActivationFunctionsDataset = framework::dataset::make("ActivationFunction", +{ + ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, + ActivationLayerInfo::ActivationFunction::RELU, + ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, + ActivationLayerInfo::ActivationFunction::LOGISTIC, + ActivationLayerInfo::ActivationFunction::TANH, + ActivationLayerInfo::ActivationFunction::LEAKY_RELU, +}); const auto QuantizedActivationDataset = combine(combine(framework::dataset::make("InPlace", { false }), concat(QuantizedActivationFunctionsDataset, framework::dataset::make("ActivationFunction", ActivationLayerInfo::ActivationFunction::HARD_SWISH))), @@ -242,7 +393,7 @@ FIXTURE_DATA_TEST_CASE(RunSmall, NEActivationLayerQuantizedFixture<uint8_t>, fra framework::dataset::make("QuantizationInfo", { QuantizationInfo(0.1f, 128.0f) }))) { // Validate output - validate(Accessor(_target), _reference, tolerance_qasymm8); + validate(Accessor(_target), _reference, tolerance_qasymm8(_function)); } TEST_SUITE_END() // QASYMM8 @@ -253,14 +404,17 @@ FIXTURE_DATA_TEST_CASE(RunSmall, NEActivationLayerQuantizedFixture<int8_t>, fram framework::dataset::make("QuantizationInfo", { QuantizationInfo(0.5f, 10.0f) }))) { // Validate output - validate(Accessor(_target), _reference, tolerance_qasymm8); + validate(Accessor(_target), _reference, tolerance_qasymm8(_function)); } TEST_SUITE_END() // QASYMM8_SIGNED /** Input data sets. */ -const auto Int16QuantizedActivationFunctionsDataset = framework::dataset::make("ActivationFunction", { ActivationLayerInfo::ActivationFunction::LOGISTIC, - ActivationLayerInfo::ActivationFunction::TANH - }); +const auto Int16QuantizedActivationFunctionsDataset = framework::dataset::make("ActivationFunction", +{ + ActivationLayerInfo::ActivationFunction::LOGISTIC, + ActivationLayerInfo::ActivationFunction::TANH, + ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, +}); const auto Int16QuantizedActivationDataset = combine(combine(framework::dataset::make("InPlace", { false }), Int16QuantizedActivationFunctionsDataset), framework::dataset::make("AlphaBeta", { 0.5f, 1.f })); @@ -277,7 +431,7 @@ TEST_SUITE_END() // QSYMM16 TEST_SUITE_END() // Quantized TEST_SUITE_END() // ActivationLayer -TEST_SUITE_END() // NEON +TEST_SUITE_END() // Neon } // namespace validation } // namespace test } // namespace arm_compute |