aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCathal Corbett <cathal.corbett@arm.com>2022-11-15 12:56:16 +0000
committerCathal Corbett <cathal.corbett@arm.com>2022-11-16 11:12:24 +0000
commitbd18eab07a8f30492de1e462b1815189014cb8d5 (patch)
tree7c26e2ecb94ffa1ea67204e02011a8166931eb09
parent194086f01bdd1af52ddd976eb5b4152255565127 (diff)
downloadarmnn-bd18eab07a8f30492de1e462b1815189014cb8d5.tar.gz
IVGCVSW-7345 Add Pooling2d support to TOSA Reference Backend
Signed-off-by: Cathal Corbett <cathal.corbett@arm.com> Change-Id: I73a47e513fe2d064ef233b121a68ef2edf0396dc
-rw-r--r--src/backends/backendsCommon/test/AdditionEndToEndTestImpl.hpp2
-rw-r--r--src/backends/backendsCommon/test/Pooling2dEndToEndTestImpl.hpp172
-rw-r--r--src/backends/tosaCommon/TosaLayerSupportRules.hpp26
-rw-r--r--src/backends/tosaCommon/TosaMappings.cpp35
-rw-r--r--src/backends/tosaCommon/TosaMappings.hpp2
-rw-r--r--src/backends/tosaCommon/operatorMappings/AvgPool2DIgnoreValueOperator.cpp107
-rw-r--r--src/backends/tosaCommon/operatorMappings/AvgPool2DIgnoreValueOperator.hpp19
-rw-r--r--src/backends/tosaCommon/operatorMappings/CMakeLists.txt4
-rw-r--r--src/backends/tosaCommon/operatorMappings/Pooling2DOperator.cpp60
-rw-r--r--src/backends/tosaCommon/operatorMappings/Pooling2DOperator.hpp19
-rw-r--r--src/backends/tosaCommon/operatorMappings/TosaCommonOperators.hpp10
-rw-r--r--src/backends/tosaCommon/operatorMappings/TosaOperatorUtils.hpp147
-rw-r--r--src/backends/tosaCommon/test/AvgPool2DIgnoreValueChecker.hpp125
-rw-r--r--src/backends/tosaCommon/test/CMakeLists.txt3
-rw-r--r--src/backends/tosaCommon/test/OneToManyMappingTests.cpp84
-rw-r--r--src/backends/tosaCommon/test/OneToOneMappingTests.cpp213
-rw-r--r--src/backends/tosaCommon/test/TosaOperatorMappingTests.cpp124
-rw-r--r--src/backends/tosaCommon/test/TosaTestUtils.hpp162
-rw-r--r--src/backends/tosaReference/TosaRefLayerSupport.cpp170
-rw-r--r--src/backends/tosaReference/test/TosaRefEndToEndTests.cpp47
-rw-r--r--src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp128
21 files changed, 1496 insertions, 163 deletions
diff --git a/src/backends/backendsCommon/test/AdditionEndToEndTestImpl.hpp b/src/backends/backendsCommon/test/AdditionEndToEndTestImpl.hpp
index a1a8bac0e7..f33521888f 100644
--- a/src/backends/backendsCommon/test/AdditionEndToEndTestImpl.hpp
+++ b/src/backends/backendsCommon/test/AdditionEndToEndTestImpl.hpp
@@ -105,4 +105,4 @@ void AdditionEndToEndFloat16(const std::vector<armnn::BackendId>& backends)
EndToEndLayerTestImpl<ArmnnType, ArmnnType>(std::move(network), inputTensorData, expectedOutputData, backends);
}
-} // anonymous namespaceS \ No newline at end of file
+} // anonymous namespace
diff --git a/src/backends/backendsCommon/test/Pooling2dEndToEndTestImpl.hpp b/src/backends/backendsCommon/test/Pooling2dEndToEndTestImpl.hpp
new file mode 100644
index 0000000000..addd27caca
--- /dev/null
+++ b/src/backends/backendsCommon/test/Pooling2dEndToEndTestImpl.hpp
@@ -0,0 +1,172 @@
+//
+// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+
+#include <armnn/INetwork.hpp>
+#include <armnn/Types.hpp>
+
+#include <CommonTestUtils.hpp>
+#include <ResolveType.hpp>
+
+#include <doctest/doctest.h>
+
+namespace
+{
+
+using namespace armnn;
+
+template<typename armnn::DataType DataType>
+armnn::INetworkPtr CreatePooling2dNetwork(const armnn::TensorShape& inputShape,
+ const armnn::TensorShape& outputShape,
+ PaddingMethod padMethod = PaddingMethod::Exclude,
+ PoolingAlgorithm poolAlg = PoolingAlgorithm::Max,
+ const float qScale = 1.0f,
+ const int32_t qOffset = 0)
+{
+ INetworkPtr network(INetwork::Create());
+
+ TensorInfo inputTensorInfo(inputShape, DataType, qScale, qOffset, true);
+ TensorInfo outputTensorInfo(outputShape, DataType, qScale, qOffset, true);
+
+ Pooling2dDescriptor descriptor;
+ descriptor.m_PoolType = poolAlg;
+ descriptor.m_PoolWidth = descriptor.m_PoolHeight = 3;
+ descriptor.m_StrideX = descriptor.m_StrideY = 1;
+ descriptor.m_PadLeft = 1;
+ descriptor.m_PadRight = 1;
+ descriptor.m_PadTop = 1;
+ descriptor.m_PadBottom = 1;
+ descriptor.m_PaddingMethod = padMethod;
+ descriptor.m_DataLayout = DataLayout::NHWC;
+
+ IConnectableLayer* pool = network->AddPooling2dLayer(descriptor, "pool");
+ IConnectableLayer* input = network->AddInputLayer(0, "input");
+ IConnectableLayer* output = network->AddOutputLayer(0, "output");
+
+ Connect(input, pool, inputTensorInfo, 0, 0);
+ Connect(pool, output, outputTensorInfo, 0, 0);
+
+ return network;
+}
+
+template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
+void MaxPool2dEndToEnd(const std::vector<armnn::BackendId>& backends,
+ PaddingMethod padMethod = PaddingMethod::Exclude)
+{
+ const TensorShape& inputShape = { 1, 3, 3, 1 };
+ const TensorShape& outputShape = { 1, 3, 3, 1 };
+
+ INetworkPtr network = CreatePooling2dNetwork<ArmnnType>(inputShape, outputShape, padMethod);
+
+ CHECK(network);
+
+ std::vector<T> inputData{ 1, 2, 3,
+ 4, 5, 6,
+ 7, 8, 9 };
+ std::vector<T> expectedOutput{ 5, 6, 6,
+ 8, 9, 9,
+ 8, 9, 9 };
+
+ std::map<int, std::vector<T>> inputTensorData = { { 0, inputData } };
+ std::map<int, std::vector<T>> expectedOutputData = { { 0, expectedOutput } };
+
+ EndToEndLayerTestImpl<ArmnnType, ArmnnType>(std::move(network), inputTensorData, expectedOutputData, backends);
+}
+
+template<armnn::DataType ArmnnType>
+void MaxPool2dEndToEndFloat16(const std::vector<armnn::BackendId>& backends)
+{
+ using namespace half_float::literal;
+ using Half = half_float::half;
+
+ const TensorShape& inputShape = { 1, 3, 3, 1 };
+ const TensorShape& outputShape = { 1, 3, 3, 1 };
+
+ INetworkPtr network = CreatePooling2dNetwork<ArmnnType>(inputShape, outputShape);
+ CHECK(network);
+
+ std::vector<Half> inputData{ 1._h, 2._h, 3._h,
+ 4._h, 5._h, 6._h,
+ 7._h, 8._h, 9._h };
+ std::vector<Half> expectedOutput{ 5._h, 6._h, 6._h,
+ 8._h, 9._h, 9._h,
+ 8._h, 9._h, 9._h };
+
+ std::map<int, std::vector<Half>> inputTensorData = { { 0, inputData } };
+ std::map<int, std::vector<Half>> expectedOutputData = { { 0, expectedOutput } };
+
+ EndToEndLayerTestImpl<ArmnnType, ArmnnType>(std::move(network), inputTensorData, expectedOutputData, backends);
+}
+
+template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
+void AvgPool2dEndToEnd(const std::vector<armnn::BackendId>& backends,
+ PaddingMethod padMethod = PaddingMethod::Exclude)
+{
+ const TensorShape& inputShape = { 1, 3, 3, 1 };
+ const TensorShape& outputShape = { 1, 3, 3, 1 };
+
+ INetworkPtr network = CreatePooling2dNetwork<ArmnnType>(
+ inputShape, outputShape, padMethod, PoolingAlgorithm::Average);
+ CHECK(network);
+
+ std::vector<T> inputData{ 1, 2, 3,
+ 4, 5, 6,
+ 7, 8, 9 };
+ std::vector<T> expectedOutput;
+ if (padMethod == PaddingMethod::Exclude)
+ {
+ expectedOutput = { 3 , 3.5 , 4 ,
+ 4.5, 5 , 5.5,
+ 6 , 6.5, 7 };
+ }
+ else
+ {
+ expectedOutput = { 1.33333, 2.33333, 1.77778,
+ 3 , 5 , 3.66667,
+ 2.66667, 4.33333, 3.11111 };
+ }
+
+ std::map<int, std::vector<T>> inputTensorData = { { 0, inputData } };
+ std::map<int, std::vector<T>> expectedOutputData = { { 0, expectedOutput } };
+
+ EndToEndLayerTestImpl<ArmnnType, ArmnnType>(std::move(network),
+ inputTensorData,
+ expectedOutputData,
+ backends,
+ 0.00001f);
+}
+
+template<armnn::DataType ArmnnType>
+void AvgPool2dEndToEndFloat16(const std::vector<armnn::BackendId>& backends,
+ PaddingMethod padMethod = PaddingMethod::IgnoreValue)
+{
+ using namespace half_float::literal;
+ using Half = half_float::half;
+
+ const TensorShape& inputShape = { 1, 3, 3, 1 };
+ const TensorShape& outputShape = { 1, 3, 3, 1 };
+
+ INetworkPtr network = CreatePooling2dNetwork<ArmnnType>(
+ inputShape, outputShape, padMethod, PoolingAlgorithm::Average);
+ CHECK(network);
+
+ std::vector<Half> inputData{ 1._h, 2._h, 3._h,
+ 4._h, 5._h, 6._h,
+ 7._h, 8._h, 9._h };
+ std::vector<Half> expectedOutput{ 1.33333_h, 2.33333_h, 1.77778_h,
+ 3._h , 5._h , 3.66667_h,
+ 2.66667_h, 4.33333_h, 3.11111_h };
+
+ std::map<int, std::vector<Half>> inputTensorData = { { 0, inputData } };
+ std::map<int, std::vector<Half>> expectedOutputData = { { 0, expectedOutput } };
+
+ EndToEndLayerTestImpl<ArmnnType, ArmnnType>(std::move(network),
+ inputTensorData,
+ expectedOutputData,
+ backends,
+ 0.00001f);
+}
+
+} // anonymous namespace
diff --git a/src/backends/tosaCommon/TosaLayerSupportRules.hpp b/src/backends/tosaCommon/TosaLayerSupportRules.hpp
index 2a2b08da99..792908c619 100644
--- a/src/backends/tosaCommon/TosaLayerSupportRules.hpp
+++ b/src/backends/tosaCommon/TosaLayerSupportRules.hpp
@@ -38,3 +38,29 @@ struct TosaTensorNumDimensionsWithinBounds : public Rule
m_Res = (tensor->GetShape().size() <= MaxNumOfTensorDimensions) || (!tensor->GetShape().empty());
}
};
+
+struct TosaAssertSize : public Rule
+{
+ template<typename Container>
+ explicit TosaAssertSize(const Container& c1, const Container& c2)
+ {
+ m_Res = (c1.size() == c2.size());
+ }
+};
+
+struct TosaContainerContains : public Rule
+{
+ explicit TosaContainerContains(std::tuple<DType, DType>& check, const std::vector<std::tuple<DType, DType>>& c)
+ {
+ for (auto item: c)
+ {
+ if (std::get<0>(check) == std::get<0>(item)
+ && std::get<1>(check) == std::get<1>(item))
+ {
+ m_Res = true;
+ return;
+ }
+ }
+ m_Res = false;
+ }
+};
diff --git a/src/backends/tosaCommon/TosaMappings.cpp b/src/backends/tosaCommon/TosaMappings.cpp
index 71d2012cbc..a37eaf29b3 100644
--- a/src/backends/tosaCommon/TosaMappings.cpp
+++ b/src/backends/tosaCommon/TosaMappings.cpp
@@ -23,10 +23,18 @@ void SetBasicBlockConstantTensorData(Layer* layer, TosaSerializationBasicBlock*
}
}
+TosaSerializationBasicBlock* CreateEmptyTosaSerializationBasicBlock()
+{
+ // empty basic block when no tosa mapping implemented/exists
+ TosaSerializationOperator* op =
+ new TosaSerializationOperator(Op_UNKNOWN, Attribute_NONE, nullptr, {}, {});
+ return new TosaSerializationBasicBlock("", {op}, {}, {}, {});
+}
+
TosaSerializationBasicBlock* GetTosaMapping(const LayerType type,
const std::vector<const TensorInfo*>& inputs,
const std::vector<const TensorInfo*>& outputs,
- const BaseDescriptor& /*descriptor*/,
+ const BaseDescriptor& descriptor,
bool isMain = false)
{
switch (type)
@@ -35,11 +43,30 @@ TosaSerializationBasicBlock* GetTosaMapping(const LayerType type,
{
return ConvertAdditionToTosaOperator(inputs, outputs, isMain);
}
+ case LayerType::Pooling2d:
+ {
+ auto poolDesc = PolymorphicDowncast<const Pooling2dDescriptor*>(&descriptor);
+
+ bool avgPoolIgnoreValue =
+ (poolDesc->m_PoolType == PoolingAlgorithm::Average) &&
+ (poolDesc->m_PaddingMethod == PaddingMethod::IgnoreValue);
+
+ if (poolDesc->m_PoolType == PoolingAlgorithm::L2)
+ {
+ return CreateEmptyTosaSerializationBasicBlock();
+ }
+ else if (avgPoolIgnoreValue)
+ {
+ return ConvertAvgPool2DIgnoreValueToTosaOperator(inputs, outputs, isMain, poolDesc);
+ }
+ else
+ {
+ return ConvertPooling2DToTosaOperator(inputs, outputs, isMain, poolDesc);
+ }
+ }
default:
{
- // empty basic block when no tosa mapping implemented/exists
- TosaSerializationOperator* op = new TosaSerializationOperator(Op_UNKNOWN, Attribute_NONE, nullptr, {}, {});
- return new TosaSerializationBasicBlock("", {op}, {}, {}, {});
+ return CreateEmptyTosaSerializationBasicBlock();
}
}
}
diff --git a/src/backends/tosaCommon/TosaMappings.hpp b/src/backends/tosaCommon/TosaMappings.hpp
index 7f137ca322..8df2493d6e 100644
--- a/src/backends/tosaCommon/TosaMappings.hpp
+++ b/src/backends/tosaCommon/TosaMappings.hpp
@@ -8,7 +8,7 @@
#include <Layer.hpp>
#include <tosa_serialization_handler.h>
-#include "operatorMappings/AdditionOperator.hpp"
+#include "operatorMappings/TosaCommonOperators.hpp"
using namespace armnn;
using namespace tosa;
diff --git a/src/backends/tosaCommon/operatorMappings/AvgPool2DIgnoreValueOperator.cpp b/src/backends/tosaCommon/operatorMappings/AvgPool2DIgnoreValueOperator.cpp
new file mode 100644
index 0000000000..b3d2687c30
--- /dev/null
+++ b/src/backends/tosaCommon/operatorMappings/AvgPool2DIgnoreValueOperator.cpp
@@ -0,0 +1,107 @@
+//
+// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "Pooling2DOperator.hpp"
+
+TosaSerializationBasicBlock* ConvertAvgPool2DIgnoreValueToTosaOperator(const std::vector<const TensorInfo*>& inputs,
+ const std::vector<const TensorInfo*>& outputs,
+ bool isMain,
+ const Pooling2dDescriptor* poolDescriptor)
+{
+
+ // A helper function with static global variables ensures uniqueness
+ // for dynamically generating input, output and block names
+ std::string padInputName = std::string("Op_PAD_input0_") + GetUniqueTosaMappingID();
+ std::string padOutputName = std::string("Op_PAD_intermediate0_") + GetUniqueTosaMappingID();
+ std::string poolOutputName = std::string("Op_AVG_POOL2D_output0_") + GetUniqueTosaMappingID();
+ std::string blockName = std::string("Op_AVG_POOL2D_block_") + GetUniqueTosaMappingID();
+
+ // If it's the first block, overwrite block name with main.
+ if (isMain)
+ {
+ blockName = std::string("main");
+ }
+
+ std::vector<int> paddings;
+ if (poolDescriptor->m_DataLayout == DataLayout::NHWC)
+ {
+ paddings = {0,
+ 0,
+ static_cast<int>(poolDescriptor->m_PadTop),
+ static_cast<int>(poolDescriptor->m_PadBottom),
+ static_cast<int>(poolDescriptor->m_PadLeft),
+ static_cast<int>(poolDescriptor->m_PadRight),
+ 0,
+ 0
+ };
+ }
+ else
+ {
+ paddings = {0,
+ 0,
+ 0,
+ 0,
+ static_cast<int>(poolDescriptor->m_PadTop),
+ static_cast<int>(poolDescriptor->m_PadBottom),
+ static_cast<int>(poolDescriptor->m_PadLeft),
+ static_cast<int>(poolDescriptor->m_PadRight)
+ };
+ }
+
+ TosaPadAttribute padAttribute(paddings, 0, 0.0f);
+ TosaSerializationOperator* opPad = new TosaSerializationOperator(Op_PAD,
+ Attribute_PadAttribute,
+ &padAttribute,
+ {padInputName},
+ {padOutputName});
+
+ std::vector<int> pad = {0, 0, 0, 0};
+ std::vector<int> kernel = {static_cast<int>(poolDescriptor->m_PoolHeight),
+ static_cast<int>(poolDescriptor->m_PoolWidth)};
+ std::vector<int> stride = {static_cast<int>(poolDescriptor->m_StrideY),
+ static_cast<int>(poolDescriptor->m_StrideX)};
+ TosaPoolAttribute poolAttribute(pad, kernel, stride, 0, 0, ArmNNToDType(inputs[0]->GetDataType()));
+
+ TosaSerializationOperator* opPool = new TosaSerializationOperator(Op_AVG_POOL2D,
+ Attribute_PoolAttribute,
+ &poolAttribute,
+ {padOutputName},
+ {poolOutputName});
+
+ std::vector<int32_t> inputShape = GetTosaTensorShape(inputs[0]->GetShape());
+ DType inputDType = ArmNNToDType(inputs[0]->GetDataType());
+
+ std::vector<int32_t> outputShape = GetTosaTensorShape(outputs[0]->GetShape());
+ DType outputDType = ArmNNToDType(outputs[0]->GetDataType());
+
+ std::vector<int32_t> intermediateShape;
+ if (poolDescriptor->m_DataLayout == DataLayout::NHWC)
+ {
+ intermediateShape = {inputShape[0],
+ inputShape[1] + paddings[2] + paddings[3],
+ inputShape[2] + paddings[4] + paddings[5],
+ inputShape[3]};
+ }
+ else
+ {
+ intermediateShape = {inputShape[0],
+ inputShape[1],
+ inputShape[2] + paddings[4] + paddings[5],
+ inputShape[3] + paddings[6] + paddings[7]};
+ }
+
+ TosaSerializationTensor* inputTensor = new TosaSerializationTensor(padInputName, inputShape, inputDType, {});
+ TosaSerializationTensor* intermediateTensor = new TosaSerializationTensor(
+ padOutputName, intermediateShape, inputDType, {});
+ TosaSerializationTensor* outputTensor = new TosaSerializationTensor(poolOutputName, outputShape, outputDType, {});
+
+ // operatorInputNames/operatorOutputNames ends up being the same as
+ // blockInputNames/blockOutputNames for one-to-one ArmNN to Tosa mappings
+ return new TosaSerializationBasicBlock(blockName, // name
+ {opPad, opPool}, // operators
+ {inputTensor, intermediateTensor, outputTensor}, // tensors
+ {padInputName}, // inputs
+ {poolOutputName}); // outputs
+} \ No newline at end of file
diff --git a/src/backends/tosaCommon/operatorMappings/AvgPool2DIgnoreValueOperator.hpp b/src/backends/tosaCommon/operatorMappings/AvgPool2DIgnoreValueOperator.hpp
new file mode 100644
index 0000000000..63ae190cc9
--- /dev/null
+++ b/src/backends/tosaCommon/operatorMappings/AvgPool2DIgnoreValueOperator.hpp
@@ -0,0 +1,19 @@
+//
+// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include <Layer.hpp>
+
+#include <tosa_serialization_handler.h>
+#include "TosaOperatorUtils.hpp"
+
+using namespace armnn;
+using namespace tosa;
+
+TosaSerializationBasicBlock* ConvertAvgPool2DIgnoreValueToTosaOperator(const std::vector<const TensorInfo*>& inputs,
+ const std::vector<const TensorInfo*>& outputs,
+ bool isMain,
+ const Pooling2dDescriptor* poolDescriptor);
diff --git a/src/backends/tosaCommon/operatorMappings/CMakeLists.txt b/src/backends/tosaCommon/operatorMappings/CMakeLists.txt
index 9fc33e9205..7fdc9226af 100644
--- a/src/backends/tosaCommon/operatorMappings/CMakeLists.txt
+++ b/src/backends/tosaCommon/operatorMappings/CMakeLists.txt
@@ -6,6 +6,10 @@
list(APPEND armnnTosaBackendOperators_sources
AdditionOperator.hpp
AdditionOperator.cpp
+ AvgPool2DIgnoreValueOperator.hpp
+ AvgPool2DIgnoreValueOperator.cpp
+ Pooling2DOperator.hpp
+ Pooling2DOperator.cpp
TosaOperatorUtils.hpp
)
diff --git a/src/backends/tosaCommon/operatorMappings/Pooling2DOperator.cpp b/src/backends/tosaCommon/operatorMappings/Pooling2DOperator.cpp
new file mode 100644
index 0000000000..cd707edb3a
--- /dev/null
+++ b/src/backends/tosaCommon/operatorMappings/Pooling2DOperator.cpp
@@ -0,0 +1,60 @@
+//
+// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "Pooling2DOperator.hpp"
+
+TosaSerializationBasicBlock* ConvertPooling2DToTosaOperator(const std::vector<const TensorInfo*>& inputs,
+ const std::vector<const TensorInfo*>& outputs,
+ bool isMain,
+ const Pooling2dDescriptor* poolDescriptor)
+{
+ std::string poolType = (poolDescriptor->m_PoolType == PoolingAlgorithm::Max) ? "Op_MAX" : "Op_AVG";
+ Op opcode = (poolDescriptor->m_PoolType == PoolingAlgorithm::Max) ? Op_MAX_POOL2D : Op_AVG_POOL2D;
+
+ // A helper function with static global variables ensures uniqueness
+ // for dynamically generating input, output and block names
+ std::string input0Name = poolType + std::string("_POOL2D_input0_") + GetUniqueTosaMappingID();
+ std::string outputName = poolType + std::string("_POOL2D_output0_") + GetUniqueTosaMappingID();
+ std::string blockName = poolType + std::string("_POOL2D_block_") + GetUniqueTosaMappingID();
+
+ // If it's the first block, overwrite block name with main.
+ if (isMain)
+ {
+ blockName = std::string("main");
+ }
+
+ std::vector<int> pad = {static_cast<int>(poolDescriptor->m_PadTop),
+ static_cast<int>(poolDescriptor->m_PadBottom),
+ static_cast<int>(poolDescriptor->m_PadLeft),
+ static_cast<int>(poolDescriptor->m_PadRight)};
+ std::vector<int> kernel = {static_cast<int>(poolDescriptor->m_PoolHeight),
+ static_cast<int>(poolDescriptor->m_PoolWidth)};
+ std::vector<int> stride = {static_cast<int>(poolDescriptor->m_StrideY),
+ static_cast<int>(poolDescriptor->m_StrideX)};
+ TosaPoolAttribute attribute(pad, kernel, stride, 0, 0, ArmNNToDType(inputs[0]->GetDataType()));
+
+ TosaSerializationOperator* op = new TosaSerializationOperator(opcode,
+ Attribute_PoolAttribute,
+ &attribute,
+ {input0Name},
+ {outputName});
+
+ std::vector<int32_t> inputShape0 = GetTosaTensorShape(inputs[0]->GetShape());
+ DType inputDType0 = ArmNNToDType(inputs[0]->GetDataType());
+
+ std::vector<int32_t> outputShape0 = GetTosaTensorShape(outputs[0]->GetShape());
+ DType outputDType0 = ArmNNToDType(outputs[0]->GetDataType());
+
+ TosaSerializationTensor* inputTensor0 = new TosaSerializationTensor(input0Name, inputShape0, inputDType0, {});
+ TosaSerializationTensor* outputTensor0 = new TosaSerializationTensor(outputName, outputShape0, outputDType0, {});
+
+ // operatorInputNames/operatorOutputNames ends up being the same as
+ // blockInputNames/blockOutputNames for one-to-one ArmNN to Tosa mappings
+ return new TosaSerializationBasicBlock(blockName, // name
+ {op}, // operators
+ {inputTensor0, outputTensor0}, // tensors
+ {input0Name}, // inputs
+ {outputName}); // outputs
+} \ No newline at end of file
diff --git a/src/backends/tosaCommon/operatorMappings/Pooling2DOperator.hpp b/src/backends/tosaCommon/operatorMappings/Pooling2DOperator.hpp
new file mode 100644
index 0000000000..22d2a3ae29
--- /dev/null
+++ b/src/backends/tosaCommon/operatorMappings/Pooling2DOperator.hpp
@@ -0,0 +1,19 @@
+//
+// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include <Layer.hpp>
+
+#include <tosa_serialization_handler.h>
+#include "TosaOperatorUtils.hpp"
+
+using namespace armnn;
+using namespace tosa;
+
+TosaSerializationBasicBlock* ConvertPooling2DToTosaOperator(const std::vector<const TensorInfo*>& inputs,
+ const std::vector<const TensorInfo*>& outputs,
+ bool isMain,
+ const Pooling2dDescriptor* poolDescriptor);
diff --git a/src/backends/tosaCommon/operatorMappings/TosaCommonOperators.hpp b/src/backends/tosaCommon/operatorMappings/TosaCommonOperators.hpp
new file mode 100644
index 0000000000..00b5f0fa68
--- /dev/null
+++ b/src/backends/tosaCommon/operatorMappings/TosaCommonOperators.hpp
@@ -0,0 +1,10 @@
+//
+// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include "AdditionOperator.hpp"
+#include "AvgPool2DIgnoreValueOperator.hpp"
+#include "Pooling2DOperator.hpp" \ No newline at end of file
diff --git a/src/backends/tosaCommon/operatorMappings/TosaOperatorUtils.hpp b/src/backends/tosaCommon/operatorMappings/TosaOperatorUtils.hpp
index f580a53ebc..f51b2109b4 100644
--- a/src/backends/tosaCommon/operatorMappings/TosaOperatorUtils.hpp
+++ b/src/backends/tosaCommon/operatorMappings/TosaOperatorUtils.hpp
@@ -59,3 +59,150 @@ inline std::string GetUniqueTosaMappingID()
{
return std::to_string(++uniqueTosaMappingID);
}
+
+// Function to return Tosa Op as string.
+inline std::string TosaOpToString(Op tosaOp)
+{
+ switch (tosaOp)
+ {
+ case Op_ADD:
+ return "Op_ADD";
+ case Op_AVG_POOL2D:
+ return "Op_AVG_POOL2D";
+ case Op_MAX_POOL2D:
+ return "Op_MAX_POOL2D";
+ case Op_PAD:
+ return "Op_PAD";
+ case Op_UNKNOWN:
+ return "Op_UNKNOWN";
+ case Op_ARGMAX:
+ return "Op_ARGMAX";
+ case Op_CONV2D:
+ return "Op_CONV2D";
+ case Op_CONV3D:
+ return "Op_CONV3D";
+ case Op_DEPTHWISE_CONV2D:
+ return "Op_DEPTHWISE_CONV2D";
+ case Op_FULLY_CONNECTED:
+ return "Op_FULLY_CONNECTED";
+ case Op_MATMUL:
+ return "Op_MATMUL";
+ case Op_TRANSPOSE_CONV2D:
+ return "Op_TRANSPOSE_CONV2D";
+ case Op_CLAMP:
+ return "Op_CLAMP";
+ case Op_RESERVED:
+ return "Op_RESERVED";
+ case Op_SIGMOID:
+ return "Op_SIGMOID";
+ case Op_TANH:
+ return "Op_TANH";
+ case Op_ARITHMETIC_RIGHT_SHIFT:
+ return "Op_ARITHMETIC_RIGHT_SHIFT";
+ case Op_BITWISE_AND:
+ return "Op_BITWISE_AND";
+ case Op_BITWISE_OR:
+ return "Op_BITWISE_OR";
+ case Op_BITWISE_XOR:
+ return "Op_BITWISE_XOR";
+ case Op_INTDIV:
+ return "Op_INTDIV";
+ case Op_LOGICAL_AND:
+ return "Op_LOGICAL_AND";
+ case Op_LOGICAL_LEFT_SHIFT:
+ return "Op_LOGICAL_LEFT_SHIFT";
+ case Op_LOGICAL_RIGHT_SHIFT:
+ return "Op_LOGICAL_RIGHT_SHIFT";
+ case Op_LOGICAL_OR:
+ return "Op_LOGICAL_OR";
+ case Op_LOGICAL_XOR:
+ return "Op_LOGICAL_XOR";
+ case Op_MAXIMUM:
+ return "Op_MAXIMUM";
+ case Op_MINIMUM:
+ return "Op_MINIMUM";
+ case Op_MUL:
+ return "Op_MUL";
+ case Op_POW:
+ return "Op_POW";
+ case Op_SUB:
+ return "Op_SUB";
+ case Op_TABLE:
+ return "Op_TABLE";
+ case Op_ABS:
+ return "Op_ABS";
+ case Op_BITWISE_NOT:
+ return "Op_BITWISE_NOT";
+ case Op_CEIL:
+ return "Op_CEIL";
+ case Op_CLZ:
+ return "Op_CLZ";
+ case Op_EXP:
+ return "Op_EXP";
+ case Op_FLOOR:
+ return "Op_FLOOR";
+ case Op_LOG:
+ return "Op_LOG";
+ case Op_LOGICAL_NOT:
+ return "Op_LOGICAL_NOT";
+ case Op_NEGATE:
+ return "Op_NEGATE";
+ case Op_RECIPROCAL:
+ return "Op_RECIPROCAL";
+ case Op_RSQRT:
+ return "Op_RSQRT";
+ case Op_SELECT:
+ return "Op_SELECT";
+ case Op_EQUAL:
+ return "Op_EQUAL";
+ case Op_GREATER:
+ return "Op_GREATER";
+ case Op_GREATER_EQUAL:
+ return "Op_GREATER_EQUAL";
+ case Op_REDUCE_ANY:
+ return "Op_REDUCE_ANY";
+ case Op_REDUCE_ALL:
+ return "Op_REDUCE_ALL";
+ case Op_REDUCE_MAX:
+ return "Op_REDUCE_MAX";
+ case Op_REDUCE_MIN:
+ return "Op_REDUCE_MIN";
+ case Op_REDUCE_PRODUCT:
+ return "Op_REDUCE_PRODUCT";
+ case Op_REDUCE_SUM:
+ return "Op_REDUCE_SUM";
+ case Op_CONCAT:
+ return "Op_CONCAT";
+ case Op_RESHAPE:
+ return "Op_RESHAPE";
+ case Op_REVERSE:
+ return "Op_REVERSE";
+ case Op_SLICE:
+ return "Op_SLICE";
+ case Op_TILE:
+ return "Op_TILE";
+ case Op_TRANSPOSE:
+ return "Op_TRANSPOSE";
+ case Op_GATHER:
+ return "Op_GATHER";
+ case Op_SCATTER:
+ return "Op_SCATTER";
+ case Op_RESIZE:
+ return "Op_RESIZE";
+ case Op_CAST:
+ return "Op_CAST";
+ case Op_RESCALE:
+ return "Op_RESCALE";
+ case Op_CONST:
+ return "Op_CONST";
+ case Op_IDENTITY:
+ return "Op_IDENTITY";
+ case Op_CUSTOM:
+ return "Op_CUSTOM";
+ case Op_COND_IF:
+ return "Op_COND_IF";
+ case Op_WHILE_LOOP:
+ return "Op_WHILE_LOOP";
+ }
+ return "";
+}
diff --git a/src/backends/tosaCommon/test/AvgPool2DIgnoreValueChecker.hpp b/src/backends/tosaCommon/test/AvgPool2DIgnoreValueChecker.hpp
new file mode 100644
index 0000000000..8869b3a8ff
--- /dev/null
+++ b/src/backends/tosaCommon/test/AvgPool2DIgnoreValueChecker.hpp
@@ -0,0 +1,125 @@
+//
+// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "TosaTestUtils.hpp"
+
+using namespace armnn;
+using namespace tosa;
+
+void VerifyAvgPool2DIgnoreValue(TosaSerializationBasicBlock* basicBlock,
+ std::vector<std::vector<int32_t>> inputShape,
+ std::vector<std::vector<int32_t>> outputShape,
+ std::vector<std::vector<int32_t>> intermediateShape,
+ const BaseDescriptor& descriptor,
+ DType dataType = DType_FP32)
+{
+ uint32_t numInputs = static_cast<uint32_t>(inputShape.size());
+ uint32_t numOutputs = static_cast<uint32_t>(outputShape.size());
+ std::string operatorString0 = TosaOpToString(Op_PAD);
+ std::string operatorString1 = TosaOpToString(Op_AVG_POOL2D);
+
+ std::string blockStr = operatorString1 + "_block_";
+ CHECK(basicBlock->GetName().find(blockStr) != std::string::npos);
+ CHECK(basicBlock->GetInputs().size() == numInputs);
+ CHECK(basicBlock->GetOutputs().size() == numOutputs);
+ CHECK(basicBlock->GetOperators().size() == 2);
+ CHECK(basicBlock->GetTensors().size() == 3);
+
+ //
+ // Verify padding operator first.
+ //
+
+ TosaSerializationOperator* padOp = basicBlock->GetOperators().at(0);
+ uint32_t padOpOutputs = 1;
+ CHECK(padOp->GetInputTensorNames().size() == numInputs);
+ CHECK(padOp->GetOutputTensorNames().size() == padOpOutputs);
+
+ for (uint32_t i = 0; i < numInputs; i++)
+ {
+ std::basic_string<char> blockInputName = basicBlock->GetInputs()[i];
+ std::basic_string<char> operatorInputName = padOp->GetInputTensorNames()[i];
+
+ std::string opStr = operatorString0 + "_input" + std::to_string(i) + "_";
+
+ CHECK(blockInputName == operatorInputName);
+ CHECK(basicBlock->GetTensorByName(blockInputName));
+ CHECK(blockInputName.find(opStr) != std::string::npos);
+
+ TosaSerializationTensor* tensor = basicBlock->GetTensorByName(operatorInputName);
+ CHECK(tensor->GetDtype() == dataType);
+ CHECK(tensor->GetData().size() == 0);
+ CHECK(tensor->GetShape() == inputShape[static_cast<unsigned long int>(i)]);
+ }
+
+ for (uint32_t i = 0; i < padOpOutputs; i++)
+ {
+ std::basic_string<char> operatorOutputName = padOp->GetOutputTensorNames()[i];
+ std::string opStr = operatorString0 + "_intermediate" + std::to_string(i) + "_";
+
+ CHECK(basicBlock->GetTensorByName(operatorOutputName));
+ CHECK(operatorOutputName.find(opStr) != std::string::npos);
+
+ TosaSerializationTensor* tensor = basicBlock->GetTensorByName(operatorOutputName);
+ CHECK(tensor->GetDtype() == dataType);
+ CHECK(tensor->GetData().size() == 0);
+ CHECK(tensor->GetShape() == intermediateShape[static_cast<unsigned long int>(i)]);
+ }
+
+ CHECK(padOp->GetAttributeType() == Attribute_PadAttribute);
+ CHECK(padOp->GetOp() == Op_PAD);
+
+ VerifyTosaAttributeFromDescriptor(descriptor,
+ padOp->GetAttribute(),
+ LayerType::Pooling2d);
+
+ //
+ // Verify average pool operator second.
+ //
+
+ TosaSerializationOperator* poolOp = basicBlock->GetOperators().at(1);
+ uint32_t poolOpInputs = 1;
+ CHECK(poolOp->GetInputTensorNames().size() == poolOpInputs);
+ CHECK(poolOp->GetOutputTensorNames().size() == numOutputs);
+
+ for (uint32_t i = 0; i < poolOpInputs; i++)
+ {
+ std::basic_string<char> operatorInputName = poolOp->GetInputTensorNames()[i];
+ std::string opStr = operatorString0 + "_intermediate" + std::to_string(i) + "_";
+
+ CHECK(basicBlock->GetTensorByName(operatorInputName));
+ CHECK(operatorInputName.find(opStr) != std::string::npos);
+
+ TosaSerializationTensor* tensor = basicBlock->GetTensorByName(operatorInputName);
+ CHECK(tensor->GetDtype() == dataType);
+ CHECK(tensor->GetData().size() == 0);
+ CHECK(tensor->GetShape() == intermediateShape[static_cast<unsigned long int>(i)]);
+ }
+
+ for (uint32_t i = 0; i < numOutputs; i++)
+ {
+ std::basic_string<char> blockOutputName = basicBlock->GetOutputs()[i];
+ std::basic_string<char> operatorOutputName = poolOp->GetOutputTensorNames()[i];
+
+ std::string opStr = operatorString1 + "_output" + std::to_string(i) + "_";
+
+ CHECK(blockOutputName == operatorOutputName);
+ CHECK(basicBlock->GetTensorByName(blockOutputName));
+ CHECK(blockOutputName.find(opStr) != std::string::npos);
+
+ TosaSerializationTensor* tensor = basicBlock->GetTensorByName(operatorOutputName);
+ CHECK(tensor->GetDtype() == dataType);
+ CHECK(tensor->GetData().size() == 0);
+ CHECK(tensor->GetShape() == outputShape[static_cast<unsigned long int>(i)]);
+ }
+
+ CHECK(poolOp->GetAttributeType() == Attribute_PoolAttribute);
+ CHECK(poolOp->GetOp() == Op_AVG_POOL2D);
+
+ VerifyTosaAttributeFromDescriptor(descriptor,
+ poolOp->GetAttribute(),
+ LayerType::Pooling2d,
+ 1);
+
+} \ No newline at end of file
diff --git a/src/backends/tosaCommon/test/CMakeLists.txt b/src/backends/tosaCommon/test/CMakeLists.txt
index 56cc66e51c..34c4b0c009 100644
--- a/src/backends/tosaCommon/test/CMakeLists.txt
+++ b/src/backends/tosaCommon/test/CMakeLists.txt
@@ -4,7 +4,8 @@
#
list(APPEND armnnTosaBackendUnitTests_sources
- TosaOperatorMappingTests.cpp
+ OneToManyMappingTests.cpp
+ OneToOneMappingTests.cpp
)
add_library(armnnTosaBackendUnitTests OBJECT ${armnnTosaBackendUnitTests_sources})
diff --git a/src/backends/tosaCommon/test/OneToManyMappingTests.cpp b/src/backends/tosaCommon/test/OneToManyMappingTests.cpp
new file mode 100644
index 0000000000..98fd563da1
--- /dev/null
+++ b/src/backends/tosaCommon/test/OneToManyMappingTests.cpp
@@ -0,0 +1,84 @@
+//
+// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "AvgPool2DIgnoreValueChecker.hpp"
+
+using namespace armnn;
+using namespace tosa;
+
+TEST_SUITE("TosaOperatorMappingOneToManyTests")
+{
+TEST_CASE("GetTosaMapping_AvgPool2DIgnoreValueLayer")
+{
+ armnn::Pooling2dDescriptor descriptor;
+ descriptor.m_PoolType = armnn::PoolingAlgorithm::Average;
+ descriptor.m_PoolWidth = descriptor.m_PoolHeight = 2;
+ descriptor.m_StrideX = descriptor.m_StrideY = 2;
+ descriptor.m_PadLeft = 1;
+ descriptor.m_PadRight = 1;
+ descriptor.m_PadTop = 1;
+ descriptor.m_PadBottom = 1;
+ descriptor.m_PaddingMethod = armnn::PaddingMethod::IgnoreValue;
+
+ armnn::TensorInfo inputTensorInfo({ 1, 1, 4, 4 }, DataType::Float32);
+ armnn::TensorInfo outputTensorInfo({ 1, 1, 3, 3 }, DataType::Float32);
+
+ std::vector<std::vector<int32_t>> inputShape = {{ 1, 1, 4, 4 }};
+ std::vector<std::vector<int32_t>> intermediateShape = {{ 1, 1, 6, 6 }};
+ std::vector<std::vector<int32_t>> outputShape = {{ 1, 1, 3, 3 }};
+
+ TosaSerializationBasicBlock* basicBlock =
+ GetTosaMapping(LayerType::Pooling2d, {&inputTensorInfo}, {&outputTensorInfo}, descriptor, false);
+ VerifyAvgPool2DIgnoreValue(basicBlock,
+ inputShape,
+ outputShape,
+ intermediateShape,
+ descriptor);
+}
+
+TEST_CASE("GetTosaMappingFromLayer_AvgPool2DIgnoreValueLayer")
+{
+ IRuntime::CreationOptions options;
+ IRuntimePtr runtime(IRuntime::Create(options));
+
+ // Builds up the structure of the network.
+ INetworkPtr net(INetwork::Create());
+
+ armnn::Pooling2dDescriptor descriptor;
+ descriptor.m_PoolType = armnn::PoolingAlgorithm::Average;
+ descriptor.m_PoolWidth = descriptor.m_PoolHeight = 2;
+ descriptor.m_StrideX = descriptor.m_StrideY = 2;
+ descriptor.m_PadLeft = 1;
+ descriptor.m_PadRight = 1;
+ descriptor.m_PadTop = 1;
+ descriptor.m_PadBottom = 1;
+ descriptor.m_PaddingMethod = armnn::PaddingMethod::IgnoreValue;
+
+ IConnectableLayer* input0 = net->AddInputLayer(0, "input0");
+ IConnectableLayer* pool = net->AddPooling2dLayer(descriptor, "pool");
+ IConnectableLayer* output = net->AddOutputLayer(0, "output");
+
+ input0->GetOutputSlot(0).Connect(pool->GetInputSlot(0));
+ pool->GetOutputSlot(0).Connect(output->GetInputSlot(0));
+
+ armnn::TensorInfo inputTensorInfo({ 1, 1, 4, 4 }, DataType::Float32);
+ armnn::TensorInfo outputTensorInfo({ 1, 1, 3, 3 }, DataType::Float32);
+
+ std::vector<std::vector<int32_t>> inputShape = {{ 1, 1, 4, 4 }};
+ std::vector<std::vector<int32_t>> intermediateShape = {{ 1, 1, 6, 6 }};
+ std::vector<std::vector<int32_t>> outputShape = {{ 1, 1, 3, 3 }};
+
+ input0->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
+ pool->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
+
+ TosaSerializationBasicBlock* basicBlock =
+ GetTosaMappingFromLayer(PolymorphicDowncast<Layer*>(pool), false);
+ VerifyAvgPool2DIgnoreValue(basicBlock,
+ inputShape,
+ outputShape,
+ intermediateShape,
+ descriptor);
+}
+} \ No newline at end of file
diff --git a/src/backends/tosaCommon/test/OneToOneMappingTests.cpp b/src/backends/tosaCommon/test/OneToOneMappingTests.cpp
new file mode 100644
index 0000000000..04d1eb46aa
--- /dev/null
+++ b/src/backends/tosaCommon/test/OneToOneMappingTests.cpp
@@ -0,0 +1,213 @@
+//
+// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "TosaTestUtils.hpp"
+
+using namespace armnn;
+using namespace tosa;
+
+TEST_SUITE("TosaOperatorMappingOneToOneTests")
+{
+TEST_CASE("GetTosaMapping_AdditionLayer")
+{
+ TensorInfo info = TensorInfo({ 1, 2, 4, 2 }, DataType::Float32, 0.0f, 0, true);
+
+ 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(LayerType::Addition, {&info, &info}, {&info}, BaseDescriptor(), false);
+ AssertTosaOneToOneMappingBasicBlock(
+ basicBlock, inputShape, outputShape, Op_ADD, Attribute_NONE, BaseDescriptor(), LayerType::Addition);
+}
+
+TEST_CASE("GetTosaMappingFromLayer_AdditionLayer")
+{
+ 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->AddAdditionLayer("add");
+ 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({ 1, 2, 4, 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 = {{ 1, 2, 4, 2 }, { 1, 2, 4, 2 }};
+ std::vector<std::vector<int32_t>> outputShape = {{ 1, 2, 4, 2 }};
+
+ TosaSerializationBasicBlock* basicBlock =
+ GetTosaMappingFromLayer(PolymorphicDowncast<Layer*>(add), false);
+ AssertTosaOneToOneMappingBasicBlock(
+ basicBlock, inputShape, outputShape, Op_ADD, Attribute_NONE, BaseDescriptor(), LayerType::Addition);
+}
+
+TEST_CASE("GetTosaMapping_MaxPool2DLayer")
+{
+ armnn::Pooling2dDescriptor descriptor;
+ descriptor.m_PoolType = armnn::PoolingAlgorithm::Max;
+ descriptor.m_PoolWidth = descriptor.m_PoolHeight = 2;
+ descriptor.m_StrideX = descriptor.m_StrideY = 2;
+ descriptor.m_PadLeft = 1;
+ descriptor.m_PadRight = 1;
+ descriptor.m_PadTop = 1;
+ descriptor.m_PadBottom = 1;
+ descriptor.m_PaddingMethod = armnn::PaddingMethod::Exclude;
+
+ armnn::TensorInfo inputTensorInfo({ 1, 1, 4, 4 }, DataType::Float32);
+ armnn::TensorInfo outputTensorInfo({ 1, 1, 3, 3 }, DataType::Float32);
+
+ std::vector<std::vector<int32_t>> inputShape = {{ 1, 1, 4, 4 }};
+ std::vector<std::vector<int32_t>> outputShape = {{ 1, 1, 3, 3 }};
+
+ TosaSerializationBasicBlock* basicBlock =
+ GetTosaMapping(LayerType::Pooling2d, {&inputTensorInfo}, {&outputTensorInfo}, descriptor, false);
+ AssertTosaOneToOneMappingBasicBlock(
+ basicBlock, inputShape, outputShape, Op_MAX_POOL2D, Attribute_PoolAttribute, descriptor, LayerType::Pooling2d);
+}
+
+TEST_CASE("GetTosaMappingFromLayer_MaxPool2DLayer")
+{
+ IRuntime::CreationOptions options;
+ IRuntimePtr runtime(IRuntime::Create(options));
+
+ // Builds up the structure of the network.
+ INetworkPtr net(INetwork::Create());
+
+ armnn::Pooling2dDescriptor descriptor;
+ descriptor.m_PoolType = armnn::PoolingAlgorithm::Max;
+ descriptor.m_PoolWidth = descriptor.m_PoolHeight = 2;
+ descriptor.m_StrideX = descriptor.m_StrideY = 2;
+ descriptor.m_PadLeft = 1;
+ descriptor.m_PadRight = 1;
+ descriptor.m_PadTop = 1;
+ descriptor.m_PadBottom = 1;
+ descriptor.m_PaddingMethod = armnn::PaddingMethod::Exclude;
+
+ IConnectableLayer* input0 = net->AddInputLayer(0, "input0");
+ IConnectableLayer* pool = net->AddPooling2dLayer(descriptor, "pool");
+ IConnectableLayer* output = net->AddOutputLayer(0, "output");
+
+ input0->GetOutputSlot(0).Connect(pool->GetInputSlot(0));
+ pool->GetOutputSlot(0).Connect(output->GetInputSlot(0));
+
+ armnn::TensorInfo inputTensorInfo({ 1, 1, 4, 4 }, DataType::Float32);
+ armnn::TensorInfo outputTensorInfo({ 1, 1, 3, 3 }, DataType::Float32);
+
+ std::vector<std::vector<int32_t>> inputShape = {{ 1, 1, 4, 4 }};
+ std::vector<std::vector<int32_t>> outputShape = {{ 1, 1, 3, 3 }};
+
+ input0->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
+ pool->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
+
+ TosaSerializationBasicBlock* basicBlock =
+ GetTosaMappingFromLayer(PolymorphicDowncast<Layer*>(pool), false);
+ AssertTosaOneToOneMappingBasicBlock(
+ basicBlock, inputShape, outputShape, Op_MAX_POOL2D, Attribute_PoolAttribute, descriptor, LayerType::Pooling2d);
+}
+
+TEST_CASE("GetTosaMapping_AvgPool2DLayer")
+{
+ armnn::Pooling2dDescriptor descriptor;
+ descriptor.m_PoolType = armnn::PoolingAlgorithm::Average;
+ descriptor.m_PoolWidth = descriptor.m_PoolHeight = 2;
+ descriptor.m_StrideX = descriptor.m_StrideY = 2;
+ descriptor.m_PadLeft = 1;
+ descriptor.m_PadRight = 1;
+ descriptor.m_PadTop = 1;
+ descriptor.m_PadBottom = 1;
+ descriptor.m_PaddingMethod = armnn::PaddingMethod::Exclude;
+
+ armnn::TensorInfo inputTensorInfo({ 1, 1, 4, 4 }, DataType::Float32);
+ armnn::TensorInfo outputTensorInfo({ 1, 1, 3, 3 }, DataType::Float32);
+
+ std::vector<std::vector<int32_t>> inputShape = {{ 1, 1, 4, 4 }};
+ std::vector<std::vector<int32_t>> outputShape = {{ 1, 1, 3, 3 }};
+
+ TosaSerializationBasicBlock* basicBlock =
+ GetTosaMapping(LayerType::Pooling2d, {&inputTensorInfo}, {&outputTensorInfo}, descriptor, false);
+ AssertTosaOneToOneMappingBasicBlock(basicBlock,
+ inputShape,
+ outputShape,
+ Op_AVG_POOL2D,
+ Attribute_PoolAttribute,
+ descriptor,
+ LayerType::Pooling2d);
+}
+
+TEST_CASE("GetTosaMappingFromLayer_AvgPool2DLayer")
+{
+ IRuntime::CreationOptions options;
+ IRuntimePtr runtime(IRuntime::Create(options));
+
+ // Builds up the structure of the network.
+ INetworkPtr net(INetwork::Create());
+
+ armnn::Pooling2dDescriptor descriptor;
+ descriptor.m_PoolType = armnn::PoolingAlgorithm::Average;
+ descriptor.m_PoolWidth = descriptor.m_PoolHeight = 2;
+ descriptor.m_StrideX = descriptor.m_StrideY = 2;
+ descriptor.m_PadLeft = 1;
+ descriptor.m_PadRight = 1;
+ descriptor.m_PadTop = 1;
+ descriptor.m_PadBottom = 1;
+ descriptor.m_PaddingMethod = armnn::PaddingMethod::Exclude;
+
+ IConnectableLayer* input0 = net->AddInputLayer(0, "input0");
+ IConnectableLayer* pool = net->AddPooling2dLayer(descriptor, "pool");
+ IConnectableLayer* output = net->AddOutputLayer(0, "output");
+
+ input0->GetOutputSlot(0).Connect(pool->GetInputSlot(0));
+ pool->GetOutputSlot(0).Connect(output->GetInputSlot(0));
+
+ armnn::TensorInfo inputTensorInfo({ 1, 1, 4, 4 }, DataType::Float32);
+ armnn::TensorInfo outputTensorInfo({ 1, 1, 3, 3 }, DataType::Float32);
+
+ std::vector<std::vector<int32_t>> inputShape = {{ 1, 1, 4, 4 }};
+ std::vector<std::vector<int32_t>> outputShape = {{ 1, 1, 3, 3 }};
+
+ input0->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
+ pool->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
+
+ TosaSerializationBasicBlock* basicBlock =
+ GetTosaMappingFromLayer(PolymorphicDowncast<Layer*>(pool), false);
+ AssertTosaOneToOneMappingBasicBlock(basicBlock,
+ inputShape,
+ outputShape,
+ Op_AVG_POOL2D,
+ Attribute_PoolAttribute,
+ descriptor,
+ LayerType::Pooling2d);
+}
+
+TEST_CASE("GetTosaMapping_Unimplemented")
+{
+ TosaSerializationBasicBlock* basicBlock =
+ GetTosaMapping(LayerType::UnidirectionalSequenceLstm, {}, {}, BaseDescriptor(), false);
+
+ CHECK(basicBlock->GetName() == "");
+ CHECK(basicBlock->GetTensors().size() == 0);
+ CHECK(basicBlock->GetOperators().size() == 1);
+ CHECK(basicBlock->GetInputs().size() == 0);
+ CHECK(basicBlock->GetOutputs().size() == 0);
+
+ TosaSerializationOperator* op = basicBlock->GetOperators()[0];
+ CHECK(op->GetAttributeType() == Attribute_NONE);
+ CHECK(op->GetOp() == tosa::Op_UNKNOWN);
+ CHECK(op->GetInputTensorNames().size() == 0);
+ CHECK(op->GetOutputTensorNames().size() == 0);
+}
+}
diff --git a/src/backends/tosaCommon/test/TosaOperatorMappingTests.cpp b/src/backends/tosaCommon/test/TosaOperatorMappingTests.cpp
deleted file mode 100644
index d7cc5d8f91..0000000000
--- a/src/backends/tosaCommon/test/TosaOperatorMappingTests.cpp
+++ /dev/null
@@ -1,124 +0,0 @@
-//
-// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
-// SPDX-License-Identifier: MIT
-//
-
-#include <Layer.hpp>
-
-#include <tosaCommon/TosaMappings.hpp>
-
-#include <doctest/doctest.h>
-
-using namespace armnn;
-using namespace tosa;
-
-void AssertTosaOneToOneMappingBasicBlock(TosaSerializationBasicBlock* basicBlock,
- std::vector<int32_t> shape,
- uint32_t numInputs,
- uint32_t numOutputs,
- Op tosaOp,
- std::string operatorString,
- DType dataType = DType_FP32)
-{
- std::string blockStr = operatorString + "_block_";
- CHECK(basicBlock->GetName().find(blockStr) != std::string::npos);
- CHECK(basicBlock->GetInputs().size() == numInputs);
- CHECK(basicBlock->GetOutputs().size() == numOutputs);
- CHECK(basicBlock->GetOperators().size() == 1);
- CHECK(basicBlock->GetTensors().size() == (numInputs + numOutputs));
-
- TosaSerializationOperator* op = basicBlock->GetOperators().at(0);
- CHECK(op->GetInputTensorNames().size() == numInputs);
- CHECK(op->GetOutputTensorNames().size() == numOutputs);
-
- for (uint32_t i = 0; i < numInputs; i++)
- {
- std::basic_string<char> blockInputName = basicBlock->GetInputs()[i];
- std::basic_string<char> operatorInputName = op->GetInputTensorNames()[i];
- std::basic_string<char> tensorName = basicBlock->GetTensors()[i]->GetName();
-
- std::string opStr = operatorString + "_input" + std::to_string(i) + "_";
-
- CHECK(blockInputName == operatorInputName);
- CHECK(tensorName == operatorInputName);
- CHECK(blockInputName.find(opStr) != std::string::npos);
- }
-
- for (uint32_t i = 0; i < numOutputs; i++)
- {
- std::basic_string<char> blockOutputName = basicBlock->GetOutputs()[i];
- std::basic_string<char> operatorOutputName = op->GetOutputTensorNames()[i];
- std::basic_string<char> tensorName = basicBlock->GetTensors()[numInputs + i]->GetName();
-
- std::string opStr = operatorString + "_output" + std::to_string(i) + "_";
-
- CHECK(blockOutputName == operatorOutputName);
- CHECK(tensorName == operatorOutputName);
- CHECK(blockOutputName.find(opStr) != std::string::npos);
- }
-
- CHECK(op->GetAttributeType() == Attribute_NONE);
- CHECK(op->GetOp() == tosaOp);
-
- TosaSerializationTensor* tensor0 = basicBlock->GetTensors()[0];
- CHECK(tensor0->GetDtype() == dataType);
- CHECK(tensor0->GetData().size() == 0);
- CHECK(tensor0->GetShape() == shape);
-}
-
-TEST_SUITE("TosaOperatorMappingOneToOneTests")
-{
-TEST_CASE("GetTosaMapping_AdditionLayer")
-{
- TensorInfo info = TensorInfo({ 1, 2, 4, 2 }, DataType::Float32, 0.0f, 0, true);
- TosaSerializationBasicBlock* basicBlock =
- GetTosaMapping(LayerType::Addition, {&info, &info}, {&info}, BaseDescriptor(), false);
- AssertTosaOneToOneMappingBasicBlock(basicBlock, { 1, 2, 4, 2 }, 2, 1, Op::Op_ADD, "Op_ADD");
-}
-
-TEST_CASE("GetTosaMappingFromLayer_AdditionLayer")
-{
- 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->AddAdditionLayer("add");
- 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({ 1, 2, 4, 2 }, DataType::Float32, 0.0f, 0, true);
-
- input0->GetOutputSlot(0).SetTensorInfo(info);
- input1->GetOutputSlot(0).SetTensorInfo(info);
- add->GetOutputSlot(0).SetTensorInfo(info);
-
- TosaSerializationBasicBlock* basicBlock =
- GetTosaMappingFromLayer(PolymorphicDowncast<Layer*>(add), false);
- AssertTosaOneToOneMappingBasicBlock(basicBlock, { 1, 2, 4, 2 }, 2, 1, Op::Op_ADD, "Op_ADD");
-}
-
-TEST_CASE("GetTosaMapping_Unimplemented")
-{
- TosaSerializationBasicBlock* basicBlock =
- GetTosaMapping(LayerType::UnidirectionalSequenceLstm, {}, {}, BaseDescriptor(), false);
-
- CHECK(basicBlock->GetName() == "");
- CHECK(basicBlock->GetTensors().size() == 0);
- CHECK(basicBlock->GetOperators().size() == 1);
- CHECK(basicBlock->GetInputs().size() == 0);
- CHECK(basicBlock->GetOutputs().size() == 0);
-
- TosaSerializationOperator* op = basicBlock->GetOperators()[0];
- CHECK(op->GetAttributeType() == Attribute_NONE);
- CHECK(op->GetOp() == tosa::Op_UNKNOWN);
- CHECK(op->GetInputTensorNames().size() == 0);
- CHECK(op->GetOutputTensorNames().size() == 0);
-}
-}
diff --git a/src/backends/tosaCommon/test/TosaTestUtils.hpp b/src/backends/tosaCommon/test/TosaTestUtils.hpp
new file mode 100644
index 0000000000..a362bde10d
--- /dev/null
+++ b/src/backends/tosaCommon/test/TosaTestUtils.hpp
@@ -0,0 +1,162 @@
+//
+// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include <Layer.hpp>
+
+#include <tosaCommon/TosaMappings.hpp>
+
+#include <doctest/doctest.h>
+
+using namespace armnn;
+using namespace tosa;
+
+inline void VerifyTosaAttributeFromDescriptor(const BaseDescriptor& descriptor,
+ const TosaAttributeBase* attribute,
+ LayerType type,
+ uint32_t mappingOpNumber = 0)
+{
+ switch (type)
+ {
+ case LayerType::Pooling2d:
+ {
+ auto poolDesc = PolymorphicDowncast<const Pooling2dDescriptor*>(&descriptor);
+ std::vector<int> pad = {static_cast<int>(poolDesc->m_PadTop),
+ static_cast<int>(poolDesc->m_PadBottom),
+ static_cast<int>(poolDesc->m_PadLeft),
+ static_cast<int>(poolDesc->m_PadRight)};
+
+ bool avgPoolIgnoreValue =
+ (poolDesc->m_PoolType == PoolingAlgorithm::Average) &&
+ (poolDesc->m_PaddingMethod == PaddingMethod::IgnoreValue);
+ if (avgPoolIgnoreValue)
+ {
+ if (mappingOpNumber == 0)
+ {
+ if (poolDesc->m_DataLayout == DataLayout::NHWC)
+ {
+ pad = {0,
+ 0,
+ static_cast<int>(poolDesc->m_PadTop),
+ static_cast<int>(poolDesc->m_PadBottom),
+ static_cast<int>(poolDesc->m_PadLeft),
+ static_cast<int>(poolDesc->m_PadRight),
+ 0,
+ 0
+ };
+ }
+ else
+ {
+ pad = {0,
+ 0,
+ 0,
+ 0,
+ static_cast<int>(poolDesc->m_PadTop),
+ static_cast<int>(poolDesc->m_PadBottom),
+ static_cast<int>(poolDesc->m_PadLeft),
+ static_cast<int>(poolDesc->m_PadRight)
+ };
+ }
+
+ TosaPadAttribute padAttribute(attribute);
+
+ CHECK(pad == padAttribute.padding());
+ CHECK(0.0f == padAttribute.pad_const_fp());
+ CHECK(0 == padAttribute.pad_const_int());
+
+ break;
+ }
+ pad = {0, 0, 0, 0};
+ }
+
+ std::vector<int> kernel = {static_cast<int>(poolDesc->m_PoolHeight),
+ static_cast<int>(poolDesc->m_PoolWidth)};
+ std::vector<int> stride = {static_cast<int>(poolDesc->m_StrideY),
+ static_cast<int>(poolDesc->m_StrideX)};
+ TosaPoolAttribute poolAttribute(attribute);
+ CHECK(pad == poolAttribute.pad());
+ CHECK(kernel == poolAttribute.kernel());
+ CHECK(stride == poolAttribute.stride());
+ }
+ default:
+ break;
+ }
+ return;
+}
+
+inline void AssertTosaOneToOneMappingBasicBlock(TosaSerializationBasicBlock* basicBlock,
+ std::vector<std::vector<int32_t>> inputShape,
+ std::vector<std::vector<int32_t>> outputShape,
+ Op tosaOp,
+ Attribute tosaAttribute,
+ const BaseDescriptor& descriptor,
+ LayerType type,
+ DType dataType = DType_FP32)
+{
+ uint32_t numInputs = static_cast<uint32_t>(inputShape.size());
+ uint32_t numOutputs = static_cast<uint32_t>(outputShape.size());
+ std::string operatorString = TosaOpToString(tosaOp);
+
+ std::string blockStr = operatorString + "_block_";
+ CHECK(basicBlock->GetName().find(blockStr) != std::string::npos);
+ CHECK(basicBlock->GetInputs().size() == numInputs);
+ CHECK(basicBlock->GetOutputs().size() == numOutputs);
+ CHECK(basicBlock->GetOperators().size() == 1);
+ CHECK(basicBlock->GetTensors().size() == (numInputs + numOutputs));
+
+ TosaSerializationOperator* op = basicBlock->GetOperators().at(0);
+ CHECK(op->GetInputTensorNames().size() == numInputs);
+ CHECK(op->GetOutputTensorNames().size() == numOutputs);
+
+ for (uint32_t i = 0; i < numInputs; i++)
+ {
+ std::basic_string<char> blockInputName = basicBlock->GetInputs()[i];
+ std::basic_string<char> operatorInputName = op->GetInputTensorNames()[i];
+ std::basic_string<char> tensorName = basicBlock->GetTensors()[i]->GetName();
+
+ std::string opStr = operatorString + "_input" + std::to_string(i) + "_";
+
+ CHECK(blockInputName == operatorInputName);
+ CHECK(tensorName == operatorInputName);
+ CHECK(blockInputName.find(opStr) != std::string::npos);
+ }
+
+ for (uint32_t i = 0; i < numOutputs; i++)
+ {
+ std::basic_string<char> blockOutputName = basicBlock->GetOutputs()[i];
+ std::basic_string<char> operatorOutputName = op->GetOutputTensorNames()[i];
+ std::basic_string<char> tensorName = basicBlock->GetTensors()[numInputs + i]->GetName();
+
+ std::string opStr = operatorString + "_output" + std::to_string(i) + "_";
+
+ CHECK(blockOutputName == operatorOutputName);
+ CHECK(tensorName == operatorOutputName);
+ CHECK(blockOutputName.find(opStr) != std::string::npos);
+ }
+
+ CHECK(op->GetAttributeType() == tosaAttribute);
+ CHECK(op->GetOp() == tosaOp);
+
+ for (uint32_t i = 0; i < numInputs; i++)
+ {
+ TosaSerializationTensor* tensor = basicBlock->GetTensors()[i];
+ CHECK(tensor->GetDtype() == dataType);
+ CHECK(tensor->GetData().size() == 0);
+ CHECK(tensor->GetShape() == inputShape[static_cast<unsigned long int>(i)]);
+ }
+
+ for (uint32_t i = 0; i < numOutputs; i++)
+ {
+ TosaSerializationTensor* tensor = basicBlock->GetTensors()[i + inputShape.size()];
+ CHECK(tensor->GetDtype() == dataType);
+ CHECK(tensor->GetData().size() == 0);
+ CHECK(tensor->GetShape() == outputShape[static_cast<unsigned long int>(i)]);
+ }
+
+ VerifyTosaAttributeFromDescriptor(descriptor,
+ op->GetAttribute(),
+ type);
+} \ No newline at end of file
diff --git a/src/backends/tosaReference/TosaRefLayerSupport.cpp b/src/backends/tosaReference/TosaRefLayerSupport.cpp
index a39bfb6c4d..ce4abbf921 100644
--- a/src/backends/tosaReference/TosaRefLayerSupport.cpp
+++ b/src/backends/tosaReference/TosaRefLayerSupport.cpp
@@ -13,24 +13,25 @@
#include <vector>
#include <array>
+#include <tuple>
namespace armnn
{
-static bool RunTosaLayerChecks(TosaSerializationOperator* op,
- const std::vector<TosaSerializationTensor*>& inputs,
- const std::vector<TosaSerializationTensor*>& outputs,
- const std::vector<Attribute>& supportedAttributes,
- const std::vector<DType>& supportedTypes,
- Optional<string&> reasonIfUnsupported)
+static bool RunTosaLayerChecksSingleDataType(TosaSerializationOperator* op,
+ const std::vector<TosaSerializationTensor*>& inputs,
+ const std::vector<TosaSerializationTensor*>& outputs,
+ const std::vector<Attribute>& supportedAttributes,
+ const std::vector<DType>& supportedTypes,
+ Optional<string&> reasonIfUnsupported)
{
bool supported = true;
- std::string opCode = std::to_string(op->GetOp());
+ std::string opString = TosaOpToString(op->GetOp());
// Check Attribute from operator (GetAttribute)
supported &= CheckSupportRule(TosaOperatorAttributeOfAny(op, supportedAttributes), reasonIfUnsupported,
- std::string("TOSA Reference Operator: " + opCode +
+ std::string("TOSA Reference Operator: " + opString +
" has an unsupported attribute.").c_str());
for (auto input : inputs)
@@ -40,14 +41,14 @@ static bool RunTosaLayerChecks(TosaSerializationOperator* op,
// Check Dtype from tensor (GetDtype)
supported &= CheckSupportRule(TosaTypeAnyOf(input, supportedTypes),
reasonIfUnsupported,
- std::string("TOSA Reference Operator: " + opCode + " for input: " +
+ std::string("TOSA Reference Operator: " + opString + " for input: " +
input->GetName() + " has an unsupported data type: " +
dataTypeCode).c_str());
// Check Shape from tensor (GetShape)
supported &= CheckSupportRule(TosaTensorNumDimensionsWithinBounds(input),
reasonIfUnsupported,
- std::string("Tosa Reference Operator: " + opCode + " for input: " +
+ std::string("Tosa Reference Operator: " + opString + " for input: " +
input->GetName() + " exceeds MaxNumOfTensorDimensions.").c_str());
}
@@ -58,20 +59,72 @@ static bool RunTosaLayerChecks(TosaSerializationOperator* op,
// Check Dtype from tensor (GetDtype)
supported &= CheckSupportRule(TosaTypeAnyOf(output, supportedTypes),
reasonIfUnsupported,
- std::string("TOSA Reference Operator: " + opCode + " for output: " +
+ std::string("TOSA Reference Operator: " + opString + " for output: " +
output->GetName() + " has an unsupported data type: " +
dataTypeCode).c_str());
// Check Shape from tensor (GetShape)
supported &= CheckSupportRule(TosaTensorNumDimensionsWithinBounds(output),
reasonIfUnsupported,
- std::string("Tosa Reference Operator: " + opCode + " for output: " +
+ std::string("Tosa Reference Operator: " + opString + " for output: " +
output->GetName() + " exceeds MaxNumOfTensorDimensions.").c_str());
}
return supported;
}
+static bool RunTosaLayerChecksInputOutputDataType(TosaSerializationOperator* op,
+ const std::vector<TosaSerializationTensor*>& inputs,
+ const std::vector<TosaSerializationTensor*>& outputs,
+ const std::vector<Attribute>& supportedAttributes,
+ const std::vector<std::tuple<DType,DType>>& supportedMappingTypes,
+ Optional<string&> reasonIfUnsupported)
+{
+ bool supported = true;
+
+ std::string opString = TosaOpToString(op->GetOp());
+
+ // Check Attribute from operator (GetAttribute)
+ supported &= CheckSupportRule(TosaOperatorAttributeOfAny(op, supportedAttributes), reasonIfUnsupported,
+ std::string("TOSA Reference Operator: " + opString +
+ " has an unsupported attribute.").c_str());
+
+ supported &= CheckSupportRule(TosaAssertSize(inputs, outputs), reasonIfUnsupported,
+ std::string("TOSA Reference Operator: " + opString +
+ " must have 1-to-1 mapping of inputs-to-outputs.").c_str());
+
+ for (uint32_t i = 0; i < inputs.size(); i++)
+ {
+ auto input = inputs[i];
+ auto output = outputs[i];
+ std::string inputDataTypeCode = std::to_string(input->GetDtype());
+ std::string outputDataTypeCode = std::to_string(output->GetDtype());
+ std::tuple<DType, DType> mappingType(input->GetDtype(), output->GetDtype());
+
+ // Check Dtype from tensor (GetDtype)
+ supported &= CheckSupportRule(TosaContainerContains(mappingType, supportedMappingTypes),
+ reasonIfUnsupported,
+ std::string("TOSA Reference Operator: " + opString + " for input: " +
+ input->GetName() + " and output: " + output->GetName() +
+ " has an unsupported input data type: " + inputDataTypeCode +
+ " to output data type: " + outputDataTypeCode).c_str());
+
+ // Check Shape from tensor (GetShape)
+ supported &= CheckSupportRule(TosaTensorNumDimensionsWithinBounds(input),
+ reasonIfUnsupported,
+ std::string("Tosa Reference Operator: " + opString + " for input: " +
+ input->GetName() + " exceeds MaxNumOfTensorDimensions.").c_str());
+
+ // Check Shape from tensor (GetShape)
+ supported &= CheckSupportRule(TosaTensorNumDimensionsWithinBounds(output),
+ reasonIfUnsupported,
+ std::string("Tosa Reference Operator: " + opString + " for output: " +
+ output->GetName() + " exceeds MaxNumOfTensorDimensions.").c_str());
+ }
+
+ return supported;
+}
+
static bool IsTosaLayerSupported(TosaSerializationOperator* op,
const std::vector<TosaSerializationTensor*>& inputs,
const std::vector<TosaSerializationTensor*>& outputs,
@@ -81,8 +134,6 @@ static bool IsTosaLayerSupported(TosaSerializationOperator* op,
{
case tosa::Op_ADD:
{
- bool supported = true;
-
std::vector<Attribute> supportedAttributes =
{
Attribute_NONE
@@ -97,14 +148,84 @@ static bool IsTosaLayerSupported(TosaSerializationOperator* op,
};
// Check the attribute, data types and bounds for inputs and outputs.
- supported = RunTosaLayerChecks(op,
- inputs,
- outputs,
- supportedAttributes,
- supportedTypes,
- reasonIfUnsupported);
-
- return supported;
+ return RunTosaLayerChecksSingleDataType(op,
+ inputs,
+ outputs,
+ supportedAttributes,
+ supportedTypes,
+ reasonIfUnsupported);
+ }
+ case tosa::Op_AVG_POOL2D:
+ {
+ std::vector<Attribute> supportedAttributes =
+ {
+ Attribute_PoolAttribute
+ };
+
+ std::vector<std::tuple<DType, DType>> supportedTypesMapping =
+ {
+ std::tuple<DType, DType>(DType_FP16, DType_FP16),
+ std::tuple<DType, DType>(DType_FP16, DType_FP32),
+ std::tuple<DType, DType>(DType_FP32, DType_FP32),
+ std::tuple<DType, DType>(DType_INT8, DType_INT32),
+ std::tuple<DType, DType>(DType_INT16, DType_INT32)
+ };
+
+ // Check the attribute, data types and bounds for inputs and outputs.
+ return RunTosaLayerChecksInputOutputDataType(op,
+ inputs,
+ outputs,
+ supportedAttributes,
+ supportedTypesMapping,
+ reasonIfUnsupported);
+ }
+ case tosa::Op_MAX_POOL2D:
+ {
+ std::vector<Attribute> supportedAttributes =
+ {
+ Attribute_PoolAttribute
+ };
+
+ std::vector<DType> supportedTypes =
+ {
+ DType_FP16,
+ DType_FP32,
+ DType_INT8,
+ DType_INT16
+ };
+
+ // Check the attribute, data types and bounds for inputs and outputs.
+ return RunTosaLayerChecksSingleDataType(op,
+ inputs,
+ outputs,
+ supportedAttributes,
+ supportedTypes,
+ reasonIfUnsupported);
+ }
+ case tosa::Op_PAD:
+ {
+ std::vector<Attribute> supportedAttributes =
+ {
+ Attribute_PadAttribute
+ };
+
+ std::vector<DType> supportedTypes =
+ {
+ DType_FP16,
+ DType_FP32,
+ DType_INT8,
+ DType_INT16,
+ DType_INT32,
+ DType_BOOL
+ };
+
+ // Check the attribute, data types and bounds for inputs and outputs.
+ return RunTosaLayerChecksSingleDataType(op,
+ inputs,
+ outputs,
+ supportedAttributes,
+ supportedTypes,
+ reasonIfUnsupported);
}
default:
SetValueChecked(reasonIfUnsupported, "Operation is currently unsupported by the TOSA Reference Backend.");
@@ -136,6 +257,11 @@ bool TosaRefLayerSupport::IsLayerSupported(const LayerType& type,
case LayerType::Input:
case LayerType::Output:
return true;
+ case LayerType::Pooling2d:
+ // Setup inputs and outputs
+ inputInfos.push_back(&infos[0]);
+ outputInfos.push_back(&infos[1]);
+ break;
default:
break;
}
diff --git a/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp b/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp
index 54d6db6cef..fbe1265fe3 100644
--- a/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp
+++ b/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp
@@ -6,27 +6,60 @@
#include "backendsCommon/test/EndToEndTestImpl.hpp"
#include "backendsCommon/test/AdditionEndToEndTestImpl.hpp"
+#include "backendsCommon/test/Pooling2dEndToEndTestImpl.hpp"
#include <doctest/doctest.h>
TEST_SUITE("TosaRefEndToEnd")
{
-std::vector<armnn::BackendId> tosaDefaultBackends = { "TosaRef" };
+std::vector<BackendId> tosaDefaultBackends = { "TosaRef" };
// Addition
-TEST_CASE("TosaRefEndtoEndTestFloat32")
+TEST_CASE("TosaRefAdditionEndtoEndTestFloat32")
{
- AdditionEndToEnd<armnn::DataType::Float32>(tosaDefaultBackends);
+ AdditionEndToEnd<DataType::Float32>(tosaDefaultBackends);
}
-TEST_CASE("TosaRefEndtoEndTestInt32")
+TEST_CASE("TosaRefAdditionEndtoEndTestInt32")
{
- AdditionEndToEnd<armnn::DataType::Signed32>(tosaDefaultBackends);
+ AdditionEndToEnd<DataType::Signed32>(tosaDefaultBackends);
}
-TEST_CASE("TosaRefEndtoEndTestFloat16")
+TEST_CASE("TosaRefAdditionEndtoEndTestFloat16")
{
- AdditionEndToEndFloat16<armnn::DataType::Float16>(tosaDefaultBackends);
+ AdditionEndToEndFloat16<DataType::Float16>(tosaDefaultBackends);
+}
+
+// Max Pool 2D
+TEST_CASE("TosaRefMaxPool2DEndtoEndTestFloat32")
+{
+ MaxPool2dEndToEnd<DataType::Float32>(tosaDefaultBackends);
+}
+
+TEST_CASE("TosaRefMaxPool2DEndtoEndTestFloat16")
+{
+ MaxPool2dEndToEndFloat16<DataType::Float16>(tosaDefaultBackends);
+}
+
+TEST_CASE("TosaRefMaxPool2DIgnoreValueEndtoEndTestFloat32")
+{
+ MaxPool2dEndToEnd<DataType::Float32>(tosaDefaultBackends, PaddingMethod::IgnoreValue);
+}
+
+// Average Pool 2D
+TEST_CASE("TosaRefAvgPool2DEndtoEndTestFloat32")
+{
+ AvgPool2dEndToEnd<DataType::Float32>(tosaDefaultBackends);
+}
+
+TEST_CASE("TosaRefAvgPool2DEndtoEndTestFloat16")
+{
+ AvgPool2dEndToEndFloat16<DataType::Float16>(tosaDefaultBackends);
+}
+
+TEST_CASE("TosaRefAvgPool2DIgnoreValueEndtoEndTestFloat32")
+{
+ AvgPool2dEndToEnd<DataType::Float32>(tosaDefaultBackends, PaddingMethod::IgnoreValue);
}
} \ No newline at end of file
diff --git a/src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp b/src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp
index 47f31380a5..48eca344bc 100644
--- a/src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp
+++ b/src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp
@@ -57,9 +57,131 @@ TEST_CASE("IsLayerSupportedTosaReferenceAdditionUnsupported")
reasonIfNotSupported);
CHECK(!supported);
- REQUIRE(reasonIfNotSupported.find("TOSA Reference Operator: 14 for input: Op_ADD_input0_") != std::string::npos);
- REQUIRE(reasonIfNotSupported.find("TOSA Reference Operator: 14 for input: Op_ADD_input1_") != std::string::npos);
- REQUIRE(reasonIfNotSupported.find("TOSA Reference Operator: 14 for output: Op_ADD_output0_") != std::string::npos);
+ REQUIRE(reasonIfNotSupported.find(
+ "TOSA Reference Operator: Op_ADD for input: Op_ADD_input0_") != std::string::npos);
+ REQUIRE(reasonIfNotSupported.find(
+ "TOSA Reference Operator: Op_ADD for input: Op_ADD_input1_") != std::string::npos);
+ REQUIRE(reasonIfNotSupported.find(
+ "TOSA Reference Operator: Op_ADD for output: Op_ADD_output0_") != std::string::npos);
+}
+
+TEST_CASE("IsLayerSupportedTosaReferenceMaxPooling2d")
+{
+ armnn::TensorShape inShape = {1,1,3,4};
+ armnn::TensorShape outShape = {1,1,3,4};
+ armnn::TensorInfo in(inShape, armnn::DataType::Float32);
+ armnn::TensorInfo out(outShape, armnn::DataType::Float32);
+
+ armnn::Pooling2dDescriptor desc;
+ armnn::TosaRefLayerSupport supportChecker;
+ std::string reasonIfNotSupported;
+ auto supported = supportChecker.IsLayerSupported(armnn::LayerType::Pooling2d,
+ {in, out},
+ desc,
+ armnn::EmptyOptional(),
+ armnn::EmptyOptional(),
+ reasonIfNotSupported);
+
+ CHECK(supported);
+}
+
+TEST_CASE("IsLayerSupportedTosaReferenceAvgPooling2d_IgnoreValue")
+{
+ armnn::TensorShape inShape = {1,1,3,4};
+ armnn::TensorShape outShape = {1,1,3,4};
+ armnn::TensorInfo in(inShape, armnn::DataType::Float32);
+ armnn::TensorInfo out(outShape, armnn::DataType::Float32);
+
+ armnn::Pooling2dDescriptor desc;
+ desc.m_PaddingMethod = armnn::PaddingMethod::IgnoreValue;
+ desc.m_PoolType = armnn::PoolingAlgorithm::Average;
+
+ armnn::TosaRefLayerSupport supportChecker;
+ std::string reasonIfNotSupported;
+ auto supported = supportChecker.IsLayerSupported(armnn::LayerType::Pooling2d,
+ {in, out},
+ desc,
+ armnn::EmptyOptional(),
+ armnn::EmptyOptional(),
+ reasonIfNotSupported);
+
+ CHECK(supported);
+}
+
+TEST_CASE("IsLayerSupportedTosaReferenceAvgPooling2d_InputOutputDatatypeDifferent")
+{
+ armnn::TensorShape inShape = {1,1,3,4};
+ armnn::TensorShape outShape = {1,1,3,4};
+ armnn::TensorInfo in(inShape, armnn::DataType::QAsymmS8);
+ armnn::TensorInfo out(outShape, armnn::DataType::Signed32);
+
+ armnn::Pooling2dDescriptor desc;
+ desc.m_PaddingMethod = armnn::PaddingMethod::IgnoreValue;
+ desc.m_PoolType = armnn::PoolingAlgorithm::Average;
+
+ armnn::TosaRefLayerSupport supportChecker;
+ std::string reasonIfNotSupported;
+ auto supported = supportChecker.IsLayerSupported(armnn::LayerType::Pooling2d,
+ {in, out},
+ desc,
+ armnn::EmptyOptional(),
+ armnn::EmptyOptional(),
+ reasonIfNotSupported);
+
+ CHECK(supported);
+}
+
+TEST_CASE("IsLayerSupportedTosaReferenceMaxPooling2dUnsupported")
+{
+ armnn::TensorShape inShape = {1,1,3,4};
+ armnn::TensorShape outShape = {1,1,3,4};
+ armnn::TensorInfo in(inShape, armnn::DataType::Signed64);
+ armnn::TensorInfo out(outShape, armnn::DataType::Signed64);
+
+ armnn::Pooling2dDescriptor desc;
+ armnn::TosaRefLayerSupport supportChecker;
+ std::string reasonIfNotSupported;
+ auto supported = supportChecker.IsLayerSupported(armnn::LayerType::Pooling2d,
+ {in, out},
+ desc,
+ armnn::EmptyOptional(),
+ armnn::EmptyOptional(),
+ reasonIfNotSupported);
+
+ CHECK(!supported);
+ REQUIRE(reasonIfNotSupported.find(
+ "TOSA Reference Operator: Op_MAX_POOL2D for input: Op_MAX_POOL2D_input0_") != std::string::npos);
+ REQUIRE(reasonIfNotSupported.find(
+ "TOSA Reference Operator: Op_MAX_POOL2D for output: Op_MAX_POOL2D_output0_") != std::string::npos);
+}
+
+TEST_CASE("IsLayerSupportedTosaReferenceAvgPooling2dUnsupported_InputOutputDatatypeDifferent")
+{
+ armnn::TensorShape inShape = {1,1,3,4};
+ armnn::TensorShape outShape = {1,1,3,4};
+ armnn::TensorInfo in(inShape, armnn::DataType::Float32);
+ armnn::TensorInfo out(outShape, armnn::DataType::Float16);
+
+ armnn::Pooling2dDescriptor desc;
+ desc.m_PaddingMethod = armnn::PaddingMethod::IgnoreValue;
+ desc.m_PoolType = armnn::PoolingAlgorithm::Average;
+
+ armnn::TosaRefLayerSupport supportChecker;
+ std::string reasonIfNotSupported;
+ auto supported = supportChecker.IsLayerSupported(armnn::LayerType::Pooling2d,
+ {in, out},
+ desc,
+ armnn::EmptyOptional(),
+ armnn::EmptyOptional(),
+ reasonIfNotSupported);
+
+ CHECK(!supported);
+ REQUIRE(reasonIfNotSupported.find(
+ "TOSA Reference Operator: Op_AVG_POOL2D for input: Op_PAD_intermediate0_") != std::string::npos);
+ REQUIRE(reasonIfNotSupported.find(
+ " and output: Op_AVG_POOL2D_output0_") != std::string::npos);
+ REQUIRE(reasonIfNotSupported.find(
+ " has an unsupported input data type: 8 to output data type: 10") != std::string::npos);
}
}