| // |
| // Copyright © 2017 Arm Ltd and Contributors. All rights reserved. |
| // SPDX-License-Identifier: MIT |
| // |
| |
| #include "Deserializer.hpp" |
| |
| #include <armnn/Descriptors.hpp> |
| #include <armnn/Exceptions.hpp> |
| #include <armnn/TypesUtils.hpp> |
| #include <armnn/LstmParams.hpp> |
| #include <armnn/QuantizedLstmParams.hpp> |
| #include <armnn/Logging.hpp> |
| |
| #include <armnnUtils/Permute.hpp> |
| #include <armnnUtils/Transpose.hpp> |
| #include <armnn/utility/Assert.hpp> |
| #include <armnn/utility/IgnoreUnused.hpp> |
| #include <armnn/utility/NumericCast.hpp> |
| |
| #include <ParserHelper.hpp> |
| #include <VerificationHelpers.hpp> |
| |
| #include <fmt/format.h> |
| |
| #include <fstream> |
| #include <algorithm> |
| #include <limits> |
| #include <numeric> |
| |
| using armnn::ParseException; |
| using namespace armnn; |
| using namespace armnnSerializer; |
| |
| namespace armnnDeserializer |
| { |
| |
| IDeserializer::IDeserializer() : pDeserializerImpl(new DeserializerImpl()){} |
| |
| IDeserializer::~IDeserializer() = default; |
| |
| IDeserializer *IDeserializer::CreateRaw() |
| { |
| return new IDeserializer(); |
| } |
| |
| IDeserializerPtr IDeserializer::Create() |
| { |
| return IDeserializerPtr(CreateRaw(), &IDeserializer::Destroy); |
| } |
| |
| void IDeserializer::Destroy(IDeserializer *parser) |
| { |
| delete parser; |
| } |
| |
| armnn::INetworkPtr IDeserializer::CreateNetworkFromBinary(const std::vector<uint8_t> &binaryContent) |
| { |
| return pDeserializerImpl->CreateNetworkFromBinary(binaryContent); |
| } |
| |
| armnn::INetworkPtr IDeserializer::CreateNetworkFromBinary(std::istream &binaryContent) |
| { |
| return pDeserializerImpl->CreateNetworkFromBinary(binaryContent); |
| } |
| |
| BindingPointInfo IDeserializer::GetNetworkInputBindingInfo(unsigned int layerId, const std::string &name) const |
| { |
| return pDeserializerImpl->GetNetworkInputBindingInfo(layerId, name); |
| } |
| |
| BindingPointInfo IDeserializer::GetNetworkOutputBindingInfo(unsigned int layerId, const std::string &name) const |
| { |
| return pDeserializerImpl->GetNetworkOutputBindingInfo(layerId, name); |
| } |
| |
| namespace |
| { |
| |
| const uint32_t VIRTUAL_LAYER_ID = std::numeric_limits<uint32_t>::max(); |
| |
| void CheckGraph(const GraphPtr& graph, |
| unsigned int layersIndex, |
| const CheckLocation& location) |
| { |
| if (graph->layers() == nullptr) |
| { |
| throw ParseException(fmt::format("{0} was called with invalid (null) graph. " |
| "Possible reason is that the graph is not yet loaded and Unpack(ed). " |
| "layers:{1} at {2}", |
| location.m_Function, |
| layersIndex, |
| location.FileLine())); |
| } |
| else if (layersIndex >= graph->layers()->size()) |
| { |
| throw ParseException(fmt::format("{0} was called with an invalid layers index. layers:{1} at {2}", |
| location.m_Function, |
| layersIndex, |
| location.FileLine())); |
| } |
| } |
| |
| void CheckLayers(const GraphPtr& graph, |
| unsigned int layersIndex, |
| unsigned int layerIndex, |
| const CheckLocation& location) |
| { |
| if (graph->layers() == nullptr) |
| { |
| throw ParseException(fmt::format("{0} was called with invalid (null) graph. " |
| "Possible reason is that the graph is not yet loaded and Unpack(ed). " |
| "layers:{1} at {2}", |
| location.m_Function, |
| layersIndex, |
| location.FileLine())); |
| } |
| else if (layersIndex >= graph->layers()->size()) |
| { |
| throw ParseException(fmt::format("{0} was called with an invalid layers index. " |
| "layers:{1} at {2}", |
| location.m_Function, |
| layersIndex, |
| location.FileLine())); |
| } |
| else if (layerIndex >= graph->layers()[layersIndex].size() |
| && layerIndex != VIRTUAL_LAYER_ID) |
| { |
| throw ParseException(fmt::format("{0} was called with an invalid layer index. " |
| "layers:{1} layer:{2} at {3}", |
| location.m_Function, |
| layersIndex, |
| layerIndex, |
| location.FileLine())); |
| } |
| } |
| |
| void CheckTensorPtr(TensorRawPtr rawPtr, |
| const CheckLocation& location) |
| { |
| if (rawPtr == nullptr) |
| { |
| throw ParseException(fmt::format("{0} was called with a null tensor pointer. at {1}", |
| location.m_Function, |
| location.FileLine())); |
| } |
| } |
| |
| void CheckConstTensorPtr(ConstTensorRawPtr rawPtr, |
| const CheckLocation& location) |
| { |
| if (rawPtr == nullptr) |
| { |
| throw ParseException(fmt::format("{0} was called with a null const tensor pointer. at {1}", |
| location.m_Function, |
| location.FileLine())); |
| } |
| } |
| |
| void CheckConstTensorSize(const unsigned int constTensorSize, |
| const unsigned int tensorSize, |
| const CheckLocation& location) |
| { |
| if (constTensorSize != tensorSize) |
| { |
| throw ParseException(fmt::format("{0} wrong number of components supplied to tensor. at:{1}", |
| location.m_Function, |
| location.FileLine())); |
| } |
| } |
| |
| #define CHECK_TENSOR_PTR(TENSOR_PTR) \ |
| CheckTensorPtr(TENSOR_PTR, CHECK_LOCATION()) |
| |
| #define CHECK_CONST_TENSOR_SIZE(CONST_TENSOR_SIZE, TENSOR_SIZE) \ |
| CheckConstTensorSize(CONST_TENSOR_SIZE, TENSOR_SIZE, CHECK_LOCATION()) |
| |
| #define CHECK_CONST_TENSOR_PTR(TENSOR_PTR) \ |
| CheckConstTensorPtr(TENSOR_PTR, CHECK_LOCATION()) |
| |
| #define CHECK_LAYERS(GRAPH, LAYERS_INDEX, LAYER_INDEX) \ |
| CheckLayers(GRAPH, LAYERS_INDEX, LAYER_INDEX, CHECK_LOCATION()) |
| |
| #define CHECK_GRAPH(GRAPH, LAYERS_INDEX) \ |
| CheckGraph(GRAPH, LAYERS_INDEX, CHECK_LOCATION()) |
| } |
| |
| bool CheckShape(const armnn::TensorShape& actual, const std::vector<uint32_t>& expected) |
| { |
| const unsigned int actualSize = actual.GetNumDimensions(); |
| if (actualSize != expected.size()) |
| { |
| return false; |
| } |
| |
| for (unsigned int i = 0u; i < actualSize; i++) |
| { |
| if (actual[i] != static_cast<unsigned int>(expected[i])) |
| { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| IDeserializer::DeserializerImpl::DeserializerImpl() |
| : m_Network(nullptr, nullptr), |
| //May require LayerType_Max to be included |
| m_ParserFunctions(Layer_MAX+1, &IDeserializer::DeserializerImpl::ParseUnsupportedLayer) |
| { |
| // register supported layers |
| m_ParserFunctions[Layer_AbsLayer] = &DeserializerImpl::ParseAbs; |
| m_ParserFunctions[Layer_ActivationLayer] = &DeserializerImpl::ParseActivation; |
| m_ParserFunctions[Layer_AdditionLayer] = &DeserializerImpl::ParseAdd; |
| m_ParserFunctions[Layer_ArgMinMaxLayer] = &DeserializerImpl::ParseArgMinMax; |
| m_ParserFunctions[Layer_BatchMatMulLayer] = &DeserializerImpl::ParseBatchMatMul; |
| m_ParserFunctions[Layer_BatchToSpaceNdLayer] = &DeserializerImpl::ParseBatchToSpaceNd; |
| m_ParserFunctions[Layer_BatchNormalizationLayer] = &DeserializerImpl::ParseBatchNormalization; |
| m_ParserFunctions[Layer_CastLayer] = &DeserializerImpl::ParseCast; |
| m_ParserFunctions[Layer_ChannelShuffleLayer] = &DeserializerImpl::ParseChannelShuffle; |
| m_ParserFunctions[Layer_ComparisonLayer] = &DeserializerImpl::ParseComparison; |
| m_ParserFunctions[Layer_ConcatLayer] = &DeserializerImpl::ParseConcat; |
| m_ParserFunctions[Layer_ConstantLayer] = &DeserializerImpl::ParseConstant; |
| m_ParserFunctions[Layer_Convolution2dLayer] = &DeserializerImpl::ParseConvolution2d; |
| m_ParserFunctions[Layer_Convolution3dLayer] = &DeserializerImpl::ParseConvolution3d; |
| m_ParserFunctions[Layer_DepthToSpaceLayer] = &DeserializerImpl::ParseDepthToSpace; |
| m_ParserFunctions[Layer_DepthwiseConvolution2dLayer] = &DeserializerImpl::ParseDepthwiseConvolution2d; |
| m_ParserFunctions[Layer_DequantizeLayer] = &DeserializerImpl::ParseDequantize; |
| m_ParserFunctions[Layer_DetectionPostProcessLayer] = &DeserializerImpl::ParseDetectionPostProcess; |
| m_ParserFunctions[Layer_DivisionLayer] = &DeserializerImpl::ParseDivision; |
| m_ParserFunctions[Layer_ElementwiseUnaryLayer] = &DeserializerImpl::ParseElementwiseUnary; |
| m_ParserFunctions[Layer_EqualLayer] = &DeserializerImpl::ParseEqual; |
| m_ParserFunctions[Layer_FullyConnectedLayer] = &DeserializerImpl::ParseFullyConnected; |
| m_ParserFunctions[Layer_FillLayer] = &DeserializerImpl::ParseFill; |
| m_ParserFunctions[Layer_FloorLayer] = &DeserializerImpl::ParseFloor; |
| m_ParserFunctions[Layer_GatherLayer] = &DeserializerImpl::ParseGather; |
| m_ParserFunctions[Layer_GatherNdLayer] = &DeserializerImpl::ParseGatherNd; |
| m_ParserFunctions[Layer_GreaterLayer] = &DeserializerImpl::ParseGreater; |
| m_ParserFunctions[Layer_InstanceNormalizationLayer] = &DeserializerImpl::ParseInstanceNormalization; |
| m_ParserFunctions[Layer_L2NormalizationLayer] = &DeserializerImpl::ParseL2Normalization; |
| m_ParserFunctions[Layer_LogicalBinaryLayer] = &DeserializerImpl::ParseLogicalBinary; |
| m_ParserFunctions[Layer_LogSoftmaxLayer] = &DeserializerImpl::ParseLogSoftmax; |
| m_ParserFunctions[Layer_LstmLayer] = &DeserializerImpl::ParseLstm; |
| m_ParserFunctions[Layer_MaximumLayer] = &DeserializerImpl::ParseMaximum; |
| m_ParserFunctions[Layer_MeanLayer] = &DeserializerImpl::ParseMean; |
| m_ParserFunctions[Layer_MinimumLayer] = &DeserializerImpl::ParseMinimum; |
| m_ParserFunctions[Layer_MergeLayer] = &DeserializerImpl::ParseMerge; |
| m_ParserFunctions[Layer_MergerLayer] = &DeserializerImpl::ParseConcat; |
| m_ParserFunctions[Layer_MultiplicationLayer] = &DeserializerImpl::ParseMultiplication; |
| m_ParserFunctions[Layer_NormalizationLayer] = &DeserializerImpl::ParseNormalization; |
| 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; |
| m_ParserFunctions[Layer_QuantizedLstmLayer] = &DeserializerImpl::ParseQuantizedLstm; |
| m_ParserFunctions[Layer_RankLayer] = &DeserializerImpl::ParseRank; |
| m_ParserFunctions[Layer_ReduceLayer] = &DeserializerImpl::ParseReduce; |
| m_ParserFunctions[Layer_ReshapeLayer] = &DeserializerImpl::ParseReshape; |
| m_ParserFunctions[Layer_ResizeBilinearLayer] = &DeserializerImpl::ParseResizeBilinear; |
| m_ParserFunctions[Layer_ResizeLayer] = &DeserializerImpl::ParseResize; |
| m_ParserFunctions[Layer_RsqrtLayer] = &DeserializerImpl::ParseRsqrt; |
| m_ParserFunctions[Layer_ShapeLayer] = &DeserializerImpl::ParseShape; |
| m_ParserFunctions[Layer_SliceLayer] = &DeserializerImpl::ParseSlice; |
| m_ParserFunctions[Layer_SoftmaxLayer] = &DeserializerImpl::ParseSoftmax; |
| m_ParserFunctions[Layer_SpaceToBatchNdLayer] = &DeserializerImpl::ParseSpaceToBatchNd; |
| m_ParserFunctions[Layer_SpaceToDepthLayer] = &DeserializerImpl::ParseSpaceToDepth; |
| m_ParserFunctions[Layer_SplitterLayer] = &DeserializerImpl::ParseSplitter; |
| m_ParserFunctions[Layer_StackLayer] = &DeserializerImpl::ParseStack; |
| m_ParserFunctions[Layer_StandInLayer] = &DeserializerImpl::ParseStandIn; |
| m_ParserFunctions[Layer_StridedSliceLayer] = &DeserializerImpl::ParseStridedSlice; |
| m_ParserFunctions[Layer_SubtractionLayer] = &DeserializerImpl::ParseSubtraction; |
| m_ParserFunctions[Layer_SwitchLayer] = &DeserializerImpl::ParseSwitch; |
| m_ParserFunctions[Layer_TransposeConvolution2dLayer] = &DeserializerImpl::ParseTransposeConvolution2d; |
| m_ParserFunctions[Layer_TransposeLayer] = &DeserializerImpl::ParseTranspose; |
| m_ParserFunctions[Layer_UnidirectionalSequenceLstmLayer] = &DeserializerImpl::ParseUnidirectionalSequenceLstm; |
| } |
| |
| LayerBaseRawPtr IDeserializer::DeserializerImpl::GetBaseLayer(const GraphPtr& graphPtr, unsigned int layerIndex) |
| { |
| auto layerType = graphPtr->layers()->Get(layerIndex)->layer_type(); |
| |
| switch(layerType) |
| { |
| case Layer::Layer_AbsLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_AbsLayer()->base(); |
| case Layer::Layer_ActivationLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_ActivationLayer()->base(); |
| case Layer::Layer_AdditionLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_AdditionLayer()->base(); |
| case Layer::Layer_ArgMinMaxLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_ArgMinMaxLayer()->base(); |
| case Layer::Layer_BatchMatMulLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_BatchMatMulLayer()->base(); |
| case Layer::Layer_BatchToSpaceNdLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_BatchToSpaceNdLayer()->base(); |
| case Layer::Layer_BatchNormalizationLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_BatchNormalizationLayer()->base(); |
| case Layer::Layer_CastLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_CastLayer()->base(); |
| case Layer::Layer_ChannelShuffleLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_ChannelShuffleLayer()->base(); |
| case Layer::Layer_ComparisonLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_ComparisonLayer()->base(); |
| case Layer::Layer_ConcatLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_ConcatLayer()->base(); |
| case Layer::Layer_ConstantLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_ConstantLayer()->base(); |
| case Layer::Layer_Convolution2dLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_Convolution2dLayer()->base(); |
| case Layer::Layer_Convolution3dLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_Convolution3dLayer()->base(); |
| case Layer::Layer_DepthToSpaceLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_DepthToSpaceLayer()->base(); |
| case Layer::Layer_DepthwiseConvolution2dLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_DepthwiseConvolution2dLayer()->base(); |
| case Layer::Layer_DequantizeLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_DequantizeLayer()->base(); |
| case Layer::Layer_DetectionPostProcessLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_DetectionPostProcessLayer()->base(); |
| case Layer::Layer_DivisionLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_DivisionLayer()->base(); |
| case Layer::Layer_EqualLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_EqualLayer()->base(); |
| case Layer::Layer_ElementwiseUnaryLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_ElementwiseUnaryLayer()->base(); |
| case Layer::Layer_FullyConnectedLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_FullyConnectedLayer()->base(); |
| case Layer::Layer_FillLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_FillLayer()->base(); |
| case Layer::Layer_FloorLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_FloorLayer()->base(); |
| case Layer::Layer_GatherLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_GatherLayer()->base(); |
| case Layer::Layer_GatherNdLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_GatherNdLayer()->base(); |
| case Layer::Layer_GreaterLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_GreaterLayer()->base(); |
| case Layer::Layer_InputLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_InputLayer()->base()->base(); |
| case Layer::Layer_InstanceNormalizationLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_InstanceNormalizationLayer()->base(); |
| case Layer::Layer_L2NormalizationLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_L2NormalizationLayer()->base(); |
| case Layer::Layer_LogicalBinaryLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_LogicalBinaryLayer()->base(); |
| case Layer::Layer_LogSoftmaxLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_LogSoftmaxLayer()->base(); |
| case Layer::Layer_LstmLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_LstmLayer()->base(); |
| case Layer::Layer_MeanLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_MeanLayer()->base(); |
| case Layer::Layer_MinimumLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_MinimumLayer()->base(); |
| case Layer::Layer_MaximumLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_MaximumLayer()->base(); |
| case Layer::Layer_MergeLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_MergeLayer()->base(); |
| case Layer::Layer_MergerLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_MergerLayer()->base(); |
| case Layer::Layer_MultiplicationLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_MultiplicationLayer()->base(); |
| case Layer::Layer_NormalizationLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_NormalizationLayer()->base(); |
| case Layer::Layer_OutputLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_OutputLayer()->base()->base(); |
| case Layer::Layer_PadLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_PadLayer()->base(); |
| case Layer::Layer_PermuteLayer: |
| 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: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_QLstmLayer()->base(); |
| case Layer::Layer_QuantizeLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_QuantizeLayer()->base(); |
| case Layer::Layer_QuantizedLstmLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_QuantizedLstmLayer()->base(); |
| case Layer::Layer_RankLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_RankLayer()->base(); |
| case Layer::Layer_ReduceLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_ReduceLayer()->base(); |
| case Layer::Layer_ReshapeLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_ReshapeLayer()->base(); |
| case Layer::Layer_ResizeBilinearLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_ResizeBilinearLayer()->base(); |
| case Layer::Layer_ResizeLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_ResizeLayer()->base(); |
| case Layer::Layer_RsqrtLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_RsqrtLayer()->base(); |
| case Layer::Layer_ShapeLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_ShapeLayer()->base(); |
| case Layer::Layer_SliceLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_SliceLayer()->base(); |
| case Layer::Layer_SoftmaxLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_SoftmaxLayer()->base(); |
| case Layer::Layer_SpaceToBatchNdLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_SpaceToBatchNdLayer()->base(); |
| case Layer::Layer_SpaceToDepthLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_SpaceToDepthLayer()->base(); |
| case Layer::Layer_SplitterLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_SplitterLayer()->base(); |
| case Layer::Layer_StackLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_StackLayer()->base(); |
| case Layer::Layer_StandInLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_StandInLayer()->base(); |
| case Layer::Layer_StridedSliceLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_StridedSliceLayer()->base(); |
| case Layer::Layer_SubtractionLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_SubtractionLayer()->base(); |
| case Layer::Layer_SwitchLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_SwitchLayer()->base(); |
| case Layer::Layer_TransposeConvolution2dLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_TransposeConvolution2dLayer()->base(); |
| case Layer::Layer_TransposeLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_TransposeLayer()->base(); |
| case Layer::Layer_UnidirectionalSequenceLstmLayer: |
| return graphPtr->layers()->Get(layerIndex)->layer_as_UnidirectionalSequenceLstmLayer()->base(); |
| case Layer::Layer_NONE: |
| default: |
| throw ParseException(fmt::format("Layer type {} not recognized", layerType)); |
| } |
| } |
| |
| std::string IDeserializer::DeserializerImpl::GetLayerName(const GraphPtr& graph, unsigned int index) |
| { |
| auto layer = GetBaseLayer(graph, index); |
| assert(layer); |
| return layer->layerName()->str(); |
| } |
| |
| int32_t IDeserializer::DeserializerImpl::GetBindingLayerInfo(const GraphPtr& graphPtr, unsigned int layerIndex) |
| { |
| auto layerType = graphPtr->layers()->Get(layerIndex)->layer_type(); |
| |
| if (layerType == Layer::Layer_InputLayer) |
| { |
| return graphPtr->layers()->Get(layerIndex)->layer_as_InputLayer()->base()->layerBindingId(); |
| } |
| else if ( layerType == Layer::Layer_OutputLayer ) |
| { |
| return graphPtr->layers()->Get(layerIndex)->layer_as_OutputLayer()->base()->layerBindingId(); |
| } |
| return 0; |
| } |
| |
| armnn::DataLayout ToDataLayout(armnnSerializer::DataLayout dataLayout) |
| { |
| switch (dataLayout) |
| { |
| case armnnSerializer::DataLayout::DataLayout_NHWC: |
| return armnn::DataLayout::NHWC; |
| case armnnSerializer::DataLayout::DataLayout_NDHWC: |
| return armnn::DataLayout::NDHWC; |
| case armnnSerializer::DataLayout::DataLayout_NCDHW: |
| return armnn::DataLayout::NCDHW; |
| case armnnSerializer::DataLayout::DataLayout_NCHW: |
| default: |
| return armnn::DataLayout::NCHW; |
| } |
| } |
| |
| armnn::ActivationFunction ToActivationFunction(armnnSerializer::ActivationFunction function) |
| { |
| switch (function) |
| { |
| case armnnSerializer::ActivationFunction_Sigmoid: |
| return armnn::ActivationFunction::Sigmoid; |
| case armnnSerializer::ActivationFunction_TanH: |
| return armnn::ActivationFunction::TanH; |
| case armnnSerializer::ActivationFunction_Linear: |
| return armnn::ActivationFunction::Linear; |
| case armnnSerializer::ActivationFunction_ReLu: |
| return armnn::ActivationFunction::ReLu; |
| case armnnSerializer::ActivationFunction_BoundedReLu: |
| return armnn::ActivationFunction::BoundedReLu; |
| case armnnSerializer::ActivationFunction_LeakyReLu: |
| return armnn::ActivationFunction::LeakyReLu; |
| case armnnSerializer::ActivationFunction_Abs: |
| return armnn::ActivationFunction::Abs; |
| case armnnSerializer::ActivationFunction_Sqrt: |
| return armnn::ActivationFunction::Sqrt; |
| case armnnSerializer::ActivationFunction_Square: |
| return armnn::ActivationFunction::Square; |
| case armnnSerializer::ActivationFunction_Elu: |
| return armnn::ActivationFunction::Elu; |
| case armnnSerializer::ActivationFunction_HardSwish: |
| return armnn::ActivationFunction::HardSwish; |
| default: |
| return armnn::ActivationFunction::Sigmoid; |
| } |
| } |
| |
| armnn::ArgMinMaxFunction ToArgMinMaxFunction(armnnSerializer::ArgMinMaxFunction function) |
| { |
| switch (function) |
| { |
| case armnnSerializer::ArgMinMaxFunction::ArgMinMaxFunction_Max: |
| return armnn::ArgMinMaxFunction::Max; |
| case armnnSerializer::ArgMinMaxFunction::ArgMinMaxFunction_Min: |
| default: |
| return armnn::ArgMinMaxFunction::Min; |
| } |
| } |
| |
| armnn::ComparisonOperation ToComparisonOperation(armnnSerializer::ComparisonOperation operation) |
| { |
| switch (operation) |
| { |
| case armnnSerializer::ComparisonOperation::ComparisonOperation_Equal: |
| return armnn::ComparisonOperation::Equal; |
| case armnnSerializer::ComparisonOperation::ComparisonOperation_Greater: |
| return armnn::ComparisonOperation::Greater; |
| case armnnSerializer::ComparisonOperation::ComparisonOperation_GreaterOrEqual: |
| return armnn::ComparisonOperation::GreaterOrEqual; |
| case armnnSerializer::ComparisonOperation::ComparisonOperation_Less: |
| return armnn::ComparisonOperation::Less; |
| case armnnSerializer::ComparisonOperation::ComparisonOperation_LessOrEqual: |
| return armnn::ComparisonOperation::LessOrEqual; |
| case armnnSerializer::ComparisonOperation::ComparisonOperation_NotEqual: |
| default: |
| return armnn::ComparisonOperation::NotEqual; |
| } |
| } |
| |
| armnn::ReduceOperation ToReduceOperation(armnnSerializer::ReduceOperation operation) |
| { |
| switch (operation) |
| { |
| case armnnSerializer::ReduceOperation::ReduceOperation_Sum: |
| return armnn::ReduceOperation::Sum; |
| case armnnSerializer::ReduceOperation::ReduceOperation_Max: |
| return armnn::ReduceOperation::Max; |
| case armnnSerializer::ReduceOperation::ReduceOperation_Mean: |
| return armnn::ReduceOperation::Mean; |
| case armnnSerializer::ReduceOperation::ReduceOperation_Min: |
| return armnn::ReduceOperation::Min; |
| case armnnSerializer::ReduceOperation::ReduceOperation_Prod: |
| return armnn::ReduceOperation::Prod; |
| default: |
| return armnn::ReduceOperation::Sum; |
| } |
| } |
| |
| armnn::LogicalBinaryOperation ToLogicalBinaryOperation(armnnSerializer::LogicalBinaryOperation operation) |
| { |
| switch (operation) |
| { |
| case armnnSerializer::LogicalBinaryOperation::LogicalBinaryOperation_LogicalAnd: |
| return armnn::LogicalBinaryOperation::LogicalAnd; |
| case armnnSerializer::LogicalBinaryOperation::LogicalBinaryOperation_LogicalOr: |
| return armnn::LogicalBinaryOperation::LogicalOr; |
| default: |
| throw armnn::InvalidArgumentException("Logical Binary operation unknown"); |
| } |
| } |
| |
| armnn::UnaryOperation ToUnaryOperation(armnnSerializer::UnaryOperation operation) |
| { |
| switch (operation) |
| { |
| case armnnSerializer::UnaryOperation::UnaryOperation_Abs: |
| return armnn::UnaryOperation::Abs; |
| case armnnSerializer::UnaryOperation::UnaryOperation_Rsqrt: |
| return armnn::UnaryOperation::Rsqrt; |
| case armnnSerializer::UnaryOperation::UnaryOperation_Sqrt: |
| return armnn::UnaryOperation::Sqrt; |
| case armnnSerializer::UnaryOperation::UnaryOperation_Exp: |
| return armnn::UnaryOperation::Exp; |
| case armnnSerializer::UnaryOperation::UnaryOperation_Neg: |
| return armnn::UnaryOperation::Neg; |
| case armnnSerializer::UnaryOperation::UnaryOperation_LogicalNot: |
| return armnn::UnaryOperation::LogicalNot; |
| case armnnSerializer::UnaryOperation::UnaryOperation_Log: |
| return armnn::UnaryOperation::Log; |
| case armnnSerializer::UnaryOperation::UnaryOperation_Sin: |
| return armnn::UnaryOperation::Sin; |
| default: |
| throw armnn::InvalidArgumentException("Unary operation unknown"); |
| } |
| } |
| |
| armnn::PaddingMode ToPaddingMode(armnnSerializer::PaddingMode paddingMode) |
| { |
| switch (paddingMode) |
| { |
| case armnnSerializer::PaddingMode::PaddingMode_Reflect: |
| return armnn::PaddingMode::Reflect; |
| case armnnSerializer::PaddingMode::PaddingMode_Symmetric: |
| return armnn::PaddingMode::Symmetric; |
| default: |
| return armnn::PaddingMode::Constant; |
| } |
| } |
| |
| armnn::ResizeMethod ToResizeMethod(armnnSerializer::ResizeMethod method) |
| { |
| switch (method) |
| { |
| case armnnSerializer::ResizeMethod_NearestNeighbor: |
| return armnn::ResizeMethod::NearestNeighbor; |
| case armnnSerializer::ResizeMethod_Bilinear: |
| return armnn::ResizeMethod::Bilinear; |
| default: |
| return armnn::ResizeMethod::NearestNeighbor; |
| } |
| } |
| |
| armnn::TensorInfo ToTensorInfo(TensorRawPtr tensorPtr) |
| { |
| armnn::DataType type; |
| CHECK_TENSOR_PTR(tensorPtr); |
| |
| switch (tensorPtr->dataType()) |
| { |
| case DataType_QAsymmS8: |
| type = armnn::DataType::QAsymmS8; |
| break; |
| case DataType_QSymmS8: |
| type = armnn::DataType::QSymmS8; |
| break; |
| case DataType_QuantisedAsymm8: |
| case DataType_QAsymmU8: |
| type = armnn::DataType::QAsymmU8; |
| break; |
| case DataType_QSymmS16: |
| case DataType_QuantisedSymm16: |
| type = armnn::DataType::QSymmS16; |
| break; |
| case DataType_Signed32: |
| type = armnn::DataType::Signed32; |
| break; |
| case DataType_Signed64: |
| type = armnn::DataType::Signed64; |
| break; |
| case DataType_Float32: |
| type = armnn::DataType::Float32; |
| break; |
| case DataType_Float16: |
| type = armnn::DataType::Float16; |
| break; |
| case DataType_Boolean: |
| type = armnn::DataType::Boolean; |
| break; |
| default: |
| { |
| CheckLocation location = CHECK_LOCATION(); |
| throw ParseException(fmt::format("Unsupported data type {0} = {1}. {2}", |
| tensorPtr->dataType(), |
| EnumNameDataType(tensorPtr->dataType()), |
| location.AsString())); |
| } |
| } |
| |
| float quantizationScale = tensorPtr->quantizationScale(); |
| int32_t quantizationOffset = tensorPtr->quantizationOffset(); |
| |
| if (tensorPtr->dimensionality() == static_cast<unsigned int>(Dimensionality::Scalar)) |
| { |
| return armnn::TensorInfo(TensorShape{armnn::Dimensionality::Scalar}, |
| type, |
| quantizationScale, |
| quantizationOffset); |
| } |
| else if (tensorPtr->dimensionality() == static_cast<unsigned int>(Dimensionality::NotSpecified)) |
| { |
| armnn::TensorInfo result(TensorShape{Dimensionality::NotSpecified}, |
| type, |
| quantizationScale, |
| quantizationOffset); |
| return result; |
| } |
| |
| auto dimensions = tensorPtr->dimensions(); |
| unsigned int size = dimensions->size(); |
| std::vector<unsigned int> outputDims(dimensions->begin(), dimensions->begin() + size); |
| bool dimensionsSpecificity[armnn::MaxNumOfTensorDimensions]; |
| std::fill_n(dimensionsSpecificity, armnn::MaxNumOfTensorDimensions, true); |
| // For backwards compatibility check if the dimensionSpecificity vector is present first. |
| // The default is to have dimensionSpecificity set to all true's anyway. |
| if (tensorPtr->dimensionSpecificity() != nullptr) |
| { |
| auto dimensionSpecificity = tensorPtr->dimensionSpecificity(); |
| size = dimensionSpecificity->size(); |
| for (unsigned int i = 0; i < size; ++i) |
| { |
| dimensionsSpecificity[i] = dimensionSpecificity->Get(i); |
| } |
| } |
| // Construct a TensorShape |
| TensorShape shape(size, outputDims.data(), dimensionsSpecificity); |
| |
| auto quantizationScales = tensorPtr->quantizationScales(); |
| if (quantizationScales) |
| { |
| unsigned int quantizationScalesSize = quantizationScales->size(); |
| std::vector<float> scales(quantizationScales->begin(), quantizationScales->begin() + quantizationScalesSize); |
| unsigned int quantizationDim = tensorPtr->quantizationDim(); |
| armnn::TensorInfo result(shape, |
| type, |
| scales, |
| quantizationDim); |
| return result; |
| } |
| |
| // two statements (on purpose) for easier debugging: |
| armnn::TensorInfo result(shape, |
| type, |
| quantizationScale, |
| quantizationOffset); |
| |
| return result; |
| } |
| |
| armnn::ConstTensor ToConstTensor(ConstTensorRawPtr constTensorPtr) |
| { |
| CHECK_CONST_TENSOR_PTR(constTensorPtr); |
| armnn::TensorInfo tensorInfo = ToTensorInfo(constTensorPtr->info()); |
| tensorInfo.SetConstant(); |
| |
| switch (constTensorPtr->data_type()) |
| { |
| case ConstTensorData_ByteData: |
| { |
| auto byteData = constTensorPtr->data_as_ByteData()->data(); |
| CHECK_CONST_TENSOR_SIZE(byteData->size(), tensorInfo.GetNumElements()); |
| return armnn::ConstTensor(tensorInfo, byteData->data()); |
| } |
| case ConstTensorData_ShortData: |
| { |
| auto shortData = constTensorPtr->data_as_ShortData()->data(); |
| CHECK_CONST_TENSOR_SIZE(shortData->size(), tensorInfo.GetNumElements()); |
| return armnn::ConstTensor(tensorInfo, shortData->data()); |
| } |
| case ConstTensorData_IntData: |
| { |
| auto intData = constTensorPtr->data_as_IntData()->data(); |
| CHECK_CONST_TENSOR_SIZE(intData->size(), tensorInfo.GetNumElements()); |
| return armnn::ConstTensor(tensorInfo, intData->data()); |
| } |
| case ConstTensorData_LongData: |
| { |
| auto longData = constTensorPtr->data_as_LongData()->data(); |
| CHECK_CONST_TENSOR_SIZE(longData->size(), tensorInfo.GetNumElements()); |
| return armnn::ConstTensor(tensorInfo, longData->data()); |
| } |
| default: |
| { |
| CheckLocation location = CHECK_LOCATION(); |
| throw ParseException(fmt::format("Unsupported data type {0} = {1}. {2}", |
| constTensorPtr->data_type(), |
| EnumNameConstTensorData(constTensorPtr->data_type()), |
| location.AsString())); |
| } |
| } |
| } |
| |
| TensorRawPtrVector IDeserializer::DeserializerImpl::GetInputs(const GraphPtr& graphPtr, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graphPtr, 0, layerIndex); |
| auto layer = GetBaseLayer(graphPtr, layerIndex); |
| const auto& numInputs = layer->inputSlots()->size(); |
| |
| TensorRawPtrVector result(numInputs); |
| |
| for (unsigned int i=0; i<numInputs; ++i) |
| { |
| auto inputId = CHECKED_NON_NEGATIVE(static_cast<int32_t> |
| (layer->inputSlots()->Get(i)->connection()->sourceLayerIndex())); |
| result[i] = GetBaseLayer(graphPtr, inputId)->outputSlots()->Get(0)->tensorInfo(); |
| } |
| return result; |
| } |
| |
| TensorRawPtrVector IDeserializer::DeserializerImpl::GetOutputs(const GraphPtr& graphPtr, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graphPtr, 0, layerIndex); |
| auto layer = GetBaseLayer(graphPtr, layerIndex); |
| const auto& numOutputs = layer->outputSlots()->size(); |
| |
| TensorRawPtrVector result(numOutputs); |
| |
| for (unsigned int i=0; i<numOutputs; ++i) |
| { |
| result[i] = layer->outputSlots()->Get(i)->tensorInfo(); |
| } |
| return result; |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseUnsupportedLayer(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| const auto layerName = GetBaseLayer(graph, layerIndex)->layerName()->c_str(); |
| throw ParseException(fmt::format("Layer not supported. layerIndex: {0} " |
| "layerName: {1} / {2}", |
| layerIndex, |
| layerName, |
| CHECK_LOCATION().AsString())); |
| } |
| |
| void IDeserializer::DeserializerImpl::ResetParser() |
| { |
| m_Network = armnn::INetworkPtr(nullptr, nullptr); |
| m_InputBindings.clear(); |
| m_OutputBindings.clear(); |
| } |
| |
| |
| INetworkPtr IDeserializer::DeserializerImpl::CreateNetworkFromBinary(const std::vector<uint8_t>& binaryContent) |
| { |
| ResetParser(); |
| GraphPtr graph = LoadGraphFromBinary(binaryContent.data(), binaryContent.size()); |
| return CreateNetworkFromGraph(graph); |
| } |
| |
| armnn::INetworkPtr IDeserializer::DeserializerImpl::CreateNetworkFromBinary(std::istream& binaryContent) |
| { |
| ResetParser(); |
| if (binaryContent.fail()) { |
| ARMNN_LOG(error) << (std::string("Cannot read input")); |
| throw ParseException("Unable to read Input stream data"); |
| } |
| binaryContent.seekg(0, std::ios::end); |
| const std::streamoff size = binaryContent.tellg(); |
| std::vector<char> content(static_cast<size_t>(size)); |
| binaryContent.seekg(0); |
| binaryContent.read(content.data(), static_cast<std::streamsize>(size)); |
| GraphPtr graph = LoadGraphFromBinary(reinterpret_cast<uint8_t*>(content.data()), static_cast<size_t>(size)); |
| return CreateNetworkFromGraph(graph); |
| } |
| |
| GraphPtr IDeserializer::DeserializerImpl::LoadGraphFromBinary(const uint8_t* binaryContent, size_t len) |
| { |
| if (binaryContent == nullptr) |
| { |
| throw InvalidArgumentException(fmt::format("Invalid (null) binary content {}", |
| CHECK_LOCATION().AsString())); |
| } |
| flatbuffers::Verifier verifier(binaryContent, len); |
| if (verifier.VerifyBuffer<SerializedGraph>() == false) |
| { |
| throw ParseException(fmt::format("Buffer doesn't conform to the expected Armnn " |
| "flatbuffers format. size:{0} {1}", |
| len, |
| CHECK_LOCATION().AsString())); |
| } |
| return GetSerializedGraph(binaryContent); |
| } |
| |
| INetworkPtr IDeserializer::DeserializerImpl::CreateNetworkFromGraph(GraphPtr graph) |
| { |
| m_Network = INetwork::Create(); |
| ARMNN_ASSERT(graph != nullptr); |
| unsigned int layerIndex = 0; |
| for (AnyLayer const* layer : *graph->layers()) |
| { |
| if (layer->layer_type() != Layer_InputLayer && |
| layer->layer_type() != Layer_OutputLayer) |
| { |
| // lookup and call the parser function |
| auto& parserFunction = m_ParserFunctions[layer->layer_type()]; |
| (this->*parserFunction)(graph, layerIndex); |
| } |
| ++layerIndex; |
| } |
| |
| SetupInputLayers(graph); |
| SetupOutputLayers(graph); |
| |
| // establish the connections from the layer outputs to the inputs of the subsequent layers |
| for (auto&& graphIt : m_GraphConnections) |
| { |
| Connections& connections = graphIt.second; |
| for (auto&& outputIt : connections.outputSlots) |
| { |
| const unsigned int outputSlotIndex = outputIt.first; |
| IOutputSlot* outputSlot = outputIt.second; |
| if (connections.inputSlots.find(outputSlotIndex) != connections.inputSlots.end()) |
| { |
| for (IInputSlot* inputSlot : connections.inputSlots[outputSlotIndex]) |
| { |
| outputSlot->Connect(*inputSlot); |
| } |
| } |
| } |
| } |
| |
| return std::move(m_Network); |
| } |
| |
| BindingPointInfo IDeserializer::DeserializerImpl::GetNetworkInputBindingInfo(unsigned int layerIndex, |
| const std::string& name) const |
| { |
| IgnoreUnused(layerIndex); |
| for (auto inputBinding : m_InputBindings) |
| { |
| if (inputBinding.first == name) |
| { |
| return inputBinding.second; |
| } |
| } |
| throw ParseException(fmt::format("No input binding found for layer:{0} / {1}", |
| name, |
| CHECK_LOCATION().AsString())); |
| } |
| |
| BindingPointInfo IDeserializer::DeserializerImpl::GetNetworkOutputBindingInfo(unsigned int layerIndex, |
| const std::string& name) const |
| { |
| IgnoreUnused(layerIndex); |
| for (auto outputBinding : m_OutputBindings) |
| { |
| if (outputBinding.first == name) |
| { |
| return outputBinding.second; |
| } |
| } |
| throw ParseException(fmt::format("No output binding found for layer:{0} / {1}", |
| name, |
| CHECK_LOCATION().AsString())); |
| } |
| |
| unsigned int IDeserializer::DeserializerImpl::GetInputLayerInVector(GraphPtr graph, int targetId) |
| { |
| for (unsigned int i = 0; i < graph->layers()->size(); i++) |
| { |
| auto layer = graph->layers()->Get(i); |
| if (layer->layer_type() == Layer::Layer_InputLayer) |
| { |
| auto layerBindingId = layer->layer_as_InputLayer()->base()->layerBindingId(); |
| if (layerBindingId == targetId) |
| { |
| return i; |
| } |
| } |
| } |
| throw ParseException("Input layer with given layerBindingId not found"); |
| } |
| |
| unsigned int IDeserializer::DeserializerImpl::GetOutputLayerInVector(GraphPtr graph, int targetId) |
| { |
| for (unsigned int i = 0; i < graph->layers()->size(); i++) |
| { |
| auto layer = graph->layers()->Get(i); |
| if (layer->layer_type() == Layer::Layer_OutputLayer) |
| { |
| auto layerBindingId = layer->layer_as_OutputLayer()->base()->layerBindingId(); |
| if (layerBindingId == targetId) |
| { |
| return i; |
| } |
| } |
| } |
| throw ParseException("Output layer with given layerBindingId not found"); |
| } |
| |
| unsigned int IDeserializer::DeserializerImpl::GetLayerIndexInVector(GraphPtr graph, unsigned int targetIndex) |
| { |
| for (unsigned int i = 0; i < graph->layers()->size(); i++) |
| { |
| LayerBaseRawPtr layer = GetBaseLayer(graph, i); |
| if (layer->index() == targetIndex) |
| { |
| return i; |
| } |
| } |
| throw ParseException("Layer with given index not found"); |
| } |
| |
| IDeserializer::DeserializerImpl::FeatureVersions IDeserializer::DeserializerImpl::GetFeatureVersions(GraphPtr graph) |
| { |
| IDeserializer::DeserializerImpl::FeatureVersions versions; |
| |
| if (graph->featureVersions()) |
| { |
| versions.m_BindingIdScheme = graph->featureVersions()->bindingIdsScheme(); |
| versions.m_WeightsLayoutScheme = graph->featureVersions()->weightsLayoutScheme(); |
| versions.m_ConstTensorsAsInputs = graph->featureVersions()->constantTensorsAsInputs(); |
| } |
| |
| return versions; |
| } |
| |
| void IDeserializer::DeserializerImpl::SetupInputLayers(GraphPtr graph) |
| { |
| CHECK_GRAPH(graph, 0); |
| const unsigned int numInputs = graph->inputIds()->size(); |
| m_InputBindings.clear(); |
| m_InputBindings.reserve(numInputs); |
| |
| for (unsigned int i = 0; i < numInputs; i++) |
| { |
| unsigned int inputLayerIndex = 0xFFFFFFFF; |
| if (GetFeatureVersions(graph).m_BindingIdScheme == 0) |
| { |
| const unsigned int inputId = armnn::numeric_cast<unsigned int>(graph->inputIds()->Get(i)); |
| inputLayerIndex = GetLayerIndexInVector(graph, inputId); |
| } |
| else |
| { |
| const int inputId = graph->inputIds()->Get(i); |
| inputLayerIndex = GetInputLayerInVector(graph, inputId); |
| } |
| |
| LayerBaseRawPtr baseLayer = GetBaseLayer(graph, inputLayerIndex); |
| |
| // GetBindingLayerInfo expect the index to be index in the vector not index property on each layer base |
| LayerBindingId bindingId = GetBindingLayerInfo(graph, inputLayerIndex); |
| ARMNN_ASSERT_MSG(baseLayer->layerName()->c_str(), "Input has no name."); |
| |
| IConnectableLayer* inputLayer = |
| m_Network->AddInputLayer(bindingId, baseLayer->layerName()->c_str()); |
| |
| const armnn::TensorInfo& tensorInfo = ToTensorInfo(baseLayer->outputSlots()->Get(0)->tensorInfo()); |
| inputLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo); |
| RegisterOutputSlots(graph, inputLayerIndex, inputLayer); |
| |
| BindingPointInfo bindingInfo = {bindingId, tensorInfo}; |
| m_InputBindings.push_back(std::make_pair(baseLayer->layerName()->c_str(), bindingInfo)); |
| } |
| } |
| |
| void IDeserializer::DeserializerImpl::SetupOutputLayers(GraphPtr graph) |
| { |
| CHECK_GRAPH(graph, 0); |
| const unsigned int numOutputs = graph->outputIds()->size(); |
| m_OutputBindings.clear(); |
| m_OutputBindings.reserve(numOutputs); |
| |
| for (unsigned int i = 0; i < numOutputs; i++) |
| { |
| unsigned int outputLayerIndex = 0xFFFFFFFF; |
| if (GetFeatureVersions(graph).m_BindingIdScheme == 0) |
| { |
| const unsigned int outputId = armnn::numeric_cast<unsigned int>(graph->outputIds()->Get(i)); |
| outputLayerIndex = GetLayerIndexInVector(graph, outputId); |
| } |
| else |
| { |
| const int outputId = graph->outputIds()->Get(i); |
| outputLayerIndex = GetOutputLayerInVector(graph, outputId); |
| } |
| |
| LayerBaseRawPtr baseLayer = GetBaseLayer(graph, outputLayerIndex); |
| |
| // GetBindingLayerInfo expect the index to be index in the vector not index property on each layer base |
| LayerBindingId bindingId = GetBindingLayerInfo(graph, outputLayerIndex); |
| ARMNN_ASSERT_MSG(baseLayer->layerName()->c_str(), "Output has no name."); |
| |
| IConnectableLayer* outputLayer = |
| m_Network->AddOutputLayer(bindingId, baseLayer->layerName()->c_str()); |
| |
| RegisterInputSlots(graph, outputLayerIndex, outputLayer); |
| unsigned int sourceLayerIndex = |
| GetLayerIndexInVector(graph, baseLayer->inputSlots()->Get(0)->connection()->sourceLayerIndex()); |
| unsigned int outputSlotIndex = |
| GetLayerIndexInVector(graph, baseLayer->inputSlots()->Get(0)->connection()->outputSlotIndex()); |
| LayerBaseRawPtr sourceBaseLayer = GetBaseLayer(graph, sourceLayerIndex); |
| const armnn::TensorInfo& tensorInfo = ToTensorInfo( |
| sourceBaseLayer->outputSlots()->Get(outputSlotIndex)->tensorInfo()); |
| BindingPointInfo bindingInfo = {bindingId, tensorInfo}; |
| m_OutputBindings.push_back(std::make_pair(baseLayer->layerName()->c_str(), bindingInfo)); |
| } |
| } |
| |
| void IDeserializer::DeserializerImpl::RegisterOutputSlots(GraphPtr graph, |
| uint32_t layerIndex, |
| IConnectableLayer* layer) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| ARMNN_ASSERT(layer != nullptr); |
| LayerBaseRawPtr baseLayer = GetBaseLayer(graph, layerIndex); |
| if (baseLayer->outputSlots()->size() != layer->GetNumOutputSlots()) |
| { |
| throw ParseException(fmt::format("The number of outputslots ({0}) does not match the number expected ({1})" |
| " for layer index: {2} {3}", |
| baseLayer->outputSlots()->size(), |
| layer->GetNumOutputSlots(), |
| layerIndex, |
| CHECK_LOCATION().AsString())); |
| } |
| |
| for (unsigned int i = 0; i < layer->GetNumOutputSlots(); ++i) |
| { |
| const unsigned int slotIndex = baseLayer->outputSlots()->Get(i)->index(); |
| armnn::IOutputSlot* outputSlot = &(layer->GetOutputSlot(slotIndex)); |
| // layerIndex is not necessarily the same as baseLayer->index(). The latter is needed here |
| RegisterOutputSlotOfConnection(baseLayer->index(), slotIndex, outputSlot); |
| } |
| } |
| |
| void IDeserializer::DeserializerImpl::RegisterInputSlots(GraphPtr graph, |
| uint32_t layerIndex, |
| armnn::IConnectableLayer* layer, |
| std::vector<unsigned int> ignoreSlots) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| ARMNN_ASSERT(layer != nullptr); |
| LayerBaseRawPtr baseLayer = GetBaseLayer(graph, layerIndex); |
| |
| if (baseLayer->inputSlots()->size() != (layer->GetNumInputSlots() - ignoreSlots.size())) |
| { |
| throw ParseException(fmt::format("The number of inputslots ({0}) does not match the number expected ({1})" |
| " for layer index:{2} {3}", |
| baseLayer->inputSlots()->size(), |
| layer->GetNumInputSlots(), |
| layerIndex, |
| CHECK_LOCATION().AsString())); |
| } |
| |
| for (unsigned int i = 0; i < layer->GetNumInputSlots(); ++i) |
| { |
| // Check if slot should be ignored. |
| if (std::find(ignoreSlots.begin(), ignoreSlots.end(), i) == ignoreSlots.end()) |
| { |
| auto fbInputSlot = baseLayer->inputSlots()->Get(i); |
| auto fbConnection = fbInputSlot->connection(); |
| armnn::IInputSlot* inputSlot = &(layer->GetInputSlot(fbInputSlot->index())); |
| RegisterInputSlotOfConnection(fbConnection->sourceLayerIndex(), fbConnection->outputSlotIndex(), inputSlot); |
| } |
| } |
| } |
| |
| void IDeserializer::DeserializerImpl::RegisterInputSlotOfConnection(uint32_t sourceLayerIndex, |
| uint32_t outputSlotIndex, |
| armnn::IInputSlot* inputSlot) |
| { |
| if (m_GraphConnections.find(sourceLayerIndex) == m_GraphConnections.end()) |
| { |
| m_GraphConnections[sourceLayerIndex] = Connections(); |
| } |
| |
| Connections& connections = m_GraphConnections[sourceLayerIndex]; |
| if (connections.inputSlots.find(outputSlotIndex) == connections.inputSlots.end()) |
| { |
| connections.inputSlots[outputSlotIndex] = {inputSlot}; |
| } |
| else |
| { |
| connections.inputSlots[outputSlotIndex].push_back(inputSlot); |
| } |
| } |
| |
| void IDeserializer::DeserializerImpl::RegisterOutputSlotOfConnection(uint32_t sourceLayerIndex, |
| uint32_t outputSlotIndex, |
| armnn::IOutputSlot* outputSlot) |
| { |
| if (m_GraphConnections.find(sourceLayerIndex) == m_GraphConnections.end()) |
| { |
| m_GraphConnections[sourceLayerIndex] = Connections(); |
| } |
| |
| Connections& connections = m_GraphConnections[sourceLayerIndex]; |
| if (connections.outputSlots.find(outputSlotIndex) != connections.outputSlots.end()) |
| { |
| throw ParseException("Same output slot index processed twice"); |
| } |
| |
| connections.outputSlots[outputSlotIndex] = outputSlot; |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseAbs(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_LOCATION(); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| |
| armnn::ElementwiseUnaryDescriptor descriptor(armnn::UnaryOperation::Abs); |
| IConnectableLayer* layer = m_Network->AddElementwiseUnaryLayer(descriptor, layerName.c_str()); |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseActivation(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_LOCATION(); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto serializerLayer = graph->layers()->Get(layerIndex)->layer_as_ActivationLayer(); |
| auto layerName = GetLayerName(graph, layerIndex); |
| auto serializerDescriptor = serializerLayer->descriptor(); |
| |
| armnn::ActivationDescriptor descriptor; |
| descriptor.m_Function = ToActivationFunction(serializerDescriptor->activationFunction()); |
| descriptor.m_A = serializerDescriptor->a(); |
| descriptor.m_B = serializerDescriptor->b(); |
| |
| IConnectableLayer* layer = m_Network->AddActivationLayer(descriptor, |
| layerName.c_str()); |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseAdd(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_LOCATION(); |
| CHECK_VALID_SIZE(inputs.size(), 2); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddAdditionLayer(layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseArgMinMax(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_LOCATION(); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto serializerLayer = graph->layers()->Get(layerIndex)->layer_as_ArgMinMaxLayer(); |
| auto serializerDescriptor = serializerLayer->descriptor(); |
| |
| armnn::ArgMinMaxDescriptor descriptor; |
| descriptor.m_Function = ToArgMinMaxFunction(serializerDescriptor->argMinMaxFunction()); |
| descriptor.m_Axis = serializerDescriptor->axis(); |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddArgMinMaxLayer(descriptor, layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseBatchMatMul(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_LOCATION(); |
| CHECK_VALID_SIZE(inputs.size(), 2); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto serializerLayer = graph->layers()->Get(layerIndex)->layer_as_BatchMatMulLayer(); |
| auto serializerDescriptor = serializerLayer->descriptor(); |
| |
| armnn::BatchMatMulDescriptor descriptor(serializerDescriptor->transposeX(), |
| serializerDescriptor->transposeY(), |
| serializerDescriptor->adjointX(), |
| serializerDescriptor->adjointY(), |
| ToDataLayout(serializerDescriptor->dataLayoutX()), |
| ToDataLayout(serializerDescriptor->dataLayoutY())); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddBatchMatMulLayer(descriptor, layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseBatchToSpaceNd(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| TensorRawPtrVector inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| TensorRawPtrVector outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_BatchToSpaceNdLayer()->descriptor(); |
| auto flatBufferCrops = flatBufferDescriptor->crops(); |
| auto flatBufferBlockShape = flatBufferDescriptor->blockShape(); |
| |
| if (flatBufferCrops->size() % 2 != 0) |
| { |
| throw ParseException(fmt::format("The size of crops must be divisible by 2 {}", CHECK_LOCATION().AsString())); |
| } |
| |
| std::vector<std::pair<unsigned int, unsigned int>> crops; |
| crops.reserve(flatBufferCrops->size() / 2); |
| for (unsigned int i = 0; i < flatBufferCrops->size() - 1; i += 2) |
| { |
| crops.emplace_back(flatBufferCrops->Get(i), flatBufferCrops->Get(i+1)); |
| } |
| |
| armnn::BatchToSpaceNdDescriptor descriptor; |
| descriptor.m_DataLayout = ToDataLayout(flatBufferDescriptor->dataLayout()); |
| descriptor.m_BlockShape = |
| std::vector<unsigned int>(flatBufferBlockShape->begin(), flatBufferBlockShape->end()); |
| descriptor.m_Crops = crops; |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddBatchToSpaceNdLayer(descriptor, layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseBatchNormalization(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| 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 layerName = GetLayerName(graph, layerIndex); |
| |
| auto serializerLayer = graph->layers()->Get(layerIndex)->layer_as_BatchNormalizationLayer(); |
| auto serializerDescriptor = serializerLayer->descriptor(); |
| |
| armnn::BatchNormalizationDescriptor descriptor; |
| descriptor.m_Eps = serializerDescriptor->eps(); |
| descriptor.m_DataLayout = ToDataLayout(serializerDescriptor->dataLayout()); |
| |
| armnn::ConstTensor mean = ToConstTensor(serializerLayer->mean()); |
| armnn::ConstTensor variance = ToConstTensor(serializerLayer->variance()); |
| armnn::ConstTensor beta = ToConstTensor(serializerLayer->beta()); |
| armnn::ConstTensor gamma = ToConstTensor(serializerLayer->gamma()); |
| |
| IConnectableLayer* layer = m_Network->AddBatchNormalizationLayer(descriptor, |
| mean, |
| variance, |
| beta, |
| gamma, |
| layerName.c_str()); |
| layer->GetOutputSlot(0).SetTensorInfo(outputInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseCast(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| TensorRawPtrVector inputs = GetInputs(graph, layerIndex); |
| CHECK_LOCATION(); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| TensorRawPtrVector outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| |
| IConnectableLayer* layer = m_Network->AddCastLayer(layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseConstant(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| CHECK_LOCATION(); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| |
| auto serializerLayer = graph->layers()->Get(layerIndex)->layer_as_ConstantLayer(); |
| auto serializerInput = serializerLayer->input(); |
| |
| armnn::ConstTensor input = ToConstTensor(serializerInput); |
| IConnectableLayer* layer; |
| |
| // Required for when Constant Layer is used as an inputs to DepthwiseConvolution2d Layer. |
| // Running a model that was created before weights layout scheme version was added to our flatbuffers |
| // file ensuring older models can still be read and executed. featureVersion weights layout scheme 1 |
| // indicates a change in the depthwise weights layout within ArmNN from [M,I,H,W] --> [1,H,W,I*M] |
| if (this->GetFeatureVersions(graph).m_WeightsLayoutScheme <= 0) |
| { |
| // Permute weights [ H, W, M, I ] --> [ 1, H, W, I*M ] |
| // Step1: [ M, I, H, W ] --> [ H, W, I, M] |
| PermutationVector permutationVector = { 3, 2, 0, 1 }; |
| armnn::TensorInfo weightsInfo = input.GetInfo(); |
| std::unique_ptr<unsigned char[]> permuteBuffer(new unsigned char[weightsInfo.GetNumBytes()]); |
| weightsInfo = armnnUtils::Permuted(weightsInfo, permutationVector); |
| armnnUtils::Permute(weightsInfo.GetShape(), permutationVector, |
| input.GetMemoryArea(), permuteBuffer.get(), |
| GetDataTypeSize(weightsInfo.GetDataType())); |
| |
| // Step2: Reshape [ H, W, I, M] --> [ 1, H, W, I*M ] |
| auto weightsShape = weightsInfo.GetShape(); |
| weightsInfo.SetShape({1, |
| weightsShape[0], |
| weightsShape[1], |
| weightsShape[2]*weightsShape[3]}); |
| weightsInfo.SetConstant(true); |
| |
| armnn::ConstTensor weightsPermuted(weightsInfo, permuteBuffer.get()); |
| |
| layer = m_Network->AddConstantLayer(weightsPermuted, layerName.c_str()); |
| |
| layer->GetOutputSlot(0).SetTensorInfo(weightsPermuted.GetInfo()); |
| |
| RegisterOutputSlots(graph, layerIndex, layer); |
| |
| return; |
| } |
| else |
| { |
| layer = m_Network->AddConstantLayer(input, layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| outputTensorInfo.SetConstant(true); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| } |
| |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseConvolution2d(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_LOCATION(); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto flatBufferLayer = graph->layers()->Get(layerIndex)->layer_as_Convolution2dLayer(); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| auto flatbufferDescriptor = flatBufferLayer->descriptor(); |
| |
| armnn::Convolution2dDescriptor descriptor; |
| descriptor.m_PadLeft = flatbufferDescriptor->padLeft(); |
| descriptor.m_PadRight = flatbufferDescriptor->padRight(); |
| descriptor.m_PadTop = flatbufferDescriptor->padTop(); |
| descriptor.m_PadBottom = flatbufferDescriptor->padBottom(); |
| descriptor.m_StrideX = flatbufferDescriptor->strideX(); |
| descriptor.m_StrideY = flatbufferDescriptor->strideY();; |
| descriptor.m_DilationX = flatbufferDescriptor->dilationX(); |
| descriptor.m_DilationY = flatbufferDescriptor->dilationY();; |
| descriptor.m_BiasEnabled = flatbufferDescriptor->biasEnabled();; |
| descriptor.m_DataLayout = ToDataLayout(flatbufferDescriptor->dataLayout()); |
| |
| armnn::IConnectableLayer* layer; |
| std::vector<unsigned int> ignoreSlots {}; |
| |
| armnn::ConstTensor biasTensor; |
| // Weights and biases used to be always constant and were stored as members of the layer. This has changed and |
| // they are now passed as inputs. If they are constant then they will be stored in a ConstantLayer. |
| if (this->GetFeatureVersions(graph).m_ConstTensorsAsInputs <= 0) |
| { |
| // If the model stores weights and biases as members of the layer we have to read them from there |
| // but add them to their own ConstantLayer for compatibility |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| layer = m_Network->AddConvolution2dLayer(descriptor, |
| layerName.c_str()); |
| |
| armnn::ConstTensor weightsTensor = ToConstTensor(flatBufferLayer->weights()); |
| auto weightsLayer = m_Network->AddConstantLayer(weightsTensor); |
| weightsLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1u)); |
| weightsLayer->GetOutputSlot(0).SetTensorInfo(weightsTensor.GetInfo()); |
| ignoreSlots.emplace_back(1u); |
| |
| if (descriptor.m_BiasEnabled) |
| { |
| biasTensor = ToConstTensor(flatBufferLayer->biases()); |
| auto biasLayer = m_Network->AddConstantLayer(biasTensor); |
| biasLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(2u)); |
| biasLayer->GetOutputSlot(0).SetTensorInfo(biasTensor.GetInfo()); |
| ignoreSlots.emplace_back(2u); |
| } |
| } |
| else |
| { |
| layer = m_Network->AddConvolution2dLayer(descriptor, |
| layerName.c_str()); |
| uint32_t numInputs = descriptor.GetNumInputs(); |
| CHECK_VALID_SIZE(inputs.size(), numInputs); |
| } |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer, ignoreSlots); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseConvolution3d(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_LOCATION(); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto serializerLayer = graph->layers()->Get(layerIndex)->layer_as_Convolution3dLayer(); |
| auto layerName = GetLayerName(graph, layerIndex); |
| auto serializerDescriptor = serializerLayer->descriptor(); |
| |
| armnn::Convolution3dDescriptor descriptor; |
| descriptor.m_PadLeft = serializerDescriptor->padLeft(); |
| descriptor.m_PadRight = serializerDescriptor->padRight(); |
| descriptor.m_PadTop = serializerDescriptor->padTop(); |
| descriptor.m_PadBottom = serializerDescriptor->padBottom(); |
| descriptor.m_PadFront = serializerDescriptor->padFront(); |
| descriptor.m_PadBack = serializerDescriptor->padBack(); |
| descriptor.m_StrideX = serializerDescriptor->strideX(); |
| descriptor.m_StrideY = serializerDescriptor->strideY(); |
| descriptor.m_StrideZ = serializerDescriptor->strideZ(); |
| descriptor.m_DilationX = serializerDescriptor->dilationX(); |
| descriptor.m_DilationY = serializerDescriptor->dilationY(); |
| descriptor.m_DilationZ = serializerDescriptor->dilationZ(); |
| descriptor.m_BiasEnabled = serializerDescriptor->biasEnabled(); |
| descriptor.m_DataLayout = ToDataLayout(serializerDescriptor->dataLayout()); |
| |
| uint32_t numInputs = descriptor.GetNumInputs(); |
| CHECK_VALID_SIZE(inputs.size(), numInputs); |
| |
| IConnectableLayer* layer = m_Network->AddConvolution3dLayer(descriptor, layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseDepthToSpace(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto fbDescriptor = graph->layers()->Get(layerIndex)->layer_as_DepthToSpaceLayer()->descriptor(); |
| |
| armnn::DepthToSpaceDescriptor descriptor; |
| descriptor.m_BlockSize = fbDescriptor->blockSize(); |
| descriptor.m_DataLayout = ToDataLayout(fbDescriptor->dataLayout()); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddDepthToSpaceLayer(descriptor, layerName.c_str()); |
| |
| armnn::TensorInfo outputInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseDepthwiseConvolution2d(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_LOCATION(); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto serializerLayer = graph->layers()->Get(layerIndex)->layer_as_DepthwiseConvolution2dLayer(); |
| auto layerName = GetLayerName(graph, layerIndex); |
| auto serializerDescriptor = serializerLayer->descriptor(); |
| |
| armnn::DepthwiseConvolution2dDescriptor descriptor; |
| descriptor.m_PadLeft = serializerDescriptor->padLeft(); |
| descriptor.m_PadRight = serializerDescriptor->padRight(); |
| descriptor.m_PadTop = serializerDescriptor->padTop(); |
| descriptor.m_PadBottom = serializerDescriptor->padBottom(); |
| descriptor.m_StrideX = serializerDescriptor->strideX(); |
| descriptor.m_StrideY = serializerDescriptor->strideY(); |
| descriptor.m_DilationX = serializerDescriptor->dilationX(); |
| descriptor.m_DilationY = serializerDescriptor->dilationY(); |
| descriptor.m_BiasEnabled = serializerDescriptor->biasEnabled(); |
| descriptor.m_DataLayout = ToDataLayout(serializerDescriptor->dataLayout()); |
| |
| IConnectableLayer* layer; |
| std::vector<unsigned int> ignoreSlots {}; |
| |
| // Weights and biases used to be always constant and were stored as members of the layer. This has changed and |
| // they are now passed as inputs. If they are constant then they will be stored in a ConstantLayer. |
| if (this->GetFeatureVersions(graph).m_ConstTensorsAsInputs <= 0) |
| { |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| // If the model stores weights and biases as members of the layer we have to read them from there |
| // but add them to their own ConstantLayer for compatibility |
| armnn::ConstTensor weights = ToConstTensor(serializerLayer->weights()); |
| ignoreSlots.emplace_back(1u); |
| |
| layer = m_Network->AddDepthwiseConvolution2dLayer(descriptor, |
| layerName.c_str()); |
| |
| armnn::Optional<armnn::ConstTensor> optionalBiases = armnn::EmptyOptional(); |
| if (descriptor.m_BiasEnabled) |
| { |
| armnn::ConstTensor biases = ToConstTensor(serializerLayer->biases()); |
| ignoreSlots.emplace_back(2u); |
| |
| auto biasLayer = m_Network->AddConstantLayer(biases); |
| biasLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(2u)); |
| biasLayer->GetOutputSlot(0).SetTensorInfo(biases.GetInfo()); |
| } |
| |
| if (this->GetFeatureVersions(graph).m_WeightsLayoutScheme <= 0) |
| { |
| // Permute weights [ H, W, M, I ] --> [ 1, H, W, I*M ] |
| // Step1: [ M, I, H, W ] --> [ H, W, I, M] |
| PermutationVector permutationVector = { 3, 2, 0, 1 }; |
| armnn::TensorInfo weightsInfo = weights.GetInfo(); |
| std::unique_ptr<unsigned char[]> permuteBuffer(new unsigned char[weightsInfo.GetNumBytes()]); |
| weightsInfo = armnnUtils::Permuted(weightsInfo, permutationVector); |
| armnnUtils::Permute(weightsInfo.GetShape(), permutationVector, |
| weights.GetMemoryArea(), permuteBuffer.get(), |
| GetDataTypeSize(weightsInfo.GetDataType())); |
| |
| // Step2: Reshape [ H, W, I, M] --> [ 1, H, W, I*M ] |
| auto weightsShape = weightsInfo.GetShape(); |
| weightsInfo.SetShape({1, |
| weightsShape[0], |
| weightsShape[1], |
| weightsShape[2]*weightsShape[3]}); |
| |
| armnn::ConstTensor weightsPermuted(weightsInfo, permuteBuffer.get()); |
| |
| auto weightsLayer = m_Network->AddConstantLayer(weightsPermuted); |
| weightsLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1u)); |
| weightsLayer->GetOutputSlot(0).SetTensorInfo(weightsPermuted.GetInfo()); |
| } |
| else |
| { |
| auto weightsLayer = m_Network->AddConstantLayer(weights); |
| weightsLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1u)); |
| weightsLayer->GetOutputSlot(0).SetTensorInfo(weights.GetInfo()); |
| } |
| } |
| else |
| { |
| layer = m_Network->AddDepthwiseConvolution2dLayer(descriptor, |
| layerName.c_str()); |
| uint32_t numInputs = descriptor.GetNumInputs(); |
| CHECK_VALID_SIZE(inputs.size(), numInputs); |
| } |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer, ignoreSlots); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseDetectionPostProcess(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_LOCATION(); |
| CHECK_VALID_SIZE(inputs.size(), 2); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 4); |
| |
| auto flatBufferLayer = graph->layers()->Get(layerIndex)->layer_as_DetectionPostProcessLayer(); |
| auto layerName = GetLayerName(graph, layerIndex); |
| auto flatBufferDescriptor = flatBufferLayer->descriptor(); |
| |
| armnn::DetectionPostProcessDescriptor descriptor; |
| descriptor.m_MaxDetections = flatBufferDescriptor->maxDetections(); |
| descriptor.m_MaxClassesPerDetection = flatBufferDescriptor->maxClassesPerDetection(); |
| descriptor.m_DetectionsPerClass = flatBufferDescriptor->detectionsPerClass(); |
| descriptor.m_NmsScoreThreshold = flatBufferDescriptor->nmsScoreThreshold(); |
| descriptor.m_NmsIouThreshold = flatBufferDescriptor->nmsIouThreshold(); |
| descriptor.m_NumClasses = flatBufferDescriptor->numClasses(); |
| descriptor.m_UseRegularNms = flatBufferDescriptor->useRegularNms(); |
| descriptor.m_ScaleX = flatBufferDescriptor->scaleX(); |
| descriptor.m_ScaleY = flatBufferDescriptor->scaleY(); |
| descriptor.m_ScaleW = flatBufferDescriptor->scaleW(); |
| descriptor.m_ScaleH = flatBufferDescriptor->scaleH(); |
| |
| armnn::ConstTensor anchors = ToConstTensor(flatBufferLayer->anchors()); |
| |
| IConnectableLayer* layer = m_Network->AddDetectionPostProcessLayer(descriptor, |
| anchors, |
| layerName.c_str()); |
| |
| for (unsigned int i = 0; i < 4; i++) |
| { |
| layer->GetOutputSlot(i).SetTensorInfo(ToTensorInfo(outputs[i])); |
| } |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseDivision(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_LOCATION(); |
| CHECK_VALID_SIZE(inputs.size(), 2); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddDivisionLayer(layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseEqual(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_LOCATION(); |
| CHECK_VALID_SIZE(inputs.size(), 2); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| armnn::ComparisonDescriptor descriptor(armnn::ComparisonOperation::Equal); |
| IConnectableLayer* layer = m_Network->AddComparisonLayer(descriptor, layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseFill(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_LOCATION(); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| armnn::FillDescriptor descriptor; |
| descriptor.m_Value = graph->layers()->Get(layerIndex)->layer_as_FillLayer()->descriptor()->value(); |
| IConnectableLayer* layer = m_Network->AddFillLayer(descriptor, layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseGreater(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_LOCATION(); |
| CHECK_VALID_SIZE(inputs.size(), 2); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| armnn::ComparisonDescriptor descriptor(armnn::ComparisonOperation::Greater); |
| IConnectableLayer* layer = m_Network->AddComparisonLayer(descriptor, layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseInstanceNormalization(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto fbLayer = graph->layers()->Get(layerIndex)->layer_as_InstanceNormalizationLayer(); |
| auto fbDescriptor = fbLayer->descriptor(); |
| |
| armnn::InstanceNormalizationDescriptor descriptor; |
| descriptor.m_Gamma = fbDescriptor->gamma(); |
| descriptor.m_Beta = fbDescriptor->beta(); |
| descriptor.m_Eps = fbDescriptor->eps(); |
| descriptor.m_DataLayout = ToDataLayout(fbDescriptor->dataLayout()); |
| |
| const std::string layerName = GetLayerName(graph, layerIndex); |
| const armnn::TensorInfo outputInfo = ToTensorInfo(outputs[0]); |
| |
| IConnectableLayer* layer = m_Network->AddInstanceNormalizationLayer(descriptor, layerName.c_str()); |
| layer->GetOutputSlot(0).SetTensorInfo(outputInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseL2Normalization(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| 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 flatBufferLayer = graph->layers()->Get(layerIndex)->layer_as_L2NormalizationLayer(); |
| auto flatBufferDescriptor = flatBufferLayer->descriptor(); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| armnn::L2NormalizationDescriptor descriptor; |
| descriptor.m_DataLayout = ToDataLayout(flatBufferDescriptor->dataLayout()); |
| descriptor.m_Eps = flatBufferDescriptor->eps(); |
| |
| IConnectableLayer* layer = m_Network->AddL2NormalizationLayer(descriptor, layerName.c_str()); |
| layer->GetOutputSlot(0).SetTensorInfo(outputInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseLogicalBinary(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| CHECK_LOCATION(); |
| |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 2); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto fbLayer = graph->layers()->Get(layerIndex)->layer_as_LogicalBinaryLayer(); |
| auto fbDescriptor = fbLayer->descriptor(); |
| |
| armnn::LogicalBinaryDescriptor descriptor; |
| descriptor.m_Operation = ToLogicalBinaryOperation(fbDescriptor->operation()); |
| |
| const std::string& layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddLogicalBinaryLayer(descriptor, layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseLogSoftmax(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| TensorRawPtrVector inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| TensorRawPtrVector outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| armnn::LogSoftmaxDescriptor descriptor; |
| descriptor.m_Beta = graph->layers()->Get(layerIndex)->layer_as_LogSoftmaxLayer()->descriptor()->beta(); |
| descriptor.m_Axis = graph->layers()->Get(layerIndex)->layer_as_LogSoftmaxLayer()->descriptor()->axis(); |
| auto layerName = GetLayerName(graph, layerIndex); |
| |
| IConnectableLayer* layer = m_Network->AddLogSoftmaxLayer(descriptor, layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseMinimum(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_LOCATION(); |
| CHECK_VALID_SIZE(inputs.size(), 2); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddMinimumLayer(layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseMaximum(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_LOCATION(); |
| CHECK_VALID_SIZE(inputs.size(), 2); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddMaximumLayer(layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| const armnnSerializer::OriginsDescriptor* GetOriginsDescriptor(const armnnSerializer::SerializedGraph* graph, |
| unsigned int layerIndex) |
| { |
| auto layerType = graph->layers()->Get(layerIndex)->layer_type(); |
| |
| switch (layerType) |
| { |
| case Layer::Layer_ConcatLayer: |
| return graph->layers()->Get(layerIndex)->layer_as_ConcatLayer()->descriptor(); |
| case Layer::Layer_MergerLayer: |
| return graph->layers()->Get(layerIndex)->layer_as_MergerLayer()->descriptor(); |
| default: |
| throw armnn::Exception("unknown layer type, should be concat or merger"); |
| } |
| } |
| void IDeserializer::DeserializerImpl::ParseChannelShuffle(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| TensorRawPtrVector inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| TensorRawPtrVector outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| armnn::ChannelShuffleDescriptor descriptor; |
| descriptor.m_Axis = graph->layers()->Get(layerIndex)->layer_as_ChannelShuffleLayer()->descriptor()->axis(); |
| descriptor.m_NumGroups = |
| graph->layers()->Get(layerIndex)->layer_as_ChannelShuffleLayer()->descriptor()->numGroups(); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddChannelShuffleLayer(descriptor, layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| void IDeserializer::DeserializerImpl::ParseComparison(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| CHECK_LOCATION(); |
| |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 2); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto fbLayer = graph->layers()->Get(layerIndex)->layer_as_ComparisonLayer(); |
| auto fbDescriptor = fbLayer->descriptor(); |
| |
| armnn::ComparisonDescriptor descriptor; |
| descriptor.m_Operation = ToComparisonOperation(fbDescriptor->operation()); |
| |
| const std::string& layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddComparisonLayer(descriptor, layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseElementwiseUnary(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| CHECK_LOCATION(); |
| |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto fbLayer = graph->layers()->Get(layerIndex)->layer_as_ElementwiseUnaryLayer(); |
| auto fbDescriptor = fbLayer->descriptor(); |
| |
| armnn::ElementwiseUnaryDescriptor descriptor; |
| descriptor.m_Operation = ToUnaryOperation(fbDescriptor->operation()); |
| |
| const std::string& layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddElementwiseUnaryLayer(descriptor, layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseConcat(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| CHECK_LOCATION(); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| auto originsDescriptor = GetOriginsDescriptor(graph, layerIndex); |
| unsigned int numViews = originsDescriptor->numViews(); |
| unsigned int numDimensions = originsDescriptor->numDimensions(); |
| |
| // can now check the number of inputs == number of views |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), numViews); |
| |
| armnn::OriginsDescriptor descriptor(numViews, numDimensions); |
| auto originsPtr = originsDescriptor->viewOrigins(); |
| for (unsigned int v = 0; v < numViews; ++v) |
| { |
| auto originPtr = originsPtr->Get(v); |
| for (unsigned int d = 0; d < numDimensions; ++d) |
| { |
| uint32_t value = originPtr->data()->Get(d); |
| descriptor.SetViewOriginCoord(v, d, value); |
| } |
| } |
| descriptor.SetConcatAxis(originsDescriptor->concatAxis()); |
| |
| IConnectableLayer* layer = m_Network->AddConcatLayer(descriptor, layerName.c_str()); |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseMultiplication(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_LOCATION(); |
| CHECK_VALID_SIZE(inputs.size(), 2); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddMultiplicationLayer(layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseFloor(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| CHECK_LOCATION(); |
| |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| |
| armnn::IConnectableLayer* layer; |
| |
| layer = m_Network->AddFloorLayer(layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseFullyConnected(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_LOCATION(); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto flatBufferLayer = graph->layers()->Get(layerIndex)->layer_as_FullyConnectedLayer(); |
| auto layerName = GetLayerName(graph, layerIndex); |
| auto flatBufferDescriptor = flatBufferLayer->descriptor(); |
| |
| armnn::FullyConnectedDescriptor fullyConnectedDescriptor; |
| fullyConnectedDescriptor.m_BiasEnabled = flatBufferDescriptor->biasEnabled(); |
| fullyConnectedDescriptor.m_TransposeWeightMatrix = flatBufferDescriptor->transposeWeightsMatrix(); |
| fullyConnectedDescriptor.m_ConstantWeights = flatBufferDescriptor->constantWeights(); |
| |
| armnn::IConnectableLayer* layer; |
| std::vector<unsigned int> ignoreSlots {}; |
| |
| // Weights and biases used to be always constant and were stored as members of the layer. This has changed and |
| // they are now passed as inputs. If they are constant then they will be stored in a ConstantLayer. |
| if (this->GetFeatureVersions(graph).m_ConstTensorsAsInputs <= 0) |
| { |
| // If the model stores weights and biases as members of the layer we have to read them from there |
| // but add them to their own ConstantLayer for compatibility |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| layer = m_Network->AddFullyConnectedLayer(fullyConnectedDescriptor, |
| layerName.c_str()); |
| |
| armnn::ConstTensor weightsTensor = ToConstTensor(flatBufferLayer->weights()); |
| auto weightsLayer = m_Network->AddConstantLayer(weightsTensor); |
| weightsLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1u)); |
| weightsLayer->GetOutputSlot(0).SetTensorInfo(weightsTensor.GetInfo()); |
| ignoreSlots.emplace_back(1u); |
| |
| if (fullyConnectedDescriptor.m_BiasEnabled) |
| { |
| armnn::ConstTensor biasTensor = ToConstTensor(flatBufferLayer->biases()); |
| auto biasLayer = m_Network->AddConstantLayer(biasTensor); |
| biasLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(2u)); |
| biasLayer->GetOutputSlot(0).SetTensorInfo(biasTensor.GetInfo()); |
| ignoreSlots.emplace_back(2u); |
| } |
| } |
| else |
| { |
| layer = m_Network->AddFullyConnectedLayer(fullyConnectedDescriptor, |
| layerName.c_str()); |
| uint32_t numInputs = fullyConnectedDescriptor.GetNumInputs(); |
| CHECK_VALID_SIZE(inputs.size(), numInputs); |
| } |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer, ignoreSlots); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParsePad(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| TensorRawPtrVector inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| TensorRawPtrVector outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_PadLayer()->descriptor(); |
| auto flatBufferPadList = flatBufferDescriptor->padList(); |
| auto paddingMode = flatBufferDescriptor->paddingMode(); |
| float padValue = flatBufferDescriptor->padValue(); |
| |
| if (flatBufferPadList->size() % 2 != 0) |
| { |
| throw ParseException(fmt::format("The size of the pad list must be divisible by 2 {}", |
| CHECK_LOCATION().AsString())); |
| } |
| |
| std::vector<std::pair<unsigned int, unsigned int>> padList; |
| padList.reserve(flatBufferPadList->size() / 2); |
| for (unsigned int i = 0; i < flatBufferPadList->size() - 1; i += 2) |
| { |
| padList.emplace_back(flatBufferPadList->Get(i), flatBufferPadList->Get(i+1)); |
| } |
| |
| armnn::PadDescriptor descriptor(padList, padValue, ToPaddingMode(paddingMode)); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddPadLayer(descriptor, layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParsePermute(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| auto dimsMapping = |
| graph->layers()->Get(layerIndex)->layer_as_PermuteLayer()->descriptor()->dimMappings(); |
| |
| 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 layerName = GetLayerName(graph, layerIndex); |
| const armnn::PermuteDescriptor descriptor(armnn::PermutationVector(dimsMapping->data(), dimsMapping->size())); |
| |
| IConnectableLayer* layer = m_Network->AddPermuteLayer(descriptor, layerName.c_str()); |
| layer->GetOutputSlot(0).SetTensorInfo(outputInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| armnn::Pooling2dDescriptor IDeserializer::DeserializerImpl::GetPooling2dDescriptor(Pooling2dDescriptor pooling2dDesc, |
| unsigned int layerIndex) |
| { |
| IgnoreUnused(layerIndex); |
| armnn::Pooling2dDescriptor desc; |
| |
| switch (pooling2dDesc->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 (pooling2dDesc->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 (pooling2dDesc->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 (pooling2dDesc->dataLayout()) |
| { |
| case DataLayout_NCHW: |
| { |
| desc.m_DataLayout = armnn::DataLayout::NCHW; |
| break; |
| } |
| case DataLayout_NHWC: |
| { |
| desc.m_DataLayout = armnn::DataLayout::NHWC; |
| break; |
| } |
| default: |
| { |
| ARMNN_ASSERT_MSG(false, "Unsupported data layout"); |
| } |
| } |
| |
| desc.m_PadRight = pooling2dDesc->padRight(); |
| desc.m_PadLeft = pooling2dDesc->padLeft(); |
| desc.m_PadBottom = pooling2dDesc->padBottom(); |
| desc.m_PadTop = pooling2dDesc->padTop(); |
| desc.m_StrideX = pooling2dDesc->strideX(); |
| desc.m_StrideY = pooling2dDesc->strideY(); |
| desc.m_PoolWidth = pooling2dDesc->poolWidth(); |
| desc.m_PoolHeight = pooling2dDesc->poolHeight(); |
| |
| 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) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| auto pooling2dDes = graph->layers()->Get(layerIndex)->layer_as_Pooling2dLayer()->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 pooling2dDescriptor = GetPooling2dDescriptor(pooling2dDes, layerIndex); |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddPooling2dLayer(pooling2dDescriptor, layerName.c_str()); |
| layer->GetOutputSlot(0).SetTensorInfo(outputInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| 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); |
| |
| 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 layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddQuantizeLayer(layerName.c_str()); |
| layer->GetOutputSlot(0).SetTensorInfo(outputInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| armnn::TensorInfo IDeserializer::DeserializerImpl::OutputShapeOfReshape(const armnn::TensorInfo& inputTensorInfo, |
| const std::vector<uint32_t>& targetDimsIn) |
| { |
| std::vector<unsigned int> outputDims(targetDimsIn.begin(), targetDimsIn.end()); |
| const auto stretchDim = std::find(targetDimsIn.begin(), targetDimsIn.end(), -1); |
| |
| if (stretchDim != targetDimsIn.end()) |
| { |
| if (std::find(std::next(stretchDim), targetDimsIn.end(), -1) != targetDimsIn.end()) |
| { |
| throw ParseException(fmt::format("At most one component of shape can be -1 {}", |
| CHECK_LOCATION().AsString())); |
| } |
| |
| auto targetNumElements = |
| armnn::numeric_cast<unsigned int>( |
| std::accumulate(targetDimsIn.begin(), targetDimsIn.end(), -1, std::multiplies<int32_t>())); |
| |
| auto stretchIndex = static_cast<size_t>(std::distance(targetDimsIn.begin(), stretchDim)); |
| outputDims[stretchIndex] = inputTensorInfo.GetNumElements() / targetNumElements; |
| } |
| |
| TensorShape outputShape = TensorShape(static_cast<unsigned int>(outputDims.size()), outputDims.data()); |
| |
| armnn::TensorInfo reshapeInfo = inputTensorInfo; |
| reshapeInfo.SetShape(outputShape); |
| |
| return reshapeInfo; |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseRank(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| TensorRawPtrVector inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| TensorRawPtrVector outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddRankLayer( layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseReduce(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| CHECK_LOCATION(); |
| |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto fbLayer = graph->layers()->Get(layerIndex)->layer_as_ReduceLayer(); |
| auto fbDescriptor = fbLayer->descriptor(); |
| auto flatBufferAxis = fbDescriptor->axis(); |
| |
| armnn::ReduceDescriptor descriptor; |
| descriptor.m_KeepDims = fbDescriptor->keepDims(); |
| descriptor.m_vAxis = std::vector<unsigned int>(flatBufferAxis->begin(), flatBufferAxis->end()); |
| descriptor.m_ReduceOperation = ToReduceOperation(fbDescriptor->reduceOperation()); |
| |
| const std::string& layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddReduceLayer(descriptor, layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseReshape(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| auto inputs = GetInputs(graph, layerIndex); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); |
| armnn::TensorInfo actualOutputTensorInfo = ToTensorInfo(outputs[0]); |
| |
| const auto targetDims = graph->layers()->Get(layerIndex)->layer_as_ReshapeLayer()->descriptor()->targetShape(); |
| std::vector<uint32_t> outputDims(targetDims->begin(), targetDims->begin() + targetDims->size()); |
| |
| armnn::TensorInfo reshapeOutputTensorInfo = DeserializerImpl::OutputShapeOfReshape(inputTensorInfo, outputDims); |
| const armnn::TensorShape& reshapeOutputTensorShape = reshapeOutputTensorInfo.GetShape(); |
| |
| const std::vector<uint32_t> expectedDims(outputs[0]->dimensions()->begin(), |
| outputs[0]->dimensions()->begin() + outputs[0]->dimensions()->size()); |
| |
| if (inputs.size() > 1 && !CheckShape(reshapeOutputTensorShape, expectedDims)) |
| { |
| std::stringstream ss; |
| ss << "New shape defined in reshape parameters " |
| << reshapeOutputTensorShape |
| << " does not equal output shape " |
| << actualOutputTensorInfo.GetShape() |
| << ": " |
| << CHECK_LOCATION().AsString(); |
| throw ParseException(ss.str()); |
| } |
| |
| armnn::ReshapeDescriptor reshapeDesc; |
| reshapeDesc.m_TargetShape = reshapeOutputTensorShape; |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str()); |
| layer->GetOutputSlot(0).SetTensorInfo(reshapeOutputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseResize(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| TensorRawPtrVector inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| TensorRawPtrVector outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_ResizeLayer()->descriptor(); |
| |
| armnn::ResizeDescriptor descriptor; |
| descriptor.m_TargetWidth = flatBufferDescriptor->targetWidth(); |
| descriptor.m_TargetHeight = flatBufferDescriptor->targetHeight(); |
| descriptor.m_Method = ToResizeMethod(flatBufferDescriptor->method()); |
| descriptor.m_DataLayout = ToDataLayout(flatBufferDescriptor->dataLayout()); |
| descriptor.m_AlignCorners = flatBufferDescriptor->alignCorners(); |
| descriptor.m_HalfPixelCenters = flatBufferDescriptor->halfPixelCenters(); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddResizeLayer(descriptor, layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| |
| /// @Note The ResizeBiliniar operation was deprecated and removed in favor of the Resize operation. |
| /// This function is kept for backwards compatibility. |
| void IDeserializer::DeserializerImpl::ParseResizeBilinear(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| TensorRawPtrVector inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| TensorRawPtrVector outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_ResizeBilinearLayer()->descriptor(); |
| |
| armnn::ResizeDescriptor descriptor; |
| descriptor.m_TargetWidth = flatBufferDescriptor->targetWidth(); |
| descriptor.m_TargetHeight = flatBufferDescriptor->targetHeight(); |
| descriptor.m_Method = armnn::ResizeMethod::Bilinear; |
| descriptor.m_DataLayout = ToDataLayout(flatBufferDescriptor->dataLayout()); |
| descriptor.m_AlignCorners = flatBufferDescriptor->alignCorners(); |
| descriptor.m_HalfPixelCenters = flatBufferDescriptor->halfPixelCenters(); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddResizeLayer(descriptor, layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseShape(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| TensorRawPtrVector inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| TensorRawPtrVector outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddShapeLayer( layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseSoftmax(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| TensorRawPtrVector inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| TensorRawPtrVector outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| armnn::SoftmaxDescriptor descriptor; |
| descriptor.m_Beta = graph->layers()->Get(layerIndex)->layer_as_SoftmaxLayer()->descriptor()->beta(); |
| descriptor.m_Axis = graph->layers()->Get(layerIndex)->layer_as_SoftmaxLayer()->descriptor()->axis(); |
| auto layerName = GetLayerName(graph, layerIndex); |
| |
| IConnectableLayer* layer = m_Network->AddSoftmaxLayer(descriptor, layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseSpaceToBatchNd(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| TensorRawPtrVector inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| TensorRawPtrVector outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_SpaceToBatchNdLayer()->descriptor(); |
| auto flatBufferPadList = flatBufferDescriptor->padList(); |
| auto flatBufferBlockShape = flatBufferDescriptor->blockShape(); |
| |
| if (flatBufferPadList->size() % 2 != 0) |
| { |
| throw ParseException(fmt::format("The size of the pad list must be divisible by 2 {}", |
| CHECK_LOCATION().AsString())); |
| } |
| |
| std::vector<std::pair<unsigned int, unsigned int>> padList; |
| padList.reserve(flatBufferPadList->size() / 2); |
| for (unsigned int i = 0; i < flatBufferPadList->size() - 1; i += 2) |
| { |
| padList.emplace_back(flatBufferPadList->Get(i), flatBufferPadList->Get(i+1)); |
| } |
| |
| armnn::SpaceToBatchNdDescriptor descriptor; |
| descriptor.m_DataLayout = ToDataLayout(flatBufferDescriptor->dataLayout()); |
| descriptor.m_BlockShape = |
| std::vector<unsigned int>(flatBufferBlockShape->begin(), flatBufferBlockShape->end()); |
| descriptor.m_PadList = padList; |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddSpaceToBatchNdLayer(descriptor, layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseSpaceToDepth(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| TensorRawPtrVector inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| TensorRawPtrVector outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_SpaceToDepthLayer()->descriptor(); |
| |
| armnn::SpaceToDepthDescriptor descriptor; |
| descriptor.m_BlockSize = flatBufferDescriptor->blockSize(); |
| descriptor.m_DataLayout = ToDataLayout(flatBufferDescriptor->dataLayout()); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddSpaceToDepthLayer(descriptor, layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| armnn::NormalizationDescriptor IDeserializer::DeserializerImpl::GetNormalizationDescriptor( |
| NormalizationDescriptorPtr normalizationDescriptor, |
| unsigned int layerIndex) |
| { |
| IgnoreUnused(layerIndex); |
| armnn::NormalizationDescriptor desc; |
| |
| switch (normalizationDescriptor->normChannelType()) |
| { |
| case NormalizationAlgorithmChannel_Across: |
| { |
| desc.m_NormChannelType = armnn::NormalizationAlgorithmChannel::Across; |
| break; |
| } |
| case NormalizationAlgorithmChannel_Within: |
| { |
| desc.m_NormChannelType = armnn::NormalizationAlgorithmChannel::Within; |
| break; |
| } |
| default: |
| { |
| ARMNN_ASSERT_MSG(false, "Unsupported normalization channel type"); |
| } |
| } |
| |
| switch (normalizationDescriptor->normMethodType()) |
| { |
| case NormalizationAlgorithmMethod_LocalBrightness: |
| { |
| desc.m_NormMethodType = armnn::NormalizationAlgorithmMethod::LocalBrightness; |
| break; |
| } |
| case NormalizationAlgorithmMethod_LocalContrast: |
| { |
| desc.m_NormMethodType = armnn::NormalizationAlgorithmMethod::LocalContrast; |
| break; |
| } |
| default: |
| { |
| ARMNN_ASSERT_MSG(false, "Unsupported normalization method type"); |
| } |
| } |
| |
| switch (normalizationDescriptor->dataLayout()) |
| { |
| case DataLayout_NCHW: |
| { |
| desc.m_DataLayout = armnn::DataLayout::NCHW; |
| break; |
| } |
| case DataLayout_NHWC: |
| { |
| desc.m_DataLayout = armnn::DataLayout::NHWC; |
| break; |
| } |
| default: |
| { |
| ARMNN_ASSERT_MSG(false, "Unsupported data layout"); |
| } |
| } |
| |
| desc.m_Alpha = normalizationDescriptor->alpha(); |
| desc.m_Beta = normalizationDescriptor->beta(); |
| desc.m_K = normalizationDescriptor->k(); |
| desc.m_NormSize = normalizationDescriptor->normSize(); |
| |
| return desc; |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseNormalization(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| auto normalizationDes = graph->layers()->Get(layerIndex)->layer_as_NormalizationLayer()->descriptor(); |
| |
| TensorRawPtrVector inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| TensorRawPtrVector outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto outputInfo = ToTensorInfo(outputs[0]); |
| |
| auto normalizationDescriptor = GetNormalizationDescriptor(normalizationDes, layerIndex); |
| auto layerName = GetLayerName(graph, layerIndex); |
| |
| IConnectableLayer* layer = m_Network->AddNormalizationLayer(normalizationDescriptor, layerName.c_str()); |
| layer->GetOutputSlot(0).SetTensorInfo(outputInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseRsqrt(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_LOCATION(); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| |
| armnn::ElementwiseUnaryDescriptor descriptor(armnn::UnaryOperation::Rsqrt); |
| IConnectableLayer* layer = m_Network->AddElementwiseUnaryLayer(descriptor, layerName.c_str()); |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseSlice(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto fbDescriptor = graph->layers()->Get(layerIndex)->layer_as_SliceLayer()->descriptor(); |
| |
| auto fbBegin = fbDescriptor->begin(); |
| auto fbSize = fbDescriptor->size(); |
| |
| if (fbBegin->size() != fbSize->size()) |
| { |
| throw ParseException(fmt::format("Begin and size descriptors must have the same length {}", |
| CHECK_LOCATION().AsString())); |
| } |
| |
| armnn::SliceDescriptor descriptor; |
| descriptor.m_Begin.insert(descriptor.m_Begin.end(), fbBegin->begin(), fbBegin->end()); |
| descriptor.m_Size.insert(descriptor.m_Size.end(), fbSize->begin(), fbSize->end()); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddSliceLayer(descriptor, layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseStridedSlice(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| TensorRawPtrVector inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| TensorRawPtrVector outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_StridedSliceLayer()->descriptor(); |
| |
| auto flatBufferBegin = flatBufferDescriptor->begin(); |
| auto flatBufferEnd = flatBufferDescriptor->end(); |
| auto flatBufferStride = flatBufferDescriptor->stride(); |
| |
| if (!(flatBufferBegin->size() == flatBufferEnd->size() && |
| flatBufferBegin->size() == flatBufferStride->size())) |
| { |
| throw ParseException(fmt::format("The size of the begin, end, and stride must be equal {}", |
| CHECK_LOCATION().AsString())); |
| } |
| |
| std::vector<int> begin(flatBufferBegin->begin(), flatBufferBegin->end()); |
| std::vector<int> end(flatBufferEnd->begin(), flatBufferEnd->end()); |
| std::vector<int> stride(flatBufferStride->begin(), flatBufferStride->end()); |
| |
| armnn::StridedSliceDescriptor descriptor(begin, end, stride); |
| descriptor.m_BeginMask = flatBufferDescriptor->beginMask(); |
| descriptor.m_EndMask = flatBufferDescriptor->endMask(); |
| descriptor.m_ShrinkAxisMask = flatBufferDescriptor->shrinkAxisMask(); |
| descriptor.m_EllipsisMask = flatBufferDescriptor->ellipsisMask(); |
| descriptor.m_NewAxisMask = flatBufferDescriptor->newAxisMask(); |
| descriptor.m_DataLayout = ToDataLayout(flatBufferDescriptor->dataLayout()); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddStridedSliceLayer(descriptor, layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseSubtraction(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_LOCATION(); |
| CHECK_VALID_SIZE(inputs.size(), 2); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddSubtractionLayer(layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseGather(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| TensorRawPtrVector inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 2); |
| |
| TensorRawPtrVector outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| armnn::GatherDescriptor descriptor; |
| descriptor.m_Axis = graph->layers()->Get(layerIndex)->layer_as_GatherLayer()->descriptor()->axis(); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddGatherLayer(descriptor, layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseGatherNd(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| TensorRawPtrVector inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 2); |
| |
| TensorRawPtrVector outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddGatherNdLayer(layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseMean(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| TensorRawPtrVector inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| TensorRawPtrVector outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_MeanLayer()->descriptor(); |
| auto flatBufferAxis = flatBufferDescriptor->axis(); |
| auto flatBufferKeepDims = flatBufferDescriptor->keepDims(); |
| |
| armnn::MeanDescriptor descriptor; |
| descriptor.m_Axis = std::vector<unsigned int>(flatBufferAxis->begin(), flatBufferAxis->end()); |
| descriptor.m_KeepDims = flatBufferKeepDims; |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddMeanLayer(descriptor, layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseSplitter(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| TensorRawPtrVector inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| TensorRawPtrVector outputs = GetOutputs(graph, layerIndex); |
| |
| auto flatBufferViewsDescriptor = graph->layers()->Get(layerIndex)->layer_as_SplitterLayer()->descriptor(); |
| auto flatBufferViewSizes = flatBufferViewsDescriptor->viewSizes(); |
| auto flatBufferOriginsDescriptor = flatBufferViewsDescriptor->origins(); |
| auto flatBufferViewOrigins = flatBufferOriginsDescriptor->viewOrigins(); |
| uint32_t numViews = flatBufferOriginsDescriptor->numViews(); |
| uint32_t numDimensions = flatBufferOriginsDescriptor->numDimensions(); |
| |
| // Check numViews and numDimensions corresponds to the ones already serialized ... |
| // numViews == flatBufferViewSizes.size(); |
| // foreach: numDimensions == flatBufferViewSizes[x].size(); |
| |
| armnn::ViewsDescriptor viewsDescriptor(numViews, numDimensions); |
| for(unsigned int vIdx = 0; vIdx < numViews; ++vIdx) |
| { |
| for (unsigned int dIdx = 0; dIdx < numDimensions; ++dIdx) |
| { |
| viewsDescriptor.SetViewSize(vIdx, dIdx, flatBufferViewSizes->Get(vIdx)->data()->Get(dIdx)); |
| viewsDescriptor.SetViewOriginCoord(vIdx, dIdx, flatBufferViewOrigins->Get(vIdx)->data()->Get(dIdx)); |
| } |
| } |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddSplitterLayer(viewsDescriptor, layerName.c_str()); |
| |
| // I could have as many outputs as views ... |
| for(unsigned int vIdx = 0; vIdx < numViews; ++vIdx) |
| { |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[vIdx]); |
| layer->GetOutputSlot(vIdx).SetTensorInfo(outputTensorInfo); |
| } |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| armnn::LstmDescriptor IDeserializer::DeserializerImpl::GetLstmDescriptor(LstmDescriptorPtr lstmDescriptor) |
| { |
| armnn::LstmDescriptor desc; |
| |
| desc.m_ActivationFunc = lstmDescriptor->activationFunc(); |
| desc.m_ClippingThresCell = lstmDescriptor->clippingThresCell(); |
| desc.m_ClippingThresProj = lstmDescriptor->clippingThresProj(); |
| desc.m_CifgEnabled = lstmDescriptor->cifgEnabled(); |
| desc.m_PeepholeEnabled = lstmDescriptor->peepholeEnabled(); |
| desc.m_ProjectionEnabled = lstmDescriptor->projectionEnabled(); |
| desc.m_LayerNormEnabled = lstmDescriptor->layerNormEnabled(); |
| |
| return desc; |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseLstm(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 3); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 4); |
| |
| auto flatBufferLayer = graph->layers()->Get(layerIndex)->layer_as_LstmLayer(); |
| auto layerName = GetLayerName(graph, layerIndex); |
| auto flatBufferDescriptor = flatBufferLayer->descriptor(); |
| auto flatBufferInputParams = flatBufferLayer->inputParams(); |
| |
| auto lstmDescriptor = GetLstmDescriptor(flatBufferDescriptor); |
| |
| armnn::LstmInputParams lstmInputParams; |
| |
| armnn::ConstTensor inputToForgetWeights = ToConstTensor(flatBufferInputParams->inputToForgetWeights()); |
| armnn::ConstTensor inputToCellWeights = ToConstTensor(flatBufferInputParams->inputToCellWeights()); |
| armnn::ConstTensor inputToOutputWeights = ToConstTensor(flatBufferInputParams->inputToOutputWeights()); |
| armnn::ConstTensor recurrentToForgetWeights = ToConstTensor(flatBufferInputParams->recurrentToForgetWeights()); |
| armnn::ConstTensor recurrentToCellWeights = ToConstTensor(flatBufferInputParams->recurrentToCellWeights()); |
| armnn::ConstTensor recurrentToOutputWeights = ToConstTensor(flatBufferInputParams->recurrentToOutputWeights()); |
| armnn::ConstTensor forgetGateBias = ToConstTensor(flatBufferInputParams->forgetGateBias()); |
| armnn::ConstTensor cellBias = ToConstTensor(flatBufferInputParams->cellBias()); |
| armnn::ConstTensor outputGateBias = ToConstTensor(flatBufferInputParams->outputGateBias()); |
| |
| lstmInputParams.m_InputToForgetWeights = &inputToForgetWeights; |
| lstmInputParams.m_InputToCellWeights = &inputToCellWeights; |
| lstmInputParams.m_InputToOutputWeights = &inputToOutputWeights; |
| lstmInputParams.m_RecurrentToForgetWeights = &recurrentToForgetWeights; |
| lstmInputParams.m_RecurrentToCellWeights = &recurrentToCellWeights; |
| lstmInputParams.m_RecurrentToOutputWeights = &recurrentToOutputWeights; |
| lstmInputParams.m_ForgetGateBias = &forgetGateBias; |
| lstmInputParams.m_CellBias = &cellBias; |
| lstmInputParams.m_OutputGateBias = &outputGateBias; |
| |
| armnn::ConstTensor inputToInputWeights; |
| armnn::ConstTensor recurrentToInputWeights; |
| armnn::ConstTensor cellToInputWeights; |
| armnn::ConstTensor inputGateBias; |
| if (!lstmDescriptor.m_CifgEnabled) |
| { |
| inputToInputWeights = ToConstTensor(flatBufferInputParams->inputToInputWeights()); |
| recurrentToInputWeights = ToConstTensor(flatBufferInputParams->recurrentToInputWeights()); |
| cellToInputWeights = ToConstTensor(flatBufferInputParams->cellToInputWeights()); |
| inputGateBias = ToConstTensor(flatBufferInputParams->inputGateBias()); |
| |
| lstmInputParams.m_InputToInputWeights = &inputToInputWeights; |
| lstmInputParams.m_RecurrentToInputWeights = &recurrentToInputWeights; |
| lstmInputParams.m_CellToInputWeights = &cellToInputWeights; |
| lstmInputParams.m_InputGateBias = &inputGateBias; |
| } |
| |
| armnn::ConstTensor projectionWeights; |
| armnn::ConstTensor projectionBias; |
| if (lstmDescriptor.m_ProjectionEnabled) |
| { |
| projectionWeights = ToConstTensor(flatBufferInputParams->projectionWeights()); |
| projectionBias = ToConstTensor(flatBufferInputParams->projectionBias()); |
| |
| lstmInputParams.m_ProjectionWeights = &projectionWeights; |
| lstmInputParams.m_ProjectionBias = &projectionBias; |
| } |
| |
| armnn::ConstTensor cellToForgetWeights; |
| armnn::ConstTensor cellToOutputWeights; |
| if (lstmDescriptor.m_PeepholeEnabled) |
| { |
| cellToForgetWeights = ToConstTensor(flatBufferInputParams->cellToForgetWeights()); |
| cellToOutputWeights = ToConstTensor(flatBufferInputParams->cellToOutputWeights()); |
| |
| lstmInputParams.m_CellToForgetWeights = &cellToForgetWeights; |
| lstmInputParams.m_CellToOutputWeights = &cellToOutputWeights; |
| } |
| |
| armnn::ConstTensor inputLayerNormWeights; |
| armnn::ConstTensor forgetLayerNormWeights; |
| armnn::ConstTensor cellLayerNormWeights; |
| armnn::ConstTensor outputLayerNormWeights; |
| if (lstmDescriptor.m_LayerNormEnabled) |
| { |
| if (!lstmDescriptor.m_CifgEnabled) |
| { |
| inputLayerNormWeights = ToConstTensor(flatBufferInputParams->inputLayerNormWeights()); |
| lstmInputParams.m_InputLayerNormWeights = &inputLayerNormWeights; |
| } |
| forgetLayerNormWeights = ToConstTensor(flatBufferInputParams->forgetLayerNormWeights()); |
| cellLayerNormWeights = ToConstTensor(flatBufferInputParams->cellLayerNormWeights()); |
| outputLayerNormWeights = ToConstTensor(flatBufferInputParams->outputLayerNormWeights()); |
| |
| lstmInputParams.m_ForgetLayerNormWeights = &forgetLayerNormWeights; |
| lstmInputParams.m_CellLayerNormWeights = &cellLayerNormWeights; |
| lstmInputParams.m_OutputLayerNormWeights = &outputLayerNormWeights; |
| } |
| |
| IConnectableLayer* layer = m_Network->AddLstmLayer(lstmDescriptor, lstmInputParams, layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo1 = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo1); |
| |
| armnn::TensorInfo outputTensorInfo2 = ToTensorInfo(outputs[1]); |
| layer->GetOutputSlot(1).SetTensorInfo(outputTensorInfo2); |
| |
| armnn::TensorInfo outputTensorInfo3 = ToTensorInfo(outputs[2]); |
| layer->GetOutputSlot(2).SetTensorInfo(outputTensorInfo3); |
| |
| armnn::TensorInfo outputTensorInfo4 = ToTensorInfo(outputs[3]); |
| layer->GetOutputSlot(3).SetTensorInfo(outputTensorInfo4); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| armnn::QLstmDescriptor IDeserializer::DeserializerImpl::GetQLstmDescriptor(QLstmDescriptorPtr qLstmDescriptor) |
| { |
| armnn::QLstmDescriptor desc; |
| |
| desc.m_CifgEnabled = qLstmDescriptor->cifgEnabled(); |
| desc.m_PeepholeEnabled = qLstmDescriptor->peepholeEnabled(); |
| desc.m_ProjectionEnabled = qLstmDescriptor->projectionEnabled(); |
| desc.m_LayerNormEnabled = qLstmDescriptor->layerNormEnabled(); |
| |
| desc.m_CellClip = qLstmDescriptor->cellClip(); |
| desc.m_ProjectionClip = qLstmDescriptor->projectionClip(); |
| |
| desc.m_InputIntermediateScale = qLstmDescriptor->inputIntermediateScale(); |
| desc.m_ForgetIntermediateScale = qLstmDescriptor->forgetIntermediateScale(); |
| desc.m_CellIntermediateScale = qLstmDescriptor->cellIntermediateScale(); |
| desc.m_OutputIntermediateScale = qLstmDescriptor->outputIntermediateScale(); |
| |
| desc.m_HiddenStateScale = qLstmDescriptor->hiddenStateScale(); |
| desc.m_HiddenStateZeroPoint = qLstmDescriptor->hiddenStateZeroPoint(); |
| |
| return desc; |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseQLstm(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 3); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 3); |
| |
| auto flatBufferLayer = graph->layers()->Get(layerIndex)->layer_as_QLstmLayer(); |
| auto layerName = GetLayerName(graph, layerIndex); |
| auto flatBufferDescriptor = flatBufferLayer->descriptor(); |
| auto flatBufferInputParams = flatBufferLayer->inputParams(); |
| |
| auto qLstmDescriptor = GetQLstmDescriptor(flatBufferDescriptor); |
| armnn::LstmInputParams qLstmInputParams; |
| |
| // Mandatory params |
| armnn::ConstTensor inputToForgetWeights = ToConstTensor(flatBufferInputParams->inputToForgetWeights()); |
| armnn::ConstTensor inputToCellWeights = ToConstTensor(flatBufferInputParams->inputToCellWeights()); |
| armnn::ConstTensor inputToOutputWeights = ToConstTensor(flatBufferInputParams->inputToOutputWeights()); |
| armnn::ConstTensor recurrentToForgetWeights = ToConstTensor(flatBufferInputParams->recurrentToForgetWeights()); |
| armnn::ConstTensor recurrentToCellWeights = ToConstTensor(flatBufferInputParams->recurrentToCellWeights()); |
| armnn::ConstTensor recurrentToOutputWeights = ToConstTensor(flatBufferInputParams->recurrentToOutputWeights()); |
| armnn::ConstTensor forgetGateBias = ToConstTensor(flatBufferInputParams->forgetGateBias()); |
| armnn::ConstTensor cellBias = ToConstTensor(flatBufferInputParams->cellBias()); |
| armnn::ConstTensor outputGateBias = ToConstTensor(flatBufferInputParams->outputGateBias()); |
| |
| qLstmInputParams.m_InputToForgetWeights = &inputToForgetWeights; |
| qLstmInputParams.m_InputToCellWeights = &inputToCellWeights; |
| qLstmInputParams.m_InputToOutputWeights = &inputToOutputWeights; |
| qLstmInputParams.m_RecurrentToForgetWeights = &recurrentToForgetWeights; |
| qLstmInputParams.m_RecurrentToCellWeights = &recurrentToCellWeights; |
| qLstmInputParams.m_RecurrentToOutputWeights = &recurrentToOutputWeights; |
| qLstmInputParams.m_ForgetGateBias = &forgetGateBias; |
| qLstmInputParams.m_CellBias = &cellBias; |
| qLstmInputParams.m_OutputGateBias = &outputGateBias; |
| |
| // Optional CIFG params |
| armnn::ConstTensor inputToInputWeights; |
| armnn::ConstTensor recurrentToInputWeights; |
| armnn::ConstTensor inputGateBias; |
| |
| if (!qLstmDescriptor.m_CifgEnabled) |
| { |
| inputToInputWeights = ToConstTensor(flatBufferInputParams->inputToInputWeights()); |
| recurrentToInputWeights = ToConstTensor(flatBufferInputParams->recurrentToInputWeights()); |
| inputGateBias = ToConstTensor(flatBufferInputParams->inputGateBias()); |
| |
| qLstmInputParams.m_InputToInputWeights = &inputToInputWeights; |
| qLstmInputParams.m_RecurrentToInputWeights = &recurrentToInputWeights; |
| qLstmInputParams.m_InputGateBias = &inputGateBias; |
| } |
| |
| // Optional projection params |
| armnn::ConstTensor projectionWeights; |
| armnn::ConstTensor projectionBias; |
| |
| if (qLstmDescriptor.m_ProjectionEnabled) |
| { |
| projectionWeights = ToConstTensor(flatBufferInputParams->projectionWeights()); |
| projectionBias = ToConstTensor(flatBufferInputParams->projectionBias()); |
| |
| qLstmInputParams.m_ProjectionWeights = &projectionWeights; |
| qLstmInputParams.m_ProjectionBias = &projectionBias; |
| } |
| |
| // Optional peephole params |
| armnn::ConstTensor cellToInputWeights; |
| armnn::ConstTensor cellToForgetWeights; |
| armnn::ConstTensor cellToOutputWeights; |
| |
| if (qLstmDescriptor.m_PeepholeEnabled) |
| { |
| if (!qLstmDescriptor.m_CifgEnabled) |
| { |
| cellToInputWeights = ToConstTensor(flatBufferInputParams->cellToInputWeights()); |
| qLstmInputParams.m_CellToInputWeights = &cellToInputWeights; |
| } |
| |
| cellToForgetWeights = ToConstTensor(flatBufferInputParams->cellToForgetWeights()); |
| cellToOutputWeights = ToConstTensor(flatBufferInputParams->cellToOutputWeights()); |
| |
| qLstmInputParams.m_CellToForgetWeights = &cellToForgetWeights; |
| qLstmInputParams.m_CellToOutputWeights = &cellToOutputWeights; |
| } |
| |
| // Optional layer norm params |
| armnn::ConstTensor inputLayerNormWeights; |
| armnn::ConstTensor forgetLayerNormWeights; |
| armnn::ConstTensor cellLayerNormWeights; |
| armnn::ConstTensor outputLayerNormWeights; |
| |
| if (qLstmDescriptor.m_LayerNormEnabled) |
| { |
| if (!qLstmDescriptor.m_CifgEnabled) |
| { |
| inputLayerNormWeights = ToConstTensor(flatBufferInputParams->inputLayerNormWeights()); |
| qLstmInputParams.m_InputLayerNormWeights = &inputLayerNormWeights; |
| } |
| |
| forgetLayerNormWeights = ToConstTensor(flatBufferInputParams->forgetLayerNormWeights()); |
| cellLayerNormWeights = ToConstTensor(flatBufferInputParams->cellLayerNormWeights()); |
| outputLayerNormWeights = ToConstTensor(flatBufferInputParams->outputLayerNormWeights()); |
| |
| qLstmInputParams.m_ForgetLayerNormWeights = &forgetLayerNormWeights; |
| qLstmInputParams.m_CellLayerNormWeights = &cellLayerNormWeights; |
| qLstmInputParams.m_OutputLayerNormWeights = &outputLayerNormWeights; |
| } |
| |
| IConnectableLayer* layer = m_Network->AddQLstmLayer(qLstmDescriptor, qLstmInputParams, layerName.c_str()); |
| |
| armnn::TensorInfo outputStateOutInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputStateOutInfo); |
| |
| armnn::TensorInfo cellStateOutInfo = ToTensorInfo(outputs[1]); |
| layer->GetOutputSlot(1).SetTensorInfo(cellStateOutInfo); |
| |
| armnn::TensorInfo outputInfo = ToTensorInfo(outputs[2]); |
| layer->GetOutputSlot(2).SetTensorInfo(outputInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseQuantizedLstm(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 3); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 2); |
| |
| auto flatBufferLayer = graph->layers()->Get(layerIndex)->layer_as_QuantizedLstmLayer(); |
| auto layerName = GetLayerName(graph, layerIndex); |
| auto flatBufferInputParams = flatBufferLayer->inputParams(); |
| |
| armnn::QuantizedLstmInputParams lstmInputParams; |
| |
| armnn::ConstTensor inputToInputWeights = ToConstTensor(flatBufferInputParams->inputToInputWeights()); |
| armnn::ConstTensor inputToForgetWeights = ToConstTensor(flatBufferInputParams->inputToForgetWeights()); |
| armnn::ConstTensor inputToCellWeights = ToConstTensor(flatBufferInputParams->inputToCellWeights()); |
| armnn::ConstTensor inputToOutputWeights = ToConstTensor(flatBufferInputParams->inputToOutputWeights()); |
| armnn::ConstTensor recurrentToInputWeights = ToConstTensor(flatBufferInputParams->recurrentToInputWeights()); |
| armnn::ConstTensor recurrentToForgetWeights = ToConstTensor(flatBufferInputParams->recurrentToForgetWeights()); |
| armnn::ConstTensor recurrentToCellWeights = ToConstTensor(flatBufferInputParams->recurrentToCellWeights()); |
| armnn::ConstTensor recurrentToOutputWeights = ToConstTensor(flatBufferInputParams->recurrentToOutputWeights()); |
| armnn::ConstTensor inputGateBias = ToConstTensor(flatBufferInputParams->inputGateBias()); |
| armnn::ConstTensor forgetGateBias = ToConstTensor(flatBufferInputParams->forgetGateBias()); |
| armnn::ConstTensor cellBias = ToConstTensor(flatBufferInputParams->cellBias()); |
| armnn::ConstTensor outputGateBias = ToConstTensor(flatBufferInputParams->outputGateBias()); |
| |
| lstmInputParams.m_InputToInputWeights = &inputToInputWeights; |
| lstmInputParams.m_InputToForgetWeights = &inputToForgetWeights; |
| lstmInputParams.m_InputToCellWeights = &inputToCellWeights; |
| lstmInputParams.m_InputToOutputWeights = &inputToOutputWeights; |
| lstmInputParams.m_RecurrentToInputWeights = &recurrentToInputWeights; |
| lstmInputParams.m_RecurrentToForgetWeights = &recurrentToForgetWeights; |
| lstmInputParams.m_RecurrentToCellWeights = &recurrentToCellWeights; |
| lstmInputParams.m_RecurrentToOutputWeights = &recurrentToOutputWeights; |
| lstmInputParams.m_InputGateBias = &inputGateBias; |
| lstmInputParams.m_ForgetGateBias = &forgetGateBias; |
| lstmInputParams.m_CellBias = &cellBias; |
| lstmInputParams.m_OutputGateBias = &outputGateBias; |
| |
| IConnectableLayer* layer = m_Network->AddQuantizedLstmLayer(lstmInputParams, layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo1 = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo1); |
| |
| armnn::TensorInfo outputTensorInfo2 = ToTensorInfo(outputs[1]); |
| layer->GetOutputSlot(1).SetTensorInfo(outputTensorInfo2); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseDequantize(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| TensorRawPtrVector inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| TensorRawPtrVector outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| const std::string layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddDequantizeLayer(layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseMerge(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| TensorRawPtrVector inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 2); |
| |
| TensorRawPtrVector outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| const std::string layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddMergeLayer(layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseSwitch(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_LOCATION(); |
| CHECK_VALID_SIZE(inputs.size(), 2); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 2); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddSwitchLayer(layerName.c_str()); |
| |
| armnn::TensorInfo output0TensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(output0TensorInfo); |
| |
| armnn::TensorInfo output1TensorInfo = ToTensorInfo(outputs[1]); |
| layer->GetOutputSlot(1).SetTensorInfo(output1TensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParsePrelu(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_LOCATION(); |
| CHECK_VALID_SIZE(inputs.size(), 2); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddPreluLayer(layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseTranspose(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| auto dimsMapping = graph->layers()->Get(layerIndex)->layer_as_TransposeLayer()->descriptor()->dimMappings(); |
| |
| 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 layerName = GetLayerName(graph, layerIndex); |
| const armnn::TransposeDescriptor descriptor(armnn::PermutationVector(dimsMapping->data(), dimsMapping->size())); |
| |
| IConnectableLayer* layer = m_Network->AddTransposeLayer(descriptor, layerName.c_str()); |
| layer->GetOutputSlot(0).SetTensorInfo(outputInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseTransposeConvolution2d(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 1); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto serializerLayer = graph->layers()->Get(layerIndex)->layer_as_TransposeConvolution2dLayer(); |
| auto layerName = GetLayerName(graph, layerIndex); |
| auto serializerDescriptor = serializerLayer->descriptor(); |
| |
| armnn::TransposeConvolution2dDescriptor descriptor; |
| descriptor.m_PadLeft = serializerDescriptor->padLeft(); |
| descriptor.m_PadRight = serializerDescriptor->padRight(); |
| descriptor.m_PadTop = serializerDescriptor->padTop(); |
| descriptor.m_PadBottom = serializerDescriptor->padBottom(); |
| descriptor.m_StrideX = serializerDescriptor->strideX(); |
| descriptor.m_StrideY = serializerDescriptor->strideY();; |
| descriptor.m_BiasEnabled = serializerDescriptor->biasEnabled();; |
| descriptor.m_DataLayout = ToDataLayout(serializerDescriptor->dataLayout()); |
| |
| // weights & biases |
| armnn::ConstTensor weights = ToConstTensor(serializerLayer->weights()); |
| armnn::Optional<armnn::ConstTensor> optionalBiases; |
| if (descriptor.m_BiasEnabled) |
| { |
| armnn::ConstTensor biases = ToConstTensor(serializerLayer->biases()); |
| optionalBiases = armnn::MakeOptional<armnn::ConstTensor>(biases); |
| } |
| |
| IConnectableLayer* layer = m_Network->AddTransposeConvolution2dLayer(descriptor, |
| weights, |
| optionalBiases, |
| layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseStack(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| auto inputs = GetInputs(graph, layerIndex); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 1); |
| |
| auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_StackLayer()->descriptor(); |
| unsigned int axis = flatBufferDescriptor->axis(); |
| unsigned int numInputs = flatBufferDescriptor->numInputs(); |
| CHECK_VALID_SIZE(inputs.size(), numInputs); |
| |
| auto flatBufferInputShape = flatBufferDescriptor->inputShape(); |
| std::vector<uint32_t> vectorInputShape(flatBufferInputShape->begin(), |
| flatBufferInputShape->begin() + flatBufferInputShape->size()); |
| |
| TensorShape inputShape(static_cast<unsigned int>(vectorInputShape.size()), vectorInputShape.data()); |
| armnn::StackDescriptor descriptor(axis, numInputs, inputShape); |
| |
| for (unsigned int i=0; i<inputs.size(); ++i) |
| { |
| armnn::TensorShape inputShape = ToTensorInfo(inputs[i]).GetShape(); |
| if (descriptor.m_InputShape != inputShape) |
| { |
| std::stringstream ss; |
| ss << "Shape of input " |
| << i |
| << " " |
| << inputShape |
| << " does not equal defined input shape " |
| << descriptor.m_InputShape |
| << ": " |
| << CHECK_LOCATION().AsString(); |
| throw ParseException(ss.str()); |
| } |
| } |
| |
| auto layerName = GetLayerName(graph, layerIndex); |
| IConnectableLayer* layer = m_Network->AddStackLayer(descriptor, layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseStandIn(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| auto inputs = GetInputs(graph, layerIndex); |
| auto outputs = GetOutputs(graph, layerIndex); |
| |
| auto fbLayer = graph->layers()->Get(layerIndex)->layer_as_StandInLayer(); |
| auto fbDescriptor = fbLayer->descriptor(); |
| |
| armnn::StandInDescriptor descriptor; |
| descriptor.m_NumInputs = fbDescriptor->numInputs(); |
| descriptor.m_NumOutputs = fbDescriptor->numOutputs(); |
| |
| CHECK_VALID_SIZE(inputs.size(), descriptor.m_NumInputs); |
| CHECK_VALID_SIZE(outputs.size(), descriptor.m_NumOutputs); |
| |
| const std::string layerName = GetLayerName(graph, layerIndex); |
| armnn::IConnectableLayer* layer = m_Network->AddStandInLayer(descriptor, layerName.c_str()); |
| |
| for (unsigned int i = 0u; i < descriptor.m_NumOutputs; ++i) |
| { |
| armnn::TensorInfo outputInfo = ToTensorInfo(outputs[i]); |
| layer->GetOutputSlot(i).SetTensorInfo(outputInfo); |
| } |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| armnn::UnidirectionalSequenceLstmDescriptor IDeserializer::DeserializerImpl::GetUnidirectionalSequenceLstmDescriptor( |
| UnidirectionalSequenceLstmDescriptorPtr descriptor) |
| { |
| armnn::UnidirectionalSequenceLstmDescriptor desc; |
| |
| desc.m_ActivationFunc = descriptor->activationFunc(); |
| desc.m_ClippingThresCell = descriptor->clippingThresCell(); |
| desc.m_ClippingThresProj = descriptor->clippingThresProj(); |
| desc.m_CifgEnabled = descriptor->cifgEnabled(); |
| desc.m_PeepholeEnabled = descriptor->peepholeEnabled(); |
| desc.m_ProjectionEnabled = descriptor->projectionEnabled(); |
| desc.m_LayerNormEnabled = descriptor->layerNormEnabled(); |
| desc.m_TimeMajor = descriptor->timeMajor(); |
| |
| return desc; |
| } |
| |
| void IDeserializer::DeserializerImpl::ParseUnidirectionalSequenceLstm(GraphPtr graph, unsigned int layerIndex) |
| { |
| CHECK_LAYERS(graph, 0, layerIndex); |
| |
| auto inputs = GetInputs(graph, layerIndex); |
| CHECK_VALID_SIZE(inputs.size(), 3); |
| |
| auto outputs = GetOutputs(graph, layerIndex); |
| CHECK_VALID_SIZE(outputs.size(), 3); |
| |
| auto flatBufferLayer = graph->layers()->Get(layerIndex)->layer_as_UnidirectionalSequenceLstmLayer(); |
| auto layerName = GetLayerName(graph, layerIndex); |
| auto flatBufferDescriptor = flatBufferLayer->descriptor(); |
| auto flatBufferInputParams = flatBufferLayer->inputParams(); |
| |
| auto descriptor = GetUnidirectionalSequenceLstmDescriptor(flatBufferDescriptor); |
| |
| armnn::LstmInputParams lstmInputParams; |
| |
| armnn::ConstTensor inputToForgetWeights = ToConstTensor(flatBufferInputParams->inputToForgetWeights()); |
| armnn::ConstTensor inputToCellWeights = ToConstTensor(flatBufferInputParams->inputToCellWeights()); |
| armnn::ConstTensor inputToOutputWeights = ToConstTensor(flatBufferInputParams->inputToOutputWeights()); |
| armnn::ConstTensor recurrentToForgetWeights = ToConstTensor(flatBufferInputParams->recurrentToForgetWeights()); |
| armnn::ConstTensor recurrentToCellWeights = ToConstTensor(flatBufferInputParams->recurrentToCellWeights()); |
| armnn::ConstTensor recurrentToOutputWeights = ToConstTensor(flatBufferInputParams->recurrentToOutputWeights()); |
| armnn::ConstTensor forgetGateBias = ToConstTensor(flatBufferInputParams->forgetGateBias()); |
| armnn::ConstTensor cellBias = ToConstTensor(flatBufferInputParams->cellBias()); |
| armnn::ConstTensor outputGateBias = ToConstTensor(flatBufferInputParams->outputGateBias()); |
| |
| lstmInputParams.m_InputToForgetWeights = &inputToForgetWeights; |
| lstmInputParams.m_InputToCellWeights = &inputToCellWeights; |
| lstmInputParams.m_InputToOutputWeights = &inputToOutputWeights; |
| lstmInputParams.m_RecurrentToForgetWeights = &recurrentToForgetWeights; |
| lstmInputParams.m_RecurrentToCellWeights = &recurrentToCellWeights; |
| lstmInputParams.m_RecurrentToOutputWeights = &recurrentToOutputWeights; |
| lstmInputParams.m_ForgetGateBias = &forgetGateBias; |
| lstmInputParams.m_CellBias = &cellBias; |
| lstmInputParams.m_OutputGateBias = &outputGateBias; |
| |
| armnn::ConstTensor inputToInputWeights; |
| armnn::ConstTensor recurrentToInputWeights; |
| armnn::ConstTensor cellToInputWeights; |
| armnn::ConstTensor inputGateBias; |
| if (!descriptor.m_CifgEnabled) |
| { |
| inputToInputWeights = ToConstTensor(flatBufferInputParams->inputToInputWeights()); |
| recurrentToInputWeights = ToConstTensor(flatBufferInputParams->recurrentToInputWeights()); |
| inputGateBias = ToConstTensor(flatBufferInputParams->inputGateBias()); |
| |
| lstmInputParams.m_InputToInputWeights = &inputToInputWeights; |
| lstmInputParams.m_RecurrentToInputWeights = &recurrentToInputWeights; |
| lstmInputParams.m_InputGateBias = &inputGateBias; |
| |
| if (descriptor.m_PeepholeEnabled) |
| { |
| cellToInputWeights = ToConstTensor(flatBufferInputParams->cellToInputWeights()); |
| lstmInputParams.m_CellToInputWeights = &cellToInputWeights; |
| } |
| } |
| |
| armnn::ConstTensor projectionWeights; |
| armnn::ConstTensor projectionBias; |
| if (descriptor.m_ProjectionEnabled) |
| { |
| projectionWeights = ToConstTensor(flatBufferInputParams->projectionWeights()); |
| projectionBias = ToConstTensor(flatBufferInputParams->projectionBias()); |
| |
| lstmInputParams.m_ProjectionWeights = &projectionWeights; |
| lstmInputParams.m_ProjectionBias = &projectionBias; |
| } |
| |
| armnn::ConstTensor cellToForgetWeights; |
| armnn::ConstTensor cellToOutputWeights; |
| if (descriptor.m_PeepholeEnabled) |
| { |
| cellToForgetWeights = ToConstTensor(flatBufferInputParams->cellToForgetWeights()); |
| cellToOutputWeights = ToConstTensor(flatBufferInputParams->cellToOutputWeights()); |
| |
| lstmInputParams.m_CellToForgetWeights = &cellToForgetWeights; |
| lstmInputParams.m_CellToOutputWeights = &cellToOutputWeights; |
| } |
| |
| armnn::ConstTensor inputLayerNormWeights; |
| armnn::ConstTensor forgetLayerNormWeights; |
| armnn::ConstTensor cellLayerNormWeights; |
| armnn::ConstTensor outputLayerNormWeights; |
| if (descriptor.m_LayerNormEnabled) |
| { |
| if (!descriptor.m_CifgEnabled) |
| { |
| inputLayerNormWeights = ToConstTensor(flatBufferInputParams->inputLayerNormWeights()); |
| lstmInputParams.m_InputLayerNormWeights = &inputLayerNormWeights; |
| } |
| forgetLayerNormWeights = ToConstTensor(flatBufferInputParams->forgetLayerNormWeights()); |
| cellLayerNormWeights = ToConstTensor(flatBufferInputParams->cellLayerNormWeights()); |
| outputLayerNormWeights = ToConstTensor(flatBufferInputParams->outputLayerNormWeights()); |
| |
| lstmInputParams.m_ForgetLayerNormWeights = &forgetLayerNormWeights; |
| lstmInputParams.m_CellLayerNormWeights = &cellLayerNormWeights; |
| lstmInputParams.m_OutputLayerNormWeights = &outputLayerNormWeights; |
| } |
| |
| IConnectableLayer* layer = m_Network->AddUnidirectionalSequenceLstmLayer(descriptor, |
| lstmInputParams, |
| layerName.c_str()); |
| |
| armnn::TensorInfo outputTensorInfo0 = ToTensorInfo(outputs[0]); |
| layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo0); |
| |
| armnn::TensorInfo outputTensorInfo1 = ToTensorInfo(outputs[1]); |
| layer->GetOutputSlot(1).SetTensorInfo(outputTensorInfo1); |
| |
| armnn::TensorInfo outputTensorInfo2 = ToTensorInfo(outputs[2]); |
| layer->GetOutputSlot(2).SetTensorInfo(outputTensorInfo2); |
| |
| RegisterInputSlots(graph, layerIndex, layer); |
| RegisterOutputSlots(graph, layerIndex, layer); |
| } |
| |
| } // namespace armnnDeserializer |