From 4164814a099773c0a512889473c980bc148e590f Mon Sep 17 00:00:00 2001 From: Georgios Pinitas Date: Tue, 3 Aug 2021 08:24:00 +0100 Subject: Implement Operator API Resolves: COMPMID-4512 Signed-off-by: Georgios Pinitas Change-Id: Id12130365fa3fe2261160931dcc7affb6b467186 Reviewed-on: https://review.mlplatform.org/c/ml/ComputeLibrary/+/6031 Tested-by: Arm Jenkins Reviewed-by: Michele Di Giorgio Comments-Addressed: Arm Jenkins --- Android.bp | 2 + SConscript | 1 + arm_compute/Acl.hpp | 19 +++++++ arm_compute/AclDescriptors.h | 9 ++-- filelist.json | 7 ++- src/c/AclContext.cpp | 6 +-- src/c/operators/AclActivation.cpp | 49 ++++++++++++++++++ src/common/IContext.h | 13 ++--- src/common/IOperator.cpp | 73 +++++++++++++++++++++++++++ src/common/IOperator.h | 72 +++++++++++--------------- src/common/Types.h | 1 + src/common/utils/LegacySupport.cpp | 54 ++++++++++++++++++++ src/common/utils/LegacySupport.h | 8 +++ src/cpu/CpuContext.h | 4 ++ src/gpu/cl/ClContext.h | 4 ++ src/runtime/cpu/operators/CpuActivation.cpp | 28 ++++++++++ src/runtime/gpu/cl/operators/ClActivation.cpp | 35 +++++++++++++ tests/validation/NEON/ActivationLayer.cpp | 43 ++++++++++++++++ 18 files changed, 369 insertions(+), 59 deletions(-) create mode 100644 src/c/operators/AclActivation.cpp create mode 100644 src/common/IOperator.cpp diff --git a/Android.bp b/Android.bp index 6b1c3c56c4..3a3f1db334 100644 --- a/Android.bp +++ b/Android.bp @@ -60,7 +60,9 @@ cc_library_static { "src/c/AclTensorPack.cpp", "src/c/AclVersion.cpp", "src/c/cl/AclOpenClExt.cpp", + "src/c/operators/AclActivation.cpp", "src/common/AllocatorWrapper.cpp", + "src/common/IOperator.cpp", "src/common/ITensorV2.cpp", "src/common/TensorPack.cpp", "src/common/cpuinfo/CpuInfo.cpp", diff --git a/SConscript b/SConscript index 682f55310e..672ba0f39d 100644 --- a/SConscript +++ b/SConscript @@ -406,6 +406,7 @@ runtime_files = Glob('src/runtime/CPP/functions/*.cpp') # C API files runtime_files_hp += filelist['c_api']['common'] +runtime_files_hp += filelist['c_api']['operators'] if env['opencl']: runtime_files_hp += filelist['c_api']['gpu'] diff --git a/arm_compute/Acl.hpp b/arm_compute/Acl.hpp index 7791c5633e..55e04e876d 100644 --- a/arm_compute/Acl.hpp +++ b/arm_compute/Acl.hpp @@ -87,6 +87,7 @@ OBJECT_DELETER(AclContext, AclDestroyContext) OBJECT_DELETER(AclQueue, AclDestroyQueue) OBJECT_DELETER(AclTensor, AclDestroyTensor) OBJECT_DELETER(AclTensorPack, AclDestroyTensorPack) +OBJECT_DELETER(AclOperator, AclDestroyOperator) #undef OBJECT_DELETER @@ -773,6 +774,24 @@ protected: /** Constructor */ Operator() = default; }; + +/// Operators +using ActivationDesc = AclActivationDescriptor; +class Activation : public Operator +{ +public: + Activation(Context &ctx, const TensorDescriptor &src, const TensorDescriptor &dst, const ActivationDesc &desc, StatusCode *status = nullptr) + { + AclOperator op; + const auto st = detail::as_enum(AclActivation(&op, ctx.get(), src.get(), dst.get(), desc)); + reset(op); + report_status(st, "[Compute Library] Failure during Activation operator creation"); + if(status) + { + *status = st; + } + } +}; } // namespace acl #undef ARM_COMPUTE_IGNORE_UNUSED #endif /* ARM_COMPUTE_ACL_HPP_ */ diff --git a/arm_compute/AclDescriptors.h b/arm_compute/AclDescriptors.h index 7b7655e9c7..a564bd2141 100644 --- a/arm_compute/AclDescriptors.h +++ b/arm_compute/AclDescriptors.h @@ -40,7 +40,7 @@ typedef enum AclLuBoundedRelu = 6, /**< Lower and Upper Bounded Rectifier */ AclLeakyRelu = 7, /**< Leaky Rectifier */ AclSoftRelu = 8, /**< Soft Rectifier */ - AclSoftElu = 9, /**< Exponential Linear Unit */ + AclElu = 9, /**< Exponential Linear Unit */ AclAbs = 10, /**< Absolute */ AclSquare = 11, /**< Square */ AclSqrt = 12, /**< Square root */ @@ -51,9 +51,10 @@ typedef enum /**< Activation layer descriptor */ typedef struct { - AclActivationType type; /**< Activation type */ - float a; /**< Factor &alpha used by some activations */ - float b; /**< Factor &beta used by some activations */ + AclActivationType type; /**< Activation type */ + float a; /**< Factor &alpha used by some activations */ + float b; /**< Factor &beta used by some activations */ + bool inplace; /**< Hint that src and dst tensors will be the same */ } AclActivationDescriptor; #ifdef __cplusplus } diff --git a/filelist.json b/filelist.json index b426411681..c5abc620cd 100644 --- a/filelist.json +++ b/filelist.json @@ -6,7 +6,8 @@ "src/common/utils/LegacySupport.cpp", "src/common/AllocatorWrapper.cpp", "src/common/ITensorV2.cpp", - "src/common/TensorPack.cpp" + "src/common/TensorPack.cpp", + "src/common/IOperator.cpp" ], "c_api": { "common": [ @@ -21,6 +22,10 @@ ], "gpu": [ "src/c/cl/AclOpenClExt.cpp" + ], + "operators": + [ + "src/c/operators/AclActivation.cpp" ] }, "gpu": { diff --git a/src/c/AclContext.cpp b/src/c/AclContext.cpp index c62e627edc..dbf2a3df88 100644 --- a/src/c/AclContext.cpp +++ b/src/c/AclContext.cpp @@ -75,7 +75,7 @@ arm_compute::IContext *create_context(AclTarget target, const AclContextOptions } } // namespace -extern "C" AclStatus AclCreateContext(AclContext *ctx, +extern "C" AclStatus AclCreateContext(AclContext *external_ctx, AclTarget target, const AclContextOptions *options) { @@ -91,13 +91,13 @@ extern "C" AclStatus AclCreateContext(AclContext *ctx, return AclInvalidArgument; } - auto acl_ctx = create_context(target, options); + auto ctx = create_context(target, options); if(ctx == nullptr) { ARM_COMPUTE_LOG_ERROR_WITH_FUNCNAME_ACL("Couldn't allocate internal resources for context creation!"); return AclOutOfMemory; } - *ctx = acl_ctx; + *external_ctx = ctx; return AclSuccess; } diff --git a/src/c/operators/AclActivation.cpp b/src/c/operators/AclActivation.cpp new file mode 100644 index 0000000000..bf604ee2dd --- /dev/null +++ b/src/c/operators/AclActivation.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021 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 "arm_compute/AclOperators.h" + +#include "src/common/IOperator.h" +#include "src/common/utils/Macros.h" +#include "src/common/utils/Validate.h" + +extern "C" AclStatus AclActivation(AclOperator *external_op, + AclContext external_ctx, + const AclTensorDescriptor *src, + const AclTensorDescriptor *dst, + const AclActivationDescriptor info) +{ + using namespace arm_compute; + + // Extract internal context + auto ctx = get_internal(external_ctx); + StatusCode status = detail::validate_internal_context(ctx); + ARM_COMPUTE_RETURN_CENUM_ON_FAILURE(status); + + bool is_validate = (external_op == ARM_COMPUTE_VALIDATE_OPERATOR_SUPPORT); + + std::tie(*external_op, status) = ctx->create_activation(*src, *dst, info, is_validate); + ARM_COMPUTE_RETURN_CENUM_ON_FAILURE(status); + + return AclSuccess; +} \ No newline at end of file diff --git a/src/common/IContext.h b/src/common/IContext.h index 31f39da06d..1ae46c57de 100644 --- a/src/common/IContext.h +++ b/src/common/IContext.h @@ -44,6 +44,7 @@ namespace arm_compute // Forward declarations class ITensorV2; class IQueue; +class IOperator; /**< Context interface */ class IContext : public AclContext_ @@ -53,13 +54,11 @@ public: : AclContext_(), _target(target), _refcount(0) { } - /** Virtual Destructor */ virtual ~IContext() { header.type = detail::ObjectType::Invalid; }; - /** Target type accessor * * @return Target that the context is associated with @@ -68,19 +67,16 @@ public: { return _target; } - /** Increment context refcount */ void inc_ref() const { ++_refcount; } - /** Decrement context refcount */ void dec_ref() const { --_refcount; } - /** Reference counter accessor * * @return The number of references pointing to this object @@ -89,7 +85,6 @@ public: { return _refcount; } - /** Checks if an object is valid * * @return True if sucessful otherwise false @@ -98,7 +93,6 @@ public: { return header.type == detail::ObjectType::Context; } - /** Create a tensor object * * @param[in] desc Descriptor to use @@ -107,7 +101,6 @@ public: * @return A pointer to the created tensor object */ virtual ITensorV2 *create_tensor(const AclTensorDescriptor &desc, bool allocate) = 0; - /** Create a queue object * * @param[in] options Queue options to be used @@ -115,6 +108,10 @@ public: * @return A pointer to the created queue object */ virtual IQueue *create_queue(const AclQueueOptions *options) = 0; + virtual std::tuple create_activation(const AclTensorDescriptor &src, + const AclTensorDescriptor &dst, + const AclActivationDescriptor &act, + bool is_validate) = 0; private: Target _target; /**< Target type of context */ diff --git a/src/common/IOperator.cpp b/src/common/IOperator.cpp new file mode 100644 index 0000000000..b56f0e97fb --- /dev/null +++ b/src/common/IOperator.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2021 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/common/IOperator.h" +#include "src/common/utils/Validate.h" + +namespace arm_compute +{ +#ifndef DOXYGEN_SKIP_THIS +IOperator::IOperator(IContext *ctx) + : AclOperator_() +{ + ARM_COMPUTE_ASSERT_NOT_NULLPTR(ctx); + this->header.ctx = ctx; + this->header.ctx->inc_ref(); +} + +IOperator::~IOperator() +{ + this->header.ctx->dec_ref(); + this->header.type = detail::ObjectType::Invalid; +} + +bool IOperator::is_valid() const +{ + return this->header.type == detail::ObjectType::Operator; +} + +StatusCode IOperator::run(ITensorPack &tensors) +{ + _op->run(tensors); + return StatusCode::Success; +} + +StatusCode IOperator::run(IQueue &queue, ITensorPack &tensors) +{ + ARM_COMPUTE_UNUSED(queue); + _op->run(tensors); + return StatusCode::Success; +} + +StatusCode IOperator::prepare(ITensorPack &tensors) +{ + _op->prepare(tensors); + return StatusCode::Success; +} + +MemoryRequirements IOperator::workspace() const +{ + return _op->workspace(); +} +#endif /* DOXYGEN_SKIP_THIS */ +} // namespace arm_compute diff --git a/src/common/IOperator.h b/src/common/IOperator.h index 7fdb443acb..1b65a09e0d 100644 --- a/src/common/IOperator.h +++ b/src/common/IOperator.h @@ -27,6 +27,11 @@ #include "src/common/IContext.h" #include "src/common/IQueue.h" +// TODO: Remove when all functions have been ported +#include "arm_compute/core/experimental/Types.h" +#include "arm_compute/runtime/IOperator.h" +#include "src/common/utils/Validate.h" + #include struct AclOperator_ @@ -42,21 +47,12 @@ namespace arm_compute { // Forward declarations class ITensorPack; - -/** Structure to capture internally memory requirements */ -struct MemoryInfo +namespace experimental { - MemoryInfo(AclTensorSlot slot_id, size_t size, size_t alignment) noexcept - : slot_id(slot_id), - size(size), - alignment(alignment) - { - } - AclTensorSlot slot_id; - size_t size; - size_t alignment; -}; -using MemoryRequirements = std::vector; +class IOperator; +} // namespace experimental + +using MemoryRequirements = experimental::MemoryRequirements; /** Base class specifying the operator interface */ class IOperator : public AclOperator_ @@ -66,55 +62,45 @@ public: * * @param[in] ctx Context to be used by the operator */ - explicit IOperator(IContext *ctx) - { - this->header.ctx = ctx; - this->header.ctx->inc_ref(); - } - + explicit IOperator(IContext *ctx); /** Destructor */ - virtual ~IOperator() - { - this->header.ctx->dec_ref(); - this->header.type = detail::ObjectType::Invalid; - }; - + virtual ~IOperator(); /** Checks if an operator is valid * * @return True if successful otherwise false */ - bool is_valid() const - { - return this->header.type == detail::ObjectType::Operator; - }; - + bool is_valid() const; /** Run the kernels contained in the function * - * @param[in] queue Queue to run a kernel on + * @param[in] queue Queue to use * @param[in] tensors Vector that contains the tensors to operate on */ - virtual StatusCode run(IQueue &queue, ITensorPack &tensors) = 0; - + virtual StatusCode run(IQueue &queue, ITensorPack &tensors); + /** Run the kernels contained in the function + * + * @param[in] tensors Vector that contains the tensors to operate on + */ + virtual StatusCode run(ITensorPack &tensors); /** Prepare the operator for execution * * Any one off pre-processing step required by the function is handled here * - * @param[in] constants Vector that contains the constants tensors. + * @param[in] tensors Vector that contains the preparation tensors. * * @note Prepare stage might not need all the function's buffers' backing memory to be available in order to execute */ - virtual StatusCode prepare(ITensorPack &constants) - { - ARM_COMPUTE_UNUSED(constants); - return StatusCode::Success; - } - + virtual StatusCode prepare(ITensorPack &tensors); /** Return the memory requirements required by the workspace */ - virtual MemoryRequirements workspace() const + virtual MemoryRequirements workspace() const; + + void set_internal_operator(std::unique_ptr op) { - return {}; + _op = std::move(op); } + +private: + std::unique_ptr _op{ nullptr }; }; /** Extract internal representation of an Operator diff --git a/src/common/Types.h b/src/common/Types.h index ba07b51d55..25ee32353a 100644 --- a/src/common/Types.h +++ b/src/common/Types.h @@ -24,6 +24,7 @@ #ifndef SRC_COMMON_TYPES_H_ #define SRC_COMMON_TYPES_H_ +#include "arm_compute/AclDescriptors.h" #include "arm_compute/AclTypes.h" namespace arm_compute diff --git a/src/common/utils/LegacySupport.cpp b/src/common/utils/LegacySupport.cpp index 569b2abd89..6623825124 100644 --- a/src/common/utils/LegacySupport.cpp +++ b/src/common/utils/LegacySupport.cpp @@ -107,5 +107,59 @@ AclTensorDescriptor convert_to_descriptor(const TensorInfo &info) }; return desc; } + +ActivationLayerInfo convert_to_activation_info(const AclActivationDescriptor &desc) +{ + ActivationLayerInfo::ActivationFunction act; + switch(desc.type) + { + case AclActivationType::AclIdentity: + act = ActivationLayerInfo::ActivationFunction::IDENTITY; + break; + case AclActivationType::AclLogistic: + act = ActivationLayerInfo::ActivationFunction::LOGISTIC; + break; + case AclActivationType::AclTanh: + act = ActivationLayerInfo::ActivationFunction::TANH; + break; + case AclActivationType::AclRelu: + act = ActivationLayerInfo::ActivationFunction::RELU; + break; + case AclActivationType::AclBoundedRelu: + act = ActivationLayerInfo::ActivationFunction::BOUNDED_RELU; + break; + case AclActivationType::AclLuBoundedRelu: + act = ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU; + break; + case AclActivationType::AclLeakyRelu: + act = ActivationLayerInfo::ActivationFunction::LEAKY_RELU; + break; + case AclActivationType::AclSoftRelu: + act = ActivationLayerInfo::ActivationFunction::SOFT_RELU; + break; + case AclActivationType::AclElu: + act = ActivationLayerInfo::ActivationFunction::ELU; + break; + case AclActivationType::AclAbs: + act = ActivationLayerInfo::ActivationFunction::ABS; + break; + case AclActivationType::AclSquare: + act = ActivationLayerInfo::ActivationFunction::SQUARE; + break; + case AclActivationType::AclSqrt: + act = ActivationLayerInfo::ActivationFunction::SQRT; + break; + case AclActivationType::AclLinear: + act = ActivationLayerInfo::ActivationFunction::LINEAR; + break; + case AclActivationType::AclHardSwish: + act = ActivationLayerInfo::ActivationFunction::HARD_SWISH; + break; + default: + return ActivationLayerInfo(); + } + + return ActivationLayerInfo(act, desc.a, desc.b); +} } // namespace detail } // namespace arm_compute diff --git a/src/common/utils/LegacySupport.h b/src/common/utils/LegacySupport.h index c2cc1bc182..3c3b09fce6 100644 --- a/src/common/utils/LegacySupport.h +++ b/src/common/utils/LegacySupport.h @@ -26,6 +26,7 @@ #include "arm_compute/Acl.h" #include "arm_compute/core/TensorInfo.h" +#include "arm_compute/core/Types.h" namespace arm_compute { @@ -45,6 +46,13 @@ TensorInfo convert_to_legacy_tensor_info(const AclTensorDescriptor &desc); * @return A converted descriptor */ AclTensorDescriptor convert_to_descriptor(const TensorInfo &info); +/** Convert an AclActivation descriptor to an internal one + * + * @param[in] desc Descriptor to convert + * + * @return Legacy tensor meta-data + */ +ActivationLayerInfo convert_to_activation_info(const AclActivationDescriptor &desc); } // namespace detail } // namespace arm_compute diff --git a/src/cpu/CpuContext.h b/src/cpu/CpuContext.h index 9a59af39c1..da241ed097 100644 --- a/src/cpu/CpuContext.h +++ b/src/cpu/CpuContext.h @@ -62,6 +62,10 @@ public: // Inherrited methods overridden ITensorV2 *create_tensor(const AclTensorDescriptor &desc, bool allocate) override; IQueue *create_queue(const AclQueueOptions *options) override; + std::tuple create_activation(const AclTensorDescriptor &src, + const AclTensorDescriptor &dst, + const AclActivationDescriptor &act, + bool is_validate) override; private: AllocatorWrapper _allocator; diff --git a/src/gpu/cl/ClContext.h b/src/gpu/cl/ClContext.h index 2a0d4ee1c8..a50b03124b 100644 --- a/src/gpu/cl/ClContext.h +++ b/src/gpu/cl/ClContext.h @@ -76,6 +76,10 @@ public: // Inherrited methods overridden ITensorV2 *create_tensor(const AclTensorDescriptor &desc, bool allocate) override; IQueue *create_queue(const AclQueueOptions *options) override; + std::tuple create_activation(const AclTensorDescriptor &src, + const AclTensorDescriptor &dst, + const AclActivationDescriptor &act, + bool is_validate) override; private: mlgo::MLGOHeuristics _mlgo_heuristics; diff --git a/src/runtime/cpu/operators/CpuActivation.cpp b/src/runtime/cpu/operators/CpuActivation.cpp index 7753c9601f..80667becff 100644 --- a/src/runtime/cpu/operators/CpuActivation.cpp +++ b/src/runtime/cpu/operators/CpuActivation.cpp @@ -23,7 +23,10 @@ */ #include "src/runtime/cpu/operators/CpuActivation.h" +#include "src/common/IOperator.h" +#include "src/common/utils/LegacySupport.h" #include "src/core/cpu/kernels/CpuActivationKernel.h" +#include "src/cpu/CpuContext.h" namespace arm_compute { @@ -40,5 +43,30 @@ Status CpuActivation::validate(const ITensorInfo *input, const ITensorInfo *outp { return kernels::CpuActivationKernel::validate(input, output, activation_info); } + +std::tuple CpuContext::create_activation(const AclTensorDescriptor &src, const AclTensorDescriptor &dst, const AclActivationDescriptor &act, bool is_validate) +{ + TensorInfo src_info = detail::convert_to_legacy_tensor_info(src); + TensorInfo dst_info = detail::convert_to_legacy_tensor_info(dst); + auto info = detail::convert_to_activation_info(act); + + if(is_validate && !bool(CpuActivation::validate(&src_info.set_is_resizable(false), &dst_info.set_is_resizable(false), info))) + { + return std::make_tuple(nullptr, StatusCode::UnsupportedConfig); + } + + auto act_op = std::make_unique(); + act_op->configure(&src_info, &dst_info, info); + + auto op = new arm_compute::IOperator(static_cast(this)); + if(op == nullptr) + { + ARM_COMPUTE_LOG_ERROR_ACL("Couldn't allocate internal resources"); + return { nullptr, StatusCode::OutOfMemory }; + } + op->set_internal_operator(std::move(act_op)); + + return std::make_tuple(op, StatusCode::Success); +} } // namespace cpu } // namespace arm_compute diff --git a/src/runtime/gpu/cl/operators/ClActivation.cpp b/src/runtime/gpu/cl/operators/ClActivation.cpp index 71aa57bdbd..bef42d7fae 100644 --- a/src/runtime/gpu/cl/operators/ClActivation.cpp +++ b/src/runtime/gpu/cl/operators/ClActivation.cpp @@ -26,6 +26,10 @@ #include "src/core/gpu/cl/ClCompileContext.h" #include "src/core/gpu/cl/kernels/ClActivationKernel.h" +#include "src/common/IOperator.h" +#include "src/common/utils/LegacySupport.h" +#include "src/gpu/cl/ClContext.h" + namespace arm_compute { namespace opencl @@ -42,4 +46,35 @@ Status ClActivation::validate(const ITensorInfo *src, const ITensorInfo *dst, co return kernels::ClActivationKernel::validate(src, dst, act_info); } } // namespace opencl + +namespace gpu +{ +namespace opencl +{ +std::tuple ClContext::create_activation(const AclTensorDescriptor &src, const AclTensorDescriptor &dst, const AclActivationDescriptor &act, bool is_validate) +{ + TensorInfo src_info = detail::convert_to_legacy_tensor_info(src); + TensorInfo dst_info = detail::convert_to_legacy_tensor_info(dst); + auto info = detail::convert_to_activation_info(act); + + if(is_validate && !bool(arm_compute::opencl::ClActivation::validate(&src_info.set_is_resizable(false), &dst_info.set_is_resizable(false), info))) + { + return std::make_tuple(nullptr, StatusCode::UnsupportedConfig); + } + + auto act_op = std::make_unique(); + act_op->configure(CLKernelLibrary::get().get_compile_context(), &src_info, &dst_info, info); + + auto op = new arm_compute::IOperator(static_cast(this)); + if(op == nullptr) + { + ARM_COMPUTE_LOG_ERROR_ACL("Couldn't allocate internal resources"); + return { nullptr, StatusCode::OutOfMemory }; + } + op->set_internal_operator(std::move(act_op)); + + return std::make_tuple(op, StatusCode::Success); +} +} // namespace opencl +} // namespace gpu } // namespace arm_compute diff --git a/tests/validation/NEON/ActivationLayer.cpp b/tests/validation/NEON/ActivationLayer.cpp index 111e969bae..69fe9053d8 100644 --- a/tests/validation/NEON/ActivationLayer.cpp +++ b/tests/validation/NEON/ActivationLayer.cpp @@ -37,6 +37,7 @@ #include "tests/validation/Validation.h" #include "tests/validation/fixtures/ActivationLayerFixture.h" +#include "arm_compute/Acl.hpp" #include "support/Requires.h" namespace arm_compute @@ -215,6 +216,48 @@ void test_float_sqrt_boundary_value() TEST_SUITE(NEON) TEST_SUITE(ActivationLayer) +/** 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) +{ + acl::StatusCode err = acl::StatusCode::Success; + + // Create context & Queue + acl::Context ctx(acl::Target::Cpu, &err); + ARM_COMPUTE_ASSERT(err == acl::StatusCode::Success); + + acl::Queue queue(ctx, &err); + ARM_COMPUTE_ASSERT(err == acl::StatusCode::Success); + + // 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 }; + + acl::Activation act(ctx, src_info, dst_info, desc, &err); + ARM_COMPUTE_ASSERT(err == acl::StatusCode::Success); + + // 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); + + acl::TensorPack pack(ctx); + err = pack.add(src, ACL_SRC); + err = pack.add(dst, ACL_DST); + ARM_COMPUTE_ASSERT(err == acl::StatusCode::Success); + + // Execute operator + err = act.run(queue, pack); + ARM_COMPUTE_ASSERT(err == acl::StatusCode::Success); +} + // *INDENT-OFF* // clang-format off DATA_TEST_CASE(Validate, framework::DatasetMode::ALL, zip(zip(zip( -- cgit v1.2.1