From 69e653f9b2a7c8a2ab0cd3556b246a9df21b81d6 Mon Sep 17 00:00:00 2001 From: Keith Davis Date: Thu, 2 Jul 2020 11:49:26 +0100 Subject: IVGCVSW-3897 Add NEON LOG_SOFTMAX Workload Signed-off-by: Keith Davis Change-Id: I632b5ac7f188853de68e232e81568b3fca238d42 --- src/armnn/test/CreateWorkload.hpp | 37 ++++++++++++++- .../test/layerTests/LogSoftmaxTestImpl.cpp | 4 +- src/backends/neon/NeonLayerSupport.cpp | 9 ++++ src/backends/neon/NeonLayerSupport.hpp | 7 ++- src/backends/neon/NeonWorkloadFactory.cpp | 14 ++++-- src/backends/neon/NeonWorkloadFactory.hpp | 5 +- src/backends/neon/backend.mk | 3 +- src/backends/neon/test/NeonCreateWorkloadTests.cpp | 33 +++++++++++++- src/backends/neon/test/NeonLayerTests.cpp | 3 ++ src/backends/neon/workloads/CMakeLists.txt | 4 +- .../neon/workloads/NeonLogSoftmaxWorkload.cpp | 53 ++++++++++++++++++++++ .../neon/workloads/NeonLogSoftmaxWorkload.hpp | 36 +++++++++++++++ src/backends/neon/workloads/NeonWorkloads.hpp | 3 +- 13 files changed, 198 insertions(+), 13 deletions(-) create mode 100644 src/backends/neon/workloads/NeonLogSoftmaxWorkload.cpp create mode 100644 src/backends/neon/workloads/NeonLogSoftmaxWorkload.hpp diff --git a/src/armnn/test/CreateWorkload.hpp b/src/armnn/test/CreateWorkload.hpp index f484a21f48..aad6244c4b 100644 --- a/src/armnn/test/CreateWorkload.hpp +++ b/src/armnn/test/CreateWorkload.hpp @@ -1,5 +1,5 @@ // -// Copyright © 2017 Arm Ltd. All rights reserved. +// Copyright © 2017 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // #pragma once @@ -1262,6 +1262,41 @@ std::unique_ptr CreateBatchToSpaceNdWorkloadTest(armnn:: return workload; } +template +std::unique_ptr CreateLogSoftmaxWorkloadTest(armnn::IWorkloadFactory& factory, + armnn::Graph& graph) +{ + // Create the layer we're testing. + LogSoftmaxDescriptor logSoftmaxDescriptor; + // Set Axis to 1 if CL or Neon until further Axes are supported. + if (factory.GetBackendId() == armnn::Compute::CpuAcc || factory.GetBackendId() == armnn::Compute::GpuAcc) + { + logSoftmaxDescriptor.m_Axis = 0; + } + + Layer* const layer = graph.AddLayer(logSoftmaxDescriptor, "layer"); + // Create extra layers. + Layer* const input = graph.AddLayer(0, "input"); + Layer* const output = graph.AddLayer(0, "output"); + + // Connect up + armnn::TensorInfo tensorInfo({4, 1}, DataType); + + Connect(input, layer, tensorInfo); + Connect(layer, output, tensorInfo); + CreateTensorHandles(graph, factory); + + // Make the workload and checks it. + auto workload = MakeAndCheckWorkload(*layer, factory); + + LogSoftmaxQueueDescriptor queueDescriptor = workload->GetData(); + BOOST_TEST(queueDescriptor.m_Inputs.size() == 1); + BOOST_TEST(queueDescriptor.m_Outputs.size() == 1); + + // Return so we can do extra, backend-specific tests. + return workload; +} + template std::unique_ptr CreateL2NormalizationWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph, DataLayout dataLayout = DataLayout::NCHW) diff --git a/src/backends/backendsCommon/test/layerTests/LogSoftmaxTestImpl.cpp b/src/backends/backendsCommon/test/layerTests/LogSoftmaxTestImpl.cpp index 208bed24a5..9ccca84bfc 100644 --- a/src/backends/backendsCommon/test/layerTests/LogSoftmaxTestImpl.cpp +++ b/src/backends/backendsCommon/test/layerTests/LogSoftmaxTestImpl.cpp @@ -1,5 +1,5 @@ // -// Copyright © 2019 Arm Ltd. All rights reserved. +// Copyright © 2019 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -57,7 +57,7 @@ LayerTestResult LogSoftmaxTestImpl( auto inputTensor = MakeTensor(inputInfo, armnnUtils::QuantizedVector(inputValues, qScale, qOffset)); CopyDataToITensorHandle(inputHandle.get(), inputTensor.origin()); - workload->Execute(); + ExecuteWorkload(*workload, memoryManager); CopyDataFromITensorHandle(result.output.origin(), outputHandle.get()); diff --git a/src/backends/neon/NeonLayerSupport.cpp b/src/backends/neon/NeonLayerSupport.cpp index f6b3b7627a..b848f0c10f 100644 --- a/src/backends/neon/NeonLayerSupport.cpp +++ b/src/backends/neon/NeonLayerSupport.cpp @@ -34,6 +34,7 @@ #include "workloads/NeonDequantizeWorkload.hpp" #include "workloads/NeonInstanceNormalizationWorkload.hpp" #include "workloads/NeonL2NormalizationFloatWorkload.hpp" +#include "workloads/NeonLogSoftmaxWorkload.hpp" #include "workloads/NeonLstmFloatWorkload.hpp" #include "workloads/NeonMaximumWorkload.hpp" #include "workloads/NeonMeanWorkload.hpp" @@ -493,6 +494,14 @@ bool NeonLayerSupport::IsL2NormalizationSupported(const TensorInfo& input, FORWARD_WORKLOAD_VALIDATE_FUNC(NeonL2NormalizationWorkloadValidate, reasonIfUnsupported, input, output, descriptor); } +bool NeonLayerSupport::IsLogSoftmaxSupported(const TensorInfo& input, + const TensorInfo& output, + const LogSoftmaxDescriptor& descriptor, + Optional reasonIfUnsupported) const +{ + FORWARD_WORKLOAD_VALIDATE_FUNC(NeonLogSoftmaxWorkloadValidate, reasonIfUnsupported, input, output, descriptor); +} + bool NeonLayerSupport::IsLstmSupported(const TensorInfo& input, const TensorInfo& outputStateIn, const TensorInfo& cellStateIn, diff --git a/src/backends/neon/NeonLayerSupport.hpp b/src/backends/neon/NeonLayerSupport.hpp index aff62d18d7..bdc905d17e 100644 --- a/src/backends/neon/NeonLayerSupport.hpp +++ b/src/backends/neon/NeonLayerSupport.hpp @@ -1,5 +1,5 @@ // -// Copyright © 2017 Arm Ltd. All rights reserved. +// Copyright © 2017 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // #pragma once @@ -153,6 +153,11 @@ public: const L2NormalizationDescriptor& descriptor, Optional reasonIfUnsupported = EmptyOptional()) const override; + bool IsLogSoftmaxSupported(const TensorInfo& input, + const TensorInfo& output, + const LogSoftmaxDescriptor& descriptor, + Optional reasonIfUnsupported = EmptyOptional()) const override; + bool IsLstmSupported(const TensorInfo& input, const TensorInfo& outputStateIn, const TensorInfo& cellStateIn, diff --git a/src/backends/neon/NeonWorkloadFactory.cpp b/src/backends/neon/NeonWorkloadFactory.cpp index 34f8445f95..40010fe329 100644 --- a/src/backends/neon/NeonWorkloadFactory.cpp +++ b/src/backends/neon/NeonWorkloadFactory.cpp @@ -1,5 +1,5 @@ // -// Copyright © 2017 Arm Ltd. All rights reserved. +// Copyright © 2017 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -320,6 +320,12 @@ std::unique_ptr NeonWorkloadFactory::CreateL2Normalization(const L2No m_MemoryManager->GetIntraLayerManager()); } +std::unique_ptr NeonWorkloadFactory::CreateLogSoftmax(const LogSoftmaxQueueDescriptor& descriptor, + const WorkloadInfo& info) const +{ + return std::make_unique(descriptor, info, m_MemoryManager->GetIntraLayerManager()); +} + std::unique_ptr NeonWorkloadFactory::CreateLstm(const LstmQueueDescriptor& descriptor, const WorkloadInfo& info) const { @@ -386,7 +392,7 @@ std::unique_ptr NeonWorkloadFactory::CreateNormalization( } std::unique_ptr NeonWorkloadFactory::CreateOutput(const OutputQueueDescriptor& descriptor, - const WorkloadInfo& info) const + const WorkloadInfo& info) const { return std::make_unique(descriptor, info); } @@ -398,13 +404,13 @@ std::unique_ptr NeonWorkloadFactory::CreatePad(const PadQueueDescript } std::unique_ptr NeonWorkloadFactory::CreatePermute(const PermuteQueueDescriptor& descriptor, - const WorkloadInfo& info) const + const WorkloadInfo& info) const { return std::make_unique(descriptor, info); } std::unique_ptr NeonWorkloadFactory::CreatePooling2d(const Pooling2dQueueDescriptor& descriptor, - const WorkloadInfo& info) const + const WorkloadInfo& info) const { return std::make_unique(descriptor, info); } diff --git a/src/backends/neon/NeonWorkloadFactory.hpp b/src/backends/neon/NeonWorkloadFactory.hpp index de49146f10..b4767f1ec7 100644 --- a/src/backends/neon/NeonWorkloadFactory.hpp +++ b/src/backends/neon/NeonWorkloadFactory.hpp @@ -1,5 +1,5 @@ // -// Copyright © 2017 Arm Ltd. All rights reserved. +// Copyright © 2017 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // #pragma once @@ -131,6 +131,9 @@ public: std::unique_ptr CreateL2Normalization(const L2NormalizationQueueDescriptor& descriptor, const WorkloadInfo& info) const override; + std::unique_ptr CreateLogSoftmax(const LogSoftmaxQueueDescriptor& descriptor, + const WorkloadInfo& info) const override; + std::unique_ptr CreateLstm(const LstmQueueDescriptor& descriptor, const WorkloadInfo& info) const override; diff --git a/src/backends/neon/backend.mk b/src/backends/neon/backend.mk index 72d1ab3a92..aeee9154ad 100644 --- a/src/backends/neon/backend.mk +++ b/src/backends/neon/backend.mk @@ -1,5 +1,5 @@ # -# Copyright © 2017 ARM Ltd. All rights reserved. +# Copyright © 2017 ARM Ltd and Contributors. All rights reserved. # SPDX-License-Identifier: MIT # @@ -46,6 +46,7 @@ BACKEND_SOURCES := \ workloads/NeonGatherWorkload.cpp \ workloads/NeonInstanceNormalizationWorkload.cpp \ workloads/NeonL2NormalizationFloatWorkload.cpp \ + workloads/NeonLogSoftmaxWorkload.cpp \ workloads/NeonLstmFloatWorkload.cpp \ workloads/NeonMaximumWorkload.cpp \ workloads/NeonMeanWorkload.cpp \ diff --git a/src/backends/neon/test/NeonCreateWorkloadTests.cpp b/src/backends/neon/test/NeonCreateWorkloadTests.cpp index 73491c7810..37d026f107 100644 --- a/src/backends/neon/test/NeonCreateWorkloadTests.cpp +++ b/src/backends/neon/test/NeonCreateWorkloadTests.cpp @@ -1,5 +1,5 @@ // -// Copyright © 2017 Arm Ltd. All rights reserved. +// Copyright © 2017 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -813,6 +813,37 @@ BOOST_AUTO_TEST_CASE(CreateL2NormalizationNhwcWorkload) NeonCreateL2NormalizationWorkloadTest(DataLayout::NHWC); } +template +static void NeonCreateLogSoftmaxWorkloadTest() +{ + Graph graph; + NeonWorkloadFactory factory = + NeonWorkloadFactoryHelper::GetFactory(NeonWorkloadFactoryHelper::GetMemoryManager()); + + auto workload = CreateLogSoftmaxWorkloadTest(factory, graph); + + // Checks that outputs and inputs are as we expect them (see definition of CreateLogSoftmaxWorkloadTest). + LogSoftmaxQueueDescriptor queueDescriptor = workload->GetData(); + auto inputHandle = PolymorphicDowncast(queueDescriptor.m_Inputs[0]); + auto outputHandle = PolymorphicDowncast(queueDescriptor.m_Outputs[0]); + armnn::TensorInfo tensorInfo({4, 1}, DataType); + + BOOST_TEST(TestNeonTensorHandleInfo(inputHandle, tensorInfo)); + BOOST_TEST(TestNeonTensorHandleInfo(outputHandle, tensorInfo)); +} + +#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +BOOST_AUTO_TEST_CASE(CreateLogSoftmaxFloat16Workload) +{ + NeonCreateLogSoftmaxWorkloadTest(); +} +#endif + +BOOST_AUTO_TEST_CASE(CreateLogSoftmaxFloatWorkload) +{ + NeonCreateLogSoftmaxWorkloadTest(); +} + template static void NeonCreateLstmWorkloadTest() { diff --git a/src/backends/neon/test/NeonLayerTests.cpp b/src/backends/neon/test/NeonLayerTests.cpp index de4a305b0f..514ca5d371 100644 --- a/src/backends/neon/test/NeonLayerTests.cpp +++ b/src/backends/neon/test/NeonLayerTests.cpp @@ -506,6 +506,9 @@ ARMNN_AUTO_TEST_CASE(Simple3dSoftmaxBeta1Uint8, Simple3dSoftmaxUint8Test, 1.0f) ARMNN_AUTO_TEST_CASE(Simple4dSoftmaxBeta1, Simple4dSoftmaxTest, 1.0f) ARMNN_AUTO_TEST_CASE(Simple4dSoftmaxBeta1Uint8, Simple4dSoftmaxUint8Test, 1.0f) +// LogSoftmax +ARMNN_AUTO_TEST_CASE(LogSoftmaxFloat32_1, LogSoftmaxTest1) + // Space To Batch Nd ARMNN_AUTO_TEST_CASE(SpaceToBatchNdSimpleFloat32, SpaceToBatchNdSimpleFloat32Test) ARMNN_AUTO_TEST_CASE(SpaceToBatchNdMultiChannelsFloat32, SpaceToBatchNdMultiChannelsFloat32Test) diff --git a/src/backends/neon/workloads/CMakeLists.txt b/src/backends/neon/workloads/CMakeLists.txt index e3b74f665f..ca9497e393 100644 --- a/src/backends/neon/workloads/CMakeLists.txt +++ b/src/backends/neon/workloads/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright © 2017 Arm Ltd. All rights reserved. +# Copyright © 2017 Arm Ltd and Contributors. All rights reserved. # SPDX-License-Identifier: MIT # @@ -56,6 +56,8 @@ list(APPEND armnnNeonBackendWorkloads_sources NeonL2NormalizationFloatWorkload.hpp NeonLstmFloatWorkload.cpp NeonLstmFloatWorkload.hpp + NeonLogSoftmaxWorkload.cpp + NeonLogSoftmaxWorkload.hpp NeonMaximumWorkload.cpp NeonMaximumWorkload.hpp NeonMeanWorkload.cpp diff --git a/src/backends/neon/workloads/NeonLogSoftmaxWorkload.cpp b/src/backends/neon/workloads/NeonLogSoftmaxWorkload.cpp new file mode 100644 index 0000000000..058756e9af --- /dev/null +++ b/src/backends/neon/workloads/NeonLogSoftmaxWorkload.cpp @@ -0,0 +1,53 @@ +// +// Copyright © 2020 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "NeonLogSoftmaxWorkload.hpp" +#include "NeonWorkloadUtils.hpp" + +#include + +#include +#include + +#include + +namespace armnn +{ + +arm_compute::Status NeonLogSoftmaxWorkloadValidate(const TensorInfo& input, + const TensorInfo& output, + const LogSoftmaxDescriptor& descriptor) +{ + const arm_compute::TensorInfo aclInputInfo = armcomputetensorutils::BuildArmComputeTensorInfo(input); + const arm_compute::TensorInfo aclOutputInfo = armcomputetensorutils::BuildArmComputeTensorInfo(output); + + int aclAxis = ComputeSoftmaxAclAxis(descriptor, input); + return arm_compute::NELogSoftmaxLayer::validate(&aclInputInfo, &aclOutputInfo, descriptor.m_Beta, aclAxis); +} + +NeonLogSoftmaxWorkload::NeonLogSoftmaxWorkload(const LogSoftmaxQueueDescriptor& descriptor, + const WorkloadInfo& info, + std::shared_ptr& memoryManager) + : BaseWorkload(descriptor, info) +{ + m_Data.ValidateInputsOutputs("NeonLogSoftmaxWorkload", 1, 1); + + arm_compute::ITensor& input = PolymorphicDowncast(m_Data.m_Inputs[0])->GetTensor(); + arm_compute::ITensor& output = PolymorphicDowncast(m_Data.m_Outputs[0])->GetTensor(); + + auto layer = std::make_unique(memoryManager); + int aclAxis = ComputeSoftmaxAclAxis(m_Data.m_Parameters, info.m_InputTensorInfos[0]); + layer->configure(&input, &output, m_Data.m_Parameters.m_Beta, aclAxis); + m_LogSoftmaxLayer.reset(layer.release()); +} + +void NeonLogSoftmaxWorkload::Execute() const +{ + ARMNN_SCOPED_PROFILING_EVENT_NEON("NeonLogSoftmaxWorkload_Execute"); + m_LogSoftmaxLayer->run(); +} + +} //namespace armnn + diff --git a/src/backends/neon/workloads/NeonLogSoftmaxWorkload.hpp b/src/backends/neon/workloads/NeonLogSoftmaxWorkload.hpp new file mode 100644 index 0000000000..dbfa28dd11 --- /dev/null +++ b/src/backends/neon/workloads/NeonLogSoftmaxWorkload.hpp @@ -0,0 +1,36 @@ +// +// Copyright © 2020 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include +#include + +#include +#include +#include + +#include + +namespace armnn +{ + +arm_compute::Status NeonLogSoftmaxWorkloadValidate(const TensorInfo& input, + const TensorInfo& output, + const LogSoftmaxDescriptor& descriptor); + +class NeonLogSoftmaxWorkload : public BaseWorkload +{ +public: + NeonLogSoftmaxWorkload(const LogSoftmaxQueueDescriptor& descriptor, const WorkloadInfo& info, + std::shared_ptr& memoryManager); + virtual void Execute() const override; + +private: + std::unique_ptr m_LogSoftmaxLayer; +}; + +} //namespace armnn + diff --git a/src/backends/neon/workloads/NeonWorkloads.hpp b/src/backends/neon/workloads/NeonWorkloads.hpp index c1bc4cca29..590b6f7a29 100644 --- a/src/backends/neon/workloads/NeonWorkloads.hpp +++ b/src/backends/neon/workloads/NeonWorkloads.hpp @@ -1,5 +1,5 @@ // -// Copyright © 2017 Arm Ltd. All rights reserved. +// Copyright © 2017 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -30,6 +30,7 @@ #include "NeonGatherWorkload.hpp" #include "NeonInstanceNormalizationWorkload.hpp" #include "NeonL2NormalizationFloatWorkload.hpp" +#include "NeonLogSoftmaxWorkload.hpp" #include "NeonLstmFloatWorkload.hpp" #include "NeonMaximumWorkload.hpp" #include "NeonMeanWorkload.hpp" -- cgit v1.2.1