From 8c1701a2d9c1da0e1decb2afdc2093aa88810242 Mon Sep 17 00:00:00 2001 From: Mike Kelly Date: Mon, 11 Feb 2019 17:01:27 +0000 Subject: IVGCVSW-2531 Serialize a simple ArmNN Network Change-Id: I68cf5072aca6e3a8b3b8c57e19b6d417cd5813fc Signed-off-by: Mike Kelly --- src/armnnSerializer/README.md | 6 + src/armnnSerializer/Schema.fbs | 4 +- src/armnnSerializer/SeralizerSupport.md | 11 ++ src/armnnSerializer/Serializer.cpp | 186 +++++++++++++++++++++++++++ src/armnnSerializer/Serializer.hpp | 72 +++++++++++ src/armnnSerializer/test/SerializerTests.cpp | 35 +++++ 6 files changed, 312 insertions(+), 2 deletions(-) create mode 100644 src/armnnSerializer/README.md create mode 100644 src/armnnSerializer/SeralizerSupport.md create mode 100644 src/armnnSerializer/Serializer.cpp create mode 100644 src/armnnSerializer/Serializer.hpp create mode 100644 src/armnnSerializer/test/SerializerTests.cpp (limited to 'src/armnnSerializer') diff --git a/src/armnnSerializer/README.md b/src/armnnSerializer/README.md new file mode 100644 index 0000000000..61478b1470 --- /dev/null +++ b/src/armnnSerializer/README.md @@ -0,0 +1,6 @@ +# The Arm NN Serializer + +The `armnnSerializer` is a library for serializing an Arm NN network to a stream. + +For more information about the layers that are supported, and the networks that have been tested, +see [SerializerSupport.md](./SerializerSupport.md) diff --git a/src/armnnSerializer/Schema.fbs b/src/armnnSerializer/Schema.fbs index 2a5fbcd2ad..2527f6d0f6 100644 --- a/src/armnnSerializer/Schema.fbs +++ b/src/armnnSerializer/Schema.fbs @@ -108,8 +108,8 @@ table AnyLayer { // Root type for serialized data is the graph of the network table SerializedGraph { layers:[AnyLayer]; - inputIds:[int]; - outputIds:[int]; + inputIds:[uint]; + outputIds:[uint]; } root_type SerializedGraph; diff --git a/src/armnnSerializer/SeralizerSupport.md b/src/armnnSerializer/SeralizerSupport.md new file mode 100644 index 0000000000..16d1940be0 --- /dev/null +++ b/src/armnnSerializer/SeralizerSupport.md @@ -0,0 +1,11 @@ +# The layers that ArmNN SDK Serializer currently supports. + +This reference guide provides a list of layers which can be serialized currently by the Arm NN SDK. + +## Fully supported + +The Arm NN SDK Serializer currently supports the following layers: + +* Addition + +More machine learning layers will be supported in future releases. \ No newline at end of file diff --git a/src/armnnSerializer/Serializer.cpp b/src/armnnSerializer/Serializer.cpp new file mode 100644 index 0000000000..57baf0e28c --- /dev/null +++ b/src/armnnSerializer/Serializer.cpp @@ -0,0 +1,186 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "Serializer.hpp" +#include +#include +#include +#include + +using namespace armnn; +namespace fb = flatbuffers; +namespace serializer = armnn::armnnSerializer; + +namespace armnnSerializer +{ + +serializer::DataType GetFlatBufferDataType(DataType dataType) +{ + switch (dataType) + { + case DataType::Float32: + return serializer::DataType::DataType_Float32; + case DataType::Float16: + return serializer::DataType::DataType_Float16; + case DataType::Signed32: + return serializer::DataType::DataType_Signed32; + case DataType::QuantisedAsymm8: + return serializer::DataType::DataType_QuantisedAsymm8; + case DataType::Boolean: + return serializer::DataType::DataType_Boolean; + default: + return serializer::DataType::DataType_Float16; + } +} + +// Build FlatBuffer for Input Layer +void Serializer::VisitInputLayer(const IConnectableLayer* layer, LayerBindingId id, const char* name) +{ + // Create FlatBuffer BaseLayer + auto flatBufferInputBaseLayer = CreateLayerBase(layer, serializer::LayerType::LayerType_Input); + + // Create FlatBuffer BindableBaseLayer + auto flatBufferInputBindableBaseLayer = serializer::CreateBindableLayerBase(m_flatBufferBuilder, + flatBufferInputBaseLayer, + id); + + // Push layer Guid to outputIds. + m_inputIds.push_back(layer->GetGuid()); + + // Create the FlatBuffer InputLayer + auto flatBufferInputLayer = serializer::CreateInputLayer(m_flatBufferBuilder, flatBufferInputBindableBaseLayer); + + // Add the AnyLayer to the FlatBufferLayers + CreateAnyLayer(flatBufferInputLayer.o, serializer::Layer::Layer_InputLayer); +} + +// Build FlatBuffer for Output Layer +void Serializer::VisitOutputLayer(const IConnectableLayer* layer, LayerBindingId id, const char* name) +{ + // Create FlatBuffer BaseLayer + auto flatBufferOutputBaseLayer = CreateLayerBase(layer, serializer::LayerType::LayerType_Output); + + // Create FlatBuffer BindableBaseLayer + auto flatBufferOutputBindableBaseLayer = serializer::CreateBindableLayerBase(m_flatBufferBuilder, + flatBufferOutputBaseLayer, + id); + // Push layer Guid to outputIds. + m_outputIds.push_back(layer->GetGuid()); + + // Create the FlatBuffer OutputLayer + auto flatBufferOutputLayer = serializer::CreateOutputLayer(m_flatBufferBuilder, flatBufferOutputBindableBaseLayer); + // Add the AnyLayer to the FlatBufferLayers + CreateAnyLayer(flatBufferOutputLayer.o, serializer::Layer::Layer_OutputLayer); +} + +// Build FlatBuffer for Addition Layer +void Serializer::VisitAdditionLayer(const IConnectableLayer* layer, const char* name) +{ + // Create FlatBuffer BaseLayer + auto flatBufferAdditionBaseLayer = CreateLayerBase(layer, serializer::LayerType::LayerType_Addition); + + // Create the FlatBuffer AdditionLayer + auto flatBufferAdditionLayer = serializer::CreateAdditionLayer(m_flatBufferBuilder, flatBufferAdditionBaseLayer); + + // Add the AnyLayer to the FlatBufferLayers + CreateAnyLayer(flatBufferAdditionLayer.o, serializer::Layer::Layer_AdditionLayer); +} + +void Serializer::Serialize(const INetwork& inNetwork) +{ + // Iterate through to network + inNetwork.Accept(*this); + + // Create FlatBuffer SerializedGraph + auto serializedGraph = serializer::CreateSerializedGraph(m_flatBufferBuilder, + m_flatBufferBuilder.CreateVector(m_serializedLayers), + m_flatBufferBuilder.CreateVector(m_inputIds), + m_flatBufferBuilder.CreateVector(m_outputIds)); + + // Serialize the graph + m_flatBufferBuilder.Finish(serializedGraph); +} + +bool Serializer::SaveSerializedToStream(std::ostream& stream) +{ + stream.write(reinterpret_cast(m_flatBufferBuilder.GetBufferPointer()), m_flatBufferBuilder.GetSize()); + return !stream.bad(); +} + +fb::Offset Serializer::CreateLayerBase(const IConnectableLayer* layer, + const serializer::LayerType layerType) +{ + std::vector> inputSlots = CreateInputSlots(layer); + std::vector> outputSlots = CreateOutputSlots(layer); + + return serializer::CreateLayerBase(m_flatBufferBuilder, + layer->GetGuid(), + m_flatBufferBuilder.CreateString(layer->GetName()), + layerType, + m_flatBufferBuilder.CreateVector(inputSlots), + m_flatBufferBuilder.CreateVector(outputSlots)); +} + +void Serializer::CreateAnyLayer(const flatbuffers::Offset& layer, const serializer::Layer serializerLayer) +{ + auto anyLayer = armnn::armnnSerializer::CreateAnyLayer(m_flatBufferBuilder, + serializerLayer, + layer); + m_serializedLayers.push_back(anyLayer); +} + +std::vector> Serializer::CreateInputSlots(const IConnectableLayer* layer) +{ + std::vector> inputSlots; + + // Get the InputSlots + for (unsigned int slotIndex = 0; slotIndexGetNumInputSlots(); ++slotIndex) + { + const IInputSlot& inputSlot = layer->GetInputSlot(slotIndex); + + // Get the Connection for the InputSlot + const IOutputSlot* connection = inputSlot.GetConnection(); + + // Create FlatBuffer Connection + serializer::Connection conn(connection->GetOwningLayerGuid(), connection->CalculateIndexOnOwner()); + // Create FlatBuffer InputSlot + inputSlots.push_back(serializer::CreateInputSlot(m_flatBufferBuilder, slotIndex, &conn)); + } + return inputSlots; +} + +std::vector> Serializer::CreateOutputSlots(const IConnectableLayer* layer) +{ + std::vector> outputSlots; + + // Get the OutputSlots + for (unsigned int slotIndex = 0; slotIndex < layer->GetNumOutputSlots(); ++slotIndex) + { + const IOutputSlot& outputSlot = layer->GetOutputSlot(slotIndex); + const TensorInfo& tensorInfo = outputSlot.GetTensorInfo(); + + // Get the dimensions + std::vector shape; + for(unsigned int dim = 0; dim < tensorInfo.GetShape().GetNumDimensions(); ++dim) + { + shape.push_back(tensorInfo.GetShape()[dim]); + } + + // Create FlatBuffer TensorInfo + auto flatBufferTensorInfo = serializer::CreateTensorInfo(m_flatBufferBuilder, + m_flatBufferBuilder.CreateVector(shape), + GetFlatBufferDataType(tensorInfo.GetDataType()), + tensorInfo.GetQuantizationScale(), + tensorInfo.GetQuantizationOffset()); + + // Create FlatBuffer Outputslot + outputSlots.push_back(serializer::CreateOutputSlot(m_flatBufferBuilder, + slotIndex, + flatBufferTensorInfo)); + } + return outputSlots; +} + +} //namespace armnnSerializer diff --git a/src/armnnSerializer/Serializer.hpp b/src/armnnSerializer/Serializer.hpp new file mode 100644 index 0000000000..697e5cfaa7 --- /dev/null +++ b/src/armnnSerializer/Serializer.hpp @@ -0,0 +1,72 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// +#pragma once + +#include +#include +#include +#include + +namespace armnnSerializer +{ + +class Serializer : public armnn::LayerVisitorBase +{ +public: + Serializer() {}; + ~Serializer() {}; + + void VisitAdditionLayer(const armnn::IConnectableLayer* layer, + const char* name = nullptr) override; + + void VisitInputLayer(const armnn::IConnectableLayer* layer, + armnn::LayerBindingId id, + const char* name = nullptr) override; + + void VisitOutputLayer(const armnn::IConnectableLayer* layer, + armnn::LayerBindingId id, + const char* name = nullptr) override; + + /// Serializes the network to ArmNN SerializedGraph. + /// @param [in] inNetwork The network to be serialized. + void Serialize(const armnn::INetwork& inNetwork); + + /// Serializes the SerializedGraph to the stream. + /// @param [stream] the stream to save to + /// @return true if graph is Serialized to the Stream, false otherwise + bool SaveSerializedToStream(std::ostream& stream); + +private: + + /// Creates the Input Slots and Output Slots and LayerBase for the layer. + flatbuffers::Offset CreateLayerBase( + const armnn::IConnectableLayer* layer, + const armnn::armnnSerializer::LayerType layerType); + + /// Creates the serializer AnyLayer for the layer and adds it to m_serializedLayers. + void CreateAnyLayer(const flatbuffers::Offset& layer, const armnn::armnnSerializer::Layer serializerLayer); + + /// Creates the serializer InputSlots for the layer. + std::vector> CreateInputSlots( + const armnn::IConnectableLayer* layer); + + /// Creates the serializer OutputSlots for the layer. + std::vector> CreateOutputSlots( + const armnn::IConnectableLayer* layer); + + /// FlatBufferBuilder to create our layers' FlatBuffers. + flatbuffers::FlatBufferBuilder m_flatBufferBuilder; + + /// AnyLayers required by the SerializedGraph. + std::vector> m_serializedLayers; + + /// Guids of all Input Layers required by the SerializedGraph. + std::vector m_inputIds; + + /// Guids of all Output Layers required by the SerializedGraph. + std::vector m_outputIds; +}; + +} //namespace armnnSerializer diff --git a/src/armnnSerializer/test/SerializerTests.cpp b/src/armnnSerializer/test/SerializerTests.cpp new file mode 100644 index 0000000000..17ad6e3695 --- /dev/null +++ b/src/armnnSerializer/test/SerializerTests.cpp @@ -0,0 +1,35 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include +#include +#include "../Serializer.hpp" +#include +#include + +BOOST_AUTO_TEST_SUITE(SerializerTests) + +BOOST_AUTO_TEST_CASE(SimpleNetworkSerialization) +{ + armnn::INetworkPtr network = armnn::INetwork::Create(); + armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0); + armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1); + + armnn::IConnectableLayer* const additionLayer0 = network->AddAdditionLayer(); + inputLayer0->GetOutputSlot(0).Connect(additionLayer0->GetInputSlot(0)); + inputLayer1->GetOutputSlot(0).Connect(additionLayer0->GetInputSlot(1)); + + armnn::IConnectableLayer* const outputLayer0 = network->AddOutputLayer(0); + additionLayer0->GetOutputSlot(0).Connect(outputLayer0->GetInputSlot(0)); + + armnnSerializer::Serializer serializer; + serializer.Serialize(*network); + + std::stringstream stream; + serializer.SaveSerializedToStream(stream); + BOOST_TEST(stream.str().length() > 0); +} + +BOOST_AUTO_TEST_SUITE_END() -- cgit v1.2.1