aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikhil Raj <nikhil.raj@arm.com>2022-12-05 11:24:35 +0000
committerNikhil Raj Arm <nikhil.raj@arm.com>2022-12-23 10:28:30 +0000
commit9a33946fd0d5e14be6f957b5a985438fa69684d6 (patch)
tree07b93ffccc31c2183567fda3523d79a82510745b
parent259adafd6840c612c2eb64653290cbe2cfa7cd8e (diff)
downloadarmnn-9a33946fd0d5e14be6f957b5a985438fa69684d6.tar.gz
IVGCVSW-7172 Add ElementwiseBinary (Subtraction & Multiplication) support to TOSA Reference Backend
* Removed AdditionOperator and moved to new ElementwiseBinaryOperator. Signed-off-by: Nikhil Raj <nikhil.raj@arm.com> Signed-off-by: Matthew Sloyan <matthew.sloyan@arm.com> Change-Id: I8ce20f7575d68334aadcd176827bca3db53d0052
-rw-r--r--src/backends/backendsCommon/test/CMakeLists.txt4
-rw-r--r--src/backends/backendsCommon/test/MultiplicationEndToEndTestImpl.hpp96
-rw-r--r--src/backends/backendsCommon/test/SubtractionEndToEndTestImpl.hpp96
-rw-r--r--src/backends/tosaCommon/TosaMappings.cpp4
-rw-r--r--src/backends/tosaCommon/operatorMappings/AdditionOperator.hpp20
-rw-r--r--src/backends/tosaCommon/operatorMappings/CMakeLists.txt4
-rw-r--r--src/backends/tosaCommon/operatorMappings/ElementwiseBinaryOperator.cpp (renamed from src/backends/tosaCommon/operatorMappings/AdditionOperator.cpp)67
-rw-r--r--src/backends/tosaCommon/operatorMappings/ElementwiseBinaryOperator.hpp20
-rw-r--r--src/backends/tosaCommon/operatorMappings/TosaCommonOperators.hpp6
-rw-r--r--src/backends/tosaCommon/test/OneToOneMappingTests.cpp48
-rw-r--r--src/backends/tosaReference/TosaRefLayerSupport.cpp2
-rw-r--r--src/backends/tosaReference/test/TosaRefEndToEndTests.cpp31
-rw-r--r--src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp88
13 files changed, 441 insertions, 45 deletions
diff --git a/src/backends/backendsCommon/test/CMakeLists.txt b/src/backends/backendsCommon/test/CMakeLists.txt
index 5fcc8b592e..d251bd2597 100644
--- a/src/backends/backendsCommon/test/CMakeLists.txt
+++ b/src/backends/backendsCommon/test/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright © 2017,2022 Arm Ltd and Contributors. All rights reserved.
+# Copyright © 2017-2022 Arm Ltd and Contributors. All rights reserved.
# SPDX-License-Identifier: MIT
#
@@ -41,6 +41,7 @@ list(APPEND armnnBackendsCommonUnitTests_sources
LogSoftmaxEndToEndTestImpl.hpp
MemoryManagerTests.cpp
MockBackendId.hpp
+ MultiplicationEndToEndTestImpl.hpp
OptimizeSubgraphViewTests.cpp
OptimizationViewsTests.cpp
PreluEndToEndTestImpl.hpp
@@ -57,6 +58,7 @@ list(APPEND armnnBackendsCommonUnitTests_sources
SpaceToDepthEndToEndTestImpl.hpp
SplitterEndToEndTestImpl.hpp
StridedSliceAsyncEndToEndTest.hpp
+ SubtractionEndToEndTestImpl.hpp
TransposeEndToEndTestImpl.hpp
TensorCopyUtils.hpp
WorkloadFactoryHelper.hpp
diff --git a/src/backends/backendsCommon/test/MultiplicationEndToEndTestImpl.hpp b/src/backends/backendsCommon/test/MultiplicationEndToEndTestImpl.hpp
new file mode 100644
index 0000000000..40442e2d47
--- /dev/null
+++ b/src/backends/backendsCommon/test/MultiplicationEndToEndTestImpl.hpp
@@ -0,0 +1,96 @@
+//
+// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+
+#include <armnn/INetwork.hpp>
+
+#include <CommonTestUtils.hpp>
+#include <ResolveType.hpp>
+
+#include <doctest/doctest.h>
+
+namespace
+{
+
+template<typename armnn::DataType DataType>
+armnn::INetworkPtr CreateMultiplicationNetwork(const armnn::TensorShape& inputXShape,
+ const armnn::TensorShape& inputYShape,
+ const armnn::TensorShape& outputShape,
+ const float qScale = 1.0f,
+ const int32_t qOffset = 0)
+{
+ using namespace armnn;
+
+ INetworkPtr network(INetwork::Create());
+
+ TensorInfo inputXTensorInfo(inputXShape, DataType, qScale, qOffset, true);
+ TensorInfo inputYTensorInfo(inputYShape, DataType, qScale, qOffset, true);
+
+ TensorInfo outputTensorInfo(outputShape, DataType, qScale, qOffset);
+
+
+ IConnectableLayer* multiplication = network->AddMultiplicationLayer("multiplication");
+ IConnectableLayer* inputX = network->AddInputLayer(0, "inputX");
+ IConnectableLayer* inputY = network->AddInputLayer(1, "inputY");
+ IConnectableLayer* output = network->AddOutputLayer(0, "output");
+
+ Connect(inputX, multiplication, inputXTensorInfo, 0, 0);
+ Connect(inputY, multiplication, inputYTensorInfo, 0, 1);
+ Connect(multiplication, output, outputTensorInfo, 0, 0);
+
+ return network;
+}
+
+template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
+void MultiplicationEndToEnd(const std::vector<armnn::BackendId>& backends)
+{
+ using namespace armnn;
+
+ const TensorShape& inputXShape = { 2, 2 };
+ const TensorShape& inputYShape = { 2, 2 };
+ const TensorShape& outputShape = { 2, 2 };
+
+ INetworkPtr network = CreateMultiplicationNetwork<ArmnnType>(inputXShape, inputYShape, outputShape);
+
+ CHECK(network);
+
+ std::vector<T> inputXData{ 1, 2, 3, 4 };
+ std::vector<T> inputYData{ 5, 2, 6, 3 };
+ std::vector<T> expectedOutput{ 5, 4, 18, 12 };
+
+ std::map<int, std::vector<T>> inputTensorData = {{ 0, inputXData }, {1, inputYData}};
+ std::map<int, std::vector<T>> expectedOutputData = { { 0, expectedOutput } };
+
+ EndToEndLayerTestImpl<ArmnnType, ArmnnType>(std::move(network), inputTensorData, expectedOutputData, backends);
+}
+
+template<armnn::DataType ArmnnType>
+void MultiplicationEndToEndFloat16(const std::vector<armnn::BackendId>& backends)
+{
+ using namespace armnn;
+ using namespace half_float::literal;
+ using Half = half_float::half;
+
+ const TensorShape& inputXShape = { 2, 2 };
+ const TensorShape& inputYShape = { 2, 2 };
+ const TensorShape& outputShape = { 2, 2 };
+
+ INetworkPtr network = CreateMultiplicationNetwork<ArmnnType>(inputXShape, inputYShape, outputShape);
+ CHECK(network);
+
+ std::vector<Half> inputXData{ 1._h, 2._h,
+ 3._h, 4._h };
+ std::vector<Half> inputYData{ 1._h, 2._h,
+ 3._h, 4._h };
+ std::vector<Half> expectedOutput{ 1._h, 4._h,
+ 9._h, 16._h };
+
+ std::map<int, std::vector<Half>> inputTensorData = {{ 0, inputXData }, { 1, inputYData }};
+ std::map<int, std::vector<Half>> expectedOutputData = { { 0, expectedOutput } };
+
+ EndToEndLayerTestImpl<ArmnnType, ArmnnType>(std::move(network), inputTensorData, expectedOutputData, backends);
+}
+
+} // anonymous namespace
diff --git a/src/backends/backendsCommon/test/SubtractionEndToEndTestImpl.hpp b/src/backends/backendsCommon/test/SubtractionEndToEndTestImpl.hpp
new file mode 100644
index 0000000000..747fe26df0
--- /dev/null
+++ b/src/backends/backendsCommon/test/SubtractionEndToEndTestImpl.hpp
@@ -0,0 +1,96 @@
+//
+// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+
+#include <armnn/INetwork.hpp>
+
+#include <CommonTestUtils.hpp>
+#include <ResolveType.hpp>
+
+#include <doctest/doctest.h>
+
+namespace
+{
+
+template<typename armnn::DataType DataType>
+armnn::INetworkPtr CreateSubtractionNetwork(const armnn::TensorShape& inputXShape,
+ const armnn::TensorShape& inputYShape,
+ const armnn::TensorShape& outputShape,
+ const float qScale = 1.0f,
+ const int32_t qOffset = 0)
+{
+ using namespace armnn;
+
+ INetworkPtr network(INetwork::Create());
+
+ TensorInfo inputXTensorInfo(inputXShape, DataType, qScale, qOffset, true);
+ TensorInfo inputYTensorInfo(inputYShape, DataType, qScale, qOffset, true);
+
+ TensorInfo outputTensorInfo(outputShape, DataType, qScale, qOffset);
+
+
+ IConnectableLayer* subtraction = network->AddSubtractionLayer("subtraction");
+ IConnectableLayer* inputX = network->AddInputLayer(0, "inputX");
+ IConnectableLayer* inputY = network->AddInputLayer(1, "inputY");
+ IConnectableLayer* output = network->AddOutputLayer(0, "output");
+
+ Connect(inputX, subtraction, inputXTensorInfo, 0, 0);
+ Connect(inputY, subtraction, inputYTensorInfo, 0, 1);
+ Connect(subtraction, output, outputTensorInfo, 0, 0);
+
+ return network;
+}
+
+template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
+void SubtractionEndToEnd(const std::vector<armnn::BackendId>& backends)
+{
+ using namespace armnn;
+
+ const TensorShape& inputXShape = { 2, 2 };
+ const TensorShape& inputYShape = { 2, 2 };
+ const TensorShape& outputShape = { 2, 2 };
+
+ INetworkPtr network = CreateSubtractionNetwork<ArmnnType>(inputXShape, inputYShape, outputShape);
+
+ CHECK(network);
+
+ std::vector<T> inputXData{ 10, 11, 12, 13 };
+ std::vector<T> inputYData{ 5, 7, 6, 8 };
+ std::vector<T> expectedOutput{ 5, 4, 6, 5 };
+
+ std::map<int, std::vector<T>> inputTensorData = {{ 0, inputXData }, {1, inputYData}};
+ std::map<int, std::vector<T>> expectedOutputData = { { 0, expectedOutput } };
+
+ EndToEndLayerTestImpl<ArmnnType, ArmnnType>(std::move(network), inputTensorData, expectedOutputData, backends);
+}
+
+template<armnn::DataType ArmnnType>
+void SubtractionEndToEndFloat16(const std::vector<armnn::BackendId>& backends)
+{
+ using namespace armnn;
+ using namespace half_float::literal;
+ using Half = half_float::half;
+
+ const TensorShape& inputXShape = { 2, 2 };
+ const TensorShape& inputYShape = { 2, 2 };
+ const TensorShape& outputShape = { 2, 2 };
+
+ INetworkPtr network = CreateSubtractionNetwork<ArmnnType>(inputXShape, inputYShape, outputShape);
+ CHECK(network);
+
+ std::vector<Half> inputXData{ 11._h, 12._h,
+ 13._h, 14._h };
+ std::vector<Half> inputYData{ 5._h, 7._h,
+ 6._h, 8._h };
+ std::vector<Half> expectedOutput{ 6._h, 5._h,
+ 7._h, 6._h };
+
+ std::map<int, std::vector<Half>> inputTensorData = {{ 0, inputXData }, { 1, inputYData }};
+ std::map<int, std::vector<Half>> expectedOutputData = { { 0, expectedOutput } };
+
+ EndToEndLayerTestImpl<ArmnnType, ArmnnType>(std::move(network), inputTensorData, expectedOutputData, backends);
+}
+
+} // anonymous namespace
diff --git a/src/backends/tosaCommon/TosaMappings.cpp b/src/backends/tosaCommon/TosaMappings.cpp
index 1452e4aefd..b0f8fd9c2d 100644
--- a/src/backends/tosaCommon/TosaMappings.cpp
+++ b/src/backends/tosaCommon/TosaMappings.cpp
@@ -24,8 +24,10 @@ TosaSerializationBasicBlock* GetTosaMapping(const Layer* layer,
switch (type)
{
case LayerType::Addition:
+ case LayerType::Multiplication:
+ case LayerType::Subtraction:
{
- return ConvertAdditionToTosaOperator(layer, inputs, outputs);
+ return ConvertElementwiseBinaryToTosaOperator(layer, type, inputs, outputs);
}
case LayerType::Concat:
{
diff --git a/src/backends/tosaCommon/operatorMappings/AdditionOperator.hpp b/src/backends/tosaCommon/operatorMappings/AdditionOperator.hpp
deleted file mode 100644
index 5eb7441531..0000000000
--- a/src/backends/tosaCommon/operatorMappings/AdditionOperator.hpp
+++ /dev/null
@@ -1,20 +0,0 @@
-//
-// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
-// SPDX-License-Identifier: MIT
-//
-
-#pragma once
-
-#include "TosaOperatorUtils.hpp"
-
-#include <Layer.hpp>
-
-#include <tosa_serialization_handler.h>
-
-using namespace armnn;
-using namespace tosa;
-
-TosaSerializationBasicBlock* ConvertAdditionToTosaOperator(const Layer* layer,
- const std::vector<const TensorInfo*>& inputs,
- const std::vector<const TensorInfo*>& outputs);
-
diff --git a/src/backends/tosaCommon/operatorMappings/CMakeLists.txt b/src/backends/tosaCommon/operatorMappings/CMakeLists.txt
index 2443dc0585..6e897aaa8c 100644
--- a/src/backends/tosaCommon/operatorMappings/CMakeLists.txt
+++ b/src/backends/tosaCommon/operatorMappings/CMakeLists.txt
@@ -4,8 +4,6 @@
#
list(APPEND armnnTosaBackendOperators_sources
- AdditionOperator.hpp
- AdditionOperator.cpp
AvgPool2DIgnoreValueOperator.hpp
AvgPool2DIgnoreValueOperator.cpp
ConcatOperator.hpp
@@ -14,6 +12,8 @@ list(APPEND armnnTosaBackendOperators_sources
ConstantOperator.cpp
Conv2dOperator.hpp
Conv2dOperator.cpp
+ ElementwiseBinaryOperator.hpp
+ ElementwiseBinaryOperator.cpp
Pooling2DOperator.hpp
Pooling2DOperator.cpp
ReshapeOperator.hpp
diff --git a/src/backends/tosaCommon/operatorMappings/AdditionOperator.cpp b/src/backends/tosaCommon/operatorMappings/ElementwiseBinaryOperator.cpp
index 7014886d92..9909e66a7d 100644
--- a/src/backends/tosaCommon/operatorMappings/AdditionOperator.cpp
+++ b/src/backends/tosaCommon/operatorMappings/ElementwiseBinaryOperator.cpp
@@ -3,22 +3,23 @@
// SPDX-License-Identifier: MIT
//
-#include "AdditionOperator.hpp"
+#include "ElementwiseBinaryOperator.hpp"
-TosaSerializationBasicBlock* ConvertAdditionToTosaOperator(const Layer* layer,
- const std::vector<const TensorInfo*>& inputs,
- const std::vector<const TensorInfo*>& outputs)
+TosaSerializationBasicBlock* ConvertElementwiseBinaryToTosaOperator(const Layer* layer,
+ const LayerType type,
+ const std::vector<const TensorInfo*>& inputs,
+ const std::vector<const TensorInfo*>& outputs)
{
std::string input0Name = std::string("input0_");
std::string input1Name = std::string("input1_");
std::string outputName = std::string("output0_");
- std::string blockName = std::string("Op_ADD_block_") + GetUniqueTosaMappingID();
+ std::string blockName;
// If a layer is present then the block will be used for execution, so input and output names need to be determined
// using the previous and following layers so the graph is connected correctly. For validation this doesn't matter.
if(layer != nullptr)
{
- // Get the layers connected to the input slots and determine unique tensors names.
+ // Get the layers connected to the input slots and determine unique tensor names.
Layer& connectedLayer0 = layer->GetInputSlot(0).GetConnectedOutputSlot()->GetOwningLayer();
input0Name = GenerateUniqueName(connectedLayer0, 0);
@@ -29,15 +30,47 @@ TosaSerializationBasicBlock* ConvertAdditionToTosaOperator(const Layer* layer,
outputName = GenerateUniqueOutputName(*layer, 0);
}
- auto* op = new TosaSerializationOperator(Op_ADD,
- Attribute_NONE,
- nullptr,
- {input0Name, input1Name},
- {outputName});
-
+ TosaSerializationOperator* op = nullptr;
+ switch(type)
+ {
+ case LayerType::Addition:
+ {
+ op = new TosaSerializationOperator(Op_ADD,
+ Attribute_NONE,
+ nullptr,
+ {input0Name, input1Name},
+ {outputName});
+ blockName = std::string("Op_ADD_block_") + GetUniqueTosaMappingID();
+ break;
+ }
+ case LayerType::Multiplication:
+ {
+ int32_t shift = 0;
+ TosaMulAttribute mulAttribute(shift);
+ op = new TosaSerializationOperator(Op_MUL,
+ Attribute_MulAttribute,
+ &mulAttribute,
+ {input0Name, input1Name},
+ {outputName});
+ blockName = std::string("Op_MUL_block_") + GetUniqueTosaMappingID();
+ break;
+ }
+ case LayerType::Subtraction:
+ {
+ op = new TosaSerializationOperator(Op_SUB,
+ Attribute_NONE,
+ nullptr,
+ {input0Name, input1Name},
+ {outputName});
+ blockName = std::string("Op_SUB_block_") + GetUniqueTosaMappingID();
+ break;
+ }
+ default:
+ throw armnn::Exception("ConvertElementwiseBinaryToTosaOperator: Unsupported layer type.");
+ }
+ ARMNN_ASSERT(op != nullptr);
std::vector<TosaSerializationTensor*> tensors;
-
// Only add input tensors if connected layer is an input layer.
// As intermediate or constant tensors will be created separately.
// There also can't be duplicate tensor.
@@ -45,15 +78,12 @@ TosaSerializationBasicBlock* ConvertAdditionToTosaOperator(const Layer* layer,
{
std::vector<int32_t> inputShape0 = GetTosaTensorShape(inputs[0]->GetShape());
DType inputDType0 = ArmNNToDType(inputs[0]->GetDataType());
-
tensors.push_back(new TosaSerializationTensor(input0Name, inputShape0, inputDType0, {}));
}
-
if(input1Name.find("input1_") != std::string::npos)
{
std::vector<int32_t> inputShape1 = GetTosaTensorShape(inputs[1]->GetShape());
DType inputDType1 = ArmNNToDType(inputs[1]->GetDataType());
-
tensors.push_back(new TosaSerializationTensor(input1Name, inputShape1, inputDType1, {}));
}
@@ -63,10 +93,11 @@ TosaSerializationBasicBlock* ConvertAdditionToTosaOperator(const Layer* layer,
tensors.push_back(new TosaSerializationTensor(outputName, outputShape0, outputDType0, {}));
// operatorInputNames/operatorOutputNames ends up being the same as
- // blockInputNames/blockOutputNames for one-to-one ArmNN to TOSA mappings
+ // blockInputNames/blockOutputNames for one-to-one ArmNN to Tosa mappings
return new TosaSerializationBasicBlock(blockName, // name
{op}, // operators
tensors, // tensors
{input0Name, input1Name}, // inputs
{outputName}); // outputs
-} \ No newline at end of file
+}
+
diff --git a/src/backends/tosaCommon/operatorMappings/ElementwiseBinaryOperator.hpp b/src/backends/tosaCommon/operatorMappings/ElementwiseBinaryOperator.hpp
new file mode 100644
index 0000000000..86031c6e06
--- /dev/null
+++ b/src/backends/tosaCommon/operatorMappings/ElementwiseBinaryOperator.hpp
@@ -0,0 +1,20 @@
+//
+// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include "TosaOperatorUtils.hpp"
+
+#include <Layer.hpp>
+
+#include <tosa_serialization_handler.h>
+
+using namespace armnn;
+using namespace tosa;
+
+TosaSerializationBasicBlock* ConvertElementwiseBinaryToTosaOperator(const Layer* layer,
+ const LayerType type,
+ const std::vector<const TensorInfo*>& inputs,
+ const std::vector<const TensorInfo*>& outputs); \ No newline at end of file
diff --git a/src/backends/tosaCommon/operatorMappings/TosaCommonOperators.hpp b/src/backends/tosaCommon/operatorMappings/TosaCommonOperators.hpp
index 052c54c3af..7b117d8443 100644
--- a/src/backends/tosaCommon/operatorMappings/TosaCommonOperators.hpp
+++ b/src/backends/tosaCommon/operatorMappings/TosaCommonOperators.hpp
@@ -5,12 +5,12 @@
#pragma once
-#include "AdditionOperator.hpp"
+#include "AvgPool2DIgnoreValueOperator.hpp"
#include "ConcatOperator.hpp"
#include "ConstantOperator.hpp"
#include "Conv2dOperator.hpp"
-#include "AvgPool2DIgnoreValueOperator.hpp"
+#include "ElementwiseBinaryOperator.hpp"
#include "Pooling2DOperator.hpp"
#include "ReshapeOperator.hpp"
#include "SliceOperator.hpp"
-#include "TransposeConv2dOperator.hpp" \ No newline at end of file
+#include "TransposeConv2dOperator.hpp"
diff --git a/src/backends/tosaCommon/test/OneToOneMappingTests.cpp b/src/backends/tosaCommon/test/OneToOneMappingTests.cpp
index b3ab14a774..146a9cba37 100644
--- a/src/backends/tosaCommon/test/OneToOneMappingTests.cpp
+++ b/src/backends/tosaCommon/test/OneToOneMappingTests.cpp
@@ -253,6 +253,54 @@ TEST_CASE("GetTosaMappingFromLayer_Conv2dLayer")
basicBlock, inputShape, outputShape, Op_CONV2D, Attribute_ConvAttribute, descriptor, LayerType::Convolution2d);
}
+TEST_CASE("GetTosaMapping_MultiplicationLayer")
+{
+
+ const TensorInfo input0Info ({ 1, 2, 4, 2 }, DataType::Float32);
+ const TensorInfo input1Info ({ 1, 2, 4, 2 }, DataType::Float32);
+ const TensorInfo outputInfo ({ 1, 2, 4, 2 }, DataType::Float32);
+
+ std::vector<std::vector<int32_t>> inputShape = {{ 1, 2, 4, 2 }, { 1, 2, 4, 2 }};
+ std::vector<std::vector<int32_t>> outputShape = {{ 1, 2, 4, 2 }};
+
+ TosaSerializationBasicBlock* basicBlock =
+ GetTosaMapping(nullptr, LayerType::Multiplication, {&input0Info, &input1Info}, {&outputInfo}, BaseDescriptor());
+ AssertTosaOneToOneMappingBasicBlock( basicBlock, inputShape, outputShape,
+ tosa::Op_MUL, tosa::Attribute_MulAttribute, BaseDescriptor(), LayerType::Multiplication);
+}
+
+TEST_CASE("GetTosaMappingFromLayer_MultiplicationLayer")
+{
+ IRuntime::CreationOptions options;
+ IRuntimePtr runtime(IRuntime::Create(options));
+
+ // Builds up the structure of the network.
+ INetworkPtr net(INetwork::Create());
+
+ IConnectableLayer* input0 = net->AddInputLayer(0, "input0");
+ IConnectableLayer* input1 = net->AddInputLayer(1, "input1");
+ IConnectableLayer* add = net->AddMultiplicationLayer("multiplication");
+ IConnectableLayer* output = net->AddOutputLayer(0, "output");
+
+ input0->GetOutputSlot(0).Connect(add->GetInputSlot(0));
+ input1->GetOutputSlot(0).Connect(add->GetInputSlot(1));
+ add->GetOutputSlot(0).Connect(output->GetInputSlot(0));
+
+ TensorInfo info = TensorInfo({ 2, 2 }, DataType::Float32, 0.0f, 0, true);
+
+ input0->GetOutputSlot(0).SetTensorInfo(info);
+ input1->GetOutputSlot(0).SetTensorInfo(info);
+ add->GetOutputSlot(0).SetTensorInfo(info);
+
+ std::vector<std::vector<int32_t>> inputShape = {{ 2, 2 }, { 2, 2 }};
+ std::vector<std::vector<int32_t>> outputShape = {{ 2, 2 }};
+
+ TosaSerializationBasicBlock* basicBlock =
+ GetTosaMappingFromLayer(PolymorphicDowncast<Layer*>(add));
+ AssertTosaOneToOneMappingBasicBlock( basicBlock, inputShape, outputShape,
+ tosa::Op_MUL, Attribute_MulAttribute, BaseDescriptor(), LayerType::Multiplication);
+}
+
TEST_CASE("GetTosaMapping_AvgPool2DLayer")
{
Pooling2dDescriptor descriptor;
diff --git a/src/backends/tosaReference/TosaRefLayerSupport.cpp b/src/backends/tosaReference/TosaRefLayerSupport.cpp
index 0d0d07a783..b37ecc4ab7 100644
--- a/src/backends/tosaReference/TosaRefLayerSupport.cpp
+++ b/src/backends/tosaReference/TosaRefLayerSupport.cpp
@@ -38,6 +38,8 @@ bool TosaRefLayerSupport::IsLayerSupported(const LayerType& type,
case LayerType::Output:
return true;
case LayerType::Addition:
+ case LayerType::Multiplication:
+ case LayerType::Subtraction:
// Setup inputs and outputs
inputInfos.push_back(&infos[0]);
inputInfos.push_back(&infos[1]);
diff --git a/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp b/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp
index a377293fbf..67b87ae8b9 100644
--- a/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp
+++ b/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp
@@ -8,9 +8,11 @@
#include "backendsCommon/test/AdditionEndToEndTestImpl.hpp"
#include "backendsCommon/test/Convolution2dEndToEndTestImpl.hpp"
#include "backendsCommon/test/ConcatEndToEndTestImpl.hpp"
+#include "backendsCommon/test/MultiplicationEndToEndTestImpl.hpp"
#include "backendsCommon/test/Pooling2dEndToEndTestImpl.hpp"
#include "backendsCommon/test/ReshapeEndToEndTestImpl.hpp"
#include "backendsCommon/test/SliceEndToEndTestImpl.hpp"
+#include "backendsCommon/test/SubtractionEndToEndTestImpl.hpp"
#include "backendsCommon/test/TransposeConvolution2dEndToEndTestImpl.hpp"
#include <doctest/doctest.h>
@@ -150,6 +152,35 @@ TEST_CASE("TosaRefSliceEndtoEndTestFloat16")
{
SliceEndToEndFloat16<DataType::Float16>(tosaDefaultBackends);
}
+TEST_CASE("TosaRefSubtractionEndtoEndTestFloat32")
+{
+ SubtractionEndToEnd<DataType::Float32>(tosaDefaultBackends);
+}
+
+TEST_CASE("TosaRefSubtractionEndtoEndTestInt32")
+{
+ SubtractionEndToEnd<DataType::Signed32>(tosaDefaultBackends);
+}
+
+TEST_CASE("TosaRefSubtractionEndtoEndTestFloat16")
+{
+ SubtractionEndToEndFloat16<DataType::Float16>(tosaDefaultBackends);
+}
+
+TEST_CASE("TosaRefMultiplicationEndtoEndTestFloat32")
+{
+ MultiplicationEndToEnd<DataType::Float32>(tosaDefaultBackends);
+}
+
+TEST_CASE("TosaRefMultiplicationEndtoEndTestInt32")
+{
+ MultiplicationEndToEnd<DataType::Signed32>(tosaDefaultBackends);
+}
+
+TEST_CASE("TosaRefMultiplicationEndtoEndTestFloat16")
+{
+ MultiplicationEndToEndFloat16<DataType::Float16>(tosaDefaultBackends);
+}
// TransposeConvolution2d
TEST_CASE("TosaRefTransposeConvolution2dEndToEndFloatNhwcTest")
diff --git a/src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp b/src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp
index 051965f541..9119b13557 100644
--- a/src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp
+++ b/src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp
@@ -190,6 +190,50 @@ TEST_CASE("IsLayerSupportedTosaReferenceConv2dUnsupported")
CHECK(!supported);
}
+TEST_CASE("IsLayerSupportedTosaReferenceMultiplication")
+{
+ TensorShape shape0 = {1,1,3,4};
+ TensorShape shape1 = {1,1,3,4};
+ TensorShape outShape = {1,1,3,4};
+ TensorInfo in0(shape0, armnn::DataType::Float32);
+ TensorInfo in1(shape1, armnn::DataType::Float32);
+ TensorInfo out(outShape, armnn::DataType::Float32);
+
+ BaseDescriptor desc;
+ TosaRefLayerSupport supportChecker;
+ std::string reasonIfNotSupported;
+ auto supported = supportChecker.IsLayerSupported(armnn::LayerType::Multiplication,
+ {in0, in1, out},
+ desc,
+ armnn::EmptyOptional(),
+ armnn::EmptyOptional(),
+ reasonIfNotSupported);
+
+ CHECK(supported);
+}
+
+TEST_CASE("IsLayerSupportedTosaReferenceMultiplicationUnsupported")
+{
+ TensorShape shape0 = {1,1,3,4};
+ TensorShape shape1 = {1,2,3,4};
+ TensorShape outShape = {1,1,3,4};
+ TensorInfo in0(shape0, armnn::DataType::Signed64);
+ TensorInfo in1(shape1, armnn::DataType::Signed64);
+ TensorInfo out(outShape, armnn::DataType::Signed64);
+
+ BaseDescriptor desc;
+ TosaRefLayerSupport supportChecker;
+ std::string reasonIfNotSupported;
+ auto supported = supportChecker.IsLayerSupported(armnn::LayerType::Multiplication,
+ {in0, in1, out},
+ desc,
+ armnn::EmptyOptional(),
+ armnn::EmptyOptional(),
+ reasonIfNotSupported);
+
+ CHECK(!supported);
+}
+
TEST_CASE("IsLayerSupportedTosaReferenceMaxPooling2d")
{
TensorShape inShape = {1,1,3,4};
@@ -376,6 +420,50 @@ TEST_CASE("IsLayerSupportedTosaReferenceSliceUnsupported")
CHECK(!supported);
}
+TEST_CASE("IsLayerSupportedTosaReferenceSubtraction")
+{
+ TensorShape shape0 = {1,1,3,4};
+ TensorShape shape1 = {1,1,3,4};
+ TensorShape outShape = {1,1,3,4};
+ TensorInfo in0(shape0, armnn::DataType::Float32);
+ TensorInfo in1(shape1, armnn::DataType::Float32);
+ TensorInfo out(outShape, armnn::DataType::Float32);
+
+ BaseDescriptor desc;
+ TosaRefLayerSupport supportChecker;
+ std::string reasonIfNotSupported;
+ auto supported = supportChecker.IsLayerSupported(armnn::LayerType::Subtraction,
+ {in0, in1, out},
+ desc,
+ armnn::EmptyOptional(),
+ armnn::EmptyOptional(),
+ reasonIfNotSupported);
+
+ CHECK(supported);
+}
+
+TEST_CASE("IsLayerSupportedTosaReferenceSubtractionUnsupported")
+{
+ TensorShape shape0 = {1,1,3,4};
+ TensorShape shape1 = {4};
+ TensorShape outShape = {1,1,3,4};
+ TensorInfo in0(shape0, armnn::DataType::Signed64);
+ TensorInfo in1(shape1, armnn::DataType::Signed64);
+ TensorInfo out(outShape, armnn::DataType::Signed64);
+
+ BaseDescriptor desc;
+ TosaRefLayerSupport supportChecker;
+ std::string reasonIfNotSupported;
+ auto supported = supportChecker.IsLayerSupported(armnn::LayerType::Subtraction,
+ {in0, in1, out},
+ desc,
+ armnn::EmptyOptional(),
+ armnn::EmptyOptional(),
+ reasonIfNotSupported);
+
+ CHECK(!supported);
+}
+
TEST_CASE("IsLayerSupportedTosaReferenceTransposeConv2d")
{
TensorInfo inputInfo ({ 1, 3, 3, 1 }, DataType::Float32);