From 878f02313d716e86a95e7f670e9d7b19cdba5e61 Mon Sep 17 00:00:00 2001 From: FrancisMurtagh Date: Wed, 19 Dec 2018 10:56:15 +0000 Subject: [PATCH] IVGCVSW-2379 Add Greater Ref workload implementation * Added the Greater operation as an element-wise workload * Added the unit tests Change-Id: Ie00ee30e47a5f5e17a728032eeb11a085d06c8f2 --- src/backends/backendsCommon/StringMapping.hpp | 16 +- src/backends/backendsCommon/WorkloadData.cpp | 13 ++ src/backends/backendsCommon/test/LayerTests.cpp | 173 +++++++++++++++++++++ src/backends/backendsCommon/test/LayerTests.hpp | 24 +++ src/backends/cl/ClLayerSupport.cpp | 12 ++ src/backends/cl/ClLayerSupport.hpp | 5 + src/backends/neon/NeonLayerSupport.cpp | 12 ++ src/backends/neon/NeonLayerSupport.hpp | 5 + src/backends/reference/RefLayerSupport.cpp | 15 ++ src/backends/reference/RefLayerSupport.hpp | 5 + src/backends/reference/RefWorkloadFactory.cpp | 2 +- src/backends/reference/test/RefLayerTests.cpp | 8 + .../reference/workloads/ElementwiseFunction.cpp | 3 +- .../reference/workloads/RefElementwiseWorkload.cpp | 13 +- .../reference/workloads/RefElementwiseWorkload.hpp | 21 ++- 15 files changed, 307 insertions(+), 20 deletions(-) diff --git a/src/backends/backendsCommon/StringMapping.hpp b/src/backends/backendsCommon/StringMapping.hpp index 8541195..073a5a6 100644 --- a/src/backends/backendsCommon/StringMapping.hpp +++ b/src/backends/backendsCommon/StringMapping.hpp @@ -19,11 +19,12 @@ public: enum Id { RefAdditionWorkload_Execute, RefEqualWorkload_Execute, - RefSubtractionWorkload_Execute, - RefMaximumWorkload_Execute, - RefMultiplicationWorkload_Execute, RefDivisionWorkload_Execute, + RefGreaterWorkload_Execute, + RefMaximumWorkload_Execute, RefMinimumWorkload_Execute, + RefMultiplicationWorkload_Execute, + RefSubtractionWorkload_Execute, MAX_STRING_ID }; @@ -38,12 +39,13 @@ private: StringMapping() { m_Strings[RefAdditionWorkload_Execute] = "RefAdditionWorkload_Execute"; + m_Strings[RefDivisionWorkload_Execute] = "RefDivisionWorkload_Execute"; m_Strings[RefEqualWorkload_Execute] = "RefEqualWorkload_Execute"; - m_Strings[RefSubtractionWorkload_Execute] = "RefSubtractionWorkload_Execute"; + m_Strings[RefGreaterWorkload_Execute] = "RefGreaterWorkload_Execute"; m_Strings[RefMaximumWorkload_Execute] = "RefMaximumWorkload_Execute"; - m_Strings[RefMultiplicationWorkload_Execute] = "RefMultiplicationWorkload_Execute"; - m_Strings[RefDivisionWorkload_Execute] = "RefDivisionWorkload_Execute"; m_Strings[RefMinimumWorkload_Execute] = "RefMinimumWorkload_Execute"; + m_Strings[RefMultiplicationWorkload_Execute] = "RefMultiplicationWorkload_Execute"; + m_Strings[RefSubtractionWorkload_Execute] = "RefSubtractionWorkload_Execute"; } StringMapping(const StringMapping &) = delete; @@ -52,4 +54,4 @@ private: const char * m_Strings[MAX_STRING_ID]; }; -} //namespace armnn \ No newline at end of file +} //namespace armnn diff --git a/src/backends/backendsCommon/WorkloadData.cpp b/src/backends/backendsCommon/WorkloadData.cpp index 67cee1c..8847b4e 100644 --- a/src/backends/backendsCommon/WorkloadData.cpp +++ b/src/backends/backendsCommon/WorkloadData.cpp @@ -1026,4 +1026,17 @@ void EqualQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const "second input"); } +void GreaterQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const +{ + ValidateTwoInputs(workloadInfo, "GreaterQueueDescriptor"); + ValidateSingleOutput(workloadInfo, "GreaterQueueDescriptor"); + + ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0], + workloadInfo.m_InputTensorInfos[1], + workloadInfo.m_OutputTensorInfos[0], + "GreaterQueueDescriptor", + "first input", + "second input"); +} + } //namespace armnn diff --git a/src/backends/backendsCommon/test/LayerTests.cpp b/src/backends/backendsCommon/test/LayerTests.cpp index 4dc49f9..43b0d33 100755 --- a/src/backends/backendsCommon/test/LayerTests.cpp +++ b/src/backends/backendsCommon/test/LayerTests.cpp @@ -1674,6 +1674,15 @@ std::unique_ptr CreateWorkload( return workloadFactory.CreateEqual(descriptor, info); } +template<> +std::unique_ptr CreateWorkload( + const armnn::IWorkloadFactory& workloadFactory, + const armnn::WorkloadInfo& info, + const armnn::GreaterQueueDescriptor& descriptor) +{ + return workloadFactory.CreateGreater(descriptor, info); +} + namespace { template LayerTestResult ElementwiseTestHelper @@ -1897,6 +1906,170 @@ LayerTestResult EqualBroadcast1DVectorUint8Test( 0); } +LayerTestResult GreaterSimpleTest(armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager) +{ + const unsigned int width = 2; + const unsigned int height = 2; + const unsigned int channelCount = 2; + const unsigned int batchSize = 2; + + unsigned int shape[] = { batchSize, channelCount, height, width }; + + std::vector input0({ 1, 1, 1, 1, 5, 5, 5, 5, + 3, 3, 3, 3, 4, 4, 4, 4 }); + + std::vector input1({ 1, 1, 1, 1, 3, 3, 3, 3, + 5, 5, 5, 5, 4, 4, 4, 4 }); + + std::vector output({ 0, 0, 0, 0, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0 }); + + return ElementwiseTestHelper + (workloadFactory, + memoryManager, + shape, + input0, + shape, + input1, + shape, + output); +} + +LayerTestResult GreaterBroadcast1ElementTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager) +{ + unsigned int shape0[] = { 1, 2, 2, 2 }; + std::vector input0({ 1, 2, 3, 4, 5, 6, 7, 8}); + + unsigned int shape1[] = { 1, 1, 1, 1 }; + std::vector input1({ 1 }); + + std::vector output({ 0, 1, 1, 1, 1, 1, 1, 1}); + + return ElementwiseTestHelper + (workloadFactory, + memoryManager, + shape0, + input0, + shape1, + input1, + shape0, + output); +} + +LayerTestResult GreaterBroadcast1DVectorTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager) +{ + const unsigned int shape0[] = { 1, 2, 2, 3 }; + const unsigned int shape1[] = { 1, 1, 1, 3 }; + + std::vector input0({ 1, 2.9f, 2.1f, 4, 5, 6, + 7, 8, 9, 10, 11, 12 }); + + std::vector input1({ 1, 3, 2}); + + std::vector output({ 0, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1 }); + + return ElementwiseTestHelper + (workloadFactory, + memoryManager, + shape0, + input0, + shape1, + input1, + shape0, + output); +} + +LayerTestResult GreaterUint8Test( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager) +{ + unsigned int shape[] = { 2, 2, 2, 2 }; + + // See dequantized values to the right. + std::vector input0({ 1, 1, 1, 1, 6, 6, 6, 6, + 3, 3, 3, 3, 5, 5, 5, 5 }); + + std::vector input1({ 2, 2, 2, 2, 6, 6, 6, 6, + 2, 2, 2, 2, 5, 5, 5, 5 }); + + std::vector output({ 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, 0, 0 }); + + return ElementwiseTestHelper + (workloadFactory, + memoryManager, + shape, + input0, + shape, + input1, + shape, + output, + 1.0f, + 0); +} + +LayerTestResult GreaterBroadcast1ElementUint8Test( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager) +{ + const unsigned int shape0[] = { 1, 2, 2, 3 }; + const unsigned int shape1[] = { 1, 1, 1, 1 }; + + std::vector input0({ 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12 }); + + std::vector input1({ 1 }); + + std::vector output({ 0, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1 }); + + return ElementwiseTestHelper + (workloadFactory, + memoryManager, + shape0, + input0, + shape1, + input1, + shape0, + output, + 1.0f, + 0); +} + +LayerTestResult GreaterBroadcast1DVectorUint8Test( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager) +{ + const unsigned int shape0[] = { 1, 2, 2, 3 }; + const unsigned int shape1[] = { 1, 1, 1, 3 }; + + std::vector input0({ 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12 }); + + std::vector input1({ 1, 1, 3}); + + std::vector output({ 0, 1, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 1 }); + + return ElementwiseTestHelper + (workloadFactory, + memoryManager, + shape0, + input0, + shape1, + input1, + shape0, + output, + 1.0f, + 0); +} + LayerTestResult MaximumSimpleTest(armnn::IWorkloadFactory& workloadFactory, const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager) { diff --git a/src/backends/backendsCommon/test/LayerTests.hpp b/src/backends/backendsCommon/test/LayerTests.hpp index 029418e..146f8c4 100644 --- a/src/backends/backendsCommon/test/LayerTests.hpp +++ b/src/backends/backendsCommon/test/LayerTests.hpp @@ -891,6 +891,30 @@ LayerTestResult EqualBroadcast1DVectorUint8Test( armnn::IWorkloadFactory& workloadFactory, const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager); +LayerTestResult GreaterSimpleTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager); + +LayerTestResult GreaterBroadcast1ElementTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager); + +LayerTestResult GreaterBroadcast1DVectorTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager); + +LayerTestResult GreaterUint8Test( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager); + +LayerTestResult GreaterBroadcast1ElementUint8Test( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager); + +LayerTestResult GreaterBroadcast1DVectorUint8Test( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager); + LayerTestResult FullyConnectedLargeTest( armnn::IWorkloadFactory& workloadFactory, const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, diff --git a/src/backends/cl/ClLayerSupport.cpp b/src/backends/cl/ClLayerSupport.cpp index 82b4647..d02dfb9 100644 --- a/src/backends/cl/ClLayerSupport.cpp +++ b/src/backends/cl/ClLayerSupport.cpp @@ -303,6 +303,18 @@ bool ClLayerSupport::IsFullyConnectedSupported(const TensorInfo& input, descriptor); } +bool ClLayerSupport::IsGreaterSupported(const TensorInfo& input0, + const TensorInfo& input1, + const TensorInfo& output, + Optional reasonIfUnsupported) const +{ + ignore_unused(input0); + ignore_unused(input1); + ignore_unused(output); + ignore_unused(reasonIfUnsupported); + return false; +} + bool ClLayerSupport::IsInputSupported(const TensorInfo& input, Optional reasonIfUnsupported) const { diff --git a/src/backends/cl/ClLayerSupport.hpp b/src/backends/cl/ClLayerSupport.hpp index 82efd00..d040a54 100644 --- a/src/backends/cl/ClLayerSupport.hpp +++ b/src/backends/cl/ClLayerSupport.hpp @@ -86,6 +86,11 @@ public: const FullyConnectedDescriptor& descriptor, Optional reasonIfUnsupported = EmptyOptional()) const override; + bool IsGreaterSupported(const TensorInfo& input0, + const TensorInfo& input1, + const TensorInfo& ouput, + Optional reasonIfUnsupported = EmptyOptional()) const override; + bool IsInputSupported(const TensorInfo& input, Optional reasonIfUnsupported = EmptyOptional()) const override; diff --git a/src/backends/neon/NeonLayerSupport.cpp b/src/backends/neon/NeonLayerSupport.cpp index 0033b86..869fd03 100644 --- a/src/backends/neon/NeonLayerSupport.cpp +++ b/src/backends/neon/NeonLayerSupport.cpp @@ -261,6 +261,18 @@ bool NeonLayerSupport::IsFullyConnectedSupported(const TensorInfo& input, descriptor); } +bool NeonLayerSupport::IsGreaterSupported(const TensorInfo& input0, + const TensorInfo& input1, + const TensorInfo& output, + Optional reasonIfUnsupported) const +{ + ignore_unused(input0); + ignore_unused(input1); + ignore_unused(output); + ignore_unused(reasonIfUnsupported); + return false; +} + bool NeonLayerSupport::IsInputSupported(const TensorInfo& input, Optional reasonIfUnsupported) const { diff --git a/src/backends/neon/NeonLayerSupport.hpp b/src/backends/neon/NeonLayerSupport.hpp index 5724ed8..43d0bd9 100644 --- a/src/backends/neon/NeonLayerSupport.hpp +++ b/src/backends/neon/NeonLayerSupport.hpp @@ -81,6 +81,11 @@ public: const FullyConnectedDescriptor& descriptor, Optional reasonIfUnsupported = EmptyOptional()) const override; + bool IsGreaterSupported(const TensorInfo& input0, + const TensorInfo& input1, + const TensorInfo& ouput, + Optional reasonIfUnsupported = EmptyOptional()) const override; + bool IsInputSupported(const TensorInfo& input, Optional reasonIfUnsupported = EmptyOptional()) const override; diff --git a/src/backends/reference/RefLayerSupport.cpp b/src/backends/reference/RefLayerSupport.cpp index 2952ae1..a64339e 100644 --- a/src/backends/reference/RefLayerSupport.cpp +++ b/src/backends/reference/RefLayerSupport.cpp @@ -257,6 +257,21 @@ bool RefLayerSupport::IsFullyConnectedSupported(const TensorInfo& input, &TrueFunc<>); } +bool RefLayerSupport::IsGreaterSupported(const TensorInfo& input0, + const TensorInfo& input1, + const TensorInfo& output, + Optional reasonIfUnsupported) const +{ + ignore_unused(input0); + ignore_unused(input1); + ignore_unused(output); + ignore_unused(reasonIfUnsupported); + return IsSupportedForDataTypeRef(reasonIfUnsupported, + input0.GetDataType(), + &TrueFunc<>, + &TrueFunc<>); +} + bool RefLayerSupport::IsInputSupported(const TensorInfo& input, Optional reasonIfUnsupported) const { diff --git a/src/backends/reference/RefLayerSupport.hpp b/src/backends/reference/RefLayerSupport.hpp index 399f7b5..3941f4b 100644 --- a/src/backends/reference/RefLayerSupport.hpp +++ b/src/backends/reference/RefLayerSupport.hpp @@ -91,6 +91,11 @@ public: const FullyConnectedDescriptor& descriptor, Optional reasonIfUnsupported = EmptyOptional()) const override; + bool IsGreaterSupported(const TensorInfo& input0, + const TensorInfo& input1, + const TensorInfo& ouput, + Optional reasonIfUnsupported = EmptyOptional()) const override; + bool IsInputSupported(const TensorInfo& input, Optional reasonIfUnsupported = EmptyOptional()) const override; diff --git a/src/backends/reference/RefWorkloadFactory.cpp b/src/backends/reference/RefWorkloadFactory.cpp index 8173bbb..eb8807e 100644 --- a/src/backends/reference/RefWorkloadFactory.cpp +++ b/src/backends/reference/RefWorkloadFactory.cpp @@ -303,7 +303,7 @@ std::unique_ptr RefWorkloadFactory::CreateStridedSlice(const StridedS std::unique_ptr RefWorkloadFactory::CreateGreater(const GreaterQueueDescriptor& descriptor, const WorkloadInfo& info) const { - return MakeWorkload(descriptor, info); + return MakeWorkload(descriptor, info); } std::unique_ptr RefWorkloadFactory::CreateDebug(const DebugQueueDescriptor& descriptor, diff --git a/src/backends/reference/test/RefLayerTests.cpp b/src/backends/reference/test/RefLayerTests.cpp index eda58a9..6e7da13 100644 --- a/src/backends/reference/test/RefLayerTests.cpp +++ b/src/backends/reference/test/RefLayerTests.cpp @@ -241,6 +241,14 @@ ARMNN_AUTO_TEST_CASE(EqualUint8, EqualUint8Test) ARMNN_AUTO_TEST_CASE(EqualBroadcast1ElementUint8, EqualBroadcast1ElementUint8Test) ARMNN_AUTO_TEST_CASE(EqualBroadcast1DVectorUint8, EqualBroadcast1DVectorUint8Test) +// Greater +ARMNN_AUTO_TEST_CASE(SimpleGreater, GreaterSimpleTest) +ARMNN_AUTO_TEST_CASE(GreaterBroadcast1Element, GreaterBroadcast1ElementTest) +ARMNN_AUTO_TEST_CASE(GreaterBroadcast1DVector, GreaterBroadcast1DVectorTest) +ARMNN_AUTO_TEST_CASE(GreaterUint8, GreaterUint8Test) +ARMNN_AUTO_TEST_CASE(GreaterBroadcast1ElementUint8, GreaterBroadcast1ElementUint8Test) +ARMNN_AUTO_TEST_CASE(GreaterBroadcast1DVectorUint8, GreaterBroadcast1DVectorUint8Test) + // Max ARMNN_AUTO_TEST_CASE(SimpleMaximum, MaximumSimpleTest) ARMNN_AUTO_TEST_CASE(MaximumBroadcast1Element, MaximumBroadcast1ElementTest) diff --git a/src/backends/reference/workloads/ElementwiseFunction.cpp b/src/backends/reference/workloads/ElementwiseFunction.cpp index 18ceade..cb8aa70 100644 --- a/src/backends/reference/workloads/ElementwiseFunction.cpp +++ b/src/backends/reference/workloads/ElementwiseFunction.cpp @@ -32,4 +32,5 @@ template struct armnn::ElementwiseFunction>; template struct armnn::ElementwiseFunction>; template struct armnn::ElementwiseFunction>; template struct armnn::ElementwiseFunction>; -template struct armnn::ElementwiseFunction>; \ No newline at end of file +template struct armnn::ElementwiseFunction>; +template struct armnn::ElementwiseFunction>; diff --git a/src/backends/reference/workloads/RefElementwiseWorkload.cpp b/src/backends/reference/workloads/RefElementwiseWorkload.cpp index d00bfd0..13d6e70 100644 --- a/src/backends/reference/workloads/RefElementwiseWorkload.cpp +++ b/src/backends/reference/workloads/RefElementwiseWorkload.cpp @@ -45,11 +45,11 @@ void BaseUint8ElementwiseWorkload::ExecuteImpl(const std::vector results(outputInfo.GetNumElements()); ElementwiseFunction(inputInfo0.GetShape(), - inputInfo1.GetShape(), - outputInfo.GetShape(), - dequant0.data(), - dequant1.data(), - results.data()); + inputInfo1.GetShape(), + outputInfo.GetShape(), + dequant0.data(), + dequant1.data(), + results.data()); Quantize(GetOutputTensorDataU8(0, data), results.data(), outputInfo); } @@ -76,3 +76,6 @@ template class armnn::BaseUint8ElementwiseWorkload>; template class armnn::BaseUint8ElementwiseWorkload>; + +template class armnn::BaseFloat32ElementwiseWorkload>; +template class armnn::BaseUint8ElementwiseWorkload>; diff --git a/src/backends/reference/workloads/RefElementwiseWorkload.hpp b/src/backends/reference/workloads/RefElementwiseWorkload.hpp index c2855b0..1b3200f 100644 --- a/src/backends/reference/workloads/RefElementwiseWorkload.hpp +++ b/src/backends/reference/workloads/RefElementwiseWorkload.hpp @@ -12,8 +12,6 @@ #include "Maximum.hpp" #include "Minimum.hpp" - - namespace armnn { @@ -86,7 +84,6 @@ using RefAdditionUint8Workload = AdditionQueueDescriptor, StringMapping::RefAdditionWorkload_Execute>; - using RefSubtractionFloat32Workload = RefElementwiseWorkload, DataType::Float32, @@ -132,9 +129,9 @@ using RefMaximumFloat32Workload = using RefMaximumUint8Workload = RefElementwiseWorkload, - DataType::QuantisedAsymm8, - MaximumQueueDescriptor, - StringMapping::RefMaximumWorkload_Execute>; + DataType::QuantisedAsymm8, + MaximumQueueDescriptor, + StringMapping::RefMaximumWorkload_Execute>; using RefMinimumFloat32Workload = RefElementwiseWorkload, @@ -159,4 +156,16 @@ using RefEqualUint8Workload = DataType::QuantisedAsymm8, EqualQueueDescriptor, StringMapping::RefEqualWorkload_Execute>; + +using RefGreaterFloat32Workload = + RefElementwiseWorkload, + DataType::Float32, + GreaterQueueDescriptor, + StringMapping::RefGreaterWorkload_Execute>; + +using RefGreaterUint8Workload = + RefElementwiseWorkload, + DataType::QuantisedAsymm8, + GreaterQueueDescriptor, + StringMapping::RefGreaterWorkload_Execute>; } // armnn -- 2.7.4