diff options
author | Matthew Sloyan <matthew.sloyan@arm.com> | 2022-11-25 16:10:00 +0000 |
---|---|---|
committer | Matthew Sloyan <matthew.sloyan@arm.com> | 2022-12-08 12:57:47 +0000 |
commit | c5fe6e71cd39096af7c2523ec2afe96008c51b0c (patch) | |
tree | 1486349bc36e17c1577465aab81d9eb3ca64e861 /src/backends/tosaCommon/test | |
parent | 3106c7f1714aea556d06d9f1e8c7faaeaeca996d (diff) | |
download | armnn-c5fe6e71cd39096af7c2523ec2afe96008c51b0c.tar.gz |
IVGCVSW-7168 Add Conv2d and Constant support to TOSA Reference Backend
* Added TOSA Conv2d and Constant mappings.
* Added unique naming to mappings based on previous and following
layers, so they are connected correctly.
* Updated existing mappings with new naming convention.
* Added all mappings to one main block in OptimizeSubgraphView.
* Removed isMain from mapping functions.
* Added Conv2d EndToEnd test.
Signed-off-by: Matthew Sloyan <matthew.sloyan@arm.com>
Change-Id: I27c3e238407c32379ce25a1f01dad11523ef5d2b
Diffstat (limited to 'src/backends/tosaCommon/test')
4 files changed, 181 insertions, 22 deletions
diff --git a/src/backends/tosaCommon/test/AvgPool2DIgnoreValueChecker.hpp b/src/backends/tosaCommon/test/AvgPool2DIgnoreValueChecker.hpp index 8869b3a8ff..a38f66b466 100644 --- a/src/backends/tosaCommon/test/AvgPool2DIgnoreValueChecker.hpp +++ b/src/backends/tosaCommon/test/AvgPool2DIgnoreValueChecker.hpp @@ -17,10 +17,8 @@ void VerifyAvgPool2DIgnoreValue(TosaSerializationBasicBlock* basicBlock, { 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_"; + std::string blockStr = TosaOpToString(Op_AVG_POOL2D) + "_block_"; CHECK(basicBlock->GetName().find(blockStr) != std::string::npos); CHECK(basicBlock->GetInputs().size() == numInputs); CHECK(basicBlock->GetOutputs().size() == numOutputs); @@ -41,7 +39,7 @@ void VerifyAvgPool2DIgnoreValue(TosaSerializationBasicBlock* basicBlock, 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) + "_"; + std::string opStr = "input" + std::to_string(i) + "_"; CHECK(blockInputName == operatorInputName); CHECK(basicBlock->GetTensorByName(blockInputName)); @@ -56,7 +54,7 @@ void VerifyAvgPool2DIgnoreValue(TosaSerializationBasicBlock* basicBlock, 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) + "_"; + std::string opStr = "intermediate" + std::to_string(i) + "_"; CHECK(basicBlock->GetTensorByName(operatorOutputName)); CHECK(operatorOutputName.find(opStr) != std::string::npos); @@ -86,7 +84,7 @@ void VerifyAvgPool2DIgnoreValue(TosaSerializationBasicBlock* basicBlock, 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) + "_"; + std::string opStr = "intermediate" + std::to_string(i) + "_"; CHECK(basicBlock->GetTensorByName(operatorInputName)); CHECK(operatorInputName.find(opStr) != std::string::npos); @@ -102,7 +100,7 @@ void VerifyAvgPool2DIgnoreValue(TosaSerializationBasicBlock* basicBlock, 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) + "_"; + std::string opStr = "output" + std::to_string(i) + "_"; CHECK(blockOutputName == operatorOutputName); CHECK(basicBlock->GetTensorByName(blockOutputName)); diff --git a/src/backends/tosaCommon/test/OneToManyMappingTests.cpp b/src/backends/tosaCommon/test/OneToManyMappingTests.cpp index 98fd563da1..dd61ba8191 100644 --- a/src/backends/tosaCommon/test/OneToManyMappingTests.cpp +++ b/src/backends/tosaCommon/test/OneToManyMappingTests.cpp @@ -30,7 +30,7 @@ TEST_CASE("GetTosaMapping_AvgPool2DIgnoreValueLayer") std::vector<std::vector<int32_t>> outputShape = {{ 1, 1, 3, 3 }}; TosaSerializationBasicBlock* basicBlock = - GetTosaMapping(LayerType::Pooling2d, {&inputTensorInfo}, {&outputTensorInfo}, descriptor, false); + GetTosaMapping(nullptr, LayerType::Pooling2d, {&inputTensorInfo}, {&outputTensorInfo}, descriptor); VerifyAvgPool2DIgnoreValue(basicBlock, inputShape, outputShape, @@ -74,7 +74,7 @@ TEST_CASE("GetTosaMappingFromLayer_AvgPool2DIgnoreValueLayer") pool->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); TosaSerializationBasicBlock* basicBlock = - GetTosaMappingFromLayer(PolymorphicDowncast<Layer*>(pool), false); + GetTosaMappingFromLayer(PolymorphicDowncast<Layer*>(pool)); VerifyAvgPool2DIgnoreValue(basicBlock, inputShape, outputShape, diff --git a/src/backends/tosaCommon/test/OneToOneMappingTests.cpp b/src/backends/tosaCommon/test/OneToOneMappingTests.cpp index 04d1eb46aa..af9f9e26df 100644 --- a/src/backends/tosaCommon/test/OneToOneMappingTests.cpp +++ b/src/backends/tosaCommon/test/OneToOneMappingTests.cpp @@ -4,6 +4,7 @@ // #include "TosaTestUtils.hpp" +#include "CommonTestUtils.hpp" using namespace armnn; using namespace tosa; @@ -18,7 +19,7 @@ TEST_CASE("GetTosaMapping_AdditionLayer") std::vector<std::vector<int32_t>> outputShape = {{ 1, 2, 4, 2 }}; TosaSerializationBasicBlock* basicBlock = - GetTosaMapping(LayerType::Addition, {&info, &info}, {&info}, BaseDescriptor(), false); + GetTosaMapping(nullptr, LayerType::Addition, {&info, &info}, {&info}, BaseDescriptor()); AssertTosaOneToOneMappingBasicBlock( basicBlock, inputShape, outputShape, Op_ADD, Attribute_NONE, BaseDescriptor(), LayerType::Addition); } @@ -50,11 +51,132 @@ TEST_CASE("GetTosaMappingFromLayer_AdditionLayer") std::vector<std::vector<int32_t>> outputShape = {{ 1, 2, 4, 2 }}; TosaSerializationBasicBlock* basicBlock = - GetTosaMappingFromLayer(PolymorphicDowncast<Layer*>(add), false); + GetTosaMappingFromLayer(PolymorphicDowncast<Layer*>(add)); AssertTosaOneToOneMappingBasicBlock( basicBlock, inputShape, outputShape, Op_ADD, Attribute_NONE, BaseDescriptor(), LayerType::Addition); } +TEST_CASE("GetTosaMapping_ConstantLayer") +{ + TensorInfo outputInfo = TensorInfo({ 1, 2, 4, 2 }, DataType::Float32, 0.0f, 0, true); + std::vector<std::vector<int32_t>> outputShape = {{ 1, 2, 4, 2 }}; + + TosaSerializationBasicBlock* basicBlock = + GetTosaMapping(nullptr, LayerType::Constant, {}, {&outputInfo}, BaseDescriptor()); + AssertTosaOneToOneMappingBasicBlock( + basicBlock, {}, outputShape, Op_CONST, Attribute_NONE, BaseDescriptor(), LayerType::Constant); +} + +TEST_CASE("GetTosaMappingFromLayer_ConstantLayer") +{ + IRuntime::CreationOptions options; + IRuntimePtr runtime(IRuntime::Create(options)); + + // Builds up the structure of the network. + INetworkPtr net(INetwork::Create()); + + TensorInfo info = TensorInfo({ 1, 2, 4, 2 }, DataType::Float32, 0.0f, 0, true); + std::vector<std::vector<int32_t>> outputShape = {{ 1, 2, 4, 2 }}; + + std::vector<float> data = GenerateRandomData<float>(info.GetNumElements()); + armnn::ConstTensor constTensor(info, data); + + IConnectableLayer* constant = net->AddConstantLayer(constTensor, "constant"); + IConnectableLayer* output = net->AddOutputLayer(0, "output"); + + constant->GetOutputSlot(0).Connect(output->GetInputSlot(0)); + constant->GetOutputSlot(0).SetTensorInfo(info); + + TosaSerializationBasicBlock* basicBlock = + GetTosaMappingFromLayer(PolymorphicDowncast<Layer*>(constant)); + AssertTosaOneToOneMappingBasicBlock( + basicBlock, {}, outputShape, Op_CONST, Attribute_NONE, BaseDescriptor(), LayerType::Constant); +} + +TEST_CASE("GetTosaMapping_Conv2dLayer") +{ + armnn::Convolution2dDescriptor descriptor; + descriptor.m_PadLeft = 1; + descriptor.m_PadRight = 1; + descriptor.m_PadTop = 1; + descriptor.m_PadBottom = 1; + descriptor.m_StrideX = 2; + descriptor.m_StrideY = 2; + descriptor.m_DilationX = 2; + descriptor.m_DilationY = 2; + descriptor.m_BiasEnabled = true; + + const armnn::TensorInfo inputInfo ({ 1, 5, 5, 1 }, armnn::DataType::Float32); + const armnn::TensorInfo outputInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32); + const armnn::TensorInfo weightsInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32, 0.0f, 0, true); + const armnn::TensorInfo biasesInfo ({ 1 }, armnn::DataType::Float32, 0.0f, 0, true); + + std::vector<std::vector<int32_t>> inputShape = {{ 1, 5, 5, 1 }, { 1, 3, 3, 1 }, { 1 }}; + std::vector<std::vector<int32_t>> outputShape = {{ 1, 3, 3, 1 }}; + + TosaSerializationBasicBlock* basicBlock = GetTosaMapping(nullptr, + LayerType::Convolution2d, + {&inputInfo, &weightsInfo, &biasesInfo}, + {&outputInfo}, + descriptor); + AssertTosaOneToOneMappingBasicBlock( + basicBlock, inputShape, outputShape, Op_CONV2D, Attribute_ConvAttribute, descriptor, LayerType::Convolution2d); +} + +TEST_CASE("GetTosaMappingFromLayer_Conv2dLayer") +{ + IRuntime::CreationOptions options; + IRuntimePtr runtime(IRuntime::Create(options)); + + // Builds up the structure of the network. + INetworkPtr net(INetwork::Create()); + + armnn::Convolution2dDescriptor descriptor; + descriptor.m_PadLeft = 1; + descriptor.m_PadRight = 1; + descriptor.m_PadTop = 1; + descriptor.m_PadBottom = 1; + descriptor.m_StrideX = 2; + descriptor.m_StrideY = 2; + descriptor.m_DilationX = 2; + descriptor.m_DilationY = 2; + descriptor.m_BiasEnabled = true; + + const armnn::TensorInfo inputInfo ({ 1, 5, 5, 1 }, armnn::DataType::Float32); + const armnn::TensorInfo outputInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32); + const armnn::TensorInfo weightsInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32, 0.0f, 0, true); + const armnn::TensorInfo biasesInfo ({ 1 }, armnn::DataType::Float32, 0.0f, 0, true); + + std::vector<std::vector<int32_t>> inputShape = {{ 1, 5, 5, 1 }}; + std::vector<std::vector<int32_t>> outputShape = {{ 1, 3, 3, 1 }}; + + std::vector<float> weightsData = GenerateRandomData<float>(weightsInfo.GetNumElements()); + armnn::ConstTensor weights(weightsInfo, weightsData); + + std::vector<float> biasesData = GenerateRandomData<float>(biasesInfo.GetNumElements()); + armnn::ConstTensor biases(biasesInfo, biasesData); + + armnn::IConnectableLayer* const inputLayer = net->AddInputLayer(0, "input0"); + armnn::IConnectableLayer* const weightsLayer = net->AddConstantLayer(weights, "weights"); + armnn::IConnectableLayer* const biasesLayer = net->AddConstantLayer(biases, "biases"); + armnn::IConnectableLayer* const convLayer = net->AddConvolution2dLayer(descriptor, "conv2d"); + armnn::IConnectableLayer* const outputLayer = net->AddOutputLayer(0); + + inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0)); + weightsLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(1)); + biasesLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(2)); + convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); + + inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo); + weightsLayer->GetOutputSlot(0).SetTensorInfo(weightsInfo); + biasesLayer->GetOutputSlot(0).SetTensorInfo(biasesInfo); + convLayer->GetOutputSlot(0).SetTensorInfo(outputInfo); + + TosaSerializationBasicBlock* basicBlock = GetTosaMappingFromLayer(PolymorphicDowncast<Layer*>(convLayer)); + AssertTosaOneToOneMappingBasicBlock( + basicBlock, inputShape, outputShape, Op_CONV2D, Attribute_ConvAttribute, descriptor, LayerType::Convolution2d); +} + TEST_CASE("GetTosaMapping_MaxPool2DLayer") { armnn::Pooling2dDescriptor descriptor; @@ -74,7 +196,7 @@ TEST_CASE("GetTosaMapping_MaxPool2DLayer") std::vector<std::vector<int32_t>> outputShape = {{ 1, 1, 3, 3 }}; TosaSerializationBasicBlock* basicBlock = - GetTosaMapping(LayerType::Pooling2d, {&inputTensorInfo}, {&outputTensorInfo}, descriptor, false); + GetTosaMapping(nullptr, LayerType::Pooling2d, {&inputTensorInfo}, {&outputTensorInfo}, descriptor); AssertTosaOneToOneMappingBasicBlock( basicBlock, inputShape, outputShape, Op_MAX_POOL2D, Attribute_PoolAttribute, descriptor, LayerType::Pooling2d); } @@ -114,7 +236,7 @@ TEST_CASE("GetTosaMappingFromLayer_MaxPool2DLayer") pool->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); TosaSerializationBasicBlock* basicBlock = - GetTosaMappingFromLayer(PolymorphicDowncast<Layer*>(pool), false); + GetTosaMappingFromLayer(PolymorphicDowncast<Layer*>(pool)); AssertTosaOneToOneMappingBasicBlock( basicBlock, inputShape, outputShape, Op_MAX_POOL2D, Attribute_PoolAttribute, descriptor, LayerType::Pooling2d); } @@ -138,7 +260,7 @@ TEST_CASE("GetTosaMapping_AvgPool2DLayer") std::vector<std::vector<int32_t>> outputShape = {{ 1, 1, 3, 3 }}; TosaSerializationBasicBlock* basicBlock = - GetTosaMapping(LayerType::Pooling2d, {&inputTensorInfo}, {&outputTensorInfo}, descriptor, false); + GetTosaMapping(nullptr, LayerType::Pooling2d, {&inputTensorInfo}, {&outputTensorInfo}, descriptor); AssertTosaOneToOneMappingBasicBlock(basicBlock, inputShape, outputShape, @@ -183,7 +305,7 @@ TEST_CASE("GetTosaMappingFromLayer_AvgPool2DLayer") pool->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); TosaSerializationBasicBlock* basicBlock = - GetTosaMappingFromLayer(PolymorphicDowncast<Layer*>(pool), false); + GetTosaMappingFromLayer(PolymorphicDowncast<Layer*>(pool)); AssertTosaOneToOneMappingBasicBlock(basicBlock, inputShape, outputShape, @@ -196,7 +318,7 @@ TEST_CASE("GetTosaMappingFromLayer_AvgPool2DLayer") TEST_CASE("GetTosaMapping_Unimplemented") { TosaSerializationBasicBlock* basicBlock = - GetTosaMapping(LayerType::UnidirectionalSequenceLstm, {}, {}, BaseDescriptor(), false); + GetTosaMapping(nullptr, LayerType::UnidirectionalSequenceLstm, {}, {}, BaseDescriptor()); CHECK(basicBlock->GetName() == ""); CHECK(basicBlock->GetTensors().size() == 0); diff --git a/src/backends/tosaCommon/test/TosaTestUtils.hpp b/src/backends/tosaCommon/test/TosaTestUtils.hpp index a362bde10d..dd63c0efdf 100644 --- a/src/backends/tosaCommon/test/TosaTestUtils.hpp +++ b/src/backends/tosaCommon/test/TosaTestUtils.hpp @@ -21,6 +21,24 @@ inline void VerifyTosaAttributeFromDescriptor(const BaseDescriptor& descriptor, { switch (type) { + case LayerType::Convolution2d: + { + auto conv2dDesc = PolymorphicDowncast<const Convolution2dDescriptor*>(&descriptor); + std::vector<int> pad = {static_cast<int>(conv2dDesc->m_PadTop), + static_cast<int>(conv2dDesc->m_PadBottom), + static_cast<int>(conv2dDesc->m_PadLeft), + static_cast<int>(conv2dDesc->m_PadRight)}; + + std::vector<int> dilation = {static_cast<int>(conv2dDesc->m_DilationY), + static_cast<int>(conv2dDesc->m_DilationX)}; + std::vector<int> stride = {static_cast<int>(conv2dDesc->m_StrideY), + static_cast<int>(conv2dDesc->m_StrideX)}; + TosaConvAttribute convAttribute(attribute); + CHECK(pad == convAttribute.pad()); + CHECK(dilation == convAttribute.dilation()); + CHECK(stride == convAttribute.stride()); + break; + } case LayerType::Pooling2d: { auto poolDesc = PolymorphicDowncast<const Pooling2dDescriptor*>(&descriptor); @@ -80,6 +98,7 @@ inline void VerifyTosaAttributeFromDescriptor(const BaseDescriptor& descriptor, CHECK(pad == poolAttribute.pad()); CHECK(kernel == poolAttribute.kernel()); CHECK(stride == poolAttribute.stride()); + break; } default: break; @@ -97,18 +116,30 @@ inline void AssertTosaOneToOneMappingBasicBlock(TosaSerializationBasicBlock* bas DType dataType = DType_FP32) { uint32_t numInputs = static_cast<uint32_t>(inputShape.size()); + uint32_t numInputTensors = static_cast<uint32_t>(inputShape.size()); uint32_t numOutputs = static_cast<uint32_t>(outputShape.size()); std::string operatorString = TosaOpToString(tosaOp); + // The number of tensors in the block can be different if there are constant layers, as they are created separately. + if(type == LayerType::Convolution2d) + { + numInputTensors = 2; + auto conv2dDesc = PolymorphicDowncast<const Convolution2dDescriptor*>(&descriptor); + if(conv2dDesc->m_BiasEnabled) + { + numInputTensors = 3; + } + } + std::string blockStr = operatorString + "_block_"; CHECK(basicBlock->GetName().find(blockStr) != std::string::npos); - CHECK(basicBlock->GetInputs().size() == numInputs); + CHECK(basicBlock->GetInputs().size() == numInputTensors); 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->GetInputTensorNames().size() == numInputTensors); CHECK(op->GetOutputTensorNames().size() == numOutputs); for (uint32_t i = 0; i < numInputs; i++) @@ -117,11 +148,11 @@ inline void AssertTosaOneToOneMappingBasicBlock(TosaSerializationBasicBlock* bas 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) + "_"; + std::string opStr = "input" + std::to_string(i) + "_"; CHECK(blockInputName == operatorInputName); CHECK(tensorName == operatorInputName); - CHECK(blockInputName.find(opStr) != std::string::npos); + CHECK(blockInputName.find(opStr) != std::string::npos); } for (uint32_t i = 0; i < numOutputs; i++) @@ -130,7 +161,11 @@ inline void AssertTosaOneToOneMappingBasicBlock(TosaSerializationBasicBlock* bas 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) + "_"; + std::string opStr = "output" + std::to_string(i) + "_"; + if (tosaOp == Op_CONST) + { + opStr = "constant_"; + } CHECK(blockOutputName == operatorOutputName); CHECK(tensorName == operatorOutputName); @@ -152,8 +187,12 @@ inline void AssertTosaOneToOneMappingBasicBlock(TosaSerializationBasicBlock* bas { 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)]); + if (tosaOp != Op_CONST) + { + // Const tensors contain data. + CHECK(tensor->GetData().size() == 0); + } } VerifyTosaAttributeFromDescriptor(descriptor, |