diff options
author | Matthew Sloyan <matthew.sloyan@arm.com> | 2021-09-08 13:05:51 +0100 |
---|---|---|
committer | Matthew Sloyan <matthew.sloyan@arm.com> | 2021-10-01 15:27:01 +0100 |
commit | b63a31170aee1d28267d83a4bc67b57708fb6b05 (patch) | |
tree | 16cea0a872939be749b72f45ad125964439bc40e /src/armnnSerializer | |
parent | eb852bb9e45b1db42a26001ece11ec7cc1f2bbfe (diff) | |
download | armnn-b63a31170aee1d28267d83a4bc67b57708fb6b05.tar.gz |
IVGCVSW-6163 Add Conv3d FrontEnd and Ref Implementation
* Added front-end
* Added Reference workload
* Added Serializer & Deserializer support
* Added unit tests
* Added NDHWC DataLayout
Signed-off-by: Matthew Sloyan <matthew.sloyan@arm.com>
Change-Id: Iec4d39e7433b5334d52fa44cf8efc6bcd39319d8
Diffstat (limited to 'src/armnnSerializer')
-rw-r--r-- | src/armnnSerializer/ArmnnSchema.fbs | 29 | ||||
-rw-r--r-- | src/armnnSerializer/ArmnnSchema_generated.h | 308 | ||||
-rw-r--r-- | src/armnnSerializer/Serializer.cpp | 58 | ||||
-rw-r--r-- | src/armnnSerializer/Serializer.hpp | 9 | ||||
-rw-r--r-- | src/armnnSerializer/SerializerUtils.cpp | 2 | ||||
-rw-r--r-- | src/armnnSerializer/test/SerializerTests.cpp | 55 |
6 files changed, 443 insertions, 18 deletions
diff --git a/src/armnnSerializer/ArmnnSchema.fbs b/src/armnnSerializer/ArmnnSchema.fbs index 740090bcc8..77982888c8 100644 --- a/src/armnnSerializer/ArmnnSchema.fbs +++ b/src/armnnSerializer/ArmnnSchema.fbs @@ -45,7 +45,8 @@ enum DataType : byte { enum DataLayout : byte { NHWC = 0, - NCHW = 1 + NCHW = 1, + NDHWC = 2 } enum ReduceOperation: byte { @@ -177,6 +178,7 @@ enum LayerType : uint { Shape = 62, UnidirectionalSequenceLstm = 63, ChannelShuffle = 64, + Convolution3d = 65, } // Base layer table to be used as part of other layers @@ -282,6 +284,30 @@ table Convolution2dDescriptor { dataLayout:DataLayout = NCHW; } +table Convolution3dLayer { + base:LayerBase; + descriptor:Convolution3dDescriptor; + weights:ConstTensor; + biases:ConstTensor; +} + +table Convolution3dDescriptor { + padLeft:uint; + padRight:uint; + padTop:uint; + padBottom:uint; + padFront:uint; + padBack:uint; + strideX:uint; + strideY:uint; + strideZ:uint; + dilationX:uint = 1; + dilationY:uint = 1; + dilationZ:uint = 1; + biasEnabled:bool = false; + dataLayout:DataLayout = NDHWC; +} + table DepthToSpaceLayer { base:LayerBase; descriptor:DepthToSpaceDescriptor; @@ -1012,6 +1038,7 @@ union Layer { ShapeLayer, UnidirectionalSequenceLstmLayer, ChannelShuffleLayer, + Convolution3dLayer, } table AnyLayer { diff --git a/src/armnnSerializer/ArmnnSchema_generated.h b/src/armnnSerializer/ArmnnSchema_generated.h index 653ea6a1e5..8234aa9c47 100644 --- a/src/armnnSerializer/ArmnnSchema_generated.h +++ b/src/armnnSerializer/ArmnnSchema_generated.h @@ -86,6 +86,12 @@ struct Convolution2dLayerBuilder; struct Convolution2dDescriptor; struct Convolution2dDescriptorBuilder; +struct Convolution3dLayer; +struct Convolution3dLayerBuilder; + +struct Convolution3dDescriptor; +struct Convolution3dDescriptorBuilder; + struct DepthToSpaceLayer; struct DepthToSpaceLayerBuilder; @@ -533,29 +539,32 @@ inline const char *EnumNameDataType(DataType e) { enum DataLayout { DataLayout_NHWC = 0, DataLayout_NCHW = 1, + DataLayout_NDHWC = 2, DataLayout_MIN = DataLayout_NHWC, - DataLayout_MAX = DataLayout_NCHW + DataLayout_MAX = DataLayout_NDHWC }; -inline const DataLayout (&EnumValuesDataLayout())[2] { +inline const DataLayout (&EnumValuesDataLayout())[3] { static const DataLayout values[] = { DataLayout_NHWC, - DataLayout_NCHW + DataLayout_NCHW, + DataLayout_NDHWC }; return values; } inline const char * const *EnumNamesDataLayout() { - static const char * const names[3] = { + static const char * const names[4] = { "NHWC", "NCHW", + "NDHWC", nullptr }; return names; } inline const char *EnumNameDataLayout(DataLayout e) { - if (flatbuffers::IsOutRange(e, DataLayout_NHWC, DataLayout_NCHW)) return ""; + if (flatbuffers::IsOutRange(e, DataLayout_NHWC, DataLayout_NDHWC)) return ""; const size_t index = static_cast<size_t>(e); return EnumNamesDataLayout()[index]; } @@ -757,11 +766,12 @@ enum LayerType { LayerType_Shape = 62, LayerType_UnidirectionalSequenceLstm = 63, LayerType_ChannelShuffle = 64, + LayerType_Convolution3d = 65, LayerType_MIN = LayerType_Addition, - LayerType_MAX = LayerType_ChannelShuffle + LayerType_MAX = LayerType_Convolution3d }; -inline const LayerType (&EnumValuesLayerType())[65] { +inline const LayerType (&EnumValuesLayerType())[66] { static const LayerType values[] = { LayerType_Addition, LayerType_Input, @@ -827,13 +837,14 @@ inline const LayerType (&EnumValuesLayerType())[65] { LayerType_Cast, LayerType_Shape, LayerType_UnidirectionalSequenceLstm, - LayerType_ChannelShuffle + LayerType_ChannelShuffle, + LayerType_Convolution3d }; return values; } inline const char * const *EnumNamesLayerType() { - static const char * const names[66] = { + static const char * const names[67] = { "Addition", "Input", "Multiplication", @@ -899,13 +910,14 @@ inline const char * const *EnumNamesLayerType() { "Shape", "UnidirectionalSequenceLstm", "ChannelShuffle", + "Convolution3d", nullptr }; return names; } inline const char *EnumNameLayerType(LayerType e) { - if (flatbuffers::IsOutRange(e, LayerType_Addition, LayerType_ChannelShuffle)) return ""; + if (flatbuffers::IsOutRange(e, LayerType_Addition, LayerType_Convolution3d)) return ""; const size_t index = static_cast<size_t>(e); return EnumNamesLayerType()[index]; } @@ -1250,11 +1262,12 @@ enum Layer { Layer_ShapeLayer = 63, Layer_UnidirectionalSequenceLstmLayer = 64, Layer_ChannelShuffleLayer = 65, + Layer_Convolution3dLayer = 66, Layer_MIN = Layer_NONE, - Layer_MAX = Layer_ChannelShuffleLayer + Layer_MAX = Layer_Convolution3dLayer }; -inline const Layer (&EnumValuesLayer())[66] { +inline const Layer (&EnumValuesLayer())[67] { static const Layer values[] = { Layer_NONE, Layer_ActivationLayer, @@ -1321,13 +1334,14 @@ inline const Layer (&EnumValuesLayer())[66] { Layer_CastLayer, Layer_ShapeLayer, Layer_UnidirectionalSequenceLstmLayer, - Layer_ChannelShuffleLayer + Layer_ChannelShuffleLayer, + Layer_Convolution3dLayer }; return values; } inline const char * const *EnumNamesLayer() { - static const char * const names[67] = { + static const char * const names[68] = { "NONE", "ActivationLayer", "AdditionLayer", @@ -1394,13 +1408,14 @@ inline const char * const *EnumNamesLayer() { "ShapeLayer", "UnidirectionalSequenceLstmLayer", "ChannelShuffleLayer", + "Convolution3dLayer", nullptr }; return names; } inline const char *EnumNameLayer(Layer e) { - if (flatbuffers::IsOutRange(e, Layer_NONE, Layer_ChannelShuffleLayer)) return ""; + if (flatbuffers::IsOutRange(e, Layer_NONE, Layer_Convolution3dLayer)) return ""; const size_t index = static_cast<size_t>(e); return EnumNamesLayer()[index]; } @@ -1669,6 +1684,10 @@ template<> struct LayerTraits<armnnSerializer::ChannelShuffleLayer> { static const Layer enum_value = Layer_ChannelShuffleLayer; }; +template<> struct LayerTraits<armnnSerializer::Convolution3dLayer> { + static const Layer enum_value = Layer_Convolution3dLayer; +}; + bool VerifyLayer(flatbuffers::Verifier &verifier, const void *obj, Layer type); bool VerifyLayerVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types); @@ -3227,6 +3246,254 @@ inline flatbuffers::Offset<Convolution2dDescriptor> CreateConvolution2dDescripto return builder_.Finish(); } +struct Convolution3dLayer FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef Convolution3dLayerBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_BASE = 4, + VT_DESCRIPTOR = 6, + VT_WEIGHTS = 8, + VT_BIASES = 10 + }; + const armnnSerializer::LayerBase *base() const { + return GetPointer<const armnnSerializer::LayerBase *>(VT_BASE); + } + const armnnSerializer::Convolution3dDescriptor *descriptor() const { + return GetPointer<const armnnSerializer::Convolution3dDescriptor *>(VT_DESCRIPTOR); + } + const armnnSerializer::ConstTensor *weights() const { + return GetPointer<const armnnSerializer::ConstTensor *>(VT_WEIGHTS); + } + const armnnSerializer::ConstTensor *biases() const { + return GetPointer<const armnnSerializer::ConstTensor *>(VT_BIASES); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_BASE) && + verifier.VerifyTable(base()) && + VerifyOffset(verifier, VT_DESCRIPTOR) && + verifier.VerifyTable(descriptor()) && + VerifyOffset(verifier, VT_WEIGHTS) && + verifier.VerifyTable(weights()) && + VerifyOffset(verifier, VT_BIASES) && + verifier.VerifyTable(biases()) && + verifier.EndTable(); + } +}; + +struct Convolution3dLayerBuilder { + typedef Convolution3dLayer Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_base(flatbuffers::Offset<armnnSerializer::LayerBase> base) { + fbb_.AddOffset(Convolution3dLayer::VT_BASE, base); + } + void add_descriptor(flatbuffers::Offset<armnnSerializer::Convolution3dDescriptor> descriptor) { + fbb_.AddOffset(Convolution3dLayer::VT_DESCRIPTOR, descriptor); + } + void add_weights(flatbuffers::Offset<armnnSerializer::ConstTensor> weights) { + fbb_.AddOffset(Convolution3dLayer::VT_WEIGHTS, weights); + } + void add_biases(flatbuffers::Offset<armnnSerializer::ConstTensor> biases) { + fbb_.AddOffset(Convolution3dLayer::VT_BIASES, biases); + } + explicit Convolution3dLayerBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + Convolution3dLayerBuilder &operator=(const Convolution3dLayerBuilder &); + flatbuffers::Offset<Convolution3dLayer> Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset<Convolution3dLayer>(end); + return o; + } +}; + +inline flatbuffers::Offset<Convolution3dLayer> CreateConvolution3dLayer( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset<armnnSerializer::LayerBase> base = 0, + flatbuffers::Offset<armnnSerializer::Convolution3dDescriptor> descriptor = 0, + flatbuffers::Offset<armnnSerializer::ConstTensor> weights = 0, + flatbuffers::Offset<armnnSerializer::ConstTensor> biases = 0) { + Convolution3dLayerBuilder builder_(_fbb); + builder_.add_biases(biases); + builder_.add_weights(weights); + builder_.add_descriptor(descriptor); + builder_.add_base(base); + return builder_.Finish(); +} + +struct Convolution3dDescriptor FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef Convolution3dDescriptorBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_PADLEFT = 4, + VT_PADRIGHT = 6, + VT_PADTOP = 8, + VT_PADBOTTOM = 10, + VT_PADFRONT = 12, + VT_PADBACK = 14, + VT_STRIDEX = 16, + VT_STRIDEY = 18, + VT_STRIDEZ = 20, + VT_DILATIONX = 22, + VT_DILATIONY = 24, + VT_DILATIONZ = 26, + VT_BIASENABLED = 28, + VT_DATALAYOUT = 30 + }; + uint32_t padLeft() const { + return GetField<uint32_t>(VT_PADLEFT, 0); + } + uint32_t padRight() const { + return GetField<uint32_t>(VT_PADRIGHT, 0); + } + uint32_t padTop() const { + return GetField<uint32_t>(VT_PADTOP, 0); + } + uint32_t padBottom() const { + return GetField<uint32_t>(VT_PADBOTTOM, 0); + } + uint32_t padFront() const { + return GetField<uint32_t>(VT_PADFRONT, 0); + } + uint32_t padBack() const { + return GetField<uint32_t>(VT_PADBACK, 0); + } + uint32_t strideX() const { + return GetField<uint32_t>(VT_STRIDEX, 0); + } + uint32_t strideY() const { + return GetField<uint32_t>(VT_STRIDEY, 0); + } + uint32_t strideZ() const { + return GetField<uint32_t>(VT_STRIDEZ, 0); + } + uint32_t dilationX() const { + return GetField<uint32_t>(VT_DILATIONX, 1); + } + uint32_t dilationY() const { + return GetField<uint32_t>(VT_DILATIONY, 1); + } + uint32_t dilationZ() const { + return GetField<uint32_t>(VT_DILATIONZ, 1); + } + bool biasEnabled() const { + return GetField<uint8_t>(VT_BIASENABLED, 0) != 0; + } + armnnSerializer::DataLayout dataLayout() const { + return static_cast<armnnSerializer::DataLayout>(GetField<int8_t>(VT_DATALAYOUT, 2)); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField<uint32_t>(verifier, VT_PADLEFT) && + VerifyField<uint32_t>(verifier, VT_PADRIGHT) && + VerifyField<uint32_t>(verifier, VT_PADTOP) && + VerifyField<uint32_t>(verifier, VT_PADBOTTOM) && + VerifyField<uint32_t>(verifier, VT_PADFRONT) && + VerifyField<uint32_t>(verifier, VT_PADBACK) && + VerifyField<uint32_t>(verifier, VT_STRIDEX) && + VerifyField<uint32_t>(verifier, VT_STRIDEY) && + VerifyField<uint32_t>(verifier, VT_STRIDEZ) && + VerifyField<uint32_t>(verifier, VT_DILATIONX) && + VerifyField<uint32_t>(verifier, VT_DILATIONY) && + VerifyField<uint32_t>(verifier, VT_DILATIONZ) && + VerifyField<uint8_t>(verifier, VT_BIASENABLED) && + VerifyField<int8_t>(verifier, VT_DATALAYOUT) && + verifier.EndTable(); + } +}; + +struct Convolution3dDescriptorBuilder { + typedef Convolution3dDescriptor Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_padLeft(uint32_t padLeft) { + fbb_.AddElement<uint32_t>(Convolution3dDescriptor::VT_PADLEFT, padLeft, 0); + } + void add_padRight(uint32_t padRight) { + fbb_.AddElement<uint32_t>(Convolution3dDescriptor::VT_PADRIGHT, padRight, 0); + } + void add_padTop(uint32_t padTop) { + fbb_.AddElement<uint32_t>(Convolution3dDescriptor::VT_PADTOP, padTop, 0); + } + void add_padBottom(uint32_t padBottom) { + fbb_.AddElement<uint32_t>(Convolution3dDescriptor::VT_PADBOTTOM, padBottom, 0); + } + void add_padFront(uint32_t padFront) { + fbb_.AddElement<uint32_t>(Convolution3dDescriptor::VT_PADFRONT, padFront, 0); + } + void add_padBack(uint32_t padBack) { + fbb_.AddElement<uint32_t>(Convolution3dDescriptor::VT_PADBACK, padBack, 0); + } + void add_strideX(uint32_t strideX) { + fbb_.AddElement<uint32_t>(Convolution3dDescriptor::VT_STRIDEX, strideX, 0); + } + void add_strideY(uint32_t strideY) { + fbb_.AddElement<uint32_t>(Convolution3dDescriptor::VT_STRIDEY, strideY, 0); + } + void add_strideZ(uint32_t strideZ) { + fbb_.AddElement<uint32_t>(Convolution3dDescriptor::VT_STRIDEZ, strideZ, 0); + } + void add_dilationX(uint32_t dilationX) { + fbb_.AddElement<uint32_t>(Convolution3dDescriptor::VT_DILATIONX, dilationX, 1); + } + void add_dilationY(uint32_t dilationY) { + fbb_.AddElement<uint32_t>(Convolution3dDescriptor::VT_DILATIONY, dilationY, 1); + } + void add_dilationZ(uint32_t dilationZ) { + fbb_.AddElement<uint32_t>(Convolution3dDescriptor::VT_DILATIONZ, dilationZ, 1); + } + void add_biasEnabled(bool biasEnabled) { + fbb_.AddElement<uint8_t>(Convolution3dDescriptor::VT_BIASENABLED, static_cast<uint8_t>(biasEnabled), 0); + } + void add_dataLayout(armnnSerializer::DataLayout dataLayout) { + fbb_.AddElement<int8_t>(Convolution3dDescriptor::VT_DATALAYOUT, static_cast<int8_t>(dataLayout), 2); + } + explicit Convolution3dDescriptorBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + Convolution3dDescriptorBuilder &operator=(const Convolution3dDescriptorBuilder &); + flatbuffers::Offset<Convolution3dDescriptor> Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset<Convolution3dDescriptor>(end); + return o; + } +}; + +inline flatbuffers::Offset<Convolution3dDescriptor> CreateConvolution3dDescriptor( + flatbuffers::FlatBufferBuilder &_fbb, + uint32_t padLeft = 0, + uint32_t padRight = 0, + uint32_t padTop = 0, + uint32_t padBottom = 0, + uint32_t padFront = 0, + uint32_t padBack = 0, + uint32_t strideX = 0, + uint32_t strideY = 0, + uint32_t strideZ = 0, + uint32_t dilationX = 1, + uint32_t dilationY = 1, + uint32_t dilationZ = 1, + bool biasEnabled = false, + armnnSerializer::DataLayout dataLayout = armnnSerializer::DataLayout_NDHWC) { + Convolution3dDescriptorBuilder builder_(_fbb); + builder_.add_dilationZ(dilationZ); + builder_.add_dilationY(dilationY); + builder_.add_dilationX(dilationX); + builder_.add_strideZ(strideZ); + builder_.add_strideY(strideY); + builder_.add_strideX(strideX); + builder_.add_padBack(padBack); + builder_.add_padFront(padFront); + builder_.add_padBottom(padBottom); + builder_.add_padTop(padTop); + builder_.add_padRight(padRight); + builder_.add_padLeft(padLeft); + builder_.add_dataLayout(dataLayout); + builder_.add_biasEnabled(biasEnabled); + return builder_.Finish(); +} + struct DepthToSpaceLayer FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { typedef DepthToSpaceLayerBuilder Builder; enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { @@ -9963,6 +10230,9 @@ struct AnyLayer FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { const armnnSerializer::ChannelShuffleLayer *layer_as_ChannelShuffleLayer() const { return layer_type() == armnnSerializer::Layer_ChannelShuffleLayer ? static_cast<const armnnSerializer::ChannelShuffleLayer *>(layer()) : nullptr; } + const armnnSerializer::Convolution3dLayer *layer_as_Convolution3dLayer() const { + return layer_type() == armnnSerializer::Layer_Convolution3dLayer ? static_cast<const armnnSerializer::Convolution3dLayer *>(layer()) : nullptr; + } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyField<uint8_t>(verifier, VT_LAYER_TYPE) && @@ -10232,6 +10502,10 @@ template<> inline const armnnSerializer::ChannelShuffleLayer *AnyLayer::layer_as return layer_as_ChannelShuffleLayer(); } +template<> inline const armnnSerializer::Convolution3dLayer *AnyLayer::layer_as<armnnSerializer::Convolution3dLayer>() const { + return layer_as_Convolution3dLayer(); +} + struct AnyLayerBuilder { typedef AnyLayer Table; flatbuffers::FlatBufferBuilder &fbb_; @@ -10722,6 +10996,10 @@ inline bool VerifyLayer(flatbuffers::Verifier &verifier, const void *obj, Layer auto ptr = reinterpret_cast<const armnnSerializer::ChannelShuffleLayer *>(obj); return verifier.VerifyTable(ptr); } + case Layer_Convolution3dLayer: { + auto ptr = reinterpret_cast<const armnnSerializer::Convolution3dLayer *>(obj); + return verifier.VerifyTable(ptr); + } default: return true; } } diff --git a/src/armnnSerializer/Serializer.cpp b/src/armnnSerializer/Serializer.cpp index 9a3a270de5..efaf9f81cd 100644 --- a/src/armnnSerializer/Serializer.cpp +++ b/src/armnnSerializer/Serializer.cpp @@ -397,6 +397,54 @@ void SerializerStrategy::SerializeConvolution2dLayer(const armnn::IConnectableLa CreateAnyLayer(flatBufferLayer.o, serializer::Layer::Layer_Convolution2dLayer); } +// Build FlatBuffer for Convolution2dLayer +void SerializerStrategy::SerializeConvolution3dLayer(const armnn::IConnectableLayer* layer, + const armnn::Convolution3dDescriptor& descriptor, + const std::vector<armnn::ConstTensor>& constants, + const char* name) +{ + IgnoreUnused(name); + + const armnn::ConstTensor weights = constants[0]; + + // Create FlatBuffer BaseLayer + auto flatBufferBaseLayer = CreateLayerBase(layer, serializer::LayerType::LayerType_Convolution2d); + + auto flatBufferDescriptor = CreateConvolution3dDescriptor(m_flatBufferBuilder, + descriptor.m_PadLeft, + descriptor.m_PadRight, + descriptor.m_PadTop, + descriptor.m_PadBottom, + descriptor.m_PadFront, + descriptor.m_PadBack, + descriptor.m_StrideX, + descriptor.m_StrideY, + descriptor.m_StrideZ, + descriptor.m_DilationX, + descriptor.m_DilationY, + descriptor.m_DilationZ, + descriptor.m_BiasEnabled, + GetFlatBufferDataLayout(descriptor.m_DataLayout)); + auto flatBufferWeightsConstTensorInfo = CreateConstTensorInfo(weights); + flatbuffers::Offset<serializer::ConstTensor> flatBufferBiasesConstTensorInfo; + + if (constants.size() > 1) + { + const armnn::ConstTensor biases = constants[1]; + flatBufferBiasesConstTensorInfo = CreateConstTensorInfo(biases); + } + + // Create the FlatBuffer Convolution2dLayer + auto flatBufferLayer = CreateConvolution3dLayer(m_flatBufferBuilder, + flatBufferBaseLayer, + flatBufferDescriptor, + flatBufferWeightsConstTensorInfo, + flatBufferBiasesConstTensorInfo); + + // Add the AnyLayer to the FlatBufferLayers + CreateAnyLayer(flatBufferLayer.o, serializer::Layer::Layer_Convolution3dLayer); +} + void SerializerStrategy::SerializeDepthToSpaceLayer(const armnn::IConnectableLayer* layer, const armnn::DepthToSpaceDescriptor& descriptor, const char* name) @@ -2054,6 +2102,16 @@ void SerializerStrategy::ExecuteStrategy(const armnn::IConnectableLayer* layer, name); break; } + case armnn::LayerType::Convolution3d : + { + const armnn::Convolution3dDescriptor& layerDescriptor = + static_cast<const armnn::Convolution3dDescriptor&>(descriptor); + SerializeConvolution3dLayer(layer, + layerDescriptor, + constants, + name); + break; + } case armnn::LayerType::DepthToSpace : { const armnn::DepthToSpaceDescriptor& layerDescriptor = diff --git a/src/armnnSerializer/Serializer.hpp b/src/armnnSerializer/Serializer.hpp index 43fb0f46b1..1161095c33 100644 --- a/src/armnnSerializer/Serializer.hpp +++ b/src/armnnSerializer/Serializer.hpp @@ -144,12 +144,17 @@ private: const char* name = nullptr); void SerializeConstantLayer(const armnn::IConnectableLayer* layer, - const std::vector<armnn::ConstTensor>& contants, + const std::vector<armnn::ConstTensor>& constants, const char* name = nullptr); void SerializeConvolution2dLayer(const armnn::IConnectableLayer* layer, const armnn::Convolution2dDescriptor& descriptor, - const std::vector<armnn::ConstTensor>& contants, + const std::vector<armnn::ConstTensor>& constants, + const char* name = nullptr); + + void SerializeConvolution3dLayer(const armnn::IConnectableLayer* layer, + const armnn::Convolution3dDescriptor& descriptor, + const std::vector<armnn::ConstTensor>& constants, const char* name = nullptr); void SerializeDepthToSpaceLayer(const armnn::IConnectableLayer* layer, diff --git a/src/armnnSerializer/SerializerUtils.cpp b/src/armnnSerializer/SerializerUtils.cpp index 85ce01d132..fca6db8449 100644 --- a/src/armnnSerializer/SerializerUtils.cpp +++ b/src/armnnSerializer/SerializerUtils.cpp @@ -97,6 +97,8 @@ armnnSerializer::DataLayout GetFlatBufferDataLayout(armnn::DataLayout dataLayout { case armnn::DataLayout::NHWC: return armnnSerializer::DataLayout::DataLayout_NHWC; + case armnn::DataLayout::NDHWC: + return armnnSerializer::DataLayout::DataLayout_NDHWC; case armnn::DataLayout::NCHW: default: return armnnSerializer::DataLayout::DataLayout_NCHW; diff --git a/src/armnnSerializer/test/SerializerTests.cpp b/src/armnnSerializer/test/SerializerTests.cpp index cd7fd5ca5b..2f8fd73717 100644 --- a/src/armnnSerializer/test/SerializerTests.cpp +++ b/src/armnnSerializer/test/SerializerTests.cpp @@ -439,6 +439,61 @@ TEST_CASE("SerializeConvolution2dWithPerAxisParams") deserializedNetwork->ExecuteStrategy(verifier); } +TEST_CASE("SerializeConvolution3d") +{ + const std::string layerName("convolution3d"); + const armnn::TensorInfo inputInfo ({ 1, 5, 5, 5, 1 }, armnn::DataType::Float32); + const armnn::TensorInfo outputInfo({ 1, 2, 2, 2, 1 }, armnn::DataType::Float32); + + const armnn::TensorInfo weightsInfo({ 3, 3, 3, 1, 1 }, armnn::DataType::Float32); + const armnn::TensorInfo biasesInfo ({ 1 }, armnn::DataType::Float32); + + std::vector<float> weightsData = GenerateRandomData<float>(weightsInfo.GetNumElements()); + armnn::ConstTensor weights(weightsInfo, weightsData); + + std::vector<float> biasesData = GenerateRandomData<float>(biasesInfo.GetNumElements()); + armnn::ConstTensor biases(biasesInfo, biasesData); + + armnn::Convolution3dDescriptor descriptor; + descriptor.m_PadLeft = 0; + descriptor.m_PadRight = 0; + descriptor.m_PadTop = 0; + descriptor.m_PadBottom = 0; + descriptor.m_PadFront = 0; + descriptor.m_PadBack = 0; + descriptor.m_DilationX = 1; + descriptor.m_DilationY = 1; + descriptor.m_DilationZ = 1; + descriptor.m_StrideX = 2; + descriptor.m_StrideY = 2; + descriptor.m_StrideZ = 2; + descriptor.m_BiasEnabled = true; + descriptor.m_DataLayout = armnn::DataLayout::NDHWC; + + armnn::INetworkPtr network = armnn::INetwork::Create(); + armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0); + armnn::IConnectableLayer* const convLayer = + network->AddConvolution3dLayer(descriptor, + weights, + armnn::Optional<armnn::ConstTensor>(biases), + layerName.c_str()); + armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0); + + inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0)); + convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); + + inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo); + convLayer->GetOutputSlot(0).SetTensorInfo(outputInfo); + + armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network)); + CHECK(deserializedNetwork); + + const std::vector<armnn::ConstTensor>& constants {weights, biases}; + LayerVerifierBaseWithDescriptorAndConstants<armnn::Convolution3dDescriptor> verifier( + layerName, {inputInfo}, {outputInfo}, descriptor, constants); + deserializedNetwork->ExecuteStrategy(verifier); +} + TEST_CASE("SerializeDepthToSpace") { const std::string layerName("depthToSpace"); |