diff options
author | Mike Kelly <mike.kelly@arm.com> | 2023-01-10 15:55:28 +0000 |
---|---|---|
committer | mike.kelly <mike.kelly@arm.com> | 2023-01-12 14:46:46 +0000 |
commit | 377fb21e956ea68ffd234be47481002a0e46ee46 (patch) | |
tree | 3d82f8d43c36cd4054fd6e29d082599e6ef0be86 /src | |
parent | 01f72693d39ed966ad06adadc8aac141bc395659 (diff) | |
download | armnn-377fb21e956ea68ffd234be47481002a0e46ee46.tar.gz |
IVGCVSW-7244 ConcatLayer overlapping views on TFLiteParser
* Added ability to calculate dynamic tensors and propagate
them through the model so that when those tensors are later
used as inputs they have the right shapes.
* Added InferOutputShapes to DetectionPostProcessLayer.
* Added InferOutputShapes to MeanLayer.
* Added InferOutputShapes to RankLayer.
* Added InferOutputShapes to ReduceLayer.
* Fixed typos in TfLiteParser.
Signed-off-by: Mike Kelly <mike.kelly@arm.com>
Change-Id: I880c0716938ef278f5dbf01a8a73a5cc99ce5ded
Diffstat (limited to 'src')
-rw-r--r-- | src/armnn/layers/ChannelShuffleLayer.hpp | 3 | ||||
-rw-r--r-- | src/armnn/layers/DetectionPostProcessLayer.cpp | 34 | ||||
-rw-r--r-- | src/armnn/layers/DetectionPostProcessLayer.hpp | 8 | ||||
-rw-r--r-- | src/armnn/layers/MeanLayer.cpp | 22 | ||||
-rw-r--r-- | src/armnn/layers/MeanLayer.hpp | 8 | ||||
-rw-r--r-- | src/armnn/layers/RankLayer.cpp | 7 | ||||
-rw-r--r-- | src/armnn/layers/RankLayer.hpp | 37 | ||||
-rw-r--r-- | src/armnn/layers/ReduceLayer.cpp | 21 | ||||
-rw-r--r-- | src/armnn/layers/ReduceLayer.hpp | 9 | ||||
-rw-r--r-- | src/armnn/layers/ReshapeLayer.cpp | 3 | ||||
-rw-r--r-- | src/armnnTfLiteParser/TfLiteParser.cpp | 507 | ||||
-rw-r--r-- | src/armnnTfLiteParser/TfLiteParser.hpp | 27 |
12 files changed, 481 insertions, 205 deletions
diff --git a/src/armnn/layers/ChannelShuffleLayer.hpp b/src/armnn/layers/ChannelShuffleLayer.hpp index 79ab426a44..45cd5e5d82 100644 --- a/src/armnn/layers/ChannelShuffleLayer.hpp +++ b/src/armnn/layers/ChannelShuffleLayer.hpp @@ -1,5 +1,5 @@ // -// Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +// Copyright © 2021-2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // #pragma once @@ -26,7 +26,6 @@ public: /// @param [in] shapeInferenceMethod Indicates if output shape shall be overwritten or just validated. void ValidateTensorShapesFromInputs() override; - // TODO Do you need to create an InferOutputShapes function for ChannelShuffle? protected: ChannelShuffleLayer(const ChannelShuffleDescriptor& param, const char* name); diff --git a/src/armnn/layers/DetectionPostProcessLayer.cpp b/src/armnn/layers/DetectionPostProcessLayer.cpp index 28c6d50659..33f894414a 100644 --- a/src/armnn/layers/DetectionPostProcessLayer.cpp +++ b/src/armnn/layers/DetectionPostProcessLayer.cpp @@ -1,5 +1,5 @@ // -// Copyright © 2017 Arm Ltd and Contributors. All rights reserved. +// Copyright © 2017-2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -49,30 +49,46 @@ void DetectionPostProcessLayer::ValidateTensorShapesFromInputs() ARMNN_ASSERT_MSG(GetNumOutputSlots() == 4, "DetectionPostProcessLayer: The layer should return 4 outputs."); - unsigned int detectedBoxes = m_Param.m_MaxDetections * m_Param.m_MaxClassesPerDetection; + std::vector<TensorShape> inferredShapes = InferOutputShapes( + { GetInputSlot(0).GetConnection()->GetTensorInfo().GetShape(), + GetInputSlot(1).GetConnection()->GetTensorInfo().GetShape() }); - const TensorShape& inferredDetectionBoxes = TensorShape({ 1, detectedBoxes, 4 }); - const TensorShape& inferredDetectionScores = TensorShape({ 1, detectedBoxes }); - const TensorShape& inferredNumberDetections = TensorShape({ 1 }); + ARMNN_ASSERT(inferredShapes.size() == 4); + ARMNN_ASSERT(inferredShapes[0].GetDimensionality() == Dimensionality::Specified); + ARMNN_ASSERT(inferredShapes[1].GetDimensionality() == Dimensionality::Specified); + ARMNN_ASSERT(inferredShapes[2].GetDimensionality() == Dimensionality::Specified); + ARMNN_ASSERT(inferredShapes[3].GetDimensionality() == Dimensionality::Specified); - ValidateAndCopyShape(outputShape, inferredDetectionBoxes, m_ShapeInferenceMethod, "DetectionPostProcessLayer"); + ValidateAndCopyShape(outputShape, inferredShapes[0], m_ShapeInferenceMethod, "DetectionPostProcessLayer"); ValidateAndCopyShape(GetOutputSlot(1).GetTensorInfo().GetShape(), - inferredDetectionScores, + inferredShapes[1], m_ShapeInferenceMethod, "DetectionPostProcessLayer", 1); ValidateAndCopyShape(GetOutputSlot(2).GetTensorInfo().GetShape(), - inferredDetectionScores, + inferredShapes[2], m_ShapeInferenceMethod, "DetectionPostProcessLayer", 2); ValidateAndCopyShape(GetOutputSlot(3).GetTensorInfo().GetShape(), - inferredNumberDetections, + inferredShapes[3], m_ShapeInferenceMethod, "DetectionPostProcessLayer", 3); } +std::vector<TensorShape> DetectionPostProcessLayer::InferOutputShapes(const std::vector<TensorShape>&) const +{ + unsigned int detectedBoxes = m_Param.m_MaxDetections * m_Param.m_MaxClassesPerDetection; + + std::vector<TensorShape> results; + results.push_back({ 1, detectedBoxes, 4 }); + results.push_back({ 1, detectedBoxes }); + results.push_back({ 1, detectedBoxes }); + results.push_back({ 1 }); + return results; +} + Layer::ConstantTensors DetectionPostProcessLayer::GetConstantTensorsByRef() { // For API stability DO NOT ALTER order and add new members to the end of vector diff --git a/src/armnn/layers/DetectionPostProcessLayer.hpp b/src/armnn/layers/DetectionPostProcessLayer.hpp index 07eb270f1f..e203032db0 100644 --- a/src/armnn/layers/DetectionPostProcessLayer.hpp +++ b/src/armnn/layers/DetectionPostProcessLayer.hpp @@ -1,5 +1,5 @@ // -// Copyright © 2017 Arm Ltd and Contributors. All rights reserved. +// Copyright © 2017-2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -34,6 +34,12 @@ public: /// @param [in] shapeInferenceMethod Indicates if output shape shall be overwritten or just validated. void ValidateTensorShapesFromInputs() override; + /// The model does not specify the output shapes. The output shapes are calculated from the max_detection and + /// max_classes_per_detection parameters in the DetectionPostProcessDescriptor. + /// @param [in] inputShapes The input shapes layer has. These are ignored for DetectionPostProcessLayer. + /// @return A vector to the inferred output shape. + std::vector<TensorShape> InferOutputShapes(const std::vector<TensorShape>& inputShapes) const override; + void ExecuteStrategy(IStrategy& strategy) const override; protected: diff --git a/src/armnn/layers/MeanLayer.cpp b/src/armnn/layers/MeanLayer.cpp index 49eac04a8e..a6f721b076 100644 --- a/src/armnn/layers/MeanLayer.cpp +++ b/src/armnn/layers/MeanLayer.cpp @@ -1,5 +1,5 @@ // -// Copyright © 2017 Arm Ltd and Contributors. All rights reserved. +// Copyright © 2017-2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -49,7 +49,19 @@ void MeanLayer::ValidateTensorShapesFromInputs() VerifyShapeInferenceType(outputShape, m_ShapeInferenceMethod); - const TensorInfo& input = GetInputSlot(0).GetConnection()->GetTensorInfo(); + std::vector<TensorShape> inferredShapes = InferOutputShapes( + { GetInputSlot(0).GetConnection()->GetTensorInfo().GetShape() }); + + ARMNN_ASSERT(inferredShapes.size() == 1); + ARMNN_ASSERT(inferredShapes[0].GetDimensionality() == Dimensionality::Specified); + + ValidateAndCopyShape(outputShape, inferredShapes[0], m_ShapeInferenceMethod, "MeanLayer"); +} + +std::vector<TensorShape> MeanLayer::InferOutputShapes(const std::vector<TensorShape>& inputShapes) const +{ + ARMNN_ASSERT(inputShapes.size() == 1); + const TensorShape& input = inputShapes[0]; ARMNN_ASSERT_MSG(input.GetNumDimensions() > 0 && input.GetNumDimensions() <= 4, "MeanLayer: Mean supports up to 4D input."); @@ -88,7 +100,7 @@ void MeanLayer::ValidateTensorShapesFromInputs() { if (std::find(m_Param.m_Axis.begin(), m_Param.m_Axis.end(), i) == m_Param.m_Axis.end()) { - dimSizes[outputIndex] = armnn::numeric_cast<unsigned int>(input.GetShape()[i]); + dimSizes[outputIndex] = armnn::numeric_cast<unsigned int>(input[i]); ++outputIndex; } else if (m_Param.m_KeepDims) @@ -98,9 +110,7 @@ void MeanLayer::ValidateTensorShapesFromInputs() } } } - const TensorShape& inferredShape = TensorShape(outputRank, dimSizes.data()); - - ValidateAndCopyShape(outputShape, inferredShape, m_ShapeInferenceMethod, "MeanLayer"); + return std::vector<TensorShape>({ TensorShape(outputRank, dimSizes.data()) }); } void MeanLayer::ExecuteStrategy(IStrategy& strategy) const diff --git a/src/armnn/layers/MeanLayer.hpp b/src/armnn/layers/MeanLayer.hpp index 87998bfc08..3bde7c6fcc 100644 --- a/src/armnn/layers/MeanLayer.hpp +++ b/src/armnn/layers/MeanLayer.hpp @@ -1,5 +1,5 @@ // -// Copyright © 2017 Arm Ltd and Contributors. All rights reserved. +// Copyright © 2017-2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -29,6 +29,12 @@ public: /// @param [in] shapeInferenceMethod Indicates if output shape shall be overwritten or just validated. void ValidateTensorShapesFromInputs() override; + /// By default returns inputShapes if the number of inputs are equal to number of outputs, + /// otherwise infers the output shapes from given input shapes and layer properties. + /// @param [in] inputShapes The input shapes layer has. + /// @return A vector to the inferred output shape. + std::vector<TensorShape> InferOutputShapes(const std::vector<TensorShape>& inputShapes) const override; + void ExecuteStrategy(IStrategy& strategy) const override; protected: diff --git a/src/armnn/layers/RankLayer.cpp b/src/armnn/layers/RankLayer.cpp index 0f9327b948..6ea271442f 100644 --- a/src/armnn/layers/RankLayer.cpp +++ b/src/armnn/layers/RankLayer.cpp @@ -1,5 +1,5 @@ // -// Copyright © 2020 Arm Ltd and Contributors. All rights reserved. +// Copyright © 2020-2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -31,6 +31,11 @@ Layer* RankLayer::Clone(Graph& graph) const return clone; } +std::vector<TensorShape> RankLayer::InferOutputShapes(const std::vector<TensorShape>&) const +{ + return std::vector<TensorShape>({ TensorShape(Dimensionality::Scalar) }); +} + void RankLayer::ValidateTensorShapesFromInputs() { VerifyLayerConnections(1, CHECK_LOCATION()); diff --git a/src/armnn/layers/RankLayer.hpp b/src/armnn/layers/RankLayer.hpp index 52d14c446e..a789917de0 100644 --- a/src/armnn/layers/RankLayer.hpp +++ b/src/armnn/layers/RankLayer.hpp @@ -1,5 +1,5 @@ // -// Copyright © 2020 Arm Ltd and Contributors. All rights reserved. +// Copyright © 2020-2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -12,21 +12,36 @@ namespace armnn class RankLayer : public Layer { - public: - /// Makes a workload for the Rank type. - /// @param [in] factory The workload factory which will create the workload. - /// @return A pointer to the created workload, or nullptr if not created. - virtual std::unique_ptr<IWorkload> CreateWorkload(const IWorkloadFactory& factory) const override; +public: + /// Makes a workload for the Rank type. + /// @param [in] factory The workload factory which will create the workload. + /// @return A pointer to the created workload, or nullptr if not created. + virtual std::unique_ptr<IWorkload> CreateWorkload(const IWorkloadFactory& factory) const override; - Layer* Clone(Graph& graph) const override; + /// Creates a dynamically-allocated copy of this layer. + /// @param [in] graph The graph into which this layer is being cloned. + Layer* Clone(Graph& graph) const override; - void ValidateTensorShapesFromInputs() override; + /// Check if the input tensor shape(s) + /// will lead to a valid configuration of @ref RankLayer. + /// @param [in] shapeInferenceMethod Indicates if output shape shall be overwritten or just validated. + void ValidateTensorShapesFromInputs() override; - void ExecuteStrategy(IStrategy& strategy) const override; + /// Rank returns a scalar specifying the rank of the input tensor. The rank of a tensor is the number + /// of dimensions it has. + /// @param [in] inputShapes The input shapes layer has. This is ignored for Rank. + /// @return A vector to the inferred output shape. + std::vector<TensorShape> InferOutputShapes(const std::vector<TensorShape>& inputShapes) const override; + + void ExecuteStrategy(IStrategy& strategy) const override; protected: - RankLayer(const char* name); - ~RankLayer() = default; + /// Constructor to create a RankLayer. + /// @param [in] name Optional name for the layer. + RankLayer(const char* name); + + /// Default destructor + ~RankLayer() = default; }; } //namespace armnn diff --git a/src/armnn/layers/ReduceLayer.cpp b/src/armnn/layers/ReduceLayer.cpp index aa54bc8f0c..e411996ced 100644 --- a/src/armnn/layers/ReduceLayer.cpp +++ b/src/armnn/layers/ReduceLayer.cpp @@ -1,5 +1,5 @@ // -// Copyright © 2020 Samsung Electronics Co Ltd and Contributors. All rights reserved. +// Copyright © 2020-2023 Samsung Electronics Co Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -53,6 +53,19 @@ void ReduceLayer::ValidateTensorShapesFromInputs() ARMNN_ASSERT_MSG(input.GetNumDimensions() > 0 && input.GetNumDimensions() <= 4, "ReduceLayer: Reduce supports up to 4D input."); + std::vector<TensorShape> inferredShapes = InferOutputShapes( {input.GetShape() }); + + ValidateAndCopyShape(outputShape, inferredShapes[0], m_ShapeInferenceMethod, "ReduceLayer"); +} + +std::vector<TensorShape> ReduceLayer::InferOutputShapes(const std::vector<TensorShape>& inputShapes) const +{ + ARMNN_ASSERT(inputShapes.size() == 1); + const TensorShape& input = inputShapes[0]; + + ARMNN_ASSERT_MSG(input.GetNumDimensions() > 0 && input.GetNumDimensions() <= 4, + "ReduceLayer: Reduce supports up to 4D input."); + unsigned int rank = input.GetNumDimensions(); unsigned int outputRank = 0; @@ -87,7 +100,7 @@ void ReduceLayer::ValidateTensorShapesFromInputs() { if (std::find(m_Param.m_vAxis.begin(), m_Param.m_vAxis.end(), i) == m_Param.m_vAxis.end()) { - dimSizes[outputIndex] = armnn::numeric_cast<unsigned int>(input.GetShape()[i]); + dimSizes[outputIndex] = armnn::numeric_cast<unsigned int>(input[i]); ++outputIndex; } else if (m_Param.m_KeepDims) @@ -97,9 +110,7 @@ void ReduceLayer::ValidateTensorShapesFromInputs() } } } - const TensorShape& inferredShape = TensorShape(outputRank, dimSizes.data()); - - ValidateAndCopyShape(outputShape, inferredShape, m_ShapeInferenceMethod, "ReduceLayer"); + return std::vector<TensorShape>({ TensorShape(outputRank, dimSizes.data()) }); } void ReduceLayer::ExecuteStrategy(IStrategy& strategy) const diff --git a/src/armnn/layers/ReduceLayer.hpp b/src/armnn/layers/ReduceLayer.hpp index e9ea5d8e3f..24f19f812f 100644 --- a/src/armnn/layers/ReduceLayer.hpp +++ b/src/armnn/layers/ReduceLayer.hpp @@ -1,5 +1,5 @@ // -// Copyright © 2020 Samsung Electronics Co Ltd and Contributors. All rights reserved. +// Copyright © 2020-2023 Samsung Electronics Co Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // #pragma once @@ -23,13 +23,18 @@ public: /// @param [in] graph The graph into which this layer is being cloned. ReduceLayer* Clone(Graph& graph) const override; + /// By default returns inputShapes if the number of inputs are equal to number of outputs, + /// otherwise infers the output shapes from given input shapes and layer properties. + /// @param [in] inputShapes The input shapes layer has. + /// @return A vector to the inferred output shape. + std::vector<TensorShape> InferOutputShapes(const std::vector<TensorShape>& inputShapes) const override; + /// Check if the input tensor shape(s) /// will lead to a valid configuration of @ref ReduceLayer. void ValidateTensorShapesFromInputs() override; void ExecuteStrategy(IStrategy& strategy) const override; - protected: /// Constructor to create a ReduceLayer. /// @param [in] param ReduceDescriptor to configure the reduction operation. diff --git a/src/armnn/layers/ReshapeLayer.cpp b/src/armnn/layers/ReshapeLayer.cpp index c5ec45f211..e68460bf32 100644 --- a/src/armnn/layers/ReshapeLayer.cpp +++ b/src/armnn/layers/ReshapeLayer.cpp @@ -1,5 +1,5 @@ // -// Copyright © 2017 Arm Ltd and Contributors. All rights reserved. +// Copyright © 2017-2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // #include "ReshapeLayer.hpp" @@ -49,6 +49,7 @@ void ReshapeLayer::ValidateTensorShapesFromInputs() auto inferredShapes = InferOutputShapes({ GetInputSlot(0).GetConnection()->GetTensorInfo().GetShape() }); ARMNN_ASSERT(inferredShapes.size() == 1); + ARMNN_ASSERT(inferredShapes[0].GetDimensionality() == Dimensionality::Specified); ValidateAndCopyShape(outputShape, inferredShapes[0], m_ShapeInferenceMethod, "ReshapeLayer"); } diff --git a/src/armnnTfLiteParser/TfLiteParser.cpp b/src/armnnTfLiteParser/TfLiteParser.cpp index f6c1ee9d38..a3bec923c1 100644 --- a/src/armnnTfLiteParser/TfLiteParser.cpp +++ b/src/armnnTfLiteParser/TfLiteParser.cpp @@ -1,5 +1,5 @@ // -// Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved. +// Copyright © 2018-2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -18,6 +18,7 @@ #include <armnn/utility/Assert.hpp> #include <armnn/utility/IgnoreUnused.hpp> #include <armnn/utility/NumericCast.hpp> +#include <armnn/LayerSupport.hpp> // armnnUtils: #include <armnnUtils/Permute.hpp> @@ -353,7 +354,7 @@ bool IsActivationSupported(tflite::ActivationFunctionType activationType) if (IsActivationSupported(OPTION->fused_activation_function) == false) \ { \ throw ParseException( \ - fmt::format("TfLite parser doesn't suppport fused activation: " \ + fmt::format("TfLite parser doesn't support fused activation: " \ "{}/{} in {} subgraph:{} operator:{} at {}", \ OPTION->fused_activation_function, \ tflite::EnumNameActivationFunctionType(\ @@ -568,14 +569,8 @@ armnn::TensorInfo ToTensorInfo(TfLiteParserImpl::TensorRawPtr tensorPtr, } } -armnn::TensorInfo ToTensorInfo(TfLiteParserImpl::TensorRawPtr tensorPtr) -{ - auto const& dimensions = AsUnsignedVector(tensorPtr->shape); - return ToTensorInfo(tensorPtr, dimensions); -} - armnn::TensorInfo ToTensorInfo(TfLiteParserImpl::TensorRawPtr tensorPtr, - const bool outputTensor) + const bool outputTensor = false) { auto const& dimensions = AsUnsignedVector(tensorPtr->shape); return ToTensorInfo(tensorPtr, dimensions, outputTensor); @@ -684,6 +679,31 @@ void CheckMatchingQuantization(const TensorInfo& first, } } +bool IsDynamic(TfLiteParserImpl::TensorRawPtr tensorPtr) +{ + auto shape = tensorPtr->shape; + + if (shape.empty()) + { + return true; + } + auto shapeSig = tensorPtr->shape_signature; + + if (shapeSig.empty()) + { + return false; + } + + for (unsigned int i = 0; i < shapeSig.size() ; ++i) + { + if (shapeSig[i] == -1) + { + return true; + } + } + return false; +} + } // <anonymous> TfLiteParserImpl::TfLiteParserImpl(const Optional<ITfLiteParser::TfLiteParserOptions>& options) @@ -777,14 +797,117 @@ TfLiteParserImpl::TfLiteParserImpl(const Optional<ITfLiteParser::TfLiteParserOpt m_CustomParserFunctions["TFLite_Detection_PostProcess"] = &TfLiteParserImpl::ParseDetectionPostProcess; } +armnn::TensorInfo TfLiteParserImpl::InputTensorInfo(size_t subgraphIndex, + size_t operatorIndex, + int input) +{ + const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex]; + const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex]; + + uint32_t inputId = CHECKED_NON_NEGATIVE(operatorPtr->inputs[input]); + auto search = armnnTfLiteParser::TfLiteParserImpl::m_TensorInfos.find(inputId); + + if (search != m_TensorInfos.end()) + { + return m_TensorInfos[inputId]; + } + else + { + auto tensorInfo = ::armnnTfLiteParser::ToTensorInfo(subgraphPtr->tensors[inputId].get()); + m_TensorInfos.insert({ inputId, tensorInfo }); + return tensorInfo; + } +} + +armnn::TensorInfo TfLiteParserImpl::OutputTensorInfoFromInputs(size_t subgraphIndex, + size_t operatorIndex, + armnn::IConnectableLayer* layer, + int output, + std::vector<int> inputs) +{ + const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex]; + const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex]; + + uint32_t outputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[output]); + + auto outputSearch = armnnTfLiteParser::TfLiteParserImpl::m_TensorInfos.find(outputId); + + if (outputSearch != m_TensorInfos.end()) + { + return m_TensorInfos[outputId]; + } + + const auto& outputTensorPtr = subgraphPtr->tensors[outputId].get(); + TensorInfo tensor = ::armnnTfLiteParser::ToTensorInfo(outputTensorPtr, true); + + if (IsDynamic(outputTensorPtr)) + { + if (inputs.empty()) + { + for (unsigned int i = 0; i < layer->GetNumInputSlots(); ++i) + { + inputs.emplace_back(i); + } + } + auto inputTensorIds = GetInputTensorIds(m_Model, subgraphIndex, operatorIndex); + std::vector<armnn::TensorShape> inputShapes; + + for (unsigned int i = 0; i < inputs.size(); ++i) + { + uint32_t inputId = CHECKED_NON_NEGATIVE(operatorPtr->inputs[inputs[i]]); + auto search = armnnTfLiteParser::TfLiteParserImpl::m_TensorInfos.find(inputId); + + if (search != m_TensorInfos.end()) + { + auto &inputTensorInfo = m_TensorInfos[inputId]; + inputShapes.push_back(inputTensorInfo.GetShape()); + } + else + { + m_Model->subgraphs[subgraphIndex]->operators[operatorIndex]; + auto inputTensorInfo = ::armnnTfLiteParser::ToTensorInfo(subgraphPtr->tensors[inputId].get()); + m_TensorInfos.insert({ inputId, inputTensorInfo}); + inputShapes.push_back(inputTensorInfo.GetShape()); + } + } + const auto outputShape = layer->InferOutputShapes(inputShapes)[output]; + tensor.SetShape(outputShape); + } + m_TensorInfos.insert({ outputId, tensor}); + return tensor; +} + +armnn::TensorInfo TfLiteParserImpl::OutputTensorInfoFromShapes(size_t subgraphIndex, + size_t operatorIndex, + armnn::IConnectableLayer* layer, + int output, + std::vector<armnn::TensorShape> inputShapes) +{ + const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex]; + const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex]; + + uint32_t outputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[output]); + const auto& outputTensorPtr = subgraphPtr->tensors[outputId].get(); + TensorInfo tensor = ::armnnTfLiteParser::ToTensorInfo(outputTensorPtr, true); + + if (IsDynamic(outputTensorPtr)) + { + const auto outputShape = layer->InferOutputShapes(inputShapes)[output]; + tensor.SetShape(outputShape); + } + m_TensorInfos.insert({ outputId, tensor}); + return tensor; +} + void TfLiteParserImpl::ResetParser() { m_Network = armnn::INetworkPtr(nullptr, nullptr); m_Model = nullptr; m_SubgraphConnections.clear(); - m_OverridenOutputShapes.clear(); + m_OverriddenOutputShapes.clear(); m_ConstantsToDequantize.clear(); m_ConstantsToBeCreated.clear(); + m_TensorInfos.clear(); } INetworkPtr TfLiteParserImpl::CreateNetworkFromBinaryFile(const char* graphFile) @@ -853,6 +976,9 @@ INetworkPtr TfLiteParserImpl::CreateNetworkFromModel() { for (SubgraphPtr const& subgraph : m_Model->subgraphs) { + SetupInputLayerTensorInfos(subgraphIndex); + SetupConstantLayerTensorInfos(subgraphIndex); + m_SubgraphConnections.emplace_back(subgraph->tensors.size()); for (OperatorPtr const& op : subgraph->operators) { @@ -980,7 +1106,7 @@ void TfLiteParserImpl::ParseCustomOperator(size_t subgraphIndex, size_t operator const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex]; const auto& customCode = m_Model->operator_codes[operatorPtr->opcode_index]->custom_code; - // Find parser function that correspondes to custom code (if any) + // Find parser function that corresponds to custom code (if any) auto iterator = m_CustomParserFunctions.find(customCode); if (iterator != m_CustomParserFunctions.end()) { @@ -1037,7 +1163,7 @@ void TfLiteParserImpl::ParseUnsupportedOperator(size_t subgraphIndex, size_t ope for (unsigned int i = 0u; i < numOutputs; ++i) { - layer->GetOutputSlot(i).SetTensorInfo(ToTensorInfo(outputs[i], true)); + layer->GetOutputSlot(i).SetTensorInfo(OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, i, {})); } auto inputTensorIds = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -1061,7 +1187,7 @@ void TfLiteParserImpl::ParseCast(size_t subgraphIndex, size_t operatorIndex) IConnectableLayer* layer = m_Network->AddCastLayer(layerName.c_str()); ARMNN_ASSERT(layer != nullptr); - TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); + TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -1093,8 +1219,8 @@ void TfLiteParserImpl::ParseConv2D(size_t subgraphIndex, size_t operatorIndex) desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor); desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor); - armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); - armnn::TensorInfo filterTensorInfo = ToTensorInfo(inputs[1]); + armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); + armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); // assuming input is NHWC unsigned int inputHeight = inputTensorInfo.GetShape()[1]; @@ -1125,7 +1251,7 @@ void TfLiteParserImpl::ParseConv2D(size_t subgraphIndex, size_t operatorIndex) if (desc.m_BiasEnabled) { - armnn::TensorInfo biasTensorInfo = ToTensorInfo(inputs[2]); + armnn::TensorInfo biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2); // Add the biases input to the registration list, a constant layer will be added by SetupConstantLayers. tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]); @@ -1138,7 +1264,7 @@ void TfLiteParserImpl::ParseConv2D(size_t subgraphIndex, size_t operatorIndex) ARMNN_ASSERT(layer != nullptr); - armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); + armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); // register the input connection slots for the layer, connections are made after all layers have been created @@ -1178,8 +1304,8 @@ void TfLiteParserImpl::ParseConv3D(size_t subgraphIndex, size_t operatorIndex) auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex); CHECK_VALID_SIZE(outputs.size(), 1); - armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); - armnn::TensorInfo filterTensorInfo = ToTensorInfo(inputs[1]); + armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); + armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); // Assuming input is NDHWC unsigned int inputDepth = inputTensorInfo.GetShape()[1]; @@ -1218,7 +1344,7 @@ void TfLiteParserImpl::ParseConv3D(size_t subgraphIndex, size_t operatorIndex) armnn::IConnectableLayer* layer = m_Network->AddConvolution3dLayer(desc, layerName.c_str()); ARMNN_ASSERT(layer != nullptr); - armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); + armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); // Register the input connection slots for the layer, connections are made after all layers have been created @@ -1258,8 +1384,8 @@ void TfLiteParserImpl::ParseDepthwiseConv2D(size_t subgraphIndex, size_t operato desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor); desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor); - armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); - armnn::TensorInfo filterTensorInfo = ToTensorInfo(inputs[1]); + armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); + armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); // Assuming input is NHWC unsigned int inputHeight = inputTensorInfo.GetShape()[1]; @@ -1287,14 +1413,14 @@ void TfLiteParserImpl::ParseDepthwiseConv2D(size_t subgraphIndex, size_t operato if (desc.m_BiasEnabled) { desc.m_BiasEnabled = true; - TensorInfo biasTensorInfo = ToTensorInfo(inputs[2]); + TensorInfo biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2); // Add the biases input to the registration list, a constant layer will be added by SetupConstantLayers. tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]); } ARMNN_ASSERT(layer != nullptr); - armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); + armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); // register the input connection slots for the layer, connections are made after all layers have been created @@ -1322,7 +1448,7 @@ void TfLiteParserImpl::ParseDequantize(size_t subgraphIndex, size_t operatorInde IConnectableLayer* layer = m_Network->AddDequantizeLayer(layerName.c_str()); ARMNN_ASSERT(layer != nullptr); - TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); + TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -1344,7 +1470,7 @@ void TfLiteParserImpl::ParseExpandDims(size_t subgraphIndex, size_t operatorInde auto layerName = fmt::format("ExpandDims:{}:{}", subgraphIndex, operatorIndex); - armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); + armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0"); @@ -1391,6 +1517,10 @@ void TfLiteParserImpl::ParseExpandDims(size_t subgraphIndex, size_t operatorInde IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str()); ARMNN_ASSERT(layer != nullptr); + + reshapeDesc.m_TargetShape = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0}).GetShape(); + outputTensorInfo.SetShape(reshapeDesc.m_TargetShape); + layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -1415,7 +1545,7 @@ void TfLiteParserImpl::ParseTranspose(size_t subgraphIndex, size_t operatorIndex if (inputs.size() == 2) { - armnn::TensorInfo permuteTensorInfo = ToTensorInfo(inputs[1]); + armnn::TensorInfo permuteTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); BufferRawPtr permuteBufferPtr = GetBuffer(m_Model, inputs[1]->buffer); auto numPermVecElements = permuteTensorInfo.GetNumElements(); std::vector<unsigned int> permuteShape(numPermVecElements); @@ -1424,13 +1554,13 @@ void TfLiteParserImpl::ParseTranspose(size_t subgraphIndex, size_t operatorIndex desc = TransposeDescriptor(permutationVector); } - - TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); - TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); - CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0"); + TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); IConnectableLayer* layer = m_Network->AddTransposeLayer(desc, layerName.c_str()); ARMNN_ASSERT(layer != nullptr); + + TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0}); + CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0"); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -1468,8 +1598,9 @@ void TfLiteParserImpl::ParseTransposeConv(size_t subgraphIndex, size_t operatorI if (inputs[0]) { - armnn::TensorInfo tensorInfo = ToTensorInfo(inputs[0]); + armnn::TensorInfo tensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); std::vector<int> output_shape(tensorInfo.GetNumElements()); + if (tensorInfo.GetDataType() == DataType::Signed32) { ::memcpy(output_shape.data(), GetBuffer(m_Model, inputs[0]->buffer)->data.data(), tensorInfo.GetNumBytes()); @@ -1488,8 +1619,8 @@ void TfLiteParserImpl::ParseTransposeConv(size_t subgraphIndex, size_t operatorI } desc.m_OutputShapeEnabled = true; } - armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[2]); - armnn::TensorInfo filterTensorInfo = ToTensorInfo(inputs[1]); + armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2); + armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); // TfLite uses NHWC tensors const unsigned int inputHeight = inputTensorInfo.GetShape()[1]; @@ -1521,7 +1652,7 @@ void TfLiteParserImpl::ParseTransposeConv(size_t subgraphIndex, size_t operatorI if (desc.m_BiasEnabled) { - auto biasTensorInfo = ToTensorInfo(inputs[3]); + auto biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 3); auto biasConstTensor = CreateConstTensorNonPermuted(inputs[3], biasTensorInfo, inputTensorInfo.GetDataType()); layer = m_Network->AddTransposeConvolution2dLayer(desc, filterTensorAndData.first, @@ -1538,7 +1669,7 @@ void TfLiteParserImpl::ParseTransposeConv(size_t subgraphIndex, size_t operatorI ARMNN_ASSERT(layer != nullptr); - armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); + armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0 , { 2, 1 }); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); // only the tensors for the inputs are relevant, exclude the const (filter) tensor @@ -1566,10 +1697,8 @@ void TfLiteParserImpl::ParseBatchMatMul(size_t subgraphIndex, size_t operatorInd auto layerName = fmt::format("BatchMatMul:{}:{}", subgraphIndex, operatorIndex); - TensorInfo inputXTensorInfo = ToTensorInfo(inputs[0]); - TensorInfo inputYTensorInfo = ToTensorInfo(inputs[1]); - - TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); + TensorInfo inputXTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); + TensorInfo inputYTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex]; const auto* options = operatorPtr->builtin_options.AsBatchMatMulOptions(); @@ -1584,6 +1713,7 @@ void TfLiteParserImpl::ParseBatchMatMul(size_t subgraphIndex, size_t operatorInd IConnectableLayer* layer = m_Network->AddBatchMatMulLayer(descriptor, layerName.c_str()); ARMNN_ASSERT(layer != nullptr); + TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -1603,10 +1733,10 @@ void TfLiteParserImpl::ParseBatchToSpaceND(size_t subgraphIndex, size_t operator auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex); CHECK_VALID_SIZE(outputs.size(), 1); - armnn::TensorInfo blockShapeTensorInfo = ToTensorInfo(inputs[1]); + armnn::TensorInfo blockShapeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); BufferRawPtr blockShapeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer); - armnn::TensorInfo cropsTensorInfo = ToTensorInfo(inputs[2]); + armnn::TensorInfo cropsTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2); BufferRawPtr cropsBufferPtr = GetBuffer(m_Model, inputs[2]->buffer); std::vector<unsigned int> blockShape(blockShapeTensorInfo.GetNumElements()); @@ -1629,12 +1759,13 @@ void TfLiteParserImpl::ParseBatchToSpaceND(size_t subgraphIndex, size_t operator auto layerName = fmt::format("BatchToSpaceND:{}:{}", subgraphIndex, operatorIndex); - TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); - TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); - CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0"); + TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); IConnectableLayer* layer = m_Network->AddBatchToSpaceNdLayer(desc, layerName.c_str()); ARMNN_ASSERT(layer != nullptr); + + TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0}); + CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0"); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -1661,7 +1792,7 @@ void TfLiteParserImpl::ParseL2Normalization(size_t subgraphIndex, size_t operato ARMNN_ASSERT(layer != nullptr); - armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); + armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -1688,15 +1819,15 @@ void TfLiteParserImpl::ParseMaximum(size_t subgraphIndex, size_t operatorIndex) auto layerName = fmt::format("Maximum:{}:{}", subgraphIndex, operatorIndex); - TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); - TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]); + TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); + TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1"); - TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); - CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0"); - IConnectableLayer* layer = m_Network->AddMaximumLayer(layerName.c_str()); ARMNN_ASSERT(layer != nullptr); + + TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1}); + CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0"); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -1718,15 +1849,15 @@ void TfLiteParserImpl::ParseMinimum(size_t subgraphIndex, size_t operatorIndex) auto layerName = fmt::format("Minimum:{}:{}", subgraphIndex, operatorIndex); - TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); - TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]); + TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); + TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1"); - TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); - CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0"); - IConnectableLayer* layer = m_Network->AddMinimumLayer(layerName.c_str()); ARMNN_ASSERT(layer != nullptr); + + TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1}); + CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0"); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -1776,7 +1907,7 @@ void TfLiteParserImpl::ParsePool(size_t subgraphIndex, auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex); CHECK_VALID_SIZE(inputs.size(), 1); - armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); + armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); // assuming input is NHWC unsigned int inputHeight = inputTensorInfo.GetShape()[1]; @@ -1790,11 +1921,11 @@ void TfLiteParserImpl::ParsePool(size_t subgraphIndex, auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex); CHECK_VALID_SIZE(outputs.size(), 1); - armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); - CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0"); - IConnectableLayer* layer = m_Network->AddPooling2dLayer(desc, layerName.c_str()); ARMNN_ASSERT(layer != nullptr); + + armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0}); + CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0"); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); // register the input connection slots for the layer, connections are made after all layers have been created @@ -1820,14 +1951,14 @@ void TfLiteParserImpl::ParseSlice(size_t subgraphIndex, size_t operatorIndex) SliceDescriptor desc; // set begin tensor info for slice descriptor - armnn::TensorInfo beginTensorInfo = ToTensorInfo(inputs[1]); + armnn::TensorInfo beginTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); BufferRawPtr beginBufferPtr = GetBuffer(m_Model, inputs[1]->buffer); std::vector<unsigned int> begin(beginTensorInfo.GetNumElements()); ::memcpy(begin.data(), beginBufferPtr->data.data(), beginTensorInfo.GetNumBytes()); // set size tensor info for slice descriptor - armnn::TensorInfo sizeTensorInfo = ToTensorInfo(inputs[2]); + armnn::TensorInfo sizeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2); BufferRawPtr sizeBufferPtr = GetBuffer(m_Model, inputs[2]->buffer); std::vector<int> signedSize(sizeTensorInfo.GetNumElements(), 1); @@ -1839,7 +1970,7 @@ void TfLiteParserImpl::ParseSlice(size_t subgraphIndex, size_t operatorIndex) } std::vector<unsigned int> size(sizeTensorInfo.GetNumElements()); - TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); + TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); for (unsigned int i = 0; i < signedSize.size(); ++i) { @@ -1868,10 +1999,10 @@ void TfLiteParserImpl::ParseSlice(size_t subgraphIndex, size_t operatorIndex) auto layerName = fmt::format("Slice:{}:{}", subgraphIndex, operatorIndex); - TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); - CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0"); - IConnectableLayer* const layer = m_Network->AddSliceLayer(desc, layerName.c_str()); + + TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0}); + CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0"); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); // register the input connection slots for the layer, connections are made after all layers have been created @@ -1901,7 +2032,7 @@ void TfLiteParserImpl::ParseSoftmax(size_t subgraphIndex, size_t operatorIndex) auto layerName = fmt::format("Softmax:{}:{}", subgraphIndex, operatorIndex); IConnectableLayer* const layer = m_Network->AddSoftmaxLayer(desc, layerName.c_str()); - armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); + armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); // register the input connection slots for the layer, connections are made after all layers have been created @@ -1928,7 +2059,7 @@ void TfLiteParserImpl::ParseLogSoftmax(size_t subgraphIndex, size_t operatorInde auto layerName = fmt::format("LogSoftmax:{}:{}", subgraphIndex, operatorIndex); IConnectableLayer* const layer = m_Network->AddLogSoftmaxLayer(desc, layerName.c_str()); - armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); + armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); // register the input connection slots for the layer, connections are made after all layers have been created @@ -1951,10 +2082,10 @@ void TfLiteParserImpl::ParseSpaceToBatchND(size_t subgraphIndex, size_t operator auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex); CHECK_VALID_SIZE(outputs.size(), 1); - armnn::TensorInfo blockShapeTensorInfo = ToTensorInfo(inputs[1]); + armnn::TensorInfo blockShapeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); BufferRawPtr blockShapeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer); - armnn::TensorInfo padListTensorInfo = ToTensorInfo(inputs[2]); + armnn::TensorInfo padListTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2); BufferRawPtr padListBufferPtr = GetBuffer(m_Model, inputs[2]->buffer); std::vector<unsigned int> blockShape(blockShapeTensorInfo.GetNumElements()); @@ -1977,12 +2108,13 @@ void TfLiteParserImpl::ParseSpaceToBatchND(size_t subgraphIndex, size_t operator auto layerName = fmt::format("SpaceToBatchND:{}:{}", subgraphIndex, operatorIndex); - TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); - TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); - CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0"); + TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); IConnectableLayer* layer = m_Network->AddSpaceToBatchNdLayer(desc, layerName.c_str()); ARMNN_ASSERT(layer != nullptr); + + TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0}); + CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0"); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -2057,8 +2189,7 @@ void TfLiteParserImpl::ParseShape(size_t subgraphIndex, size_t operatorIndex) IConnectableLayer* layer = m_Network->AddShapeLayer(layerName.c_str()); ARMNN_ASSERT(layer != nullptr); - - TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); + TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); // Check if output tensor type is Signed32 or Signed64 @@ -2092,7 +2223,7 @@ void TfLiteParserImpl::ParseSqueeze(size_t subgraphIndex, size_t operatorIndex) const auto * options = operatorPtr->builtin_options.AsSqueezeOptions(); auto layerName = fmt::format("Squeeze:{}:{}", subgraphIndex, operatorIndex); - armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); + armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); std::vector<uint32_t> squeezeDim; // A single negative dim index is interpreted as a negative index in python @@ -2146,19 +2277,19 @@ void TfLiteParserImpl::ParseStridedSlice(size_t subgraphIndex, size_t operatorIn desc.m_ShrinkAxisMask = options->shrink_axis_mask; desc.m_DataLayout = armnn::DataLayout::NHWC; - armnn::TensorInfo beginTensorInfo = ToTensorInfo(inputs[1]); + armnn::TensorInfo beginTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); BufferRawPtr beginBufferPtr = GetBuffer(m_Model, inputs[1]->buffer); std::vector<int> begin(beginTensorInfo.GetNumElements()); ::memcpy(begin.data(), beginBufferPtr->data.data(), beginTensorInfo.GetNumBytes()); - armnn::TensorInfo endTensorInfo = ToTensorInfo(inputs[2]); + armnn::TensorInfo endTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2); BufferRawPtr endBufferPtr = GetBuffer(m_Model, inputs[2]->buffer); std::vector<int> end(endTensorInfo.GetNumElements()); ::memcpy(end.data(), endBufferPtr->data.data(), endTensorInfo.GetNumBytes()); - armnn::TensorInfo strideTensorInfo = ToTensorInfo(inputs[3]); + armnn::TensorInfo strideTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 3); BufferRawPtr strideBufferPtr = GetBuffer(m_Model, inputs[3]->buffer); std::vector<int> stride(strideTensorInfo.GetNumElements()); @@ -2172,7 +2303,7 @@ void TfLiteParserImpl::ParseStridedSlice(size_t subgraphIndex, size_t operatorIn IConnectableLayer* layer = m_Network->AddStridedSliceLayer(desc, layerName.c_str()); ARMNN_ASSERT(layer != nullptr); - armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); + armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -2195,14 +2326,14 @@ void TfLiteParserImpl::ParseSub(size_t subgraphIndex, size_t operatorIndex) auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex); CHECK_VALID_SIZE(outputs.size(), 1); - armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); - armnn::TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]); + armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); + armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); auto layerName = fmt::format("Sub:{}:{}", subgraphIndex, operatorIndex); IConnectableLayer* layer = m_Network->AddSubtractionLayer(layerName.c_str()); ARMNN_ASSERT(layer != nullptr); - TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); + TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -2227,14 +2358,14 @@ void TfLiteParserImpl::ParseDiv(size_t subgraphIndex, size_t operatorIndex) auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex); CHECK_VALID_SIZE(outputs.size(), 1); - armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); - armnn::TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]); + armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); + armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); auto layerName = fmt::format("Div:{}:{}", subgraphIndex, operatorIndex); IConnectableLayer* layer = m_Network->AddDivisionLayer(layerName.c_str()); ARMNN_ASSERT(layer != nullptr); - TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); + TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -2255,14 +2386,14 @@ void TfLiteParserImpl::ParseFloorDiv(size_t subgraphIndex, size_t operatorIndex) auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex); CHECK_VALID_SIZE(outputs.size(), 1); - armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); - armnn::TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]); + armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); + armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); auto layerName = fmt::format("Div:{}:{}", subgraphIndex, operatorIndex); IConnectableLayer* layer = m_Network->AddDivisionLayer(layerName.c_str()); ARMNN_ASSERT(layer != nullptr); - TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); + TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -2286,14 +2417,14 @@ void TfLiteParserImpl::ParseAdd(size_t subgraphIndex, size_t operatorIndex) auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex); CHECK_VALID_SIZE(outputs.size(), 1); - armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); - armnn::TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]); + armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); + armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); auto layerName = fmt::format("Add:{}:{}", subgraphIndex, operatorIndex); IConnectableLayer* layer = m_Network->AddAdditionLayer(layerName.c_str()); ARMNN_ASSERT(layer != nullptr); - TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); + TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -2317,14 +2448,14 @@ void TfLiteParserImpl::ParseMul(size_t subgraphIndex, size_t operatorIndex) auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex); CHECK_VALID_SIZE(outputs.size(), 1); - armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); - armnn::TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]); + armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); + armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); auto layerName = fmt::format("Mul:{}:{}", subgraphIndex, operatorIndex); IConnectableLayer* layer = m_Network->AddMultiplicationLayer(layerName.c_str()); ARMNN_ASSERT(layer != nullptr); - TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); + TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -2344,7 +2475,7 @@ void TfLiteParserImpl::ParseMean(size_t subgraphIndex, size_t operatorIndex) auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex); CHECK_VALID_SIZE(outputs.size(), 1); - armnn::TensorInfo dimTensorInfo = ToTensorInfo(inputs[1]); + armnn::TensorInfo dimTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[1]->buffer); armnn::MeanDescriptor desc; @@ -2352,17 +2483,18 @@ void TfLiteParserImpl::ParseMean(size_t subgraphIndex, size_t operatorIndex) ::memcpy(axis.data(), bufferPtr->data.data(), dimTensorInfo.GetNumBytes()); desc.m_Axis = axis; - armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); + armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); desc.m_KeepDims = - inputTensorInfo.GetNumDimensions() == outputTensorInfo.GetNumDimensions() ? + inputTensorInfo.GetNumDimensions() == outputTensorInfo.GetNumDimensions() ? true : false; auto layerName = fmt::format("Mean:{}:{}", subgraphIndex, operatorIndex); IConnectableLayer* layer = m_Network->AddMeanLayer(desc, layerName.c_str()); ARMNN_ASSERT(layer != nullptr); + outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -2381,8 +2513,8 @@ void TfLiteParserImpl::ParsePad(size_t subgraphIndex, size_t operatorIndex) TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex); CHECK_VALID_SIZE(outputs.size(), 1); - armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); - armnn::TensorInfo padTensorInfo = ToTensorInfo(inputs[1]); + armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); + armnn::TensorInfo padTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); std::vector<unsigned int> padBuffer = GetUIntBuffer(padTensorInfo, m_Model, inputs[1]->buffer); @@ -2403,7 +2535,7 @@ void TfLiteParserImpl::ParsePad(size_t subgraphIndex, size_t operatorIndex) { CHECK_VALID_SIZE(inputs.size(), 3); - armnn::TensorInfo padValueTensorInfo = ToTensorInfo(inputs[2]); + armnn::TensorInfo padValueTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2); if (padValueTensorInfo.GetNumElements() != 1) { @@ -2458,10 +2590,10 @@ void TfLiteParserImpl::ParsePad(size_t subgraphIndex, size_t operatorIndex) auto layerName = (opcode == tflite::BuiltinOperator_PAD) ? fmt::format("Pad:{}:{}", subgraphIndex, operatorIndex) : fmt::format("PadV2:{}:{}", subgraphIndex, operatorIndex); - TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); IConnectableLayer* layer = m_Network->AddPadLayer(desc, layerName.c_str()); ARMNN_ASSERT(layer != nullptr); + TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -2481,9 +2613,9 @@ void TfLiteParserImpl::ParseMirrorPad(size_t subgraphIndex, size_t operatorIndex TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex); CHECK_VALID_SIZE(outputs.size(), 1); - armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); + armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); - armnn::TensorInfo padTensorInfo = ToTensorInfo(inputs[1]); + armnn::TensorInfo padTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[1]->buffer); std::vector<unsigned int> padBuffer(padTensorInfo.GetNumElements()); @@ -2529,10 +2661,10 @@ void TfLiteParserImpl::ParseMirrorPad(size_t subgraphIndex, size_t operatorIndex } auto layerName = fmt::format("MirrorPad:{}:{}", subgraphIndex, operatorIndex); - TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); IConnectableLayer* layer = m_Network->AddPadLayer(desc, layerName.c_str()); ARMNN_ASSERT(layer != nullptr); + TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -2554,14 +2686,12 @@ void TfLiteParserImpl::ParsePrelu(size_t subgraphIndex, size_t operatorIndex) auto layerName = fmt::format("Prelu:{}:{}", subgraphIndex, operatorIndex); - armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); - armnn::TensorInfo alphaTensorInfo = ToTensorInfo(inputs[1]); - armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); - CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0"); + armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); + armnn::TensorInfo alphaTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); IConnectableLayer* layer = m_Network->AddPreluLayer(layerName.c_str()); ARMNN_ASSERT(layer != nullptr); - layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); + if (IsConstTensor(inputs[1])) { @@ -2589,6 +2719,10 @@ void TfLiteParserImpl::ParsePrelu(size_t subgraphIndex, size_t operatorIndex) RegisterInputSlots(subgraphIndex, operatorIndex, layer, inputTensorIndexes); } + armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1}); + CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0"); + layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); + auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex)); RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes); } @@ -2608,7 +2742,7 @@ void TfLiteParserImpl::ParseQuantize(size_t subgraphIndex, size_t operatorIndex) IConnectableLayer* layer = m_Network->AddQuantizeLayer(layerName.c_str()); ARMNN_ASSERT(layer != nullptr); - TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); + TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -2723,7 +2857,7 @@ void TfLiteParserImpl::ParseActivation(size_t subgraphIndex, size_t operatorInde IConnectableLayer* const layer = m_Network->AddActivationLayer(activationDesc, layerName.c_str()); - TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); + TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); // register the input connection slots for the layer, connections are made after all layers have been created @@ -2778,7 +2912,7 @@ void TfLiteParserImpl::ParseReshape(size_t subgraphIndex, size_t operatorIndex) const auto* options = operatorPtr->builtin_options.AsReshapeOptions(); auto layerName = fmt::format("Reshape:{}:{}", subgraphIndex, operatorIndex); - armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); + armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); armnn::TensorInfo actualOutputTensorInfo = ToTensorInfo(outputs[0]); CheckMatchingQuantization(inputTensorInfo, actualOutputTensorInfo, layerName, "Input 0", "Output 0"); @@ -2835,7 +2969,8 @@ void TfLiteParserImpl::ParseReshape(size_t subgraphIndex, size_t operatorIndex) try { // We attempt to infer during Runtime. - TensorShape reshapeShapes = ToTensorInfo(inputs[1]).GetShape(); + TensorShape reshapeShapes =ToTensorInfo(inputs[1]).GetShape(); + reshapeShapes = InputTensorInfo(subgraphIndex, operatorIndex, 1).GetShape(); // The parser only supports shape (batch, -1) or (-1) for non-constant shape input. if (reshapeShapes[0] > 2) { @@ -2905,9 +3040,11 @@ void TfLiteParserImpl::ParseReshape(size_t subgraphIndex, size_t operatorIndex) throw ParseException(ss.str()); } } + auto outputTensorIds = GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex); ReshapeDescriptor reshapeDesc; reshapeDesc.m_TargetShape = reshapeOutputTensorInfo.GetShape(); + m_TensorInfos[outputTensorIds[0]] = reshapeOutputTensorInfo; IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str()); ARMNN_ASSERT(layer != nullptr); @@ -2940,7 +3077,7 @@ void TfLiteParserImpl::ParseResize(size_t subgraphIndex, size_t operatorIndex, R auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex); CHECK_VALID_SIZE(outputs.size(), 1); - armnn::TensorInfo sizeTensorInfo = ToTensorInfo(inputs[1]); + armnn::TensorInfo sizeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); // Data for the parsed tensor args (size) must be stored locally. std::vector<int32_t> sizeTensorData(sizeTensorInfo.GetNumElements()); @@ -2981,12 +3118,12 @@ void TfLiteParserImpl::ParseResize(size_t subgraphIndex, size_t operatorIndex, R } } - TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); - TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); - CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0"); + TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); IConnectableLayer* layer = m_Network->AddResizeLayer(desc, layerName.c_str()); ARMNN_ASSERT(layer != nullptr); + TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0}); + CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0"); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -3007,33 +3144,34 @@ void TfLiteParserImpl::ParseConcatenation(size_t subgraphIndex, size_t operatorI auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex); auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex); + auto inputTensorIds = GetInputTensorIds(m_Model, subgraphIndex, operatorIndex); + CHECK_VALID_SIZE(outputs.size(), 1); unsigned int numConcatView = static_cast<unsigned int>(inputs.size()); - uint32_t inputRank = ToTensorInfo(inputs[0]).GetNumDimensions(); + uint32_t inputRank = InputTensorInfo(subgraphIndex, operatorIndex, 0).GetNumDimensions(); const unsigned int concatDimInput = static_cast<unsigned int>( - (static_cast<int>(inputRank) + options->axis) % static_cast<int>(inputRank)); + (static_cast<int>(inputRank) + options->axis) % static_cast<int>(inputRank)); OriginsDescriptor concatDescriptor(static_cast<uint32_t>(numConcatView), inputRank); concatDescriptor.SetConcatAxis(concatDimInput); - unsigned int mergeDimOrigin = 0; for (unsigned int viewIndex = 0; viewIndex < numConcatView; ++viewIndex) { - TensorInfo inputTensorInfo = ToTensorInfo(inputs[viewIndex]); + TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, viewIndex); // This set up concatDescriptor view origin armnnUtils::ProcessConcatInputTensorInfo( - inputTensorInfo, concatDescriptor, concatDimInput, viewIndex, mergeDimOrigin); + inputTensorInfo, concatDescriptor, concatDimInput, viewIndex, mergeDimOrigin); } auto layerName = fmt::format("Concatenation:{}:{}", subgraphIndex, operatorIndex); - TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); IConnectableLayer* layer = m_Network->AddConcatLayer(concatDescriptor, layerName.c_str()); ARMNN_ASSERT(layer != nullptr); + TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -3063,7 +3201,7 @@ void TfLiteParserImpl::ParseFullyConnected(size_t subgraphIndex, size_t operator auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex); CHECK_VALID_SIZE(outputs.size(), 1); - armnn::TensorInfo filterTensorInfo = ToTensorInfo(inputs[1]); + armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); // Fully Connected Layer accepts two dimensional weights input int32_t weightsDimension = static_cast<int32_t>(filterTensorInfo.GetNumDimensions()); @@ -3083,7 +3221,7 @@ void TfLiteParserImpl::ParseFullyConnected(size_t subgraphIndex, size_t operator // Add the first input tensor to the registration list std::vector<unsigned int> tensorIndexesToRegister = {inputTensorIndexes[0]}; std::vector<unsigned int> ignoreInputWhenRegister = {}; - armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); + armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); desc.m_ConstantWeights = IsConstTensor(inputs[1]); @@ -3098,7 +3236,7 @@ void TfLiteParserImpl::ParseFullyConnected(size_t subgraphIndex, size_t operator if (inputs.size() == 3) { desc.m_BiasEnabled = true; - armnn::TensorInfo biasTensorInfo = ToTensorInfo(inputs[2]); + armnn::TensorInfo biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2); // Add the biases input to the registration list, constant layer will be added by SetupConstantLayers. tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]); @@ -3133,8 +3271,9 @@ void TfLiteParserImpl::ParseFullyConnected(size_t subgraphIndex, size_t operator CHECK_LOCATION().AsString())); } - armnn::TensorInfo reshapedTensorInfo = ToTensorInfo(inputs[0]); + armnn::TensorInfo reshapedTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); reshapedTensorInfo.SetShape(armnn::TensorShape{ 2, reshapedDimensions.data() }); + inputTensorInfo = reshapedTensorInfo; std::string reshapeLayerName = fmt::format("Reshape_for:{}", layer->GetName()); armnn::ReshapeDescriptor reshapeDescriptor; @@ -3144,6 +3283,9 @@ void TfLiteParserImpl::ParseFullyConnected(size_t subgraphIndex, size_t operator reshapeLayer->GetOutputSlot(0).SetTensorInfo(reshapedTensorInfo); reshapeLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0)); + auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex)); + m_TensorInfos[outputTensorIndexes[0]] = reshapedTensorInfo; + RegisterInputSlots(subgraphIndex, operatorIndex, reshapeLayer, {inputTensorIndexes[0]}); // Fc layer connects to the reshape layer, so we skip the first input slot when registering fc's input slots tensorIndexesToRegister.erase(tensorIndexesToRegister.begin()); @@ -3152,7 +3294,9 @@ void TfLiteParserImpl::ParseFullyConnected(size_t subgraphIndex, size_t operator RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister, startingSlotIndex); - armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); + armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromShapes(subgraphIndex, operatorIndex, layer, 0, + { inputTensorInfo.GetShape(), + filterTensorInfo.GetShape() }); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); // we need to add the activation layer and fortunately we don't need to care about the data layout @@ -3205,7 +3349,7 @@ void TfLiteParserImpl::ParseDetectionPostProcess(size_t subgraphIndex, size_t op "must be positive and less than or equal to 1."); } - armnn::TensorInfo anchorTensorInfo = ToTensorInfo(inputs[2]); + armnn::TensorInfo anchorTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2); auto anchorTensorAndData = CreateConstTensorNonPermuted(inputs[2], anchorTensorInfo); auto layerName = fmt::format("DetectionPostProcess:{}:{}", subgraphIndex, operatorIndex); @@ -3217,14 +3361,14 @@ void TfLiteParserImpl::ParseDetectionPostProcess(size_t subgraphIndex, size_t op // The model does not specify the output shapes. // The output shapes are calculated from the max_detection and max_classes_per_detection. unsigned int numDetectedBox = desc.m_MaxDetections * desc.m_MaxClassesPerDetection; - m_OverridenOutputShapes.push_back({ 1, numDetectedBox, 4 }); - m_OverridenOutputShapes.push_back({ 1, numDetectedBox }); - m_OverridenOutputShapes.push_back({ 1, numDetectedBox }); - m_OverridenOutputShapes.push_back({ 1 }); + m_OverriddenOutputShapes.push_back({ 1, numDetectedBox, 4 }); + m_OverriddenOutputShapes.push_back({ 1, numDetectedBox }); + m_OverriddenOutputShapes.push_back({ 1, numDetectedBox }); + m_OverriddenOutputShapes.push_back({ 1 }); for (unsigned int i = 0 ; i < outputs.size() ; ++i) { - armnn::TensorInfo detectionBoxOutputTensorInfo = ToTensorInfo(outputs[i], m_OverridenOutputShapes[i]); + armnn::TensorInfo detectionBoxOutputTensorInfo = ToTensorInfo(outputs[i], m_OverriddenOutputShapes[i]); layer->GetOutputSlot(i).SetTensorInfo(detectionBoxOutputTensorInfo); } @@ -3263,7 +3407,7 @@ void TfLiteParserImpl::ParsePack(size_t subgraphIndex, size_t operatorIndex) desc.m_NumInputs = static_cast<uint32_t>(inputs.size()); // Use the tensor shape of the first input as the "correct" input shape in the descriptor - armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); + armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); desc.m_InputShape = inputTensorInfo.GetShape(); auto layerName = fmt::format("Pack:{}:{}", subgraphIndex, operatorIndex); @@ -3271,7 +3415,7 @@ void TfLiteParserImpl::ParsePack(size_t subgraphIndex, size_t operatorIndex) ARMNN_ASSERT(layer != nullptr); - armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); + armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -3297,7 +3441,7 @@ void TfLiteParserImpl::ParseUnidirectionalSequenceLSTM(size_t subgraphIndex, siz const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex]; const auto nodeParams = operatorPtr->builtin_options.AsUnidirectionalSequenceLSTMOptions(); CHECK_SUPPORTED_FUSED_ACTIVATION(nodeParams, subgraphIndex, operatorIndex); - auto inputTensorInfo = ToTensorInfo(inputs[0]); + auto inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); auto outputTensorInfo = ToTensorInfo(outputs[0]); // Set the params structure for the AddUnidirectionalSequenceLstmLayer call @@ -3568,7 +3712,7 @@ void TfLiteParserImpl::ParseUnpack(size_t subgraphIndex, size_t operatorIndex) auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex); CHECK_VALID_SIZE(inputs.size(), 1); - armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); + armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); if (unpackAxis >= inputTensorInfo.GetNumDimensions()) { @@ -3688,8 +3832,8 @@ void TfLiteParserImpl::ParseSplit(size_t subgraphIndex, size_t operatorIndex) auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex); CHECK_VALID_SIZE(outputs.size(), numSplits); - armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[1]); - armnn::TensorInfo axisTensorInfo = ToTensorInfo(inputs[0]); + armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); + armnn::TensorInfo axisTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1); BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[0]->buffer); @@ -3955,8 +4099,8 @@ void TfLiteParserImpl::ParseArgMinMax(size_t subgraphIndex, size_t operatorIndex auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex); CHECK_VALID_SIZE(outputs.size(), 1); - armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); - armnn::TensorInfo axisTensorInfo = ToTensorInfo(inputs[1]); + armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); + armnn::TensorInfo axisTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1); @@ -4004,6 +4148,7 @@ void TfLiteParserImpl::ParseArgMinMax(size_t subgraphIndex, size_t operatorIndex auto layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex); IConnectableLayer *layer = m_Network->AddArgMinMaxLayer(desc, layerNameFormatted.c_str()); ARMNN_ASSERT(layer != nullptr); + outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); // Register input tensor to the layer. @@ -4024,9 +4169,9 @@ void TfLiteParserImpl::ParseGather(size_t subgraphIndex, size_t operatorIndex) TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex); CHECK_VALID_SIZE(outputs.size(), 1); - armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); - armnn::TensorInfo indicesTensorInfo = ToTensorInfo(inputs[1]); - TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); + armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); + armnn::TensorInfo indicesTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); + armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); armnn::GatherDescriptor gatherDescriptor; @@ -4034,6 +4179,8 @@ void TfLiteParserImpl::ParseGather(size_t subgraphIndex, size_t operatorIndex) const auto* options = operatorPtr->builtin_options.AsGatherOptions(); auto axis = options->axis; + auto layerName = fmt::format("Gather:{}:{}", subgraphIndex, operatorIndex); + auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions()); auto indicesDimensions = indicesTensorInfo.GetNumDimensions(); auto outputDimensions = outputTensorInfo.GetNumDimensions(); @@ -4056,9 +4203,9 @@ void TfLiteParserImpl::ParseGather(size_t subgraphIndex, size_t operatorIndex) gatherDescriptor.m_Axis = axis; - auto layerName = fmt::format("Gather:{}:{}", subgraphIndex, operatorIndex); IConnectableLayer* layer = m_Network->AddGatherLayer(gatherDescriptor, layerName.c_str()); ARMNN_ASSERT(layer != nullptr); + outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -4077,13 +4224,13 @@ void TfLiteParserImpl::ParseGatherNd(size_t subgraphIndex, size_t operatorIndex) TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex); CHECK_VALID_SIZE(outputs.size(), 1); - armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); - armnn::TensorInfo indicesTensorInfo = ToTensorInfo(inputs[1]); - TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); + armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); + armnn::TensorInfo indicesTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); auto layerName = fmt::format("GatherNd:{}:{}", subgraphIndex, operatorIndex); IConnectableLayer* layer = m_Network->AddGatherNdLayer(layerName.c_str()); ARMNN_ASSERT(layer != nullptr); + TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -4119,7 +4266,7 @@ void TfLiteParserImpl::ParseDepthToSpace(size_t subgraphIndex, size_t operatorIn auto layerName = fmt::format("DepthToSpace:{}:{}", subgraphIndex, operatorIndex); IConnectableLayer* layer = m_Network->AddDepthToSpaceLayer(descriptor, layerName.c_str()); ARMNN_ASSERT(layer != nullptr); - TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); + TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -4164,8 +4311,8 @@ void TfLiteParserImpl::ParseReduce(size_t subgraphIndex, size_t operatorIndex, R auto layerName = fmt::format("Reduce:{}:{}", subgraphIndex, operatorIndex); - armnn::TensorInfo inputTensorInfo0 = ToTensorInfo(inputs[0]); - armnn::TensorInfo inputTensorInfo1 = ToTensorInfo(inputs[1]); + armnn::TensorInfo inputTensorInfo0 = InputTensorInfo(subgraphIndex, operatorIndex, 0); + armnn::TensorInfo inputTensorInfo1 = InputTensorInfo(subgraphIndex, operatorIndex, 1); ReduceDescriptor desc; BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer); @@ -4199,7 +4346,7 @@ void TfLiteParserImpl::ParseReduce(size_t subgraphIndex, size_t operatorIndex, R // Register a new layer object, Sum. IConnectableLayer* layer = m_Network->AddReduceLayer(desc, layerName.c_str()); - armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]); + armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); // Register input tensor to the layer. @@ -4224,7 +4371,7 @@ void TfLiteParserImpl::ParseLocalResponseNormalization(size_t subgraphIndex, siz auto layerName = fmt::format("LRN:{}:{}", subgraphIndex, operatorIndex); std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex); - armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); + armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex]; const auto* options = operatorPtr->builtin_options.AsLocalResponseNormalizationOptions(); @@ -4245,7 +4392,7 @@ void TfLiteParserImpl::ParseLocalResponseNormalization(size_t subgraphIndex, siz IConnectableLayer* layer = m_Network->AddNormalizationLayer(descriptor, layerNameFormatted.c_str()); ARMNN_ASSERT(layer != nullptr); - TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); + TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -4313,7 +4460,7 @@ void TfLiteParserImpl::ParseElementwiseUnary(size_t subgraphIndex, size_t operat IConnectableLayer* layer = m_Network->AddElementwiseUnaryLayer(desc, layerNameFormatted.c_str()); ARMNN_ASSERT(layer != nullptr); - TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); + TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -4367,8 +4514,8 @@ void TfLiteParserImpl::ParseComparison(size_t subgraphIndex, size_t operatorInde auto layerName = std::string(GetComparisonOperationAsCString(comparisonOperation)) + ":{}:{}"; std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex); - armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); - armnn::TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]); + armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0); + armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1); CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerNameFormatted, "Input 0", "Input 1"); ComparisonDescriptor desc; @@ -4376,7 +4523,7 @@ void TfLiteParserImpl::ParseComparison(size_t subgraphIndex, size_t operatorInde IConnectableLayer* layer = m_Network->AddComparisonLayer(desc, layerNameFormatted.c_str()); ARMNN_ASSERT(layer != nullptr); - TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true); + TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1}); layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -4429,7 +4576,7 @@ armnn::IConnectableLayer* TfLiteParserImpl::AddFusedActivationLayer(armnn::IConn default: { throw ParseException( - fmt::format("TfLite parser doesn't suppport fused activation: " + fmt::format("TfLite parser doesn't support fused activation: " "{}/{} {} ", activationType, tflite::EnumNameActivationFunctionType(activationType), @@ -4667,6 +4814,18 @@ void TfLiteParserImpl::RegisterOutputSlots(size_t subgraphIndex, } } +void TfLiteParserImpl::SetupInputLayerTensorInfos(size_t subgraphIndex) +{ + CHECK_SUBGRAPH(m_Model, subgraphIndex); + + auto inputs = GetSubgraphInputs(m_Model, subgraphIndex); + for (auto const& tensorIdAndPtr : inputs) + { + auto tensorInfo = ToTensorInfo(tensorIdAndPtr.second); + m_TensorInfos.insert({tensorIdAndPtr.first, tensorInfo}); + } +} + void TfLiteParserImpl::SetupInputLayers(size_t subgraphIndex) { CHECK_SUBGRAPH(m_Model, subgraphIndex); @@ -4706,6 +4865,28 @@ void TfLiteParserImpl::SetupOutputLayers(size_t subgraphIndex) } } +void TfLiteParserImpl::SetupConstantLayerTensorInfos(size_t subgraph) +{ + CHECK_SUBGRAPH(m_Model, subgraph); + + const auto & subgraphPtr = m_Model->subgraphs[subgraph]; + for (unsigned int subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex) + { + for (unsigned int tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex) + { + if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot == nullptr && + m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size() > 0) + { + TensorRawPtr tensorPtr = subgraphPtr->tensors[tensorIndex].get(); + + armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr); + + m_TensorInfos.insert({tensorIndex, tensorInfo}); + } + } + } +} + void TfLiteParserImpl::SetupConstantLayers(size_t subgraph) { CHECK_SUBGRAPH(m_Model, subgraph); @@ -4999,8 +5180,8 @@ BindingPointInfo TfLiteParserImpl::GetNetworkOutputBindingInfo(size_t subgraphId if (output.second->name == name) { auto bindingId = GenerateLayerBindingId(subgraphId, output.first); - std::vector<unsigned int> shape = m_OverridenOutputShapes.size() > 0 ? - m_OverridenOutputShapes[i] : AsUnsignedVector(output.second->shape); + std::vector<unsigned int> shape = m_OverriddenOutputShapes.size() > 0 ? + m_OverriddenOutputShapes[i] : AsUnsignedVector(output.second->shape); return std::make_pair(bindingId, ToTensorInfo(output.second, shape)); } } diff --git a/src/armnnTfLiteParser/TfLiteParser.hpp b/src/armnnTfLiteParser/TfLiteParser.hpp index 7eb6c48501..cf334cc70c 100644 --- a/src/armnnTfLiteParser/TfLiteParser.hpp +++ b/src/armnnTfLiteParser/TfLiteParser.hpp @@ -1,9 +1,10 @@ // -// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// Copyright © 2018-2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // #pragma once +#include <armnn/Descriptors.hpp> #include "armnn/INetwork.hpp" #include "armnnTfLiteParser/ITfLiteParser.hpp" #include "armnn/Types.hpp" @@ -204,6 +205,9 @@ private: armnn::IConnectableLayer* layer, const std::vector<unsigned int>& tensorIndexes); + void SetupInputLayerTensorInfos(size_t subgraphIndex); + void SetupConstantLayerTensorInfos(size_t subgraphIndex); + void SetupInputLayers(size_t subgraphIndex); void SetupOutputLayers(size_t subgraphIndex); void SetupConstantLayers(size_t subgraphIndex); @@ -273,7 +277,23 @@ private: CreateConstTensorPtr(TensorRawPtr tensorPtr, armnn::TensorInfo& inputTensorInfo); - // Settings for configuring the TfLiteParser + armnn::TensorInfo InputTensorInfo(size_t subgraphIndex, + size_t operatorIndex, + int input); + + armnn::TensorInfo OutputTensorInfoFromInputs(size_t subgraphIndex, + size_t operatorIndex, + armnn::IConnectableLayer* layer, + int output, + std::vector<int> inputs); + + armnn::TensorInfo OutputTensorInfoFromShapes(size_t subgraphIndex, + size_t operatorIndex, + armnn::IConnectableLayer* layer, + int output = 0, + std::vector<armnn::TensorShape> inputShapes = {}); + + /// Settings for configuring the TfLiteParser armnn::Optional<ITfLiteParser::TfLiteParserOptions> m_Options; /// The network we're building. Gets cleared after it is passed to the user @@ -300,10 +320,11 @@ private: /// This is used in case that the model does not specify the output. /// The shape can be calculated from the options. - std::vector<std::vector<unsigned int>> m_OverridenOutputShapes; + std::vector<std::vector<unsigned int>> m_OverriddenOutputShapes; std::vector<unsigned int> m_ConstantsToDequantize; std::vector<unsigned int> m_ConstantsToBeCreated; + std::map<size_t, armnn::TensorInfo> m_TensorInfos; }; } |