aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCathal Corbett <cathal.corbett@arm.com>2022-12-09 12:17:27 +0000
committerTeresaARM <teresa.charlinreyes@arm.com>2022-12-13 12:13:20 +0000
commit3b9acd515918ac1af5498b3e7501c0b16a88a8e0 (patch)
treea537cbdd7c45fea1772cbb34f8a23ecc7dbd6e1a
parent8107ccce5167f160b9c98a6042878dd0408220b5 (diff)
downloadarmnn-3b9acd515918ac1af5498b3e7501c0b16a88a8e0.tar.gz
IVGCVSW-7342 Add Slice support to TOSA Reference Backend
Signed-off-by: Cathal Corbett <cathal.corbett@arm.com> Change-Id: I8be286b69bebd4cd36033e3145632bb043938d16
-rw-r--r--src/backends/backendsCommon/test/CMakeLists.txt1
-rw-r--r--src/backends/backendsCommon/test/SliceEndToEndTestImpl.hpp99
-rw-r--r--src/backends/tosaCommon/TosaMappings.cpp5
-rw-r--r--src/backends/tosaCommon/operatorMappings/CMakeLists.txt2
-rw-r--r--src/backends/tosaCommon/operatorMappings/SliceOperator.cpp57
-rw-r--r--src/backends/tosaCommon/operatorMappings/SliceOperator.hpp20
-rw-r--r--src/backends/tosaCommon/operatorMappings/TosaCommonOperators.hpp3
-rw-r--r--src/backends/tosaCommon/test/OneToOneMappingTests.cpp63
-rw-r--r--src/backends/tosaCommon/test/TosaTestUtils.hpp21
-rw-r--r--src/backends/tosaReference/TosaRefLayerSupport.cpp19
-rw-r--r--src/backends/tosaReference/test/TosaRefEndToEndTests.cpp17
-rw-r--r--src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp52
12 files changed, 358 insertions, 1 deletions
diff --git a/src/backends/backendsCommon/test/CMakeLists.txt b/src/backends/backendsCommon/test/CMakeLists.txt
index 881e4d6e18..5fcc8b592e 100644
--- a/src/backends/backendsCommon/test/CMakeLists.txt
+++ b/src/backends/backendsCommon/test/CMakeLists.txt
@@ -52,6 +52,7 @@ list(APPEND armnnBackendsCommonUnitTests_sources
ReshapeEndToEndTestImpl.hpp
ResizeEndToEndTestImpl.hpp
RuntimeTestImpl.hpp
+ SliceEndToEndTestImpl.hpp
SpaceToDepthEndToEndTestImpl.cpp
SpaceToDepthEndToEndTestImpl.hpp
SplitterEndToEndTestImpl.hpp
diff --git a/src/backends/backendsCommon/test/SliceEndToEndTestImpl.hpp b/src/backends/backendsCommon/test/SliceEndToEndTestImpl.hpp
new file mode 100644
index 0000000000..811ce27b79
--- /dev/null
+++ b/src/backends/backendsCommon/test/SliceEndToEndTestImpl.hpp
@@ -0,0 +1,99 @@
+//
+// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+
+#include <armnn/INetwork.hpp>
+
+#include <CommonTestUtils.hpp>
+#include <ResolveType.hpp>
+
+#include <doctest/doctest.h>
+
+namespace
+{
+
+template<typename armnn::DataType DataType>
+armnn::INetworkPtr CreateSliceNetwork(const armnn::TensorShape& inputShape,
+ const armnn::TensorShape& outputShape,
+ const armnn::SliceDescriptor& descriptor,
+ const float qScale = 1.0f,
+ const int32_t qOffset = 0)
+{
+ using namespace armnn;
+
+ INetworkPtr network(INetwork::Create());
+
+ TensorInfo inputTensorInfo(inputShape, DataType, qScale, qOffset, true);
+ TensorInfo outputTensorInfo(outputShape, DataType, qScale, qOffset);
+
+
+ IConnectableLayer* slice = network->AddSliceLayer(descriptor, "slice");
+ IConnectableLayer* input = network->AddInputLayer(0, "input");
+ IConnectableLayer* output = network->AddOutputLayer(0, "output");
+
+ Connect(input, slice, inputTensorInfo, 0, 0);
+ Connect(slice, output, outputTensorInfo, 0, 0);
+
+ return network;
+}
+
+template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
+void SliceEndToEnd(const std::vector<armnn::BackendId>& backends)
+{
+ using namespace armnn;
+
+ const TensorShape& inputShape = { 3, 2, 3 };
+ const TensorShape& outputShape = { 2, 1, 3 };
+
+ SliceDescriptor descriptor;
+ descriptor.m_Begin = { 1, 0, 0 };
+ descriptor.m_Size = { 2, 1, 3 };
+
+ INetworkPtr network = CreateSliceNetwork<ArmnnType>(inputShape, outputShape, descriptor);
+
+ CHECK(network);
+
+ std::vector<T> inputData{ 1, 1, 1, 2, 2, 2,
+ 3, 3, 3, 4, 4, 4,
+ 5, 5, 5, 6, 6, 6 };
+ std::vector<T> expectedOutput{ 3, 3, 3,
+ 5, 5, 5 };
+
+ 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 SliceEndToEndFloat16(const std::vector<armnn::BackendId>& backends)
+{
+ using namespace armnn;
+ using namespace half_float::literal;
+ using Half = half_float::half;
+
+ const TensorShape& inputShape = { 3, 2, 3 };
+ const TensorShape& outputShape = { 2, 1, 3 };
+
+ SliceDescriptor descriptor;
+ descriptor.m_Begin = { 1, 0, 0 };
+ descriptor.m_Size = { 2, 1, 3 };
+
+ INetworkPtr network = CreateSliceNetwork<ArmnnType>(inputShape, outputShape, descriptor);
+ CHECK(network);
+
+ std::vector<Half> inputData{ 1._h, 1._h, 1._h, 2._h, 2._h, 2._h,
+ 3._h, 3._h, 3._h, 4._h, 4._h, 4._h,
+ 5._h, 5._h, 5._h, 6._h, 6._h, 6._h };
+ std::vector<Half> expectedOutput{ 3._h, 3._h, 3._h,
+ 5._h, 5._h, 5._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);
+}
+
+} // anonymous namespace \ No newline at end of file
diff --git a/src/backends/tosaCommon/TosaMappings.cpp b/src/backends/tosaCommon/TosaMappings.cpp
index 318735db77..15629ffab0 100644
--- a/src/backends/tosaCommon/TosaMappings.cpp
+++ b/src/backends/tosaCommon/TosaMappings.cpp
@@ -62,6 +62,11 @@ TosaSerializationBasicBlock* GetTosaMapping(const Layer* layer,
auto reshapeDesc = PolymorphicDowncast<const ReshapeDescriptor*>(&descriptor);
return ConvertReshapeToTosaOperator(layer, inputs, outputs, reshapeDesc);
}
+ case LayerType::Slice:
+ {
+ auto sliceDesc = PolymorphicDowncast<const SliceDescriptor*>(&descriptor);
+ return ConvertSliceToTosaOperator(layer, inputs, outputs, sliceDesc);
+ }
default:
{
return CreateEmptyTosaSerializationBasicBlock();
diff --git a/src/backends/tosaCommon/operatorMappings/CMakeLists.txt b/src/backends/tosaCommon/operatorMappings/CMakeLists.txt
index 7733d01abb..cb1d68e625 100644
--- a/src/backends/tosaCommon/operatorMappings/CMakeLists.txt
+++ b/src/backends/tosaCommon/operatorMappings/CMakeLists.txt
@@ -16,6 +16,8 @@ list(APPEND armnnTosaBackendOperators_sources
Pooling2DOperator.cpp
ReshapeOperator.hpp
ReshapeOperator.cpp
+ SliceOperator.hpp
+ SliceOperator.cpp
TosaOperatorUtils.hpp
)
diff --git a/src/backends/tosaCommon/operatorMappings/SliceOperator.cpp b/src/backends/tosaCommon/operatorMappings/SliceOperator.cpp
new file mode 100644
index 0000000000..fc2e40a95c
--- /dev/null
+++ b/src/backends/tosaCommon/operatorMappings/SliceOperator.cpp
@@ -0,0 +1,57 @@
+//
+// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "SliceOperator.hpp"
+
+TosaSerializationBasicBlock* ConvertSliceToTosaOperator(const Layer* layer,
+ const std::vector<const TensorInfo*>& inputs,
+ const std::vector<const TensorInfo*>& outputs,
+ const SliceDescriptor* sliceDescriptor)
+{
+ std::string inputName = std::string("input0_");
+ std::string outputName = std::string("output0_");
+ std::string blockName = std::string("Op_SLICE_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 slots and determine unique layer names.
+ Layer& connectedLayer = layer->GetInputSlot(0).GetConnectedOutputSlot()->GetOwningLayer();
+ inputName = GenerateUniqueName(connectedLayer, 0);
+
+ // Get the layer connected to the output slot and determine unique layer name.
+ Layer& connectedOutputLayer = layer->GetOutputSlot().GetConnection(0)->GetOwningLayer();
+ outputName = GenerateUniqueName(connectedOutputLayer, 0);
+ }
+
+ std::vector<int32_t> begin(sliceDescriptor->m_Begin.begin(), sliceDescriptor->m_Begin.end());
+ std::vector<int32_t> size(sliceDescriptor->m_Size.begin(), sliceDescriptor->m_Size.end());
+
+ TosaSliceAttribute attribute(begin, size);
+
+ auto* op = new TosaSerializationOperator(Op_SLICE,
+ Attribute_SliceAttribute,
+ &attribute,
+ {inputName},
+ {outputName});
+
+ 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());
+
+ auto* inputTensor = new TosaSerializationTensor(inputName, inputShape, inputDType, {});
+ auto* outputTensor = new TosaSerializationTensor(outputName, 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
+ {op}, // operators
+ {inputTensor, outputTensor}, // tensors
+ {inputName}, // inputs
+ {outputName}); // outputs
+} \ No newline at end of file
diff --git a/src/backends/tosaCommon/operatorMappings/SliceOperator.hpp b/src/backends/tosaCommon/operatorMappings/SliceOperator.hpp
new file mode 100644
index 0000000000..127cc81255
--- /dev/null
+++ b/src/backends/tosaCommon/operatorMappings/SliceOperator.hpp
@@ -0,0 +1,20 @@
+//
+// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include "TosaOperatorUtils.hpp"
+
+#include <Layer.hpp>
+
+#include <tosa_serialization_handler.h>
+
+using namespace armnn;
+using namespace tosa;
+
+TosaSerializationBasicBlock* ConvertSliceToTosaOperator(const Layer* layer,
+ const std::vector<const TensorInfo*>& inputs,
+ const std::vector<const TensorInfo*>& outputs,
+ const SliceDescriptor* sliceDescriptor); \ No newline at end of file
diff --git a/src/backends/tosaCommon/operatorMappings/TosaCommonOperators.hpp b/src/backends/tosaCommon/operatorMappings/TosaCommonOperators.hpp
index 0711095a25..a3597f0461 100644
--- a/src/backends/tosaCommon/operatorMappings/TosaCommonOperators.hpp
+++ b/src/backends/tosaCommon/operatorMappings/TosaCommonOperators.hpp
@@ -10,4 +10,5 @@
#include "Conv2dOperator.hpp"
#include "AvgPool2DIgnoreValueOperator.hpp"
#include "Pooling2DOperator.hpp"
-#include "ReshapeOperator.hpp" \ No newline at end of file
+#include "ReshapeOperator.hpp"
+#include "SliceOperator.hpp" \ No newline at end of file
diff --git a/src/backends/tosaCommon/test/OneToOneMappingTests.cpp b/src/backends/tosaCommon/test/OneToOneMappingTests.cpp
index b1fa6847bc..07ffae41d1 100644
--- a/src/backends/tosaCommon/test/OneToOneMappingTests.cpp
+++ b/src/backends/tosaCommon/test/OneToOneMappingTests.cpp
@@ -375,6 +375,69 @@ TEST_CASE("GetTosaMappingFromLayer_ReshapeLayer")
LayerType::Reshape);
}
+TEST_CASE("GetTosaMapping_SliceLayer")
+{
+ TensorInfo inputInfo = TensorInfo({ 3, 2, 3 }, DataType::Float32);
+ TensorInfo outputInfo = TensorInfo({ 2, 1, 3 }, DataType::Float32);
+
+ std::vector<std::vector<int32_t>> inputShape = {{ 3, 2, 3 }};
+ std::vector<std::vector<int32_t>> outputShape = {{ 2, 1, 3 }};
+
+ SliceDescriptor descriptor;
+ descriptor.m_Begin = { 3 };
+ descriptor.m_Size = { 3 };
+
+ TosaSerializationBasicBlock* basicBlock =
+ GetTosaMapping(nullptr, LayerType::Slice, {&inputInfo}, {&outputInfo}, descriptor);
+ AssertTosaOneToOneMappingBasicBlock(basicBlock,
+ inputShape,
+ outputShape,
+ Op_SLICE,
+ Attribute_SliceAttribute,
+ descriptor,
+ LayerType::Slice);
+}
+
+TEST_CASE("GetTosaMappingFromLayer_SliceLayer")
+{
+ IRuntime::CreationOptions options;
+ IRuntimePtr runtime(IRuntime::Create(options));
+
+ // Builds up the structure of the network.
+ INetworkPtr net(INetwork::Create());
+
+ TensorInfo inputInfo = TensorInfo({ 3, 2, 3 }, DataType::Float32);
+ TensorInfo outputInfo = TensorInfo({ 2, 1, 3 }, DataType::Float32);
+
+ std::vector<std::vector<int32_t>> inputShape = {{ 3, 2, 3 }};
+ std::vector<std::vector<int32_t>> outputShape = {{ 2, 1, 3 }};
+
+ SliceDescriptor descriptor;
+ descriptor.m_Begin = { 1, 0, 0 };
+ descriptor.m_Size = { 2, 1, 3 };
+
+ IConnectableLayer* input = net->AddInputLayer(0, "input");
+ IConnectableLayer* slice = net->AddSliceLayer(descriptor, "slice");
+ IConnectableLayer* output = net->AddOutputLayer(0, "output");
+
+ input->GetOutputSlot(0).Connect(slice->GetInputSlot(0));
+ slice->GetOutputSlot(0).Connect(output->GetInputSlot(0));
+
+ input->GetOutputSlot(0).SetTensorInfo(inputInfo);
+ slice->GetOutputSlot(0).SetTensorInfo(outputInfo);
+
+ TosaSerializationBasicBlock* basicBlock =
+ GetTosaMappingFromLayer(PolymorphicDowncast<Layer*>(slice));
+ AssertTosaOneToOneMappingBasicBlock(basicBlock,
+ inputShape,
+ outputShape,
+ Op_SLICE,
+ Attribute_SliceAttribute,
+ descriptor,
+ LayerType::Slice);
+}
+
+
TEST_CASE("GetTosaMapping_Unimplemented")
{
TosaSerializationBasicBlock* basicBlock =
diff --git a/src/backends/tosaCommon/test/TosaTestUtils.hpp b/src/backends/tosaCommon/test/TosaTestUtils.hpp
index 5c10a6d638..93b9e7d36f 100644
--- a/src/backends/tosaCommon/test/TosaTestUtils.hpp
+++ b/src/backends/tosaCommon/test/TosaTestUtils.hpp
@@ -122,6 +122,27 @@ inline void VerifyTosaAttribute(const BaseDescriptor& descriptor,
1,
std::multiplies<int32_t>());
CHECK(numInputElements == numAttributeShapeElements);
+
+ break;
+ }
+ case LayerType::Slice:
+ {
+ auto sliceDesc = PolymorphicDowncast<const SliceDescriptor*>(&descriptor);
+ TosaSliceAttribute reshapeAttribute(attribute);
+
+ std::vector<int32_t> begin(sliceDesc->m_Begin.begin(), sliceDesc->m_Begin.end());
+ std::vector<int32_t> size(sliceDesc->m_Size.begin(), sliceDesc->m_Size.end());
+
+ CHECK(begin == reshapeAttribute.start());
+ CHECK(size == reshapeAttribute.size());
+
+ CHECK(begin.size() == inputShape.size());
+ CHECK(size.size() == inputShape.size());
+
+ CHECK(begin.size() == outputShape.size());
+ CHECK(size.size() == outputShape.size());
+
+ break;
}
default:
break;
diff --git a/src/backends/tosaReference/TosaRefLayerSupport.cpp b/src/backends/tosaReference/TosaRefLayerSupport.cpp
index 5cda85af20..daa27f63dc 100644
--- a/src/backends/tosaReference/TosaRefLayerSupport.cpp
+++ b/src/backends/tosaReference/TosaRefLayerSupport.cpp
@@ -303,6 +303,24 @@ static bool IsTosaLayerSupported(TosaSerializationOperator* op,
return RunTosaLayerChecksSingleDataType(
op, inputs, outputs, supportedAttributes, supportedTypes, reasonIfUnsupported);
}
+ case tosa::Op_SLICE:
+ {
+ std::vector<Attribute> supportedAttributes = { Attribute_SliceAttribute };
+
+ 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.");
return false;
@@ -351,6 +369,7 @@ bool TosaRefLayerSupport::IsLayerSupported(const LayerType& type,
}
case LayerType::Pooling2d:
case LayerType::Reshape:
+ case LayerType::Slice:
// Setup inputs and outputs
inputInfos.push_back(&infos[0]);
outputInfos.push_back(&infos[1]);
diff --git a/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp b/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp
index aaf8a678e3..2f1231013a 100644
--- a/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp
+++ b/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp
@@ -9,6 +9,7 @@
#include "backendsCommon/test/Convolution2dEndToEndTestImpl.hpp"
#include "backendsCommon/test/Pooling2dEndToEndTestImpl.hpp"
#include "backendsCommon/test/ReshapeEndToEndTestImpl.hpp"
+#include "backendsCommon/test/SliceEndToEndTestImpl.hpp"
#include <doctest/doctest.h>
@@ -91,4 +92,20 @@ TEST_CASE("TosaRefReshapeEndtoEndTestFloat16")
ReshapeEndToEndFloat16<DataType::Float16>(tosaDefaultBackends);
}
+// Slice
+TEST_CASE("TosaRefSliceEndtoEndTestFloat32")
+{
+ SliceEndToEnd<DataType::Float32>(tosaDefaultBackends);
+}
+
+TEST_CASE("TosaRefSliceEndtoEndTestInt32")
+{
+ SliceEndToEnd<DataType::Signed32>(tosaDefaultBackends);
+}
+
+TEST_CASE("TosaRefSliceEndtoEndTestFloat16")
+{
+ SliceEndToEndFloat16<DataType::Float16>(tosaDefaultBackends);
+}
+
} \ No newline at end of file
diff --git a/src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp b/src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp
index 86b01d8d0c..a1bab83e72 100644
--- a/src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp
+++ b/src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp
@@ -329,4 +329,56 @@ TEST_CASE("IsLayerSupportedTosaReferenceReshapeUnsupported")
"has an unsupported data type: DType_UNKNOWN") != std::string::npos);
}
+TEST_CASE("IsLayerSupportedTosaReferenceSlice")
+{
+ TensorShape inShape = {3,2,3};
+ TensorShape outShape = {2,1,3};
+ TensorInfo in(inShape, DataType::Float32);
+ TensorInfo out(outShape, DataType::Float32);
+
+ SliceDescriptor descriptor;
+ descriptor.m_Begin = {1,0,0 };
+ descriptor.m_Size = {2,1,3 };
+
+ TosaRefLayerSupport supportChecker;
+ std::string reasonIfNotSupported;
+ auto supported = supportChecker.IsLayerSupported(LayerType::Slice,
+ {in, out},
+ descriptor,
+ EmptyOptional(),
+ EmptyOptional(),
+ reasonIfNotSupported);
+
+ CHECK(supported);
+}
+
+TEST_CASE("IsLayerSupportedTosaReferenceSliceUnsupported")
+{
+ TensorShape inShape = {3,2,3};
+ TensorShape outShape = {2,1,3};
+ TensorInfo in(inShape, DataType::Signed64);
+ TensorInfo out(outShape, DataType::Signed64);
+
+ SliceDescriptor descriptor;
+ descriptor.m_Begin = {1,0,0};
+ descriptor.m_Size = {2,1,3};
+
+ TosaRefLayerSupport supportChecker;
+ std::string reasonIfNotSupported;
+ auto supported = supportChecker.IsLayerSupported(LayerType::Slice,
+ {in, out},
+ descriptor,
+ EmptyOptional(),
+ EmptyOptional(),
+ reasonIfNotSupported);
+
+ CHECK(!supported);
+ REQUIRE(reasonIfNotSupported.find(
+ "TOSA Reference Operator: Op_SLICE for input: input0_") != std::string::npos);
+ REQUIRE(reasonIfNotSupported.find(
+ "TOSA Reference Operator: Op_SLICE for output: output0_") != std::string::npos);
+ REQUIRE(reasonIfNotSupported.find(
+ "has an unsupported data type: DType_UNKNOWN") != std::string::npos);
+}
+
}