From d5166106ebfc11b1db832a708892e12edeaf997e Mon Sep 17 00:00:00 2001 From: Matthew Jackson Date: Wed, 31 Jul 2019 14:06:28 +0100 Subject: IVGCVSW-3539 Add CL support and tests for Stack * Added CL backend support for Stack * Added unit tests for Stack on the CL backend * Refactored unit tests to support generic data types Signed-off-by: Matthew Jackson Change-Id: I38ee3e9d8947ea98a3104c982698001e704d7d89 --- src/armnn/test/CreateWorkload.hpp | 9 ++- src/backends/backendsCommon/WorkloadFactory.hpp | 2 +- src/backends/cl/ClLayerSupport.cpp | 13 ++++ src/backends/cl/ClLayerSupport.hpp | 5 ++ src/backends/cl/ClWorkloadFactory.cpp | 6 ++ src/backends/cl/ClWorkloadFactory.hpp | 3 + src/backends/cl/backend.mk | 1 + src/backends/cl/test/ClCreateWorkloadTests.cpp | 38 +++++++++++ src/backends/cl/test/ClLayerTests.cpp | 7 ++ src/backends/cl/workloads/CMakeLists.txt | 2 + src/backends/cl/workloads/ClStackWorkload.cpp | 74 ++++++++++++++++++++++ src/backends/cl/workloads/ClStackWorkload.hpp | 29 +++++++++ src/backends/cl/workloads/ClWorkloads.hpp | 1 + .../reference/test/RefCreateWorkloadTests.cpp | 36 ++++++----- 14 files changed, 204 insertions(+), 22 deletions(-) create mode 100644 src/backends/cl/workloads/ClStackWorkload.cpp create mode 100644 src/backends/cl/workloads/ClStackWorkload.hpp diff --git a/src/armnn/test/CreateWorkload.hpp b/src/armnn/test/CreateWorkload.hpp index 619c6d02cd..98cdfaff0e 100644 --- a/src/armnn/test/CreateWorkload.hpp +++ b/src/armnn/test/CreateWorkload.hpp @@ -1381,17 +1381,16 @@ std::unique_ptr CreateSpaceToDepthWorkloadTest(armnn::IWor return workload; } -template +template std::unique_ptr CreateStackWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph, const armnn::TensorShape& inputShape, const armnn::TensorShape& outputShape, unsigned int axis, - unsigned int numInputs, - armnn::DataType dataType) + unsigned int numInputs) { - armnn::TensorInfo inputTensorInfo(inputShape, dataType); - armnn::TensorInfo outputTensorInfo(outputShape, dataType); + armnn::TensorInfo inputTensorInfo(inputShape, DataType); + armnn::TensorInfo outputTensorInfo(outputShape, DataType); // Constructs the Stack layer. armnn::StackDescriptor descriptor(axis, numInputs, inputShape); diff --git a/src/backends/backendsCommon/WorkloadFactory.hpp b/src/backends/backendsCommon/WorkloadFactory.hpp index 6d03da74fc..bd7f1c627b 100644 --- a/src/backends/backendsCommon/WorkloadFactory.hpp +++ b/src/backends/backendsCommon/WorkloadFactory.hpp @@ -193,7 +193,7 @@ public: const WorkloadInfo& info) const; virtual std::unique_ptr CreateStack(const StackQueueDescriptor& descriptor, - const WorkloadInfo& Info) const; + const WorkloadInfo& info) const; virtual std::unique_ptr CreateStridedSlice(const StridedSliceQueueDescriptor& descriptor, const WorkloadInfo& Info) const; diff --git a/src/backends/cl/ClLayerSupport.cpp b/src/backends/cl/ClLayerSupport.cpp index b737daf7f4..05539623a5 100644 --- a/src/backends/cl/ClLayerSupport.cpp +++ b/src/backends/cl/ClLayerSupport.cpp @@ -46,6 +46,7 @@ #include "workloads/ClSpaceToBatchNdWorkload.hpp" #include "workloads/ClSpaceToDepthWorkload.hpp" #include "workloads/ClSplitterWorkload.hpp" +#include "workloads/ClStackWorkload.hpp" #include "workloads/ClStridedSliceWorkload.hpp" #include "workloads/ClSubtractionWorkload.hpp" #include "workloads/ClTransposeConvolution2dWorkload.hpp" @@ -671,6 +672,18 @@ bool ClLayerSupport::IsSplitterSupported(const TensorInfo& input, return true; } +bool ClLayerSupport::IsStackSupported(const std::vector& inputs, + const TensorInfo& output, + const StackDescriptor& descriptor, + Optional reasonIfUnsupported) const +{ + FORWARD_WORKLOAD_VALIDATE_FUNC(ClStackWorkloadValidate, + reasonIfUnsupported, + inputs, + output, + descriptor); +} + bool ClLayerSupport::IsStridedSliceSupported(const TensorInfo& input, const TensorInfo& output, const StridedSliceDescriptor& descriptor, diff --git a/src/backends/cl/ClLayerSupport.hpp b/src/backends/cl/ClLayerSupport.hpp index 63a4daf864..4879e8b4b8 100644 --- a/src/backends/cl/ClLayerSupport.hpp +++ b/src/backends/cl/ClLayerSupport.hpp @@ -218,6 +218,11 @@ public: const ViewsDescriptor& descriptor, Optional reasonIfUnsupported = EmptyOptional()) const override; + bool IsStackSupported(const std::vector& inputs, + const TensorInfo& output, + const StackDescriptor& descriptor, + Optional reasonIfUnsupported = EmptyOptional()) const override; + bool IsStridedSliceSupported(const TensorInfo& input, const TensorInfo& output, const StridedSliceDescriptor& descriptor, diff --git a/src/backends/cl/ClWorkloadFactory.cpp b/src/backends/cl/ClWorkloadFactory.cpp index 6ce87d872e..4a593aac63 100644 --- a/src/backends/cl/ClWorkloadFactory.cpp +++ b/src/backends/cl/ClWorkloadFactory.cpp @@ -433,4 +433,10 @@ std::unique_ptr ClWorkloadFactory::CreateSpaceToDepth(const SpaceToDe return MakeWorkload(descriptor, info); } +std::unique_ptr ClWorkloadFactory::CreateStack(const StackQueueDescriptor& descriptor, + const WorkloadInfo& info) const +{ + return MakeWorkload(descriptor, info); +} + } // namespace armnn diff --git a/src/backends/cl/ClWorkloadFactory.hpp b/src/backends/cl/ClWorkloadFactory.hpp index 3b0ac826d7..8586435481 100644 --- a/src/backends/cl/ClWorkloadFactory.hpp +++ b/src/backends/cl/ClWorkloadFactory.hpp @@ -182,6 +182,9 @@ public: std::unique_ptr CreateSpaceToDepth(const SpaceToDepthQueueDescriptor& descriptor, const WorkloadInfo& info) const override; + std::unique_ptr CreateStack(const StackQueueDescriptor& descriptor, + const WorkloadInfo& info) const override; + private: template static std::unique_ptr MakeWorkload(const QueueDescriptorType& descriptor, diff --git a/src/backends/cl/backend.mk b/src/backends/cl/backend.mk index 57d7cb9f03..ee6447f340 100644 --- a/src/backends/cl/backend.mk +++ b/src/backends/cl/backend.mk @@ -55,6 +55,7 @@ BACKEND_SOURCES := \ workloads/ClSpaceToBatchNdWorkload.cpp \ workloads/ClSpaceToDepthWorkload.cpp \ workloads/ClSplitterWorkload.cpp \ + workloads/ClStackWorkload.cpp \ workloads/ClStridedSliceWorkload.cpp \ workloads/ClSubtractionWorkload.cpp \ workloads/ClTransposeConvolution2dWorkload.cpp diff --git a/src/backends/cl/test/ClCreateWorkloadTests.cpp b/src/backends/cl/test/ClCreateWorkloadTests.cpp index de13390f87..f453ccc9fd 100644 --- a/src/backends/cl/test/ClCreateWorkloadTests.cpp +++ b/src/backends/cl/test/ClCreateWorkloadTests.cpp @@ -936,4 +936,42 @@ BOOST_AUTO_TEST_CASE(CreateSpaceToDepthQSymm16Workload) ClSpaceToDepthWorkloadTest(); } +template +static void ClCreateStackWorkloadTest(const std::initializer_list& inputShape, + const std::initializer_list& outputShape, + unsigned int axis, + unsigned int numInputs) +{ + armnn::Graph graph; + ClWorkloadFactory factory = + ClWorkloadFactoryHelper::GetFactory(ClWorkloadFactoryHelper::GetMemoryManager()); + + auto workload = CreateStackWorkloadTest(factory, + graph, + TensorShape(inputShape), + TensorShape(outputShape), + axis, + numInputs); + + // Check inputs and output are as expected + StackQueueDescriptor queueDescriptor = workload->GetData(); + for (unsigned int i = 0; i < numInputs; ++i) + { + auto inputHandle = boost::polymorphic_downcast(queueDescriptor.m_Inputs[i]); + BOOST_TEST(CompareIClTensorHandleShape(inputHandle, inputShape)); + } + auto outputHandle = boost::polymorphic_downcast(queueDescriptor.m_Outputs[0]); + BOOST_TEST(CompareIClTensorHandleShape(outputHandle, outputShape)); +} + +BOOST_AUTO_TEST_CASE(CreateStackFloat32Workload) +{ + ClCreateStackWorkloadTest({ 3, 4, 5 }, { 3, 4, 2, 5 }, 2, 2); +} + +BOOST_AUTO_TEST_CASE(CreateStackUint8Workload) +{ + ClCreateStackWorkloadTest({ 3, 4, 5 }, { 3, 4, 2, 5 }, 2, 2); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/backends/cl/test/ClLayerTests.cpp b/src/backends/cl/test/ClLayerTests.cpp index 37af471658..dd4c16edf4 100644 --- a/src/backends/cl/test/ClLayerTests.cpp +++ b/src/backends/cl/test/ClLayerTests.cpp @@ -496,6 +496,13 @@ ARMNN_AUTO_TEST_CASE(SpaceToDepthNCHW2Float32, SpaceToDepthNCHWFloat32Test2) ARMNN_AUTO_TEST_CASE(SpaceToDepthNHWCQSymm16, SpaceToDepthNHWCQSymm16Test) ARMNN_AUTO_TEST_CASE(SpaceToDepthNCHWQSymm16, SpaceToDepthNCHWQSymm16Test) +// Stack +ARMNN_AUTO_TEST_CASE(Stack0Axis, Stack0AxisTest) +ARMNN_AUTO_TEST_CASE(Stack4dOutput1Axis, Stack4dOutput1AxisTest) +ARMNN_AUTO_TEST_CASE(Stack4dOutput2Axis, Stack4dOutput2AxisTest) +ARMNN_AUTO_TEST_CASE(Stack4dOutput3Axis, Stack4dOutput3AxisTest) +ARMNN_AUTO_TEST_CASE(Stack3dOutput1Axis3Input, Stack3dOutput1Axis3InputTest) + // Strided Slice ARMNN_AUTO_TEST_CASE(StridedSlice4DFloat32, StridedSlice4DFloat32Test) ARMNN_AUTO_TEST_CASE(StridedSlice4DReverseFloat32, StridedSlice4DReverseFloat32Test) diff --git a/src/backends/cl/workloads/CMakeLists.txt b/src/backends/cl/workloads/CMakeLists.txt index 2a3b1ad6b6..49a8b177d0 100644 --- a/src/backends/cl/workloads/CMakeLists.txt +++ b/src/backends/cl/workloads/CMakeLists.txt @@ -74,6 +74,8 @@ list(APPEND armnnClBackendWorkloads_sources ClSpaceToDepthWorkload.hpp ClSplitterWorkload.cpp ClSplitterWorkload.hpp + ClStackWorkload.cpp + ClStackWorkload.hpp ClStridedSliceWorkload.cpp ClStridedSliceWorkload.hpp ClSubtractionWorkload.cpp diff --git a/src/backends/cl/workloads/ClStackWorkload.cpp b/src/backends/cl/workloads/ClStackWorkload.cpp new file mode 100644 index 0000000000..3ba698ec4d --- /dev/null +++ b/src/backends/cl/workloads/ClStackWorkload.cpp @@ -0,0 +1,74 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// +#include "ClStackWorkload.hpp" +#include "ClWorkloadUtils.hpp" +#include +#include +#include +#include + +#include + +#include +#include + +namespace armnn +{ +using namespace armcomputetensorutils; + +namespace +{ +int CalcAxis(const unsigned int axis, const unsigned int inputDimensions) +{ + const int intAxis = boost::numeric_cast(axis); + return boost::numeric_cast(inputDimensions) - intAxis; +} +} //namespace + +arm_compute::Status ClStackWorkloadValidate(const std::vector& inputs, + const TensorInfo& output, + const StackDescriptor& descriptor) +{ + std::vector aclInputPtrs; + arm_compute::TensorInfo aclInputInfo; + for (const TensorInfo* input : inputs) + { + aclInputInfo = BuildArmComputeTensorInfo(*input); + aclInputPtrs.emplace_back(&aclInputInfo); + } + const arm_compute::TensorInfo aclOutputInfo = BuildArmComputeTensorInfo(output); + + int aclAxis = CalcAxis(descriptor.m_Axis, descriptor.m_InputShape.GetNumDimensions()); + + return arm_compute::CLStackLayer::validate(aclInputPtrs, aclAxis, &aclOutputInfo); +} + +ClStackWorkload::ClStackWorkload(const StackQueueDescriptor& descriptor, const WorkloadInfo& info) +: BaseWorkload(descriptor, info) +{ + std::vector aclInputs; + for (auto input : m_Data.m_Inputs) + { + arm_compute::ICLTensor& aclInput = boost::polymorphic_pointer_downcast(input)->GetTensor(); + aclInputs.emplace_back(&aclInput); + } + arm_compute::ICLTensor& output = boost::polymorphic_pointer_downcast( + m_Data.m_Outputs[0])->GetTensor(); + + m_Layer.reset(new arm_compute::CLStackLayer()); + int aclAxis = CalcAxis(descriptor.m_Parameters.m_Axis, descriptor.m_Parameters.m_InputShape.GetNumDimensions()); + m_Layer->configure(aclInputs, aclAxis, &output); +} + +void ClStackWorkload::Execute() const +{ + if (m_Layer) + { + ARMNN_SCOPED_PROFILING_EVENT_CL("ClStackWorkload_Execute"); + m_Layer->run(); + } +} + +} //namespace armnn \ No newline at end of file diff --git a/src/backends/cl/workloads/ClStackWorkload.hpp b/src/backends/cl/workloads/ClStackWorkload.hpp new file mode 100644 index 0000000000..75008697a3 --- /dev/null +++ b/src/backends/cl/workloads/ClStackWorkload.hpp @@ -0,0 +1,29 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include + +#include + +namespace armnn +{ +arm_compute::Status ClStackWorkloadValidate(const std::vector& inputs, + const TensorInfo& output, + const StackDescriptor& descriptor); + +class ClStackWorkload : public BaseWorkload +{ +public: + ClStackWorkload(const StackQueueDescriptor& descriptor, const WorkloadInfo& info); + + void Execute() const override; + +private: + mutable std::unique_ptr m_Layer; +}; + +} //namespace armnn diff --git a/src/backends/cl/workloads/ClWorkloads.hpp b/src/backends/cl/workloads/ClWorkloads.hpp index a64dea27e7..03dffc4edc 100644 --- a/src/backends/cl/workloads/ClWorkloads.hpp +++ b/src/backends/cl/workloads/ClWorkloads.hpp @@ -36,6 +36,7 @@ #include "ClSpaceToBatchNdWorkload.hpp" #include "ClSpaceToDepthWorkload.hpp" #include "ClSplitterWorkload.hpp" +#include "ClStackWorkload.hpp" #include "ClStridedSliceWorkload.hpp" #include "ClSubtractionWorkload.hpp" #include "ClConvertFp16ToFp32Workload.hpp" diff --git a/src/backends/reference/test/RefCreateWorkloadTests.cpp b/src/backends/reference/test/RefCreateWorkloadTests.cpp index f7999d0ffe..04c9acbe39 100644 --- a/src/backends/reference/test/RefCreateWorkloadTests.cpp +++ b/src/backends/reference/test/RefCreateWorkloadTests.cpp @@ -990,41 +990,45 @@ BOOST_AUTO_TEST_CASE(CreateSpaceToDepthWorkloadQSymm16) RefCreateSpaceToDepthWorkloadTest(); } +template static void RefCreateStackWorkloadTest(const armnn::TensorShape& inputShape, const armnn::TensorShape& outputShape, unsigned int axis, - unsigned int numInputs, - armnn::DataType dataType) + unsigned int numInputs) { armnn::Graph graph; RefWorkloadFactory factory; - auto workload = CreateStackWorkloadTest(factory, - graph, - inputShape, - outputShape, - axis, - numInputs, - dataType); - - // Check output is as expected - auto queueDescriptor = workload->GetData(); + auto workload = CreateStackWorkloadTest(factory, + graph, + inputShape, + outputShape, + axis, + numInputs); + + // Check inputs and output are as expected + StackQueueDescriptor queueDescriptor = workload->GetData(); + for (unsigned int i = 0; i < numInputs; ++i) + { + auto inputHandle = boost::polymorphic_downcast(queueDescriptor.m_Inputs[i]); + BOOST_TEST((inputHandle->GetTensorInfo() == TensorInfo(inputShape, DataType))); + } auto outputHandle = boost::polymorphic_downcast(queueDescriptor.m_Outputs[0]); - BOOST_TEST((outputHandle->GetTensorInfo() == TensorInfo(outputShape, dataType))); + BOOST_TEST((outputHandle->GetTensorInfo() == TensorInfo(outputShape, DataType))); } BOOST_AUTO_TEST_CASE(CreateStackFloat32Workload) { - RefCreateStackWorkloadTest({ 3, 4, 5 }, { 3, 4, 2, 5 }, 2, 2, armnn::DataType::Float32); + RefCreateStackWorkloadTest({ 3, 4, 5 }, { 3, 4, 2, 5 }, 2, 2); } BOOST_AUTO_TEST_CASE(CreateStackUint8Workload) { - RefCreateStackWorkloadTest({ 3, 4, 5 }, { 3, 4, 2, 5 }, 2, 2, armnn::DataType::QuantisedAsymm8); + RefCreateStackWorkloadTest({ 3, 4, 5 }, { 3, 4, 2, 5 }, 2, 2); } BOOST_AUTO_TEST_CASE(CreateStackUint16Workload) { - RefCreateStackWorkloadTest({ 3, 4, 5 }, { 3, 4, 2, 5 }, 2, 2, armnn::DataType::QuantisedSymm16); + RefCreateStackWorkloadTest({ 3, 4, 5 }, { 3, 4, 2, 5 }, 2, 2); } BOOST_AUTO_TEST_SUITE_END() -- cgit v1.2.1