diff options
author | Tamas Nyiri <tamas.nyiri@arm.com> | 2021-11-05 14:55:33 +0000 |
---|---|---|
committer | Tamas Nyiri <tamas.nyiri@arm.com> | 2021-11-17 11:32:55 +0000 |
commit | d998a1cfbcc7b4ed9922532ffe19c51283fcae68 (patch) | |
tree | 53317946bb5845f4f253ebfd53b668c6698fcfee /src | |
parent | 7b885b3cce70154596b1994b013ea91527117c26 (diff) | |
download | armnn-d998a1cfbcc7b4ed9922532ffe19c51283fcae68.tar.gz |
IVGCVSW-6510 Serialization + Deserialization implementation
Subtask of story: IVGCVSW-6164 Add a Pooling3d FrontEnd and Ref Implementation
* Add serialization support
* Add deserialization support
* Add corresponding unit tests
Change-Id: I7cce5421f0a9b7c47a03524e733f3315131ba125
Signed-off-by: Tamas Nyiri <tamas.nyiri@arm.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/armnn/SerializeLayerParameters.cpp | 31 | ||||
-rw-r--r-- | src/armnn/SerializeLayerParameters.hpp | 5 | ||||
-rw-r--r-- | src/armnnDeserializer/Deserializer.cpp | 125 | ||||
-rw-r--r-- | src/armnnDeserializer/Deserializer.hpp | 8 | ||||
-rw-r--r-- | src/armnnDeserializer/test/DeserializePooling3d.cpp | 173 | ||||
-rw-r--r-- | src/armnnSerializer/ArmnnSchema.fbs | 26 | ||||
-rw-r--r-- | src/armnnSerializer/ArmnnSchema_generated.h | 293 | ||||
-rw-r--r-- | src/armnnSerializer/Serializer.cpp | 40 | ||||
-rw-r--r-- | src/armnnSerializer/Serializer.hpp | 4 | ||||
-rw-r--r-- | src/armnnSerializer/test/SerializerTests.cpp | 43 |
10 files changed, 733 insertions, 15 deletions
diff --git a/src/armnn/SerializeLayerParameters.cpp b/src/armnn/SerializeLayerParameters.cpp index c60d4faf79..d7f38034f5 100644 --- a/src/armnn/SerializeLayerParameters.cpp +++ b/src/armnn/SerializeLayerParameters.cpp @@ -121,7 +121,7 @@ void StringifyLayerParameters<Convolution3dDescriptor>::Serialize(ParameterStrin { std::stringstream ss; ss << "(" << desc.m_DilationX << "," << desc.m_DilationY << "," << desc.m_DilationZ << ")"; - fn("Dilation(X,Y)", ss.str()); + fn("Dilation(X,Y,Z)", ss.str()); } fn("BiasEnabled",(desc.m_BiasEnabled ? "true" : "false")); @@ -331,6 +331,35 @@ void StringifyLayerParameters<Pooling2dDescriptor>::Serialize(ParameterStringify fn("DataLayout", GetDataLayoutName(desc.m_DataLayout)); } +void StringifyLayerParameters<Pooling3dDescriptor>::Serialize(ParameterStringifyFunction& fn, + const Pooling3dDescriptor& desc) +{ + fn("Type", GetPoolingAlgorithmAsCString(desc.m_PoolType)); + { + std::stringstream ss; + ss << "(" << desc.m_PadTop << "," << desc.m_PadLeft + << "," << desc.m_PadBottom << "," << desc.m_PadRight + << "," << desc.m_PadFront << "," << desc.m_PadBack << ")"; + fn("Padding(T,L,B,R,F,B)", ss.str()); + } + + { + std::stringstream ss; + ss << "(" << desc.m_PoolWidth << "," << desc.m_PoolHeight << "," << desc.m_PoolDepth << ")"; + fn("(Width,Height,Depth)", ss.str()); + } + + { + std::stringstream ss; + ss << "(" << desc.m_StrideX << "," << desc.m_StrideY << "," << desc.m_StrideZ << ")"; + fn("Stride(X,Y,Z)", ss.str()); + } + + fn("OutputShapeRounding", GetOutputShapeRoundingAsCString(desc.m_OutputShapeRounding)); + fn("PaddingMethod", GetPaddingMethodAsCString(desc.m_PaddingMethod)); + fn("DataLayout", GetDataLayoutName(desc.m_DataLayout)); +} + void StringifyLayerParameters<PermuteDescriptor>::Serialize(ParameterStringifyFunction& fn, const PermuteDescriptor& desc) { diff --git a/src/armnn/SerializeLayerParameters.hpp b/src/armnn/SerializeLayerParameters.hpp index 5c1e6f3759..d2c7d76d7d 100644 --- a/src/armnn/SerializeLayerParameters.hpp +++ b/src/armnn/SerializeLayerParameters.hpp @@ -124,6 +124,11 @@ template <> struct StringifyLayerParameters<Pooling2dDescriptor> static void Serialize(ParameterStringifyFunction& fn, const Pooling2dDescriptor& desc); }; +template <> struct StringifyLayerParameters<Pooling3dDescriptor> +{ + static void Serialize(ParameterStringifyFunction& fn, const Pooling3dDescriptor& desc); +}; + template <> struct StringifyLayerParameters<PreCompiledDescriptor> { static void Serialize(ParameterStringifyFunction& fn, const PreCompiledDescriptor& desc); diff --git a/src/armnnDeserializer/Deserializer.cpp b/src/armnnDeserializer/Deserializer.cpp index 8b1e9b970c..a5114ecfca 100644 --- a/src/armnnDeserializer/Deserializer.cpp +++ b/src/armnnDeserializer/Deserializer.cpp @@ -249,6 +249,7 @@ m_ParserFunctions(Layer_MAX+1, &IDeserializer::DeserializerImpl::ParseUnsupporte m_ParserFunctions[Layer_PadLayer] = &DeserializerImpl::ParsePad; m_ParserFunctions[Layer_PermuteLayer] = &DeserializerImpl::ParsePermute; m_ParserFunctions[Layer_Pooling2dLayer] = &DeserializerImpl::ParsePooling2d; + m_ParserFunctions[Layer_Pooling3dLayer] = &DeserializerImpl::ParsePooling3d; m_ParserFunctions[Layer_PreluLayer] = &DeserializerImpl::ParsePrelu; m_ParserFunctions[Layer_QLstmLayer] = &DeserializerImpl::ParseQLstm; m_ParserFunctions[Layer_QuantizeLayer] = &DeserializerImpl::ParseQuantize; @@ -365,6 +366,8 @@ LayerBaseRawPtr IDeserializer::DeserializerImpl::GetBaseLayer(const GraphPtr& gr return graphPtr->layers()->Get(layerIndex)->layer_as_PermuteLayer()->base(); case Layer::Layer_Pooling2dLayer: return graphPtr->layers()->Get(layerIndex)->layer_as_Pooling2dLayer()->base(); + case Layer::Layer_Pooling3dLayer: + return graphPtr->layers()->Get(layerIndex)->layer_as_Pooling3dLayer()->base(); case Layer::Layer_PreluLayer: return graphPtr->layers()->Get(layerIndex)->layer_as_PreluLayer()->base(); case Layer::Layer_QLstmLayer: @@ -2130,7 +2133,7 @@ void IDeserializer::DeserializerImpl::ParsePermute(GraphPtr graph, unsigned int RegisterOutputSlots(graph, layerIndex, layer); } -armnn::Pooling2dDescriptor IDeserializer::DeserializerImpl::GetPoolingDescriptor(PoolingDescriptor pooling2dDesc, +armnn::Pooling2dDescriptor IDeserializer::DeserializerImpl::GetPooling2dDescriptor(Pooling2dDescriptor pooling2dDesc, unsigned int layerIndex) { IgnoreUnused(layerIndex); @@ -2225,7 +2228,104 @@ armnn::Pooling2dDescriptor IDeserializer::DeserializerImpl::GetPoolingDescriptor return desc; } +armnn::Pooling3dDescriptor IDeserializer::DeserializerImpl::GetPooling3dDescriptor(Pooling3dDescriptor pooling3dDesc, + unsigned int layerIndex) +{ + IgnoreUnused(layerIndex); + armnn::Pooling3dDescriptor desc; + + switch (pooling3dDesc->poolType()) + { + case PoolingAlgorithm_Average: + { + desc.m_PoolType = armnn::PoolingAlgorithm::Average; + break; + } + case PoolingAlgorithm_Max: + { + desc.m_PoolType = armnn::PoolingAlgorithm::Max; + break; + } + case PoolingAlgorithm_L2: + { + desc.m_PoolType = armnn::PoolingAlgorithm::L2; + break; + } + default: + { + ARMNN_ASSERT_MSG(false, "Unsupported pooling algorithm"); + } + } + + switch (pooling3dDesc->outputShapeRounding()) + { + case OutputShapeRounding_Floor: + { + desc.m_OutputShapeRounding = armnn::OutputShapeRounding::Floor; + break; + } + case OutputShapeRounding_Ceiling: + { + desc.m_OutputShapeRounding = armnn::OutputShapeRounding::Ceiling; + break; + } + default: + { + ARMNN_ASSERT_MSG(false, "Unsupported output shape rounding"); + } + } + + switch (pooling3dDesc->paddingMethod()) + { + case PaddingMethod_Exclude: + { + desc.m_PaddingMethod = armnn::PaddingMethod::Exclude; + break; + } + case PaddingMethod_IgnoreValue: + { + desc.m_PaddingMethod = armnn::PaddingMethod::IgnoreValue; + break; + } + default: + { + ARMNN_ASSERT_MSG(false, "Unsupported padding method"); + } + } + + switch (pooling3dDesc->dataLayout()) + { + case DataLayout_NCDHW: + { + desc.m_DataLayout = armnn::DataLayout::NCDHW; + break; + } + case DataLayout_NDHWC: + { + desc.m_DataLayout = armnn::DataLayout::NDHWC; + break; + } + default: + { + ARMNN_ASSERT_MSG(false, "Unsupported data layout"); + } + } + desc.m_PadRight = pooling3dDesc->padRight(); + desc.m_PadLeft = pooling3dDesc->padLeft(); + desc.m_PadBottom = pooling3dDesc->padBottom(); + desc.m_PadTop = pooling3dDesc->padTop(); + desc.m_PadFront = pooling3dDesc->padFront(); + desc.m_PadBack = pooling3dDesc->padBack(); + desc.m_StrideX = pooling3dDesc->strideX(); + desc.m_StrideY = pooling3dDesc->strideY(); + desc.m_StrideZ = pooling3dDesc->strideZ(); + desc.m_PoolWidth = pooling3dDesc->poolWidth(); + desc.m_PoolHeight = pooling3dDesc->poolHeight(); + desc.m_PoolDepth = pooling3dDesc->poolDepth(); + + return desc; +} void IDeserializer::DeserializerImpl::ParsePooling2d(GraphPtr graph, unsigned int layerIndex) { @@ -2239,7 +2339,7 @@ void IDeserializer::DeserializerImpl::ParsePooling2d(GraphPtr graph, unsigned in CHECK_VALID_SIZE(outputs.size(), 1); auto outputInfo = ToTensorInfo(outputs[0]); - auto pooling2dDescriptor = GetPoolingDescriptor(pooling2dDes, layerIndex); + auto pooling2dDescriptor = GetPooling2dDescriptor(pooling2dDes, layerIndex); auto layerName = GetLayerName(graph, layerIndex); IConnectableLayer* layer = m_Network->AddPooling2dLayer(pooling2dDescriptor, layerName.c_str()); layer->GetOutputSlot(0).SetTensorInfo(outputInfo); @@ -2248,6 +2348,27 @@ void IDeserializer::DeserializerImpl::ParsePooling2d(GraphPtr graph, unsigned in RegisterOutputSlots(graph, layerIndex, layer); } +void IDeserializer::DeserializerImpl::ParsePooling3d(GraphPtr graph, unsigned int layerIndex) +{ + CHECK_LAYERS(graph, 0, layerIndex); + + auto pooling3dDes = graph->layers()->Get(layerIndex)->layer_as_Pooling3dLayer()->descriptor(); + auto inputs = GetInputs(graph, layerIndex); + CHECK_VALID_SIZE(inputs.size(), 1); + + auto outputs = GetOutputs(graph, layerIndex); + CHECK_VALID_SIZE(outputs.size(), 1); + auto outputInfo = ToTensorInfo(outputs[0]); + + auto pooling3dDescriptor = GetPooling3dDescriptor(pooling3dDes, layerIndex); + auto layerName = GetLayerName(graph, layerIndex); + IConnectableLayer* layer = m_Network->AddPooling3dLayer(pooling3dDescriptor, layerName.c_str()); + layer->GetOutputSlot(0).SetTensorInfo(outputInfo); + + RegisterInputSlots(graph, layerIndex, layer); + RegisterOutputSlots(graph, layerIndex, layer); +} + void IDeserializer::DeserializerImpl::ParseQuantize(GraphPtr graph, unsigned int layerIndex) { CHECK_LAYERS(graph, 0, layerIndex); diff --git a/src/armnnDeserializer/Deserializer.hpp b/src/armnnDeserializer/Deserializer.hpp index d2291c07a7..8de492ed5f 100644 --- a/src/armnnDeserializer/Deserializer.hpp +++ b/src/armnnDeserializer/Deserializer.hpp @@ -18,7 +18,8 @@ namespace armnnDeserializer using ConstTensorRawPtr = const armnnSerializer::ConstTensor *; using GraphPtr = const armnnSerializer::SerializedGraph *; using TensorRawPtr = const armnnSerializer::TensorInfo *; -using PoolingDescriptor = const armnnSerializer::Pooling2dDescriptor *; +using Pooling2dDescriptor = const armnnSerializer::Pooling2dDescriptor *; +using Pooling3dDescriptor = const armnnSerializer::Pooling3dDescriptor *; using NormalizationDescriptorPtr = const armnnSerializer::NormalizationDescriptor *; using LstmDescriptorPtr = const armnnSerializer::LstmDescriptor *; using LstmInputParamsPtr = const armnnSerializer::LstmInputParams *; @@ -60,7 +61,9 @@ public: static LayerBaseRawPtr GetBaseLayer(const GraphPtr& graphPtr, unsigned int layerIndex); static int32_t GetBindingLayerInfo(const GraphPtr& graphPtr, unsigned int layerIndex); static std::string GetLayerName(const GraphPtr& graph, unsigned int index); - static armnn::Pooling2dDescriptor GetPoolingDescriptor(PoolingDescriptor pooling2dDescriptor, + static armnn::Pooling2dDescriptor GetPooling2dDescriptor(Pooling2dDescriptor pooling2dDescriptor, + unsigned int layerIndex); + static armnn::Pooling3dDescriptor GetPooling3dDescriptor(Pooling3dDescriptor pooling3dDescriptor, unsigned int layerIndex); static armnn::NormalizationDescriptor GetNormalizationDescriptor( NormalizationDescriptorPtr normalizationDescriptor, unsigned int layerIndex); @@ -121,6 +124,7 @@ private: void ParsePad(GraphPtr graph, unsigned int layerIndex); void ParsePermute(GraphPtr graph, unsigned int layerIndex); void ParsePooling2d(GraphPtr graph, unsigned int layerIndex); + void ParsePooling3d(GraphPtr graph, unsigned int layerIndex); void ParsePrelu(GraphPtr graph, unsigned int layerIndex); void ParseQLstm(GraphPtr graph, unsigned int layerIndex); void ParseQuantize(GraphPtr graph, unsigned int layerIndex); diff --git a/src/armnnDeserializer/test/DeserializePooling3d.cpp b/src/armnnDeserializer/test/DeserializePooling3d.cpp new file mode 100644 index 0000000000..62fdc5cd60 --- /dev/null +++ b/src/armnnDeserializer/test/DeserializePooling3d.cpp @@ -0,0 +1,173 @@ +// +// Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "ParserFlatbuffersSerializeFixture.hpp" +#include <armnnDeserializer/IDeserializer.hpp> + +#include <string> + +TEST_SUITE("Deserializer_Pooling3d") +{ +struct Pooling3dFixture : public ParserFlatbuffersSerializeFixture +{ + explicit Pooling3dFixture(const std::string &inputShape, + const std::string &outputShape, + const std::string &dataType, + const std::string &dataLayout, + const std::string &poolingAlgorithm) + { + m_JsonString = R"( + { + inputIds: [0], + outputIds: [2], + layers: [ + { + layer_type: "InputLayer", + layer: { + base: { + layerBindingId: 0, + base: { + index: 0, + layerName: "InputLayer", + layerType: "Input", + inputSlots: [{ + index: 0, + connection: {sourceLayerIndex:0, outputSlotIndex:0 }, + }], + outputSlots: [ { + index: 0, + tensorInfo: { + dimensions: )" + inputShape + R"(, + dataType: )" + dataType + R"( + }}] + } + }}}, + { + layer_type: "Pooling3dLayer", + layer: { + base: { + index: 1, + layerName: "Pooling3dLayer", + layerType: "Pooling3d", + inputSlots: [{ + index: 0, + connection: {sourceLayerIndex:0, outputSlotIndex:0 }, + }], + outputSlots: [ { + index: 0, + tensorInfo: { + dimensions: )" + outputShape + R"(, + dataType: )" + dataType + R"( + + }}]}, + descriptor: { + poolType: )" + poolingAlgorithm + R"(, + outputShapeRounding: "Floor", + paddingMethod: Exclude, + dataLayout: )" + dataLayout + R"(, + padLeft: 0, + padRight: 0, + padTop: 0, + padBottom: 0, + padFront: 0, + padBack: 0, + poolWidth: 2, + poolHeight: 2, + poolDepth: 2, + strideX: 2, + strideY: 2, + strideZ: 2 + } + }}, + { + layer_type: "OutputLayer", + layer: { + base:{ + layerBindingId: 0, + base: { + index: 2, + layerName: "OutputLayer", + layerType: "Output", + inputSlots: [{ + index: 0, + connection: {sourceLayerIndex:1, outputSlotIndex:0 }, + }], + outputSlots: [ { + index: 0, + tensorInfo: { + dimensions: )" + outputShape + R"(, + dataType: )" + dataType + R"( + }, + }], + }}}, + }] + } + )"; + SetupSingleInputSingleOutput("InputLayer", "OutputLayer"); + } +}; + +struct SimpleAvgPooling3dFixture : Pooling3dFixture +{ + SimpleAvgPooling3dFixture() : Pooling3dFixture("[ 1, 2, 2, 2, 1 ]", + "[ 1, 1, 1, 1, 1 ]", + "Float32", "NDHWC", "Average") {} +}; + +struct SimpleAvgPooling3dFixture2 : Pooling3dFixture +{ + SimpleAvgPooling3dFixture2() : Pooling3dFixture("[ 1, 2, 2, 2, 1 ]", + "[ 1, 1, 1, 1, 1 ]", + "QuantisedAsymm8", "NDHWC", "Average") {} +}; + +struct SimpleMaxPooling3dFixture : Pooling3dFixture +{ + SimpleMaxPooling3dFixture() : Pooling3dFixture("[ 1, 1, 2, 2, 2 ]", + "[ 1, 1, 1, 1, 1 ]", + "Float32", "NCDHW", "Max") {} +}; + +struct SimpleMaxPooling3dFixture2 : Pooling3dFixture +{ + SimpleMaxPooling3dFixture2() : Pooling3dFixture("[ 1, 1, 2, 2, 2 ]", + "[ 1, 1, 1, 1, 1 ]", + "QuantisedAsymm8", "NCDHW", "Max") {} +}; + +struct SimpleL2Pooling3dFixture : Pooling3dFixture +{ + SimpleL2Pooling3dFixture() : Pooling3dFixture("[ 1, 2, 2, 2, 1 ]", + "[ 1, 1, 1, 1, 1 ]", + "Float32", "NDHWC", "L2") {} +}; + +TEST_CASE_FIXTURE(SimpleAvgPooling3dFixture, "Pooling3dFloat32Avg") +{ + RunTest<5, armnn::DataType::Float32>(0, { 2, 3, 5, 2, 3, 2, 3, 4 }, { 3 }); +} + +TEST_CASE_FIXTURE(SimpleAvgPooling3dFixture2, "Pooling3dQuantisedAsymm8Avg") +{ + RunTest<5, armnn::DataType::QAsymmU8>(0,{ 20, 40, 60, 80, 50, 60, 70, 30 },{ 50 }); +} + +TEST_CASE_FIXTURE(SimpleMaxPooling3dFixture, "Pooling3dFloat32Max") +{ + RunTest<5, armnn::DataType::Float32>(0, { 2, 5, 5, 2, 1, 3, 4, 0 }, { 5 }); +} + +TEST_CASE_FIXTURE(SimpleMaxPooling3dFixture2, "Pooling3dQuantisedAsymm8Max") +{ + RunTest<5, armnn::DataType::QAsymmU8>(0,{ 20, 40, 60, 80, 10, 40, 0, 70 },{ 80 }); +} + +TEST_CASE_FIXTURE(SimpleL2Pooling3dFixture, "Pooling3dFloat32L2") +{ + RunTest<5, armnn::DataType::Float32>(0, { 2, 3, 5, 2, 4, 1, 1, 3 }, { 2.93683503112f }); +} + +} + diff --git a/src/armnnSerializer/ArmnnSchema.fbs b/src/armnnSerializer/ArmnnSchema.fbs index 362dd5c653..c8ffce48bc 100644 --- a/src/armnnSerializer/ArmnnSchema.fbs +++ b/src/armnnSerializer/ArmnnSchema.fbs @@ -180,6 +180,7 @@ enum LayerType : uint { UnidirectionalSequenceLstm = 63, ChannelShuffle = 64, Convolution3d = 65, + Pooling3d = 66, } // Base layer table to be used as part of other layers @@ -453,6 +454,11 @@ table Pooling2dLayer { descriptor:Pooling2dDescriptor; } +table Pooling3dLayer { + base:LayerBase; + descriptor:Pooling3dDescriptor; +} + enum PoolingAlgorithm : byte { Max = 0, Average = 1, @@ -484,6 +490,25 @@ table Pooling2dDescriptor { dataLayout:DataLayout; } +table Pooling3dDescriptor { + poolType:PoolingAlgorithm; + padLeft:uint; + padRight:uint; + padTop:uint; + padBottom:uint; + padFront:uint; + padBack:uint; + poolWidth:uint; + poolHeight:uint; + poolDepth:uint; + strideX:uint; + strideY:uint; + strideZ:uint; + outputShapeRounding:OutputShapeRounding; + paddingMethod:PaddingMethod; + dataLayout:DataLayout; +} + table QuantizeLayer { base:LayerBase; } @@ -1046,6 +1071,7 @@ union Layer { UnidirectionalSequenceLstmLayer, ChannelShuffleLayer, Convolution3dLayer, + Pooling3dLayer, } table AnyLayer { diff --git a/src/armnnSerializer/ArmnnSchema_generated.h b/src/armnnSerializer/ArmnnSchema_generated.h index b66bac69db..76a6460c85 100644 --- a/src/armnnSerializer/ArmnnSchema_generated.h +++ b/src/armnnSerializer/ArmnnSchema_generated.h @@ -173,9 +173,15 @@ struct MultiplicationLayerBuilder; struct Pooling2dLayer; struct Pooling2dLayerBuilder; +struct Pooling3dLayer; +struct Pooling3dLayerBuilder; + struct Pooling2dDescriptor; struct Pooling2dDescriptorBuilder; +struct Pooling3dDescriptor; +struct Pooling3dDescriptorBuilder; + struct QuantizeLayer; struct QuantizeLayerBuilder; @@ -770,11 +776,12 @@ enum LayerType { LayerType_UnidirectionalSequenceLstm = 63, LayerType_ChannelShuffle = 64, LayerType_Convolution3d = 65, + LayerType_Pooling3d = 66, LayerType_MIN = LayerType_Addition, - LayerType_MAX = LayerType_Convolution3d + LayerType_MAX = LayerType_Pooling3d }; -inline const LayerType (&EnumValuesLayerType())[66] { +inline const LayerType (&EnumValuesLayerType())[67] { static const LayerType values[] = { LayerType_Addition, LayerType_Input, @@ -841,13 +848,14 @@ inline const LayerType (&EnumValuesLayerType())[66] { LayerType_Shape, LayerType_UnidirectionalSequenceLstm, LayerType_ChannelShuffle, - LayerType_Convolution3d + LayerType_Convolution3d, + LayerType_Pooling3d }; return values; } inline const char * const *EnumNamesLayerType() { - static const char * const names[67] = { + static const char * const names[68] = { "Addition", "Input", "Multiplication", @@ -914,13 +922,14 @@ inline const char * const *EnumNamesLayerType() { "UnidirectionalSequenceLstm", "ChannelShuffle", "Convolution3d", + "Pooling3d", nullptr }; return names; } inline const char *EnumNameLayerType(LayerType e) { - if (flatbuffers::IsOutRange(e, LayerType_Addition, LayerType_Convolution3d)) return ""; + if (flatbuffers::IsOutRange(e, LayerType_Addition, LayerType_Pooling3d)) return ""; const size_t index = static_cast<size_t>(e); return EnumNamesLayerType()[index]; } @@ -1299,11 +1308,12 @@ enum Layer { Layer_UnidirectionalSequenceLstmLayer = 64, Layer_ChannelShuffleLayer = 65, Layer_Convolution3dLayer = 66, + Layer_Pooling3dLayer = 67, Layer_MIN = Layer_NONE, - Layer_MAX = Layer_Convolution3dLayer + Layer_MAX = Layer_Pooling3dLayer }; -inline const Layer (&EnumValuesLayer())[67] { +inline const Layer (&EnumValuesLayer())[68] { static const Layer values[] = { Layer_NONE, Layer_ActivationLayer, @@ -1371,13 +1381,14 @@ inline const Layer (&EnumValuesLayer())[67] { Layer_ShapeLayer, Layer_UnidirectionalSequenceLstmLayer, Layer_ChannelShuffleLayer, - Layer_Convolution3dLayer + Layer_Convolution3dLayer, + Layer_Pooling3dLayer }; return values; } inline const char * const *EnumNamesLayer() { - static const char * const names[68] = { + static const char * const names[69] = { "NONE", "ActivationLayer", "AdditionLayer", @@ -1445,13 +1456,14 @@ inline const char * const *EnumNamesLayer() { "UnidirectionalSequenceLstmLayer", "ChannelShuffleLayer", "Convolution3dLayer", + "Pooling3dLayer", nullptr }; return names; } inline const char *EnumNameLayer(Layer e) { - if (flatbuffers::IsOutRange(e, Layer_NONE, Layer_Convolution3dLayer)) return ""; + if (flatbuffers::IsOutRange(e, Layer_NONE, Layer_Pooling3dLayer)) return ""; const size_t index = static_cast<size_t>(e); return EnumNamesLayer()[index]; } @@ -1724,6 +1736,10 @@ template<> struct LayerTraits<armnnSerializer::Convolution3dLayer> { static const Layer enum_value = Layer_Convolution3dLayer; }; +template<> struct LayerTraits<armnnSerializer::Pooling3dLayer> { + static const Layer enum_value = Layer_Pooling3dLayer; +}; + 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); @@ -4874,6 +4890,60 @@ inline flatbuffers::Offset<Pooling2dLayer> CreatePooling2dLayer( return builder_.Finish(); } +struct Pooling3dLayer FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef Pooling3dLayerBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_BASE = 4, + VT_DESCRIPTOR = 6 + }; + const armnnSerializer::LayerBase *base() const { + return GetPointer<const armnnSerializer::LayerBase *>(VT_BASE); + } + const armnnSerializer::Pooling3dDescriptor *descriptor() const { + return GetPointer<const armnnSerializer::Pooling3dDescriptor *>(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 Pooling3dLayerBuilder { + typedef Pooling3dLayer Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_base(flatbuffers::Offset<armnnSerializer::LayerBase> base) { + fbb_.AddOffset(Pooling3dLayer::VT_BASE, base); + } + void add_descriptor(flatbuffers::Offset<armnnSerializer::Pooling3dDescriptor> descriptor) { + fbb_.AddOffset(Pooling3dLayer::VT_DESCRIPTOR, descriptor); + } + explicit Pooling3dLayerBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + Pooling3dLayerBuilder &operator=(const Pooling3dLayerBuilder &); + flatbuffers::Offset<Pooling3dLayer> Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset<Pooling3dLayer>(end); + return o; + } +}; + +inline flatbuffers::Offset<Pooling3dLayer> CreatePooling3dLayer( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset<armnnSerializer::LayerBase> base = 0, + flatbuffers::Offset<armnnSerializer::Pooling3dDescriptor> descriptor = 0) { + Pooling3dLayerBuilder builder_(_fbb); + builder_.add_descriptor(descriptor); + builder_.add_base(base); + return builder_.Finish(); +} + struct Pooling2dDescriptor FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { typedef Pooling2dDescriptorBuilder Builder; enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { @@ -5026,6 +5096,198 @@ inline flatbuffers::Offset<Pooling2dDescriptor> CreatePooling2dDescriptor( return builder_.Finish(); } +struct Pooling3dDescriptor FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef Pooling3dDescriptorBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_POOLTYPE = 4, + VT_PADLEFT = 6, + VT_PADRIGHT = 8, + VT_PADTOP = 10, + VT_PADBOTTOM = 12, + VT_PADFRONT = 14, + VT_PADBACK = 16, + VT_POOLWIDTH = 18, + VT_POOLHEIGHT = 20, + VT_POOLDEPTH = 22, + VT_STRIDEX = 24, + VT_STRIDEY = 26, + VT_STRIDEZ = 28, + VT_OUTPUTSHAPEROUNDING = 30, + VT_PADDINGMETHOD = 32, + VT_DATALAYOUT = 34 + }; + armnnSerializer::PoolingAlgorithm poolType() const { + return static_cast<armnnSerializer::PoolingAlgorithm>(GetField<int8_t>(VT_POOLTYPE, 0)); + } + 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 poolWidth() const { + return GetField<uint32_t>(VT_POOLWIDTH, 0); + } + uint32_t poolHeight() const { + return GetField<uint32_t>(VT_POOLHEIGHT, 0); + } + uint32_t poolDepth() const { + return GetField<uint32_t>(VT_POOLDEPTH, 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); + } + armnnSerializer::OutputShapeRounding outputShapeRounding() const { + return static_cast<armnnSerializer::OutputShapeRounding>(GetField<int8_t>(VT_OUTPUTSHAPEROUNDING, 0)); + } + armnnSerializer::PaddingMethod paddingMethod() const { + return static_cast<armnnSerializer::PaddingMethod>(GetField<int8_t>(VT_PADDINGMETHOD, 0)); + } + armnnSerializer::DataLayout dataLayout() const { + return static_cast<armnnSerializer::DataLayout>(GetField<int8_t>(VT_DATALAYOUT, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField<int8_t>(verifier, VT_POOLTYPE) && + 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_POOLWIDTH) && + VerifyField<uint32_t>(verifier, VT_POOLHEIGHT) && + VerifyField<uint32_t>(verifier, VT_POOLDEPTH) && + VerifyField<uint32_t>(verifier, VT_STRIDEX) && + VerifyField<uint32_t>(verifier, VT_STRIDEY) && + VerifyField<uint32_t>(verifier, VT_STRIDEZ) && + VerifyField<int8_t>(verifier, VT_OUTPUTSHAPEROUNDING) && + VerifyField<int8_t>(verifier, VT_PADDINGMETHOD) && + VerifyField<int8_t>(verifier, VT_DATALAYOUT) && + verifier.EndTable(); + } +}; + +struct Pooling3dDescriptorBuilder { + typedef Pooling3dDescriptor Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_poolType(armnnSerializer::PoolingAlgorithm poolType) { + fbb_.AddElement<int8_t>(Pooling3dDescriptor::VT_POOLTYPE, static_cast<int8_t>(poolType), 0); + } + void add_padLeft(uint32_t padLeft) { + fbb_.AddElement<uint32_t>(Pooling3dDescriptor::VT_PADLEFT, padLeft, 0); + } + void add_padRight(uint32_t padRight) { + fbb_.AddElement<uint32_t>(Pooling3dDescriptor::VT_PADRIGHT, padRight, 0); + } + void add_padTop(uint32_t padTop) { + fbb_.AddElement<uint32_t>(Pooling3dDescriptor::VT_PADTOP, padTop, 0); + } + void add_padBottom(uint32_t padBottom) { + fbb_.AddElement<uint32_t>(Pooling3dDescriptor::VT_PADBOTTOM, padBottom, 0); + } + void add_padFront(uint32_t padFront) { + fbb_.AddElement<uint32_t>(Pooling3dDescriptor::VT_PADFRONT, padFront, 0); + } + void add_padBack(uint32_t padBack) { + fbb_.AddElement<uint32_t>(Pooling3dDescriptor::VT_PADBACK, padBack, 0); + } + void add_poolWidth(uint32_t poolWidth) { + fbb_.AddElement<uint32_t>(Pooling3dDescriptor::VT_POOLWIDTH, poolWidth, 0); + } + void add_poolHeight(uint32_t poolHeight) { + fbb_.AddElement<uint32_t>(Pooling3dDescriptor::VT_POOLHEIGHT, poolHeight, 0); + } + void add_poolDepth(uint32_t poolDepth) { + fbb_.AddElement<uint32_t>(Pooling3dDescriptor::VT_POOLDEPTH, poolDepth, 0); + } + void add_strideX(uint32_t strideX) { + fbb_.AddElement<uint32_t>(Pooling3dDescriptor::VT_STRIDEX, strideX, 0); + } + void add_strideY(uint32_t strideY) { + fbb_.AddElement<uint32_t>(Pooling3dDescriptor::VT_STRIDEY, strideY, 0); + } + void add_strideZ(uint32_t strideZ) { + fbb_.AddElement<uint32_t>(Pooling3dDescriptor::VT_STRIDEZ, strideZ, 0); + } + void add_outputShapeRounding(armnnSerializer::OutputShapeRounding outputShapeRounding) { + fbb_.AddElement<int8_t>(Pooling3dDescriptor::VT_OUTPUTSHAPEROUNDING, static_cast<int8_t>(outputShapeRounding), 0); + } + void add_paddingMethod(armnnSerializer::PaddingMethod paddingMethod) { + fbb_.AddElement<int8_t>(Pooling3dDescriptor::VT_PADDINGMETHOD, static_cast<int8_t>(paddingMethod), 0); + } + void add_dataLayout(armnnSerializer::DataLayout dataLayout) { + fbb_.AddElement<int8_t>(Pooling3dDescriptor::VT_DATALAYOUT, static_cast<int8_t>(dataLayout), 0); + } + explicit Pooling3dDescriptorBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + Pooling3dDescriptorBuilder &operator=(const Pooling3dDescriptorBuilder &); + flatbuffers::Offset<Pooling3dDescriptor> Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset<Pooling3dDescriptor>(end); + return o; + } +}; + +inline flatbuffers::Offset<Pooling3dDescriptor> CreatePooling3dDescriptor( + flatbuffers::FlatBufferBuilder &_fbb, + armnnSerializer::PoolingAlgorithm poolType = armnnSerializer::PoolingAlgorithm_Max, + 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 poolWidth = 0, + uint32_t poolHeight = 0, + uint32_t poolDepth = 0, + uint32_t strideX = 0, + uint32_t strideY = 0, + uint32_t strideZ = 0, + armnnSerializer::OutputShapeRounding outputShapeRounding = armnnSerializer::OutputShapeRounding_Floor, + armnnSerializer::PaddingMethod paddingMethod = armnnSerializer::PaddingMethod_IgnoreValue, + armnnSerializer::DataLayout dataLayout = armnnSerializer::DataLayout_NHWC) { + Pooling3dDescriptorBuilder builder_(_fbb); + builder_.add_strideZ(strideZ); + builder_.add_strideY(strideY); + builder_.add_strideX(strideX); + builder_.add_poolDepth(poolDepth); + builder_.add_poolHeight(poolHeight); + builder_.add_poolWidth(poolWidth); + 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_paddingMethod(paddingMethod); + builder_.add_outputShapeRounding(outputShapeRounding); + builder_.add_poolType(poolType); + return builder_.Finish(); +} + struct QuantizeLayer FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { typedef QuantizeLayerBuilder Builder; enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { @@ -10269,6 +10531,9 @@ struct AnyLayer FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { const armnnSerializer::Convolution3dLayer *layer_as_Convolution3dLayer() const { return layer_type() == armnnSerializer::Layer_Convolution3dLayer ? static_cast<const armnnSerializer::Convolution3dLayer *>(layer()) : nullptr; } + const armnnSerializer::Pooling3dLayer *layer_as_Pooling3dLayer() const { + return layer_type() == armnnSerializer::Layer_Pooling3dLayer ? static_cast<const armnnSerializer::Pooling3dLayer *>(layer()) : nullptr; + } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyField<uint8_t>(verifier, VT_LAYER_TYPE) && @@ -10542,6 +10807,10 @@ template<> inline const armnnSerializer::Convolution3dLayer *AnyLayer::layer_as< return layer_as_Convolution3dLayer(); } +template<> inline const armnnSerializer::Pooling3dLayer *AnyLayer::layer_as<armnnSerializer::Pooling3dLayer>() const { + return layer_as_Pooling3dLayer(); +} + struct AnyLayerBuilder { typedef AnyLayer Table; flatbuffers::FlatBufferBuilder &fbb_; @@ -11036,6 +11305,10 @@ inline bool VerifyLayer(flatbuffers::Verifier &verifier, const void *obj, Layer auto ptr = reinterpret_cast<const armnnSerializer::Convolution3dLayer *>(obj); return verifier.VerifyTable(ptr); } + case Layer_Pooling3dLayer: { + auto ptr = reinterpret_cast<const armnnSerializer::Pooling3dLayer *>(obj); + return verifier.VerifyTable(ptr); + } default: return true; } } diff --git a/src/armnnSerializer/Serializer.cpp b/src/armnnSerializer/Serializer.cpp index a9f7b7d307..4249e08c71 100644 --- a/src/armnnSerializer/Serializer.cpp +++ b/src/armnnSerializer/Serializer.cpp @@ -1079,6 +1079,39 @@ void SerializerStrategy::SerializePooling2dLayer(const armnn::IConnectableLayer* CreateAnyLayer(fbPooling2dLayer.o, serializer::Layer::Layer_Pooling2dLayer); } +void SerializerStrategy::SerializePooling3dLayer(const armnn::IConnectableLayer* layer, + const armnn::Pooling3dDescriptor& pooling3dDescriptor, + const char* name) +{ + IgnoreUnused(name); + + auto fbPooling3dBaseLayer = CreateLayerBase(layer, serializer::LayerType::LayerType_Pooling3d); + auto fbPooling3dDescriptor = serializer::CreatePooling3dDescriptor( + m_flatBufferBuilder, + GetFlatBufferPoolingAlgorithm(pooling3dDescriptor.m_PoolType), + pooling3dDescriptor.m_PadLeft, + pooling3dDescriptor.m_PadRight, + pooling3dDescriptor.m_PadTop, + pooling3dDescriptor.m_PadBottom, + pooling3dDescriptor.m_PadFront, + pooling3dDescriptor.m_PadBack, + pooling3dDescriptor.m_PoolWidth, + pooling3dDescriptor.m_PoolHeight, + pooling3dDescriptor.m_PoolDepth, + pooling3dDescriptor.m_StrideX, + pooling3dDescriptor.m_StrideY, + pooling3dDescriptor.m_StrideZ, + GetFlatBufferOutputShapeRounding(pooling3dDescriptor.m_OutputShapeRounding), + GetFlatBufferPaddingMethod(pooling3dDescriptor.m_PaddingMethod), + GetFlatBufferDataLayout(pooling3dDescriptor.m_DataLayout)); + + auto fbPooling3dLayer = serializer::CreatePooling3dLayer(m_flatBufferBuilder, + fbPooling3dBaseLayer, + fbPooling3dDescriptor); + + CreateAnyLayer(fbPooling3dLayer.o, serializer::Layer::Layer_Pooling3dLayer); +} + void SerializerStrategy::SerializePreluLayer(const armnn::IConnectableLayer* layer, const char* name) { @@ -2208,6 +2241,13 @@ void SerializerStrategy::ExecuteStrategy(const armnn::IConnectableLayer* layer, SerializePooling2dLayer(layer, layerDescriptor, name); break; } + case armnn::LayerType::Pooling3d : + { + const armnn::Pooling3dDescriptor& layerDescriptor = + static_cast<const armnn::Pooling3dDescriptor&>(descriptor); + SerializePooling3dLayer(layer, layerDescriptor, name); + break; + } case armnn::LayerType::Prelu : { SerializePreluLayer(layer, name); diff --git a/src/armnnSerializer/Serializer.hpp b/src/armnnSerializer/Serializer.hpp index 1c0a9a619f..bb6455f842 100644 --- a/src/armnnSerializer/Serializer.hpp +++ b/src/armnnSerializer/Serializer.hpp @@ -248,6 +248,10 @@ private: const armnn::Pooling2dDescriptor& pooling2dDescriptor, const char* name = nullptr); + void SerializePooling3dLayer(const armnn::IConnectableLayer* layer, + const armnn::Pooling3dDescriptor& pooling3dDescriptor, + const char* name = nullptr); + void SerializePreluLayer(const armnn::IConnectableLayer* layer, const char* name = nullptr); diff --git a/src/armnnSerializer/test/SerializerTests.cpp b/src/armnnSerializer/test/SerializerTests.cpp index f4e25998d9..632a80a748 100644 --- a/src/armnnSerializer/test/SerializerTests.cpp +++ b/src/armnnSerializer/test/SerializerTests.cpp @@ -1834,6 +1834,49 @@ TEST_CASE("SerializePooling2d") deserializedNetwork->ExecuteStrategy(verifier); } +TEST_CASE("SerializePooling3d") +{ + const std::string layerName("pooling3d"); + const armnn::TensorInfo inputInfo({1, 1, 2, 2, 2}, armnn::DataType::Float32); + const armnn::TensorInfo outputInfo({1, 1, 1, 1, 1}, armnn::DataType::Float32); + + armnn::Pooling3dDescriptor desc; + desc.m_DataLayout = armnn::DataLayout::NDHWC; + desc.m_PadFront = 0; + desc.m_PadBack = 0; + desc.m_PadTop = 0; + desc.m_PadBottom = 0; + desc.m_PadLeft = 0; + desc.m_PadRight = 0; + desc.m_PoolType = armnn::PoolingAlgorithm::Average; + desc.m_OutputShapeRounding = armnn::OutputShapeRounding::Floor; + desc.m_PaddingMethod = armnn::PaddingMethod::Exclude; + desc.m_PoolHeight = 2; + desc.m_PoolWidth = 2; + desc.m_PoolDepth = 2; + desc.m_StrideX = 2; + desc.m_StrideY = 2; + desc.m_StrideZ = 2; + + armnn::INetworkPtr network = armnn::INetwork::Create(); + armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0); + armnn::IConnectableLayer* const pooling3dLayer = network->AddPooling3dLayer(desc, layerName.c_str()); + armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0); + + inputLayer->GetOutputSlot(0).Connect(pooling3dLayer->GetInputSlot(0)); + pooling3dLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); + + inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo); + pooling3dLayer->GetOutputSlot(0).SetTensorInfo(outputInfo); + + armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network)); + CHECK(deserializedNetwork); + + LayerVerifierBaseWithDescriptor<armnn::Pooling3dDescriptor> verifier( + layerName, {inputInfo}, {outputInfo}, desc); + deserializedNetwork->ExecuteStrategy(verifier); +} + TEST_CASE("SerializeQuantize") { const std::string layerName("quantize"); |