From b5433ee34fd9d38c1453dc062b36348d65677002 Mon Sep 17 00:00:00 2001 From: Matthew Jackson Date: Thu, 11 Jul 2019 15:54:20 +0100 Subject: IVGCVSW-3420 Add Serialization support for the new Stack layer * Adds serialization/deserialization support * Adds related unit test Signed-off-by: Matthew Jackson Change-Id: I69deb5397b8a06c679715e24971e9bb1c282140d --- src/armnnDeserializer/Deserializer.cpp | 51 ++++++++++++++++++++++++ src/armnnDeserializer/Deserializer.hpp | 1 + src/armnnDeserializer/DeserializerSupport.md | 1 + src/armnnSerializer/ArmnnSchema.fbs | 17 +++++++- src/armnnSerializer/Serializer.cpp | 16 +++++++- src/armnnSerializer/SerializerSupport.md | 1 + src/armnnSerializer/test/SerializerTests.cpp | 59 ++++++++++++++++++++++++++++ 7 files changed, 143 insertions(+), 3 deletions(-) diff --git a/src/armnnDeserializer/Deserializer.cpp b/src/armnnDeserializer/Deserializer.cpp index 461208bf39..7f1831c989 100644 --- a/src/armnnDeserializer/Deserializer.cpp +++ b/src/armnnDeserializer/Deserializer.cpp @@ -223,6 +223,7 @@ m_ParserFunctions(Layer_MAX+1, &Deserializer::ParseUnsupportedLayer) m_ParserFunctions[Layer_SpaceToBatchNdLayer] = &Deserializer::ParseSpaceToBatchNd; m_ParserFunctions[Layer_SpaceToDepthLayer] = &Deserializer::ParseSpaceToDepth; m_ParserFunctions[Layer_SplitterLayer] = &Deserializer::ParseSplitter; + m_ParserFunctions[Layer_StackLayer] = &Deserializer::ParseStack; m_ParserFunctions[Layer_StridedSliceLayer] = &Deserializer::ParseStridedSlice; m_ParserFunctions[Layer_SubtractionLayer] = &Deserializer::ParseSubtraction; m_ParserFunctions[Layer_SwitchLayer] = &Deserializer::ParseSwitch; @@ -315,6 +316,8 @@ Deserializer::LayerBaseRawPtr Deserializer::GetBaseLayer(const GraphPtr& graphPt return graphPtr->layers()->Get(layerIndex)->layer_as_SpaceToDepthLayer()->base(); case Layer::Layer_SplitterLayer: return graphPtr->layers()->Get(layerIndex)->layer_as_SplitterLayer()->base(); + case Layer::Layer_StackLayer: + return graphPtr->layers()->Get(layerIndex)->layer_as_StackLayer()->base(); case Layer::Layer_StridedSliceLayer: return graphPtr->layers()->Get(layerIndex)->layer_as_StridedSliceLayer()->base(); case Layer::Layer_SubtractionLayer: @@ -2314,4 +2317,52 @@ void Deserializer::ParseTransposeConvolution2d(GraphPtr graph, unsigned int laye RegisterOutputSlots(graph, layerIndex, layer); } +void Deserializer::ParseStack(GraphPtr graph, unsigned int layerIndex) +{ + CHECK_LAYERS(graph, 0, layerIndex); + auto inputs = GetInputs(graph, layerIndex); + + auto outputs = GetOutputs(graph, layerIndex); + CHECK_VALID_SIZE(outputs.size(), 1); + + auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_StackLayer()->descriptor(); + unsigned int axis = flatBufferDescriptor->axis(); + unsigned int numInputs = flatBufferDescriptor->numInputs(); + CHECK_VALID_SIZE(inputs.size(), numInputs); + + auto flatBufferInputShape = flatBufferDescriptor->inputShape(); + std::vector vectorInputShape(flatBufferInputShape->begin(), + flatBufferInputShape->begin() + flatBufferInputShape->size()); + + TensorShape inputShape(static_cast(vectorInputShape.size()), vectorInputShape.data()); + armnn::StackDescriptor descriptor(axis, numInputs, inputShape); + + for (unsigned int i=0; iAddStackLayer(descriptor, layerName.c_str()); + + armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); + layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); + + RegisterInputSlots(graph, layerIndex, layer); + RegisterOutputSlots(graph, layerIndex, layer); +} + } // namespace armnnDeserializer diff --git a/src/armnnDeserializer/Deserializer.hpp b/src/armnnDeserializer/Deserializer.hpp index 6a63f0fb6a..b9d6a170a1 100644 --- a/src/armnnDeserializer/Deserializer.hpp +++ b/src/armnnDeserializer/Deserializer.hpp @@ -113,6 +113,7 @@ private: void ParseSpaceToBatchNd(GraphPtr graph, unsigned int layerIndex); void ParseSpaceToDepth(GraphPtr graph, unsigned int layerIndex); void ParseSplitter(GraphPtr graph, unsigned int layerIndex); + void ParseStack(GraphPtr graph, unsigned int layerIndex); void ParseStridedSlice(GraphPtr graph, unsigned int layerIndex); void ParseSubtraction(GraphPtr graph, unsigned int layerIndex); void ParseSwitch(GraphPtr graph, unsigned int layerIndex); diff --git a/src/armnnDeserializer/DeserializerSupport.md b/src/armnnDeserializer/DeserializerSupport.md index 1f51cd3fa0..698340bd31 100644 --- a/src/armnnDeserializer/DeserializerSupport.md +++ b/src/armnnDeserializer/DeserializerSupport.md @@ -42,6 +42,7 @@ The Arm NN SDK Deserialize parser currently supports the following layers: * SpaceToBatchNd * SpaceToDepth * Splitter +* Stack * StridedSlice * Subtraction * Switch diff --git a/src/armnnSerializer/ArmnnSchema.fbs b/src/armnnSerializer/ArmnnSchema.fbs index 09187927ae..e3953df83e 100644 --- a/src/armnnSerializer/ArmnnSchema.fbs +++ b/src/armnnSerializer/ArmnnSchema.fbs @@ -130,7 +130,8 @@ enum LayerType : uint { SpaceToDepth = 40, Prelu = 41, TransposeConvolution2d = 42, - Resize = 43 + Resize = 43, + Stack = 44 } // Base layer table to be used as part of other layers @@ -599,6 +600,17 @@ table ResizeDescriptor { dataLayout:DataLayout; } +table StackLayer { + base:LayerBase; + descriptor:StackDescriptor; +} + +table StackDescriptor { + axis:uint; + numInputs:uint; + inputShape:[uint]; +} + union Layer { ActivationLayer, AdditionLayer, @@ -643,7 +655,8 @@ union Layer { SpaceToDepthLayer, PreluLayer, TransposeConvolution2dLayer, - ResizeLayer + ResizeLayer, + StackLayer } table AnyLayer { diff --git a/src/armnnSerializer/Serializer.cpp b/src/armnnSerializer/Serializer.cpp index 0a9e3353d7..b59bac6041 100644 --- a/src/armnnSerializer/Serializer.cpp +++ b/src/armnnSerializer/Serializer.cpp @@ -929,7 +929,21 @@ void SerializerVisitor::VisitStackLayer(const armnn::IConnectableLayer* layer, const armnn::StackDescriptor& stackDescriptor, const char* name) { - throw UnimplementedException("SerializerVisitor::VisitStackLayer not yet implemented"); + auto stackBaseLayer = CreateLayerBase(layer, serializer::LayerType::LayerType_Stack); + + std::vector inputShape; + for (unsigned int i =0; i < stackDescriptor.m_InputShape.GetNumDimensions(); i++) + { + inputShape.push_back(stackDescriptor.m_InputShape[i]); + } + + auto flatBufferStackDescriptor = CreateStackDescriptor(m_flatBufferBuilder, + stackDescriptor.m_Axis, + stackDescriptor.m_NumInputs, + m_flatBufferBuilder.CreateVector(inputShape)); + + auto stackLayer = serializer::CreateStackLayer(m_flatBufferBuilder, stackBaseLayer, flatBufferStackDescriptor); + CreateAnyLayer(stackLayer.o, serializer::Layer::Layer_StackLayer); } void SerializerVisitor::VisitStridedSliceLayer(const armnn::IConnectableLayer* layer, diff --git a/src/armnnSerializer/SerializerSupport.md b/src/armnnSerializer/SerializerSupport.md index 924bab423f..1d47399376 100644 --- a/src/armnnSerializer/SerializerSupport.md +++ b/src/armnnSerializer/SerializerSupport.md @@ -42,6 +42,7 @@ The Arm NN SDK Serializer currently supports the following layers: * SpaceToBatchNd * SpaceToDepth * Splitter +* Stack * StridedSlice * Subtraction * Switch diff --git a/src/armnnSerializer/test/SerializerTests.cpp b/src/armnnSerializer/test/SerializerTests.cpp index 33f10ef435..3d74d88e30 100644 --- a/src/armnnSerializer/test/SerializerTests.cpp +++ b/src/armnnSerializer/test/SerializerTests.cpp @@ -2379,6 +2379,65 @@ BOOST_AUTO_TEST_CASE(SerializeSplitter) deserializedNetwork->Accept(verifier); } +BOOST_AUTO_TEST_CASE(SerializeStack) +{ + class StackLayerVerifier : public LayerVerifierBase + { + public: + StackLayerVerifier(const std::string& layerName, + const std::vector& inputInfos, + const std::vector& outputInfos, + const armnn::StackDescriptor& descriptor) + : LayerVerifierBase(layerName, inputInfos, outputInfos) + , m_Descriptor(descriptor) {} + + void VisitStackLayer(const armnn::IConnectableLayer* layer, + const armnn::StackDescriptor& descriptor, + const char* name) override + { + VerifyNameAndConnections(layer, name); + VerifyDescriptor(descriptor); + } + + private: + void VerifyDescriptor(const armnn::StackDescriptor& descriptor) + { + BOOST_TEST(descriptor.m_Axis == m_Descriptor.m_Axis); + BOOST_TEST(descriptor.m_InputShape == m_Descriptor.m_InputShape); + BOOST_TEST(descriptor.m_NumInputs == m_Descriptor.m_NumInputs); + } + + armnn::StackDescriptor m_Descriptor; + }; + + const std::string layerName("stack"); + + armnn::TensorInfo inputTensorInfo ({4, 3, 5}, armnn::DataType::Float32); + armnn::TensorInfo outputTensorInfo({4, 3, 2, 5}, armnn::DataType::Float32); + + armnn::StackDescriptor descriptor(2, 2, {4, 3, 5}); + + armnn::INetworkPtr network = armnn::INetwork::Create(); + armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(0); + armnn::IConnectableLayer* const inputLayer2 = network->AddInputLayer(1); + armnn::IConnectableLayer* const stackLayer = network->AddStackLayer(descriptor, layerName.c_str()); + armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0); + + inputLayer1->GetOutputSlot(0).Connect(stackLayer->GetInputSlot(0)); + inputLayer2->GetOutputSlot(0).Connect(stackLayer->GetInputSlot(1)); + stackLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); + + inputLayer1->GetOutputSlot(0).SetTensorInfo(inputTensorInfo); + inputLayer2->GetOutputSlot(0).SetTensorInfo(inputTensorInfo); + stackLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); + + armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network)); + BOOST_CHECK(deserializedNetwork); + + StackLayerVerifier verifier(layerName, {inputTensorInfo, inputTensorInfo}, {outputTensorInfo}, descriptor); + deserializedNetwork->Accept(verifier); +} + BOOST_AUTO_TEST_CASE(SerializeStridedSlice) { class StridedSliceLayerVerifier : public LayerVerifierBase -- cgit v1.2.1