From 51f67776a695c217a32596af806afeeb080f5528 Mon Sep 17 00:00:00 2001 From: Simon Obute Date: Fri, 3 Sep 2021 15:50:13 +0100 Subject: IVGCVSW-3705 Add Channel Shuffle Front end and Ref Implementation * Add front end * Add reference workload * Add unit tests * Add Serializer and Deserializer * Update ArmNN Versioning Signed-off-by: Simon Obute Change-Id: I9ac1f953af3974382eac8e8d62d794d2344e8f47 --- src/armnnSerializer/ArmnnSchema.fbs | 12 +++ src/armnnSerializer/ArmnnSchema_generated.h | 155 +++++++++++++++++++++++++-- src/armnnSerializer/Serializer.cpp | 22 ++++ src/armnnSerializer/Serializer.hpp | 4 + src/armnnSerializer/test/SerializerTests.cpp | 28 +++++ 5 files changed, 210 insertions(+), 11 deletions(-) (limited to 'src/armnnSerializer') diff --git a/src/armnnSerializer/ArmnnSchema.fbs b/src/armnnSerializer/ArmnnSchema.fbs index a285a110cc..740090bcc8 100644 --- a/src/armnnSerializer/ArmnnSchema.fbs +++ b/src/armnnSerializer/ArmnnSchema.fbs @@ -176,6 +176,7 @@ enum LayerType : uint { Cast = 61, Shape = 62, UnidirectionalSequenceLstm = 63, + ChannelShuffle = 64, } // Base layer table to be used as part of other layers @@ -228,6 +229,16 @@ table CastLayer { base:LayerBase; } +table ChannelShuffleLayer { + base:LayerBase; + descriptor:ChannelShuffleDescriptor; +} + +table ChannelShuffleDescriptor { + axis:uint = 0; + numGroups:uint = 0; +} + enum ComparisonOperation : byte { Equal = 0, Greater = 1, @@ -1000,6 +1011,7 @@ union Layer { CastLayer, ShapeLayer, UnidirectionalSequenceLstmLayer, + ChannelShuffleLayer, } table AnyLayer { diff --git a/src/armnnSerializer/ArmnnSchema_generated.h b/src/armnnSerializer/ArmnnSchema_generated.h index cf28a7a313..653ea6a1e5 100644 --- a/src/armnnSerializer/ArmnnSchema_generated.h +++ b/src/armnnSerializer/ArmnnSchema_generated.h @@ -65,6 +65,12 @@ struct ArgMinMaxDescriptorBuilder; struct CastLayer; struct CastLayerBuilder; +struct ChannelShuffleLayer; +struct ChannelShuffleLayerBuilder; + +struct ChannelShuffleDescriptor; +struct ChannelShuffleDescriptorBuilder; + struct ComparisonDescriptor; struct ComparisonDescriptorBuilder; @@ -588,7 +594,7 @@ inline const char * const *EnumNamesReduceOperation() { } inline const char *EnumNameReduceOperation(ReduceOperation e) { - if (flatbuffers::IsOutRange(e, ReduceOperation_Sum, ReduceOperation_Min)) return ""; + if (flatbuffers::IsOutRange(e, ReduceOperation_Sum, ReduceOperation_Prod)) return ""; const size_t index = static_cast(e); return EnumNamesReduceOperation()[index]; } @@ -750,11 +756,12 @@ enum LayerType { LayerType_Cast = 61, LayerType_Shape = 62, LayerType_UnidirectionalSequenceLstm = 63, + LayerType_ChannelShuffle = 64, LayerType_MIN = LayerType_Addition, - LayerType_MAX = LayerType_UnidirectionalSequenceLstm + LayerType_MAX = LayerType_ChannelShuffle }; -inline const LayerType (&EnumValuesLayerType())[64] { +inline const LayerType (&EnumValuesLayerType())[65] { static const LayerType values[] = { LayerType_Addition, LayerType_Input, @@ -819,13 +826,14 @@ inline const LayerType (&EnumValuesLayerType())[64] { LayerType_Reduce, LayerType_Cast, LayerType_Shape, - LayerType_UnidirectionalSequenceLstm + LayerType_UnidirectionalSequenceLstm, + LayerType_ChannelShuffle }; return values; } inline const char * const *EnumNamesLayerType() { - static const char * const names[65] = { + static const char * const names[66] = { "Addition", "Input", "Multiplication", @@ -890,13 +898,14 @@ inline const char * const *EnumNamesLayerType() { "Cast", "Shape", "UnidirectionalSequenceLstm", + "ChannelShuffle", nullptr }; return names; } inline const char *EnumNameLayerType(LayerType e) { - if (flatbuffers::IsOutRange(e, LayerType_Addition, LayerType_UnidirectionalSequenceLstm)) return ""; + if (flatbuffers::IsOutRange(e, LayerType_Addition, LayerType_ChannelShuffle)) return ""; const size_t index = static_cast(e); return EnumNamesLayerType()[index]; } @@ -1240,11 +1249,12 @@ enum Layer { Layer_CastLayer = 62, Layer_ShapeLayer = 63, Layer_UnidirectionalSequenceLstmLayer = 64, + Layer_ChannelShuffleLayer = 65, Layer_MIN = Layer_NONE, - Layer_MAX = Layer_UnidirectionalSequenceLstmLayer + Layer_MAX = Layer_ChannelShuffleLayer }; -inline const Layer (&EnumValuesLayer())[65] { +inline const Layer (&EnumValuesLayer())[66] { static const Layer values[] = { Layer_NONE, Layer_ActivationLayer, @@ -1310,13 +1320,14 @@ inline const Layer (&EnumValuesLayer())[65] { Layer_ReduceLayer, Layer_CastLayer, Layer_ShapeLayer, - Layer_UnidirectionalSequenceLstmLayer + Layer_UnidirectionalSequenceLstmLayer, + Layer_ChannelShuffleLayer }; return values; } inline const char * const *EnumNamesLayer() { - static const char * const names[66] = { + static const char * const names[67] = { "NONE", "ActivationLayer", "AdditionLayer", @@ -1382,13 +1393,14 @@ inline const char * const *EnumNamesLayer() { "CastLayer", "ShapeLayer", "UnidirectionalSequenceLstmLayer", + "ChannelShuffleLayer", nullptr }; return names; } inline const char *EnumNameLayer(Layer e) { - if (flatbuffers::IsOutRange(e, Layer_NONE, Layer_UnidirectionalSequenceLstmLayer)) return ""; + if (flatbuffers::IsOutRange(e, Layer_NONE, Layer_ChannelShuffleLayer)) return ""; const size_t index = static_cast(e); return EnumNamesLayer()[index]; } @@ -1653,6 +1665,10 @@ template<> struct LayerTraits static const Layer enum_value = Layer_UnidirectionalSequenceLstmLayer; }; +template<> struct LayerTraits { + static const Layer enum_value = Layer_ChannelShuffleLayer; +}; + bool VerifyLayer(flatbuffers::Verifier &verifier, const void *obj, Layer type); bool VerifyLayerVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector> *values, const flatbuffers::Vector *types); @@ -2747,6 +2763,112 @@ inline flatbuffers::Offset CreateCastLayer( return builder_.Finish(); } +struct ChannelShuffleLayer FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ChannelShuffleLayerBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_BASE = 4, + VT_DESCRIPTOR = 6 + }; + const armnnSerializer::LayerBase *base() const { + return GetPointer(VT_BASE); + } + const armnnSerializer::ChannelShuffleDescriptor *descriptor() const { + return GetPointer(VT_DESCRIPTOR); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_BASE) && + verifier.VerifyTable(base()) && + VerifyOffset(verifier, VT_DESCRIPTOR) && + verifier.VerifyTable(descriptor()) && + verifier.EndTable(); + } +}; + +struct ChannelShuffleLayerBuilder { + typedef ChannelShuffleLayer Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_base(flatbuffers::Offset base) { + fbb_.AddOffset(ChannelShuffleLayer::VT_BASE, base); + } + void add_descriptor(flatbuffers::Offset descriptor) { + fbb_.AddOffset(ChannelShuffleLayer::VT_DESCRIPTOR, descriptor); + } + explicit ChannelShuffleLayerBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ChannelShuffleLayerBuilder &operator=(const ChannelShuffleLayerBuilder &); + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateChannelShuffleLayer( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset base = 0, + flatbuffers::Offset descriptor = 0) { + ChannelShuffleLayerBuilder builder_(_fbb); + builder_.add_descriptor(descriptor); + builder_.add_base(base); + return builder_.Finish(); +} + +struct ChannelShuffleDescriptor FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ChannelShuffleDescriptorBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_AXIS = 4, + VT_NUMGROUPS = 6 + }; + uint32_t axis() const { + return GetField(VT_AXIS, 0); + } + uint32_t numGroups() const { + return GetField(VT_NUMGROUPS, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_AXIS) && + VerifyField(verifier, VT_NUMGROUPS) && + verifier.EndTable(); + } +}; + +struct ChannelShuffleDescriptorBuilder { + typedef ChannelShuffleDescriptor Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_axis(uint32_t axis) { + fbb_.AddElement(ChannelShuffleDescriptor::VT_AXIS, axis, 0); + } + void add_numGroups(uint32_t numGroups) { + fbb_.AddElement(ChannelShuffleDescriptor::VT_NUMGROUPS, numGroups, 0); + } + explicit ChannelShuffleDescriptorBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ChannelShuffleDescriptorBuilder &operator=(const ChannelShuffleDescriptorBuilder &); + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateChannelShuffleDescriptor( + flatbuffers::FlatBufferBuilder &_fbb, + uint32_t axis = 0, + uint32_t numGroups = 0) { + ChannelShuffleDescriptorBuilder builder_(_fbb); + builder_.add_numGroups(numGroups); + builder_.add_axis(axis); + return builder_.Finish(); +} + struct ComparisonDescriptor FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { typedef ComparisonDescriptorBuilder Builder; enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { @@ -9838,6 +9960,9 @@ struct AnyLayer FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { const armnnSerializer::UnidirectionalSequenceLstmLayer *layer_as_UnidirectionalSequenceLstmLayer() const { return layer_type() == armnnSerializer::Layer_UnidirectionalSequenceLstmLayer ? static_cast(layer()) : nullptr; } + const armnnSerializer::ChannelShuffleLayer *layer_as_ChannelShuffleLayer() const { + return layer_type() == armnnSerializer::Layer_ChannelShuffleLayer ? static_cast(layer()) : nullptr; + } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyField(verifier, VT_LAYER_TYPE) && @@ -10103,6 +10228,10 @@ template<> inline const armnnSerializer::UnidirectionalSequenceLstmLayer *AnyLay return layer_as_UnidirectionalSequenceLstmLayer(); } +template<> inline const armnnSerializer::ChannelShuffleLayer *AnyLayer::layer_as() const { + return layer_as_ChannelShuffleLayer(); +} + struct AnyLayerBuilder { typedef AnyLayer Table; flatbuffers::FlatBufferBuilder &fbb_; @@ -10589,6 +10718,10 @@ inline bool VerifyLayer(flatbuffers::Verifier &verifier, const void *obj, Layer auto ptr = reinterpret_cast(obj); return verifier.VerifyTable(ptr); } + case Layer_ChannelShuffleLayer: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } default: return true; } } diff --git a/src/armnnSerializer/Serializer.cpp b/src/armnnSerializer/Serializer.cpp index 195b41657a..9a3a270de5 100644 --- a/src/armnnSerializer/Serializer.cpp +++ b/src/armnnSerializer/Serializer.cpp @@ -302,6 +302,19 @@ void SerializerStrategy::SerializeCastLayer(const armnn::IConnectableLayer* laye CreateAnyLayer(fbCastLayer.o, serializer::Layer::Layer_CastLayer); } +void SerializerStrategy::SerializeChannelShuffleLayer(const armnn::IConnectableLayer* layer, + const armnn::ChannelShuffleDescriptor& descriptor, + const char* name) +{ + IgnoreUnused(name); + auto fbDescriptor = CreateChannelShuffleDescriptor(m_flatBufferBuilder, + descriptor.m_Axis, + descriptor.m_NumGroups); + auto fbBaseLayer = CreateLayerBase(layer, serializer::LayerType::LayerType_ChannelShuffle); + auto fbChannelShuffleLayer = serializer::CreateChannelShuffleLayer(m_flatBufferBuilder, fbBaseLayer, fbDescriptor); + CreateAnyLayer(fbChannelShuffleLayer.o, serializer::Layer::Layer_ChannelShuffleLayer); +} + void SerializerStrategy::SerializeComparisonLayer(const armnn::IConnectableLayer* layer, const armnn::ComparisonDescriptor& descriptor, const char* name) @@ -1997,6 +2010,15 @@ void SerializerStrategy::ExecuteStrategy(const armnn::IConnectableLayer* layer, SerializeCastLayer(layer, name); break; } + case armnn::LayerType::ChannelShuffle : + { + const armnn::ChannelShuffleDescriptor& layerDescriptor = + static_cast(descriptor); + SerializeChannelShuffleLayer(layer, + layerDescriptor, + name); + break; + } case armnn::LayerType::Comparison : { const armnn::ComparisonDescriptor& layerDescriptor = diff --git a/src/armnnSerializer/Serializer.hpp b/src/armnnSerializer/Serializer.hpp index 18b2cc77ac..43fb0f46b1 100644 --- a/src/armnnSerializer/Serializer.hpp +++ b/src/armnnSerializer/Serializer.hpp @@ -131,6 +131,10 @@ private: void SerializeCastLayer(const armnn::IConnectableLayer* layer, const char* name = nullptr); + void SerializeChannelShuffleLayer(const armnn::IConnectableLayer* layer, + const armnn::ChannelShuffleDescriptor& descriptor, + const char* name = nullptr); + void SerializeComparisonLayer(const armnn::IConnectableLayer* layer, const armnn::ComparisonDescriptor& descriptor, const char* name = nullptr); diff --git a/src/armnnSerializer/test/SerializerTests.cpp b/src/armnnSerializer/test/SerializerTests.cpp index 9e9df0d1ea..cd7fd5ca5b 100644 --- a/src/armnnSerializer/test/SerializerTests.cpp +++ b/src/armnnSerializer/test/SerializerTests.cpp @@ -202,6 +202,34 @@ TEST_CASE("SerializeCast") deserializedNetwork->ExecuteStrategy(verifier); } +TEST_CASE("SerializeChannelShuffle") +{ + const std::string layerName("channelShuffle"); + const armnn::TensorInfo inputInfo({1, 9}, armnn::DataType::Float32); + const armnn::TensorInfo outputInfo({1, 9}, armnn::DataType::Float32); + + armnn::ChannelShuffleDescriptor descriptor({3, 1}); + + armnn::INetworkPtr network = armnn::INetwork::Create(); + armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0); + armnn::IConnectableLayer* const ChannelShuffleLayer = + network->AddChannelShuffleLayer(descriptor, layerName.c_str()); + armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0); + + inputLayer->GetOutputSlot(0).Connect(ChannelShuffleLayer->GetInputSlot(0)); + ChannelShuffleLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); + + inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo); + ChannelShuffleLayer->GetOutputSlot(0).SetTensorInfo(outputInfo); + + armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network)); + CHECK(deserializedNetwork); + + LayerVerifierBaseWithDescriptor verifier( + layerName, {inputInfo}, {outputInfo}, descriptor); + deserializedNetwork->ExecuteStrategy(verifier); +} + TEST_CASE("SerializeComparison") { const std::string layerName("comparison"); -- cgit v1.2.1