From 944fb508b1c30415e423b8916849c66a13867ea4 Mon Sep 17 00:00:00 2001 From: Tracy Narine Date: Tue, 4 Jul 2023 15:08:57 +0100 Subject: IVGCVSW-7832 Add REVERSE_V2 to Serializer and Deserializer * Support for ReverseV2 for the serializer and deserializer added * Tests added * CMake files updated for the build * Fixed an issue with the operator_list documentation for Resize and ReverseV2 Signed-off-by: Tracy Narine Change-Id: If396f55ecdd763d6f91c51707809f4bd58715cec --- CMakeLists.txt | 1 + docs/02_operator_list.dox | 48 ++-- docs/05_02_deserializer_serializer.dox | 6 +- src/armnnDeserializer/Deserializer.cpp | 29 +++ src/armnnDeserializer/Deserializer.hpp | 3 +- .../test/DeserializeReverseV2.cpp | 251 +++++++++++++++++++++ src/armnnSerializer/ArmnnSchema.fbs | 11 + src/armnnSerializer/Serializer.cpp | 26 +++ src/armnnSerializer/Serializer.hpp | 4 + src/armnnSerializer/test/SerializerTests.cpp | 29 ++- 10 files changed, 381 insertions(+), 27 deletions(-) create mode 100644 src/armnnDeserializer/test/DeserializeReverseV2.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 537455d3b3..6dae8e485f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -819,6 +819,7 @@ if(BUILD_UNIT_TESTS) src/armnnDeserializer/test/DeserializeReduceSum.cpp src/armnnDeserializer/test/DeserializeReshape.cpp src/armnnDeserializer/test/DeserializeResizeBilinear.cpp + src/armnnDeserializer/test/DeserializeReverseV2.cpp src/armnnDeserializer/test/DeserializeRsqrt.cpp src/armnnDeserializer/test/DeserializeShape.cpp src/armnnDeserializer/test/DeserializeSlice.cpp diff --git a/docs/02_operator_list.dox b/docs/02_operator_list.dox index d329901af9..8fa6178aff 100644 --- a/docs/02_operator_list.dox +++ b/docs/02_operator_list.dox @@ -2781,12 +2781,27 @@ where N = batches, C = channels, H = height, W = width FLOAT16 FLOAT32 + + GpuAcc + + + + +
+
QASYMMU8 +
QASYMMS8 +
FLOAT16 +
FLOAT32 +
ReverseV2Layer - Layer to perform ReverseV2 operations. + Layer to perform reverse of a tensor. CpuRef @@ -2807,36 +2822,23 @@ where N = batches, C = channels, H = height, W = width CpuAcc - - - - GpuAcc - - - + +
+
All +
GpuAcc
-
QASYMMU8 -
QASYMMS8 -
FLOAT16 -
FLOAT32 +
All
RsqrtLayer @@ -3505,4 +3507,4 @@ where N = batches, C = channels, H = height, W = width */ -} // namespace \ No newline at end of file +} // namespace diff --git a/docs/05_02_deserializer_serializer.dox b/docs/05_02_deserializer_serializer.dox index c36e010323..ab821b8d66 100644 --- a/docs/05_02_deserializer_serializer.dox +++ b/docs/05_02_deserializer_serializer.dox @@ -1,4 +1,4 @@ -/// Copyright (c) 2021 ARM Limited and Contributors. All rights reserved. +/// Copyright (c) 2021-2023 ARM Limited and Contributors. All rights reserved. /// /// SPDX-License-Identifier: MIT /// @@ -68,6 +68,7 @@ The Arm NN SDK Serializer currently supports the following layers: - Reduce - Reshape - Resize +- ReverseV2 - Shape - Slice - Softmax @@ -161,6 +162,7 @@ The Arm NN SDK Deserialize parser currently supports the following layers: - Reshape - Resize - ResizeBilinear +- ReverseV2 - Slice - Softmax - SpaceToBatchNd @@ -187,4 +189,4 @@ Some layers have been deprecated and replaced by others layers. In order to main - ResizeBilinear will deserialize as Resize **/ -} \ No newline at end of file +} diff --git a/src/armnnDeserializer/Deserializer.cpp b/src/armnnDeserializer/Deserializer.cpp index 79cc3987d5..e940bd69ec 100644 --- a/src/armnnDeserializer/Deserializer.cpp +++ b/src/armnnDeserializer/Deserializer.cpp @@ -263,6 +263,7 @@ m_ParserFunctions(Layer_MAX+1, &IDeserializer::DeserializerImpl::ParseUnsupporte m_ParserFunctions[Layer_ReshapeLayer] = &DeserializerImpl::ParseReshape; m_ParserFunctions[Layer_ResizeBilinearLayer] = &DeserializerImpl::ParseResizeBilinear; m_ParserFunctions[Layer_ResizeLayer] = &DeserializerImpl::ParseResize; + m_ParserFunctions[Layer_ReverseV2Layer] = &DeserializerImpl::ParseReverseV2; m_ParserFunctions[Layer_RsqrtLayer] = &DeserializerImpl::ParseRsqrt; m_ParserFunctions[Layer_ShapeLayer] = &DeserializerImpl::ParseShape; m_ParserFunctions[Layer_SliceLayer] = &DeserializerImpl::ParseSlice; @@ -396,6 +397,8 @@ LayerBaseRawPtr IDeserializer::DeserializerImpl::GetBaseLayer(const GraphPtr& gr return graphPtr->layers()->Get(layerIndex)->layer_as_ResizeBilinearLayer()->base(); case Layer::Layer_ResizeLayer: return graphPtr->layers()->Get(layerIndex)->layer_as_ResizeLayer()->base(); + case Layer::Layer_ReverseV2Layer: + return graphPtr->layers()->Get(layerIndex)->layer_as_ReverseV2Layer()->base(); case Layer::Layer_RsqrtLayer: return graphPtr->layers()->Get(layerIndex)->layer_as_RsqrtLayer()->base(); case Layer::Layer_ShapeLayer: @@ -2734,6 +2737,32 @@ void IDeserializer::DeserializerImpl::ParseResize(GraphPtr graph, unsigned int l RegisterOutputSlots(graph, layerIndex, layer); } +void IDeserializer::DeserializerImpl::ParseReverseV2(GraphPtr graph, unsigned int layerIndex) +{ + CHECK_LAYERS(graph, 0, layerIndex); + + TensorRawPtrVector inputs = GetInputs(graph, layerIndex); + CHECK_VALID_SIZE(inputs.size(), 1); + + TensorRawPtrVector outputs = GetOutputs(graph, layerIndex); + CHECK_VALID_SIZE(outputs.size(), 1); + + auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_ReverseV2Layer()->descriptor(); + auto flatBufferAxis = flatBufferDescriptor->axis(); + + armnn::ReverseV2Descriptor descriptor; + descriptor.m_Axis = + std::vector(flatBufferAxis->begin(), flatBufferAxis->end()); + + auto layerName = GetLayerName(graph, layerIndex); + IConnectableLayer* layer = m_Network->AddReverseV2Layer(descriptor, layerName.c_str()); + + armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); + layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); + + RegisterInputSlots(graph, layerIndex, layer); + RegisterOutputSlots(graph, layerIndex, layer); +} /// @Note The ResizeBiliniar operation was deprecated and removed in favor of the Resize operation. /// This function is kept for backwards compatibility. diff --git a/src/armnnDeserializer/Deserializer.hpp b/src/armnnDeserializer/Deserializer.hpp index b75c68db0c..b4b93e6fe1 100644 --- a/src/armnnDeserializer/Deserializer.hpp +++ b/src/armnnDeserializer/Deserializer.hpp @@ -136,6 +136,7 @@ private: void ParseReshape(GraphPtr graph, unsigned int layerIndex); void ParseResize(GraphPtr graph, unsigned int layerIndex); void ParseResizeBilinear(GraphPtr graph, unsigned int layerIndex); + void ParseReverseV2(GraphPtr graph, unsigned int layerIndex); void ParseRsqrt(GraphPtr graph, unsigned int layerIndex); void ParseShape(GraphPtr graph, unsigned int layerIndex); void ParseSlice(GraphPtr graph, unsigned int layerIndex); @@ -212,4 +213,4 @@ private: std::unordered_map m_GraphConnections; }; -} // namespace armnnDeserializer \ No newline at end of file +} // namespace armnnDeserializer diff --git a/src/armnnDeserializer/test/DeserializeReverseV2.cpp b/src/armnnDeserializer/test/DeserializeReverseV2.cpp new file mode 100644 index 0000000000..73816f8588 --- /dev/null +++ b/src/armnnDeserializer/test/DeserializeReverseV2.cpp @@ -0,0 +1,251 @@ +// +// Copyright © 2023 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "ParserFlatbuffersSerializeFixture.hpp" +#include + +#include + +#include + +TEST_SUITE("Deserializer_ReverseV2") +{ + struct ReverseV2Fixture : public ParserFlatbuffersSerializeFixture + { + explicit ReverseV2Fixture(const std::string& inputShape, + const std::string& outputShape, + const std::string& dataType, + const std::string& axis) + { + m_JsonString = R"( + { + inputIds: [0], + outputIds: [2], + layers: [ + { + layer_type: "InputLayer", + layer: { + base: { + layerBindingId: 0, + base: { + index: 0, + layerName: "InputLayer", + layerType: "Input", + inputSlots: [{ + index: 0, + connection: {sourceLayerIndex:0, outputSlotIndex:0 }, + }], + outputSlots: [{ + index: 0, + tensorInfo: { + dimensions: )" + inputShape + R"(, + dataType: )" + dataType + R"( + } + }] + } + } + } + }, + { + layer_type: "ReverseV2Layer", + layer: { + base: { + index: 1, + layerName: "ReverseV2Layer", + layerType: "ReverseV2", + inputSlots: [{ + index: 0, + connection: {sourceLayerIndex:0, outputSlotIndex:0 }, + }], + outputSlots: [{ + index: 0, + tensorInfo: { + dimensions: )" + outputShape + R"(, + dataType: )" + dataType + R"( + } + }] + }, + descriptor: { + axis: )" + axis + R"( + } + } + }, + { + layer_type: "OutputLayer", + layer: { + base:{ + layerBindingId: 2, + base: { + index: 2, + layerName: "OutputLayer", + layerType: "Output", + inputSlots: [{ + index: 0, + connection: {sourceLayerIndex:1, outputSlotIndex:0 }, + }], + outputSlots: [{ + index: 0, + tensorInfo: { + dimensions: )" + outputShape + R"(, + dataType: )" + dataType + R"( + }, + }], + } + } + } + } + ] + } + )"; + + SetupSingleInputSingleOutput("InputLayer", "OutputLayer"); + } + }; + + // Test cases + + struct SimpleReverseV2FixtureFloat32 : ReverseV2Fixture + { + SimpleReverseV2FixtureFloat32() + : ReverseV2Fixture("[ 2, 2 ]", + "[ 2, 2 ]", + "Float32", + "[1]") + {} + }; + + TEST_CASE_FIXTURE(SimpleReverseV2FixtureFloat32, "SimpleReverseV2TestFloat32") + { + RunTest<4, armnn::DataType::Float32>( + 0, + { 1.0f, 2.0f, + 3.0f, 4.0f }, + { 2.0f, 1.0f, + 4.0f, 3.0f } + ); + } + + struct SimpleReverseV2FixtureFloat32ZeroAxis : ReverseV2Fixture + { + SimpleReverseV2FixtureFloat32ZeroAxis() + : ReverseV2Fixture("[ 2, 2 ]", + "[ 2, 2 ]", + "Float32", + "[0]") + {} + }; + + TEST_CASE_FIXTURE(SimpleReverseV2FixtureFloat32ZeroAxis, "SimpleReverseV2TestFloat32ZeroAxis") + { + RunTest<4, armnn::DataType::Float32>( + 0, + { 1.0f, 2.0f, + 3.0f, 4.0f }, + { 3.0f, 4.0f, + 1.0f, 2.0f } + ); + } + + struct SimpleReverseV2FixtureFloat32NegativeAxis : ReverseV2Fixture + { + SimpleReverseV2FixtureFloat32NegativeAxis() + : ReverseV2Fixture("[ 3, 3 ]", + "[ 3, 3 ]", + "Float32", + "[-1]") + {} + }; + + TEST_CASE_FIXTURE(SimpleReverseV2FixtureFloat32NegativeAxis, "SimpleReverseV2TestFloat32NegativeAxis") + { + RunTest<4, armnn::DataType::Float32>( + 0, + { 1.0f, 2.0f, 3.0f, + 4.0f, 5.0f, 6.0f, + 7.0f, 8.0f, 9.0f }, + { 3.0f, 2.0f, 1.0f, + 6.0f, 5.0f, 4.0f, + 9.0f, 8.0f, 7.0f } + ); + } + + struct SimpleReverseV2FixtureFloat32ThreeAxis : ReverseV2Fixture + { + SimpleReverseV2FixtureFloat32ThreeAxis() + : ReverseV2Fixture("[ 3, 3, 3 ]", + "[ 3, 3, 3 ]", + "Float32", + "[0, 2, 1]") + {} + }; + + TEST_CASE_FIXTURE(SimpleReverseV2FixtureFloat32ThreeAxis, "SimpleReverseV2TestFloat32ThreeAxis") + { + RunTest<4, armnn::DataType::Float32>( + 0, + { 1.0f, 2.0f, 3.0f, + 4.0f, 5.0f, 6.0f, + 7.0f, 8.0f, 9.0f, + + 11.0f, 12.0f, 13.0f, + 14.0f, 15.0f, 16.0f, + 17.0f, 18.0f, 19.0f, + + 21.0f, 22.0f, 23.0f, + 24.0f, 25.0f, 26.0f, + 27.0f, 28.0f, 29.0f }, + { 29.0f, 28.0f, 27.0f, + 26.0f, 25.0f, 24.0f, + 23.0f, 22.0f, 21.0f, + + 19.0f, 18.0f, 17.0f, + 16.0f, 15.0f, 14.0f, + 13.0f, 12.0f, 11.0f, + + 9.0f, 8.0f, 7.0f, + 6.0f, 5.0f, 4.0f, + 3.0f, 2.0f, 1.0f } + ); + } + + struct SimpleReverseV2FixtureQuantisedAsymm8ThreeAxis : ReverseV2Fixture + { + SimpleReverseV2FixtureQuantisedAsymm8ThreeAxis() + : ReverseV2Fixture("[ 3, 3, 3 ]", + "[ 3, 3, 3 ]", + "QuantisedAsymm8", + "[0, 2, 1]") + {} + }; + + TEST_CASE_FIXTURE(SimpleReverseV2FixtureQuantisedAsymm8ThreeAxis, "SimpleReverseV2TestQuantisedAsymm8ThreeAxis") + { + RunTest<4, armnn::DataType::QAsymmU8>( + 0, + { 1, 2, 3, + 4, 5, 6, + 7, 8, 9, + + 11, 12, 13, + 14, 15, 16, + 17, 18, 19, + + 21, 22, 23, + 24, 25, 26, + 27, 28, 29 }, + { 29, 28, 27, + 26, 25, 24, + 23, 22, 21, + + 19, 18, 17, + 16, 15, 14, + 13, 12, 11, + + 9, 8, 7, + 6, 5, 4, + 3, 2, 1 } + ); + } +} diff --git a/src/armnnSerializer/ArmnnSchema.fbs b/src/armnnSerializer/ArmnnSchema.fbs index 84149bd60d..76a1c12787 100644 --- a/src/armnnSerializer/ArmnnSchema.fbs +++ b/src/armnnSerializer/ArmnnSchema.fbs @@ -184,6 +184,7 @@ enum LayerType : uint { GatherNd = 67, BatchMatMul = 68, ElementwiseBinary = 69, + ReverseV2 = 70, } // Base layer table to be used as part of other layers @@ -979,6 +980,15 @@ table ResizeDescriptor { halfPixelCenters:bool; } +table ReverseV2Layer { + base:LayerBase; + descriptor:ReverseV2Descriptor; +} + +table ReverseV2Descriptor { + axis:[int]; +} + table StackLayer { base:LayerBase; descriptor:StackDescriptor; @@ -1117,6 +1127,7 @@ union Layer { GatherNdLayer, BatchMatMulLayer, ElementwiseBinaryLayer, + ReverseV2Layer, } table AnyLayer { diff --git a/src/armnnSerializer/Serializer.cpp b/src/armnnSerializer/Serializer.cpp index 5a095d9887..cf098eb5f8 100644 --- a/src/armnnSerializer/Serializer.cpp +++ b/src/armnnSerializer/Serializer.cpp @@ -1035,6 +1035,25 @@ void SerializerStrategy::SerializeResizeLayer(const armnn::IConnectableLayer* la CreateAnyLayer(flatBufferLayer.o, serializer::Layer::Layer_ResizeLayer); } +void SerializerStrategy::SerializeReverseV2Layer(const armnn::IConnectableLayer* layer, + const armnn::ReverseV2Descriptor& reverseV2Descriptor, + const char* name) +{ + IgnoreUnused(name); + + auto flatBufferBaseLayer = CreateLayerBase(layer, serializer::LayerType::LayerType_ReverseV2); + + auto flatBufferDescriptor = + CreateReverseV2Descriptor(m_flatBufferBuilder, + m_flatBufferBuilder.CreateVector(reverseV2Descriptor.m_Axis)); + + auto flatBufferLayer = serializer::CreateReverseV2Layer(m_flatBufferBuilder, + flatBufferBaseLayer, + flatBufferDescriptor); + + CreateAnyLayer(flatBufferLayer.o, serializer::Layer::Layer_ReverseV2Layer); +} + void SerializerStrategy::SerializeSliceLayer(const armnn::IConnectableLayer* layer, const armnn::SliceDescriptor& sliceDescriptor, const char* name) @@ -2332,6 +2351,13 @@ void SerializerStrategy::ExecuteStrategy(const armnn::IConnectableLayer* layer, SerializeResizeLayer(layer, layerDescriptor, name); break; } + case armnn::LayerType::ReverseV2: + { + const armnn::ReverseV2Descriptor& layerDescriptor = + static_cast(descriptor); + SerializeReverseV2Layer(layer, layerDescriptor, name); + break; + } case armnn::LayerType::Shape: { SerializeShapeLayer(layer, name); diff --git a/src/armnnSerializer/Serializer.hpp b/src/armnnSerializer/Serializer.hpp index 4d5e806db1..eb724752f2 100644 --- a/src/armnnSerializer/Serializer.hpp +++ b/src/armnnSerializer/Serializer.hpp @@ -289,6 +289,10 @@ private: const armnn::ResizeDescriptor& resizeDescriptor, const char* name = nullptr); + void SerializeReverseV2Layer(const armnn::IConnectableLayer* layer, + const armnn::ReverseV2Descriptor& reverseV2Descriptor, + const char* name = nullptr); + void SerializeSliceLayer(const armnn::IConnectableLayer* layer, const armnn::SliceDescriptor& sliceDescriptor, const char* name = nullptr); diff --git a/src/armnnSerializer/test/SerializerTests.cpp b/src/armnnSerializer/test/SerializerTests.cpp index bd8a76a103..7a988ee134 100644 --- a/src/armnnSerializer/test/SerializerTests.cpp +++ b/src/armnnSerializer/test/SerializerTests.cpp @@ -2453,6 +2453,33 @@ TEST_CASE("EnsureResizeBilinearBackwardCompatibility") deserializedNetwork->ExecuteStrategy(verifier); } +TEST_CASE("SerializeReverseV2") +{ + const std::string layerName("reverseV2"); + const armnn::TensorInfo inputInfo = armnn::TensorInfo({2, 3, 4}, armnn::DataType::Float32); + const armnn::TensorInfo outputInfo = armnn::TensorInfo({2, 3, 4}, armnn::DataType::Float32); + + armnn::ReverseV2Descriptor desc; + desc.m_Axis = {1, 0, 2}; + + armnn::INetworkPtr network = armnn::INetwork::Create(); + armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0); + armnn::IConnectableLayer* const reverseV2Layer = network->AddReverseV2Layer(desc, layerName.c_str()); + armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0); + + inputLayer->GetOutputSlot(0).Connect(reverseV2Layer->GetInputSlot(0)); + reverseV2Layer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); + + inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo); + reverseV2Layer->GetOutputSlot(0).SetTensorInfo(outputInfo); + + armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network)); + CHECK(deserializedNetwork); + + LayerVerifierBaseWithDescriptor verifier(layerName, {inputInfo}, {outputInfo}, desc); + deserializedNetwork->ExecuteStrategy(verifier); +} + TEST_CASE("SerializeShape") { const std::string layerName("shape"); @@ -2981,4 +3008,4 @@ TEST_CASE("SerializeDeserializeNonLinearNetwork") deserializedNetwork->ExecuteStrategy(verifier); } -} \ No newline at end of file +} -- cgit v1.2.1