From 0bb096d9cd11bec1a890066064c8a28c4a4fd6ee Mon Sep 17 00:00:00 2001 From: Cathal Corbett Date: Thu, 22 Dec 2022 13:09:38 +0000 Subject: IVGCVSW-7343 Add Transpose support to TOSA Reference Backend Signed-off-by: Cathal Corbett Change-Id: I11505f672349e1f04143edfdc2df8775f685372d --- src/backends/tosaCommon/TosaMappings.cpp | 5 ++ .../tosaCommon/operatorMappings/CMakeLists.txt | 2 + .../operatorMappings/TosaCommonOperators.hpp | 1 + .../operatorMappings/TransposeOperator.cpp | 65 ++++++++++++++++++++++ .../operatorMappings/TransposeOperator.hpp | 20 +++++++ .../tosaCommon/test/OneToOneMappingTests.cpp | 58 +++++++++++++++++++ src/backends/tosaCommon/test/TosaTestUtils.hpp | 8 +++ src/backends/tosaReference/TosaRefLayerSupport.cpp | 2 +- .../tosaReference/test/TosaRefEndToEndTests.cpp | 7 +++ .../test/TosaRefLayerSupportTests.cpp | 42 ++++++++++++++ 10 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 src/backends/tosaCommon/operatorMappings/TransposeOperator.cpp create mode 100644 src/backends/tosaCommon/operatorMappings/TransposeOperator.hpp (limited to 'src') diff --git a/src/backends/tosaCommon/TosaMappings.cpp b/src/backends/tosaCommon/TosaMappings.cpp index b0f8fd9c2d..0b5fa1a158 100644 --- a/src/backends/tosaCommon/TosaMappings.cpp +++ b/src/backends/tosaCommon/TosaMappings.cpp @@ -79,6 +79,11 @@ TosaSerializationBasicBlock* GetTosaMapping(const Layer* layer, auto transposeConv2dDesc = PolymorphicDowncast(&descriptor); return ConvertTransposeConv2dToTosaOperator(layer, inputs, outputs, transposeConv2dDesc); } + case LayerType::Transpose: + { + auto transposeDesc = PolymorphicDowncast(&descriptor); + return ConvertTransposeToTosaOperator(layer, inputs, outputs, transposeDesc); + } default: { return CreateEmptyTosaSerializationBasicBlock(); diff --git a/src/backends/tosaCommon/operatorMappings/CMakeLists.txt b/src/backends/tosaCommon/operatorMappings/CMakeLists.txt index 6e897aaa8c..2ec052cd43 100644 --- a/src/backends/tosaCommon/operatorMappings/CMakeLists.txt +++ b/src/backends/tosaCommon/operatorMappings/CMakeLists.txt @@ -23,6 +23,8 @@ list(APPEND armnnTosaBackendOperators_sources TosaOperatorUtils.hpp TransposeConv2dOperator.hpp TransposeConv2dOperator.cpp + TransposeOperator.hpp + TransposeOperator.cpp ) add_library(armnnTosaBackendOperators OBJECT ${armnnTosaBackendOperators_sources}) diff --git a/src/backends/tosaCommon/operatorMappings/TosaCommonOperators.hpp b/src/backends/tosaCommon/operatorMappings/TosaCommonOperators.hpp index 7b117d8443..3f27371295 100644 --- a/src/backends/tosaCommon/operatorMappings/TosaCommonOperators.hpp +++ b/src/backends/tosaCommon/operatorMappings/TosaCommonOperators.hpp @@ -14,3 +14,4 @@ #include "ReshapeOperator.hpp" #include "SliceOperator.hpp" #include "TransposeConv2dOperator.hpp" +#include "TransposeOperator.hpp" diff --git a/src/backends/tosaCommon/operatorMappings/TransposeOperator.cpp b/src/backends/tosaCommon/operatorMappings/TransposeOperator.cpp new file mode 100644 index 0000000000..56178e428b --- /dev/null +++ b/src/backends/tosaCommon/operatorMappings/TransposeOperator.cpp @@ -0,0 +1,65 @@ +// +// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "TransposeOperator.hpp" + +TosaSerializationBasicBlock* ConvertTransposeToTosaOperator(const Layer* layer, + const std::vector& inputs, + const std::vector& outputs, + const TransposeDescriptor* transposeDescriptor) +{ + std::string input0Name = std::string("input0_"); + std::string outputName = std::string("output0_"); + std::string blockName = std::string("Op_TRANSPOSE_block_") + GetUniqueTosaMappingID(); + + // If a layer is present then the block will be used for execution, so input and output names need to be determined + // using the previous and following layers so the graph is connected correctly. For validation this doesn't matter. + if(layer != nullptr) + { + // Get the layers connected to the input slot and determine unique tensor name. + Layer& connectedLayer0 = layer->GetInputSlot(0).GetConnectedOutputSlot()->GetOwningLayer(); + input0Name = GenerateUniqueName(connectedLayer0, 0); + + // Determine unique output tensor name. + outputName = GenerateUniqueOutputName(*layer, 0); + } + + std::vector mappings(transposeDescriptor->m_DimMappings.begin(), + transposeDescriptor->m_DimMappings.end()); + TosaTransposeAttribute attribute(mappings); + + auto* op = new TosaSerializationOperator(Op_TRANSPOSE, + Attribute_TransposeAttribute, + &attribute, + {input0Name}, + {outputName}); + + + std::vector tensors; + + // Only add input tensors if connected layer is an input layer. + // As intermediate or constant tensors will be created separately. + // There also can't be duplicate tensor. + if(input0Name.find("input0_") != std::string::npos) + { + std::vector inputShape0 = GetTosaTensorShape(inputs[0]->GetShape()); + DType inputDType0 = ArmNNToDType(inputs[0]->GetDataType()); + + tensors.push_back(new TosaSerializationTensor(input0Name, inputShape0, inputDType0, {})); + } + + std::vector outputShape0 = GetTosaTensorShape(outputs[0]->GetShape()); + DType outputDType0 = ArmNNToDType(outputs[0]->GetDataType()); + + tensors.push_back(new TosaSerializationTensor(outputName, outputShape0, outputDType0, {})); + + // operatorInputNames/operatorOutputNames ends up being the same as + // blockInputNames/blockOutputNames for one-to-one ArmNN to TOSA mappings + return new TosaSerializationBasicBlock(blockName, // name + {op}, // operators + tensors, // tensors + {input0Name}, // inputs + {outputName}); // outputs +} \ No newline at end of file diff --git a/src/backends/tosaCommon/operatorMappings/TransposeOperator.hpp b/src/backends/tosaCommon/operatorMappings/TransposeOperator.hpp new file mode 100644 index 0000000000..3d1e2acd14 --- /dev/null +++ b/src/backends/tosaCommon/operatorMappings/TransposeOperator.hpp @@ -0,0 +1,20 @@ +// +// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include "TosaOperatorUtils.hpp" + +#include + +#include + +using namespace armnn; +using namespace tosa; + +TosaSerializationBasicBlock* ConvertTransposeToTosaOperator(const Layer* layer, + const std::vector& inputs, + const std::vector& outputs, + const TransposeDescriptor* transposeDescriptor); diff --git a/src/backends/tosaCommon/test/OneToOneMappingTests.cpp b/src/backends/tosaCommon/test/OneToOneMappingTests.cpp index 146a9cba37..4cc37918e5 100644 --- a/src/backends/tosaCommon/test/OneToOneMappingTests.cpp +++ b/src/backends/tosaCommon/test/OneToOneMappingTests.cpp @@ -664,6 +664,64 @@ TEST_CASE("GetTosaMappingFromLayer_TransposeConv2dLayer") LayerType::TransposeConvolution2d); } +TEST_CASE("GetTosaMapping_TransposeLayer") +{ + TensorInfo inputInfo = TensorInfo({ 1, 1, 5, 3 }, DataType::Float32, 0.0f, 0, true); + TensorInfo outputInfo = TensorInfo({ 1, 5, 1, 3 }, DataType::Float32, 0.0f, 0, true); + + std::vector> inputShape = {{ 1, 1, 5, 3 }}; + std::vector> outputShape = {{ 1, 5, 1, 3 }}; + + TransposeDescriptor transposeDescriptor = TransposeDescriptor({ 0, 2, 1 ,3 }); + + TosaSerializationBasicBlock* basicBlock = + GetTosaMapping(nullptr, LayerType::Transpose, {&inputInfo,}, {&outputInfo}, transposeDescriptor); + AssertTosaOneToOneMappingBasicBlock(basicBlock, + inputShape, + outputShape, + Op_TRANSPOSE, + Attribute_TransposeAttribute, + transposeDescriptor, + LayerType::Transpose); +} + +TEST_CASE("GetTosaMappingFromLayer_TransposeLayer") +{ + IRuntime::CreationOptions options; + IRuntimePtr runtime(IRuntime::Create(options)); + + // Builds up the structure of the network. + INetworkPtr net(INetwork::Create()); + + TransposeDescriptor transposeDescriptor = TransposeDescriptor({ 0, 2, 1 ,3 }); + + IConnectableLayer* input = net->AddInputLayer(0, "input0"); + IConnectableLayer* transpose = net->AddTransposeLayer(transposeDescriptor, "transpose"); + IConnectableLayer* output = net->AddOutputLayer(0, "output"); + + input->GetOutputSlot(0).Connect(transpose->GetInputSlot(0)); + transpose->GetOutputSlot(0).Connect(output->GetInputSlot(0)); + + TensorInfo inputInfo = TensorInfo({ 1, 1, 5, 3 }, DataType::Float32, 0.0f, 0, true); + TensorInfo outputInfo = TensorInfo({ 1, 5, 1, 3 }, DataType::Float32, 0.0f, 0, true); + + input->GetOutputSlot(0).SetTensorInfo(inputInfo); + transpose->GetOutputSlot(0).SetTensorInfo(outputInfo); + + std::vector> inputShape = {{ 1, 1, 5, 3 }}; + std::vector> outputShape = {{ 1, 5, 1, 3 }}; + + TosaSerializationBasicBlock* basicBlock = + GetTosaMappingFromLayer(PolymorphicDowncast(transpose)); + AssertTosaOneToOneMappingBasicBlock(basicBlock, + inputShape, + outputShape, + Op_TRANSPOSE, + Attribute_TransposeAttribute, + transposeDescriptor, + LayerType::Transpose); +} + TEST_CASE("GetTosaMapping_Unimplemented") { TosaSerializationBasicBlock* basicBlock = diff --git a/src/backends/tosaCommon/test/TosaTestUtils.hpp b/src/backends/tosaCommon/test/TosaTestUtils.hpp index 140cb83983..e24055371f 100644 --- a/src/backends/tosaCommon/test/TosaTestUtils.hpp +++ b/src/backends/tosaCommon/test/TosaTestUtils.hpp @@ -158,6 +158,14 @@ inline void VerifyTosaAttribute(const BaseDescriptor& descriptor, CHECK(stride == transposeConvAttribute.stride()); break; } + case LayerType::Transpose: + { + auto transposeDesc = PolymorphicDowncast(&descriptor); + std::vector outPerm(transposeDesc->m_DimMappings.begin(), transposeDesc->m_DimMappings.end()); + TosaTransposeAttribute transposeAttribute(attribute); + CHECK(outPerm == transposeAttribute.perms()); + break; + } default: break; } diff --git a/src/backends/tosaReference/TosaRefLayerSupport.cpp b/src/backends/tosaReference/TosaRefLayerSupport.cpp index b37ecc4ab7..6113b5861a 100644 --- a/src/backends/tosaReference/TosaRefLayerSupport.cpp +++ b/src/backends/tosaReference/TosaRefLayerSupport.cpp @@ -71,7 +71,7 @@ bool TosaRefLayerSupport::IsLayerSupported(const LayerType& type, case LayerType::Pooling2d: case LayerType::Reshape: case LayerType::Slice: - // Setup inputs and outputs + case LayerType::Transpose: inputInfos.push_back(&infos[0]); outputInfos.push_back(&infos[1]); break; diff --git a/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp b/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp index 67b87ae8b9..e19462e986 100644 --- a/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp +++ b/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp @@ -14,6 +14,7 @@ #include "backendsCommon/test/SliceEndToEndTestImpl.hpp" #include "backendsCommon/test/SubtractionEndToEndTestImpl.hpp" #include "backendsCommon/test/TransposeConvolution2dEndToEndTestImpl.hpp" +#include "backendsCommon/test/TransposeEndToEndTestImpl.hpp" #include @@ -195,4 +196,10 @@ TEST_CASE("TosaRefSimpleTransposeConvolution2dEndToEndFloatNhwcTest") tosaDefaultBackends, armnn::DataLayout::NHWC); } +// Transpose +TEST_CASE("TosaRefTransposeEndtoEndTestFloat32") +{ + TransposeEndToEnd(tosaDefaultBackends); +} + } \ No newline at end of file diff --git a/src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp b/src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp index 9119b13557..66dfbe8dff 100644 --- a/src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp +++ b/src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp @@ -509,4 +509,46 @@ TEST_CASE("IsLayerSupportedTosaReferenceTransposeConv2dUnsupported") CHECK(!supported); } +TEST_CASE("IsLayerSupportedTosaReferenceTranspose") +{ + TensorShape inShape = { 1, 1, 5, 3 }; + TensorShape outShape = { 1, 5, 1, 3 }; + TensorInfo in(inShape, DataType::Float32); + TensorInfo out(outShape, DataType::Float32); + + TransposeDescriptor transposeDescriptor = TransposeDescriptor({ 0, 2, 1 ,3 }); + + TosaRefLayerSupport supportChecker; + std::string reasonIfNotSupported; + auto supported = supportChecker.IsLayerSupported(LayerType::Transpose, + {in, out}, + transposeDescriptor, + EmptyOptional(), + EmptyOptional(), + reasonIfNotSupported); + + CHECK(supported); +} + +TEST_CASE("IsLayerSupportedTosaReferenceTransposeUnsupported") +{ + TensorShape inShape = { 1, 1, 5, 3 }; + TensorShape outShape = { 1, 5, 1, 3 }; + TensorInfo in(inShape, DataType::Signed64); + TensorInfo out(outShape, DataType::Signed64); + + TransposeDescriptor transposeDescriptor = TransposeDescriptor({ 0, 2, 1 ,3 }); + + TosaRefLayerSupport supportChecker; + std::string reasonIfNotSupported; + auto supported = supportChecker.IsLayerSupported(LayerType::Transpose, + {in, out}, + transposeDescriptor, + EmptyOptional(), + EmptyOptional(), + reasonIfNotSupported); + + CHECK(!supported); +} + } -- cgit v1.2.1