From af484013329a8ca5b3c4c9d16395fb79dd19b1b2 Mon Sep 17 00:00:00 2001 From: Mike Kelly Date: Wed, 20 Feb 2019 16:53:11 +0000 Subject: IVGCVSW-2643 Add Serializer & Deserializer for Activation * Added ActivationLayer to Schema.fbs * Added Activation serialization and deserialization support * Added serialization and deserialization unit tests Change-Id: Ib5df45f123674988b994ffe3f111d3fb57864912 Signed-off-by: Mike Kelly --- src/armnnSerializer/Schema.fbs | 28 +++++++- src/armnnSerializer/Serializer.cpp | 50 ++++++++++++++ src/armnnSerializer/Serializer.hpp | 4 ++ .../test/ActivationSerializationTests.cpp | 78 ++++++++++++++++++++++ 4 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 src/armnnSerializer/test/ActivationSerializationTests.cpp (limited to 'src/armnnSerializer') diff --git a/src/armnnSerializer/Schema.fbs b/src/armnnSerializer/Schema.fbs index 1b7427b185..e81365166f 100644 --- a/src/armnnSerializer/Schema.fbs +++ b/src/armnnSerializer/Schema.fbs @@ -9,6 +9,19 @@ file_identifier "ARMN"; file_extension "armnn"; +enum ActivationFunction : byte { + Sigmoid = 0, + TanH = 1, + Linear = 2, + ReLu = 3, + BoundedReLu = 4, + SoftReLu = 5, + LeakyReLu = 6, + Abs = 7, + Sqrt = 8, + Square = 9 +} + enum DataType : byte { Float16 = 0, Float32 = 1, @@ -76,7 +89,8 @@ enum LayerType : uint { Reshape = 5, Softmax = 6, Convolution2d = 7, - DepthwiseConvolution2d = 8 + DepthwiseConvolution2d = 8, + Activation = 9 } // Base layer table to be used as part of other layers @@ -94,6 +108,17 @@ table BindableLayerBase { } // Table for each layer defined below +table ActivationLayer { + base:LayerBase; + descriptor:ActivationDescriptor; +} + +table ActivationDescriptor { + function:ActivationFunction = Sigmoid; + a:float; + b:float; +} + table AdditionLayer { base:LayerBase; } @@ -201,6 +226,7 @@ table ReshapeDescriptor { } union Layer { + ActivationLayer, AdditionLayer, Convolution2dLayer, DepthwiseConvolution2dLayer, diff --git a/src/armnnSerializer/Serializer.cpp b/src/armnnSerializer/Serializer.cpp index b85c45aa10..bee1a3cdb5 100644 --- a/src/armnnSerializer/Serializer.cpp +++ b/src/armnnSerializer/Serializer.cpp @@ -22,6 +22,33 @@ namespace serializer = armnnSerializer; namespace armnnSerializer { +serializer::ActivationFunction GetFlatBufferActivationFunction(armnn::ActivationFunction function) +{ + switch (function) + { + case armnn::ActivationFunction::Sigmoid: + return serializer::ActivationFunction::ActivationFunction_Sigmoid; + case armnn::ActivationFunction::TanH: + return serializer::ActivationFunction::ActivationFunction_TanH; + case armnn::ActivationFunction::Linear: + return serializer::ActivationFunction::ActivationFunction_Linear; + case armnn::ActivationFunction::ReLu: + return serializer::ActivationFunction::ActivationFunction_ReLu; + case armnn::ActivationFunction::BoundedReLu: + return serializer::ActivationFunction::ActivationFunction_BoundedReLu; + case armnn::ActivationFunction::LeakyReLu: + return serializer::ActivationFunction::ActivationFunction_LeakyReLu; + case armnn::ActivationFunction::Abs: + return serializer::ActivationFunction::ActivationFunction_Abs; + case armnn::ActivationFunction::Sqrt: + return serializer::ActivationFunction::ActivationFunction_Sqrt; + case armnn::ActivationFunction::Square: + return serializer::ActivationFunction::ActivationFunction_Square; + default: + return serializer::ActivationFunction::ActivationFunction_Sigmoid; + } +} + uint32_t SerializerVisitor::GetSerializedId(unsigned int guid) { std::pair guidPair(guid, m_layerId); @@ -78,6 +105,29 @@ void SerializerVisitor::VisitOutputLayer(const armnn::IConnectableLayer* layer, CreateAnyLayer(flatBufferOutputLayer.o, serializer::Layer::Layer_OutputLayer); } +// Build FlatBuffer for Activation Layer +void SerializerVisitor::VisitActivationLayer(const armnn::IConnectableLayer* layer, + const armnn::ActivationDescriptor& descriptor, + const char* name) +{ + // Create FlatBuffer BaseLayer + auto flatBufferBaseLayer = CreateLayerBase(layer, serializer::LayerType::LayerType_Activation); + + // Create the FlatBuffer ActivationDescriptor + auto flatBufferDescriptor = CreateActivationDescriptor(m_flatBufferBuilder, + GetFlatBufferActivationFunction(descriptor.m_Function), + descriptor.m_A, + descriptor.m_B); + + // Create the FlatBuffer ActivationLayer + auto flatBufferAdditionLayer = CreateActivationLayer(m_flatBufferBuilder, + flatBufferBaseLayer, + flatBufferDescriptor); + + // Add the AnyLayer to the FlatBufferLayers + CreateAnyLayer(flatBufferAdditionLayer.o, serializer::Layer::Layer_ActivationLayer); +} + // Build FlatBuffer for Addition Layer void SerializerVisitor::VisitAdditionLayer(const armnn::IConnectableLayer* layer, const char* name) { diff --git a/src/armnnSerializer/Serializer.hpp b/src/armnnSerializer/Serializer.hpp index aa765a2065..0c442e0788 100644 --- a/src/armnnSerializer/Serializer.hpp +++ b/src/armnnSerializer/Serializer.hpp @@ -42,6 +42,10 @@ public: return m_serializedLayers; } + void VisitActivationLayer(const armnn::IConnectableLayer* layer, + const armnn::ActivationDescriptor& descriptor, + const char* name = nullptr) override; + void VisitAdditionLayer(const armnn::IConnectableLayer* layer, const char* name = nullptr) override; diff --git a/src/armnnSerializer/test/ActivationSerializationTests.cpp b/src/armnnSerializer/test/ActivationSerializationTests.cpp new file mode 100644 index 0000000000..c20f2864f9 --- /dev/null +++ b/src/armnnSerializer/test/ActivationSerializationTests.cpp @@ -0,0 +1,78 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include +#include +#include +#include "../Serializer.hpp" +#include +#include + +BOOST_AUTO_TEST_SUITE(SerializerTests) + +BOOST_AUTO_TEST_CASE(ActivationSerialization) +{ + armnnDeserializer::IDeserializerPtr parser = armnnDeserializer::IDeserializer::Create(); + + armnn::TensorInfo inputInfo(armnn::TensorShape({1, 2, 2, 1}), armnn::DataType::Float32, 1.0f, 0); + armnn::TensorInfo outputInfo(armnn::TensorShape({1, 2, 2, 1}), armnn::DataType::Float32, 4.0f, 0); + + // Construct network + armnn::INetworkPtr network = armnn::INetwork::Create(); + + armnn::ActivationDescriptor descriptor; + descriptor.m_Function = armnn::ActivationFunction::ReLu; + descriptor.m_A = 0; + descriptor.m_B = 0; + + armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0, "input"); + armnn::IConnectableLayer* const activationLayer = network->AddActivationLayer(descriptor, "activation"); + armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0, "output"); + + inputLayer->GetOutputSlot(0).Connect(activationLayer->GetInputSlot(0)); + inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo); + + activationLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); + activationLayer->GetOutputSlot(0).SetTensorInfo(outputInfo); + + armnnSerializer::Serializer serializer; + serializer.Serialize(*network); + + std::stringstream stream; + serializer.SaveSerializedToStream(stream); + + std::string const serializerString{stream.str()}; + std::vector const serializerVector{serializerString.begin(), serializerString.end()}; + + armnn::INetworkPtr deserializedNetwork = parser->CreateNetworkFromBinary(serializerVector); + + armnn::IRuntime::CreationOptions options; // default options + armnn::IRuntimePtr run = armnn::IRuntime::Create(options); + auto deserializedOptimized = Optimize(*deserializedNetwork, { armnn::Compute::CpuRef }, run->GetDeviceSpec()); + + armnn::NetworkId networkIdentifier; + + // Load graph into runtime + run->LoadNetwork(networkIdentifier, std::move(deserializedOptimized)); + + std::vector inputData {0.0f, -5.3f, 42.0f, -42.0f}; + armnn::InputTensors inputTensors + { + {0, armnn::ConstTensor(run->GetInputTensorInfo(networkIdentifier, 0), inputData.data())} + }; + + std::vector expectedOutputData {0.0f, 0.0f, 42.0f, 0.0f}; + + std::vector outputData(4); + armnn::OutputTensors outputTensors + { + {0, armnn::Tensor(run->GetOutputTensorInfo(networkIdentifier, 0), outputData.data())} + }; + run->EnqueueWorkload(networkIdentifier, inputTensors, outputTensors); + BOOST_CHECK_EQUAL_COLLECTIONS(outputData.begin(), outputData.end(), + expectedOutputData.begin(), expectedOutputData.end()); +} + +BOOST_AUTO_TEST_SUITE_END() -- cgit v1.2.1