aboutsummaryrefslogtreecommitdiff
path: root/src/backends/tosaCommon
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 /src/backends/tosaCommon
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
Diffstat (limited to 'src/backends/tosaCommon')
-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
16 files changed, 1010 insertions, 130 deletions
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