diff options
Diffstat (limited to 'src/backends/backendsCommon')
9 files changed, 193 insertions, 17 deletions
diff --git a/src/backends/backendsCommon/CMakeLists.txt b/src/backends/backendsCommon/CMakeLists.txt index 8d7e114fa5..28ff205d6e 100644 --- a/src/backends/backendsCommon/CMakeLists.txt +++ b/src/backends/backendsCommon/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright © 2017, 2023 Arm Ltd and Contributors. All rights reserved. +# Copyright © 2017-2023 Arm Ltd and Contributors. All rights reserved. # SPDX-License-Identifier: MIT # diff --git a/src/backends/backendsCommon/WorkloadData.cpp b/src/backends/backendsCommon/WorkloadData.cpp index 62dfc6a38b..6a5963ddcb 100644 --- a/src/backends/backendsCommon/WorkloadData.cpp +++ b/src/backends/backendsCommon/WorkloadData.cpp @@ -1,5 +1,5 @@ // -// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// Copyright © 2017-2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -35,11 +35,8 @@ DataType GetBiasDataType(DataType inputDataType) case DataType::Float32: return DataType::Float32; case DataType::QAsymmS8: - return DataType::Signed32; case DataType::QAsymmU8: - return DataType::Signed32; case DataType::QSymmS8: - return DataType::Signed32; case DataType::QSymmS16: return DataType::Signed32; default: @@ -3668,6 +3665,35 @@ void ComparisonQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const } } +void ElementwiseBinaryQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const +{ + const std::string descriptorName{"ElementwiseBinaryQueueDescriptor"}; + + ValidateNumInputs(workloadInfo, descriptorName, 2); + ValidateNumOutputs(workloadInfo, descriptorName, 1); + + const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0]; + const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1]; + const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; + + std::vector<DataType> supportedTypes = + { + DataType::BFloat16, + DataType::Float16, + DataType::Float32, + DataType::QAsymmS8, + DataType::QAsymmU8, + DataType::QSymmS16, + DataType::Signed32 + }; + + ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName); + ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName); + + ValidateTensorDataTypesMatch(inputTensorInfo0, outputTensorInfo, descriptorName, "input", "output"); + ValidateTensorDataTypesMatch(inputTensorInfo1, outputTensorInfo, descriptorName, "input", "output"); +} + void ElementwiseUnaryQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const { const std::string descriptorName{"ElementwiseUnaryQueueDescriptor"}; diff --git a/src/backends/backendsCommon/WorkloadFactory.cpp b/src/backends/backendsCommon/WorkloadFactory.cpp index 1283f67660..51bc3e60cb 100644 --- a/src/backends/backendsCommon/WorkloadFactory.cpp +++ b/src/backends/backendsCommon/WorkloadFactory.cpp @@ -1,5 +1,5 @@ // -// Copyright © 2017 Arm Ltd and Contributors. All rights reserved. +// Copyright © 2017-2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -15,7 +15,6 @@ #include <armnn/utility/TransformIterator.hpp> #include <armnn/backends/WorkloadFactory.hpp> -#include <armnn/backends/TensorHandle.hpp> #include <sstream> @@ -91,7 +90,8 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId, auto backendFactory = backendRegistry.GetFactory(backendId); auto backendObject = backendFactory(); - auto layerSupportObject = LayerSupportHandle(backendObject->GetLayerSupport(modelOptions), backendId); + auto layerSupport = backendObject->GetLayerSupport(modelOptions); + auto layerSupportObject = LayerSupportHandle(layerSupport, backendId); switch(layer.GetType()) { @@ -109,6 +109,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId, } case LayerType::Addition: { + ARMNN_NO_DEPRECATE_WARN_BEGIN const TensorInfo& input0 = layer.GetInputSlot(0).GetConnection()->GetTensorInfo(); const TensorInfo& input1 = layer.GetInputSlot(1).GetConnection()->GetTensorInfo(); const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo(); @@ -117,6 +118,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId, OverrideDataType(input1, dataType), OverrideDataType(output, dataType), reason); + ARMNN_NO_DEPRECATE_WARN_END break; } case LayerType::ArgMinMax: @@ -392,6 +394,24 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId, reason); break; } + case LayerType::ElementwiseBinary: + { + auto cLayer = PolymorphicDowncast<const ElementwiseBinaryLayer*>(&layer); + + const TensorInfo& input0 = layer.GetInputSlot(0).GetConnection()->GetTensorInfo(); + const TensorInfo& input1 = layer.GetInputSlot(1).GetConnection()->GetTensorInfo(); + const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo(); + std::vector<TensorInfo> infos = { OverrideDataType(input0, dataType), + OverrideDataType(input1, dataType), + OverrideDataType(output, dataType) }; + result = layerSupport->IsLayerSupported(LayerType::ElementwiseBinary, + infos, + cLayer->GetParameters(), + EmptyOptional(), + EmptyOptional(), + reason); + break; + } case LayerType::ElementwiseUnary: { auto cLayer = PolymorphicDowncast<const ElementwiseUnaryLayer*>(&layer); @@ -740,6 +760,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId, } case LayerType::Maximum: { + ARMNN_NO_DEPRECATE_WARN_BEGIN const TensorInfo& input0 = layer.GetInputSlot(0).GetConnection()->GetTensorInfo(); const TensorInfo& input1 = layer.GetInputSlot(1).GetConnection()->GetTensorInfo(); const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo(); @@ -748,6 +769,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId, OverrideDataType(input1, dataType), OverrideDataType(output, dataType), reason); + ARMNN_NO_DEPRECATE_WARN_END break; } case LayerType::MemCopy: @@ -814,6 +836,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId, } case LayerType::Multiplication: { + ARMNN_NO_DEPRECATE_WARN_BEGIN const TensorInfo& input0 = layer.GetInputSlot(0).GetConnection()->GetTensorInfo(); const TensorInfo& input1 = layer.GetInputSlot(1).GetConnection()->GetTensorInfo(); const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo(); @@ -822,6 +845,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId, OverrideDataType(input1, dataType), OverrideDataType(output, dataType), reason); + ARMNN_NO_DEPRECATE_WARN_END break; } case LayerType::Normalization: @@ -1052,6 +1076,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId, } case LayerType::Division: { + ARMNN_NO_DEPRECATE_WARN_BEGIN const TensorInfo& input0 = layer.GetInputSlot(0).GetConnection()->GetTensorInfo(); const TensorInfo& input1 = layer.GetInputSlot(1).GetConnection()->GetTensorInfo(); const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo(); @@ -1060,6 +1085,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId, OverrideDataType(input1, dataType), OverrideDataType(output, dataType), reason); + ARMNN_NO_DEPRECATE_WARN_END break; } case LayerType::Rank: @@ -1254,6 +1280,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId, } case LayerType::Subtraction: { + ARMNN_NO_DEPRECATE_WARN_BEGIN const TensorInfo& input0 = layer.GetInputSlot(0).GetConnection()->GetTensorInfo(); const TensorInfo& input1 = layer.GetInputSlot(1).GetConnection()->GetTensorInfo(); const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo(); @@ -1262,6 +1289,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId, OverrideDataType(input1, dataType), OverrideDataType(output, dataType), reason); + ARMNN_NO_DEPRECATE_WARN_END break; } case LayerType::Switch: @@ -1291,6 +1319,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId, } case LayerType::Minimum: { + ARMNN_NO_DEPRECATE_WARN_BEGIN const TensorInfo& input0 = layer.GetInputSlot(0).GetConnection()->GetTensorInfo(); const TensorInfo& input1 = layer.GetInputSlot(1).GetConnection()->GetTensorInfo(); const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo(); @@ -1298,6 +1327,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId, OverrideDataType(input1, dataType), OverrideDataType(output, dataType), reason); + ARMNN_NO_DEPRECATE_WARN_END break; } case LayerType::Prelu: @@ -1670,6 +1700,11 @@ std::unique_ptr<IWorkload> IWorkloadFactory::CreateWorkload(LayerType type, auto divisionQueueDescriptor = PolymorphicDowncast<const DivisionQueueDescriptor*>(&descriptor); return CreateDivision(*divisionQueueDescriptor, info); } + case LayerType::ElementwiseBinary: + { + auto queueDescriptor = PolymorphicDowncast<const ElementwiseBinaryQueueDescriptor*>(&descriptor); + return CreateWorkload(LayerType::ElementwiseBinary, *queueDescriptor, info); + } case LayerType::ElementwiseUnary: { auto elementwiseUnaryQueueDescriptor diff --git a/src/backends/backendsCommon/common.mk b/src/backends/backendsCommon/common.mk index 3545331c8f..986d2530c2 100644 --- a/src/backends/backendsCommon/common.mk +++ b/src/backends/backendsCommon/common.mk @@ -1,5 +1,5 @@ # -# Copyright © 2017 ARM Ltd. All rights reserved. +# Copyright © 2017-2023 ARM Ltd and Contributors. All rights reserved. # SPDX-License-Identifier: MIT # diff --git a/src/backends/backendsCommon/test/CMakeLists.txt b/src/backends/backendsCommon/test/CMakeLists.txt index 509157a378..77335d550a 100644 --- a/src/backends/backendsCommon/test/CMakeLists.txt +++ b/src/backends/backendsCommon/test/CMakeLists.txt @@ -24,6 +24,7 @@ list(APPEND armnnBackendsCommonUnitTests_sources DetectionPostProcessEndToEndTestImpl.hpp DynamicBackendTests.cpp DynamicBackendTests.hpp + ElementwiseBinaryEndToEndTestImpl.hpp ElementwiseUnaryEndToEndTestImpl.hpp EndToEndTestImpl.hpp FillEndToEndTestImpl.hpp diff --git a/src/backends/backendsCommon/test/ElementwiseBinaryEndToEndTestImpl.hpp b/src/backends/backendsCommon/test/ElementwiseBinaryEndToEndTestImpl.hpp new file mode 100644 index 0000000000..6546a6ae9e --- /dev/null +++ b/src/backends/backendsCommon/test/ElementwiseBinaryEndToEndTestImpl.hpp @@ -0,0 +1,107 @@ +// +// Copyright © 2023 Arm Ltd and contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// +#pragma once + +#include "CommonTestUtils.hpp" + +#include <ResolveType.hpp> + +#include <armnn/INetwork.hpp> +#include <armnn/utility/NumericCast.hpp> + +#include <doctest/doctest.h> + +#include <vector> + +namespace +{ + +template<armnn::DataType ArmnnTypeInput> +INetworkPtr CreateElementwiseBinaryNetwork(const TensorShape& input1Shape, + const TensorShape& input2Shape, + const TensorShape& outputShape, + BinaryOperation operation, + const float qScale = 1.0f, + const int32_t qOffset = 0) +{ + using namespace armnn; + + INetworkPtr net(INetwork::Create()); + + TensorInfo input1TensorInfo(input1Shape, ArmnnTypeInput, qScale, qOffset, true); + TensorInfo input2TensorInfo(input2Shape, ArmnnTypeInput, qScale, qOffset, true); + TensorInfo outputTensorInfo(outputShape, ArmnnTypeInput, qScale, qOffset); + + IConnectableLayer* input1 = net->AddInputLayer(armnn::numeric_cast<LayerBindingId>(0)); + IConnectableLayer* input2 = net->AddInputLayer(armnn::numeric_cast<LayerBindingId>(1)); + IConnectableLayer* elementwiseBinaryLayer = net->AddElementwiseBinaryLayer(operation, "elementwiseUnary"); + IConnectableLayer* output = net->AddOutputLayer(0, "output"); + + Connect(input1, elementwiseBinaryLayer, input1TensorInfo, 0, 0); + Connect(input2, elementwiseBinaryLayer, input2TensorInfo, 0, 1); + Connect(elementwiseBinaryLayer, output, outputTensorInfo, 0, 0); + + return net; +} + +template<armnn::DataType ArmnnInType, + typename TInput = armnn::ResolveType<ArmnnInType>> +void ElementwiseBinarySimpleEndToEnd(const std::vector<BackendId>& backends, + BinaryOperation operation) +{ + using namespace armnn; + + const float qScale = IsQuantizedType<TInput>() ? 0.25f : 1.0f; + const int32_t qOffset = IsQuantizedType<TInput>() ? 50 : 0; + + const TensorShape& input1Shape = { 2, 2, 2, 2 }; + const TensorShape& input2Shape = { 1 }; + const TensorShape& outputShape = { 2, 2, 2, 2 }; + + // Builds up the structure of the network + INetworkPtr net = CreateElementwiseBinaryNetwork<ArmnnInType>(input1Shape, input2Shape, outputShape, + operation, qScale, qOffset); + + CHECK(net); + + const std::vector<float> input1({ 1, -1, 1, 1, 5, -5, 5, 5, -3, 3, 3, 3, 4, 4, -4, 4 }); + + const std::vector<float> input2({ 2 }); + std::vector<float> expectedOutput; + switch (operation) { + case armnn::BinaryOperation::Add: + expectedOutput = { 3, 1, 3, 3, 7, -3, 7, 7, -1, 5, 5, 5, 6, 6, -2, 6 }; + break; + case armnn::BinaryOperation::Div: + expectedOutput = {0.5f, -0.5f, 0.5f, 0.5f, 2.5f, -2.5f, 2.5f, 2.5f, -1.5f, 1.5f, 1.5f, 1.5f, 2, 2, -2, 2}; + break; + case armnn::BinaryOperation::Maximum: + expectedOutput = { 2, 2, 2, 2, 5, 2, 5, 5, 2, 3, 3, 3, 4, 4, 2, 4 }; + break; + case armnn::BinaryOperation::Minimum: + expectedOutput = { 1, -1, 1, 1, 2, -5, 2, 2, -3, 2, 2, 2, 2, 2, -4, 2 }; + break; + case armnn::BinaryOperation::Mul: + expectedOutput = { 2, -2, 2, 2, 10, -10, 10, 10, -6, 6, 6, 6, 8, 8, -8, 8 }; + break; + case armnn::BinaryOperation::Sub: + expectedOutput = { -1, -3, -1, -1, 3, -7, 3, 3, -5, 1, 1, 1, 2, 2, -6, 2 }; + break; + default: + throw("Invalid Elementwise Binary operation"); + } + const std::vector<float> expectedOutput_const = expectedOutput; + // quantize data + std::vector<TInput> qInput1Data = armnnUtils::QuantizedVector<TInput>(input1, qScale, qOffset); + std::vector<TInput> qInput2Data = armnnUtils::QuantizedVector<TInput>(input2, qScale, qOffset); + std::vector<TInput> qExpectedOutput = armnnUtils::QuantizedVector<TInput>(expectedOutput_const, qScale, qOffset); + + std::map<int, std::vector<TInput>> inputTensorData = {{ 0, qInput1Data }, { 1, qInput2Data }}; + std::map<int, std::vector<TInput>> expectedOutputData = {{ 0, qExpectedOutput }}; + + EndToEndLayerTestImpl<ArmnnInType, ArmnnInType>(std::move(net), inputTensorData, expectedOutputData, backends); +} + +} // anonymous namespace diff --git a/src/backends/backendsCommon/test/IsLayerSupportedTestImpl.hpp b/src/backends/backendsCommon/test/IsLayerSupportedTestImpl.hpp index fb7a0271d4..5b95d3cd92 100644 --- a/src/backends/backendsCommon/test/IsLayerSupportedTestImpl.hpp +++ b/src/backends/backendsCommon/test/IsLayerSupportedTestImpl.hpp @@ -1,5 +1,5 @@ // -// Copyright © 2017,2022 Arm Ltd and Contributors. All rights reserved. +// Copyright © 2017-2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // #pragma once @@ -664,6 +664,8 @@ DECLARE_LAYER_POLICY_1_PARAM(Dequantize) DECLARE_LAYER_POLICY_2_PARAM(DetectionPostProcess) +DECLARE_LAYER_POLICY_2_PARAM(ElementwiseBinary) + DECLARE_LAYER_POLICY_2_PARAM(ElementwiseUnary) DECLARE_LAYER_POLICY_2_PARAM(FakeQuantization) diff --git a/src/backends/backendsCommon/test/OptimizedNetworkTests.cpp b/src/backends/backendsCommon/test/OptimizedNetworkTests.cpp index cd865def71..5e619df8dd 100644 --- a/src/backends/backendsCommon/test/OptimizedNetworkTests.cpp +++ b/src/backends/backendsCommon/test/OptimizedNetworkTests.cpp @@ -1,5 +1,5 @@ // -// Copyright © 2017 Arm Ltd. All rights reserved. +// Copyright © 2017-2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -21,7 +21,7 @@ TEST_CASE("SerializeToDot") //Defines layers. auto input = net->AddInputLayer(0); - auto add = net->AddAdditionLayer(); + auto add = net->AddElementwiseBinaryLayer(armnn::BinaryOperation::Add); auto output = net->AddOutputLayer(0); // Connects layers. @@ -54,7 +54,7 @@ TEST_CASE("SerializeToDot") " edge [fontsize=8 fontcolor=\"blue\" fontname=\"arial-bold\"];\n" " " << inputId << " [label=\"{Input|Guid : " << inputId << "\\lLayerType : Input\\l" "BackendID : CpuRef\\l}\"];\n" - " " << addId << " [label=\"{Addition|Guid : " << addId << "\\lLayerType : Addition\\l" + " " << addId << " [label=\"{ElementwiseBinary|Guid : " << addId << "\\lLayerType : ElementwiseBinary\\l" "BackendID : CpuRef\\l}\"];\n" " " << outputId << " [label=\"{Output|Guid : " << outputId << "\\lLayerType : Output\\l" "BackendID : CpuRef\\l}\"];\n" @@ -187,7 +187,7 @@ TEST_CASE("OptimizeValidateWorkloadsUndefinedComputeDevice") layer->GetOutputSlot(0).SetTensorInfo(desc); armnn::IConnectableLayer* prevLayer = layer; - layer = net->AddMultiplicationLayer("ml"); + layer = net->AddElementwiseBinaryLayer(armnn::BinaryOperation::Mul, "ml"); prevLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0)); normLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1)); @@ -258,7 +258,7 @@ TEST_CASE("OptimizeValidateWorkloadsUndefinedComputeDeviceWithFallback") layer->GetOutputSlot(0).SetTensorInfo(desc); armnn::IConnectableLayer* prevLayer = layer; - layer = net->AddMultiplicationLayer("ml"); + layer = net->AddElementwiseBinaryLayer(armnn::BinaryOperation::Mul, "ml"); prevLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0)); normLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1)); diff --git a/src/backends/backendsCommon/test/mockBackend/MockImportLayerSupport.hpp b/src/backends/backendsCommon/test/mockBackend/MockImportLayerSupport.hpp index 380ce4a3f5..da4b7ab7d0 100644 --- a/src/backends/backendsCommon/test/mockBackend/MockImportLayerSupport.hpp +++ b/src/backends/backendsCommon/test/mockBackend/MockImportLayerSupport.hpp @@ -1,5 +1,5 @@ // -// Copyright © 2020 Arm Ltd and Contributors. All rights reserved. +// Copyright © 2020-2021,2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // #pragma once @@ -16,7 +16,7 @@ class MockImportLayerSupport : public LayerSupportBase public: bool IsLayerSupported(const LayerType& type, const std::vector<TensorInfo>& infos, - const BaseDescriptor& /*descriptor*/, + const BaseDescriptor& descriptor, const Optional<LstmInputParamsInfo>& /*lstmParamsInfo*/, const Optional<QuantizedLstmInputParamsInfo>& /*quantizedLstmParamsInfo*/, Optional<std::string&> reasonIfUnsupported) const override @@ -25,6 +25,11 @@ public: { case LayerType::Addition: return IsAdditionSupported(infos[0], infos[1], infos[2], reasonIfUnsupported); + case LayerType::ElementwiseBinary: + { + auto elementwiseDesc = *(PolymorphicDowncast<const ElementwiseBinaryDescriptor*>(&descriptor)); + return (elementwiseDesc.m_Operation == BinaryOperation::Add); + } case LayerType::Input: return IsInputSupported(infos[0], reasonIfUnsupported); case LayerType::Output: |