• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright © 2017-2023 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include "TfLiteParser.hpp"
7 
8 #include "armnnTfLiteParser/Version.hpp"
9 #include "armnn/LstmParams.hpp"
10 
11 #include <armnn/BackendOptions.hpp>
12 #include <armnn/Descriptors.hpp>
13 #include <armnn/Exceptions.hpp>
14 #include <armnn/Logging.hpp>
15 #include <armnn/Tensor.hpp>
16 #include <armnnUtils/TensorUtils.hpp>
17 #include <armnn/TypesUtils.hpp>
18 #include <armnn/utility/Assert.hpp>
19 #include <armnn/utility/IgnoreUnused.hpp>
20 #include <armnn/utility/NumericCast.hpp>
21 #include <armnn/LayerSupport.hpp>
22 
23 // armnnUtils:
24 #include <armnnUtils/Permute.hpp>
25 #include <armnnUtils/Filesystem.hpp>
26 
27 #include <ParserHelper.hpp>
28 #include <VerificationHelpers.hpp>
29 
30 // The generated code based on the Tf Lite schema:
31 #include <schema_generated.h>
32 
33 #include <flatbuffers/flexbuffers.h>
34 
35 #include <fmt/format.h>
36 
37 #include <algorithm>
38 #include <iostream>
39 #include <limits>
40 #include <numeric>
41 
42 #define ARMNN_THROW_PARSE_EXCEPTION(msg) \
43           { \
44             throw armnn::ParseException( static_cast<const std::stringstream&>( std::stringstream() << msg \
45                << ": " \
46                << CHECK_LOCATION().AsString()).str()); \
47           }
48 
49 using namespace armnn;
50 using armnn::CheckLocation;
51 namespace armnnTfLiteParser
52 {
53 
ITfLiteParser(const armnn::Optional<TfLiteParserOptions> & options)54 ITfLiteParser::ITfLiteParser(const armnn::Optional<TfLiteParserOptions>& options) :
55     pTfLiteParserImpl(new TfLiteParserImpl(options)) {}
56 
57 ITfLiteParser::~ITfLiteParser() = default;
58 
CreateRaw(const armnn::Optional<TfLiteParserOptions> & options)59 ITfLiteParser* ITfLiteParser::CreateRaw(const armnn::Optional<TfLiteParserOptions>& options)
60 {
61     return new ITfLiteParser(options);
62 }
63 
Create(const armnn::Optional<TfLiteParserOptions> & options)64 ITfLiteParserPtr ITfLiteParser::Create(const armnn::Optional<TfLiteParserOptions>& options)
65 {
66     return ITfLiteParserPtr(CreateRaw(options), &ITfLiteParser::Destroy);
67 }
68 
Destroy(ITfLiteParser * parser)69 void ITfLiteParser::Destroy(ITfLiteParser* parser)
70 {
71     delete parser;
72 }
73 
CreateNetworkFromBinaryFile(const char * graphFile)74 armnn::INetworkPtr ITfLiteParser::CreateNetworkFromBinaryFile(const char* graphFile)
75 {
76     return pTfLiteParserImpl->CreateNetworkFromBinaryFile(graphFile);
77 }
78 
CreateNetworkFromBinary(const std::vector<uint8_t> & binaryContent)79 armnn::INetworkPtr ITfLiteParser::CreateNetworkFromBinary(const std::vector<uint8_t>& binaryContent)
80 {
81     return pTfLiteParserImpl->CreateNetworkFromBinary(binaryContent);
82 }
83 
GetNetworkInputBindingInfo(size_t subgraphId,const std::string & name) const84 BindingPointInfo ITfLiteParser::GetNetworkInputBindingInfo(size_t subgraphId,
85                                                            const std::string& name) const
86 {
87     return pTfLiteParserImpl->GetNetworkInputBindingInfo(subgraphId, name);
88 }
89 
GetNetworkOutputBindingInfo(size_t subgraphId,const std::string & name) const90 BindingPointInfo ITfLiteParser::GetNetworkOutputBindingInfo(size_t subgraphId,
91                                                             const std::string& name) const
92 {
93     return pTfLiteParserImpl->GetNetworkOutputBindingInfo(subgraphId, name);
94 }
95 
GetSubgraphCount() const96 size_t ITfLiteParser::GetSubgraphCount() const
97 {
98     return pTfLiteParserImpl->GetSubgraphCount();
99 }
100 
GetSubgraphInputTensorNames(size_t subgraphId) const101 std::vector<std::string> ITfLiteParser::GetSubgraphInputTensorNames(size_t subgraphId) const
102 {
103     return pTfLiteParserImpl->GetSubgraphInputTensorNames(subgraphId);
104 }
105 
GetSubgraphOutputTensorNames(size_t subgraphId) const106 std::vector<std::string> ITfLiteParser::GetSubgraphOutputTensorNames(size_t subgraphId) const
107 {
108     return pTfLiteParserImpl->GetSubgraphOutputTensorNames(subgraphId);
109 }
110 
111 namespace
112 {
113 
114 const uint32_t VIRTUAL_OPERATOR_ID = std::numeric_limits<uint32_t>::max();
115 
CheckSubgraph(const TfLiteParserImpl::ModelPtr & model,size_t subgraphIndex,const CheckLocation & location)116 void CheckSubgraph(const TfLiteParserImpl::ModelPtr& model,
117                    size_t subgraphIndex,
118                    const CheckLocation& location)
119 {
120     if (model.get() == nullptr)
121     {
122         throw ParseException(
123             fmt::format("{} was called with invalid (null) model. "
124                         "Possible reason is that the model is not yet loaded and Unpack(ed). "
125                         "subgraph:{} at {}",
126                         location.m_Function,
127                         subgraphIndex,
128                         location.FileLine()));
129     }
130     else if (subgraphIndex >= model->subgraphs.size())
131     {
132         throw ParseException(
133             fmt::format("{} was called with an invalid subgraph index. "
134                         "subgraph:{} at {}",
135                         location.m_Function,
136                         subgraphIndex,
137                         location.FileLine()));
138     }
139 }
140 
141 #define CHECK_SUBGRAPH(MODEL, SUBGRAPH_INDEX) \
142     CheckSubgraph(MODEL, SUBGRAPH_INDEX, CHECK_LOCATION())
143 
CheckModel(const TfLiteParserImpl::ModelPtr & model,size_t subgraphIndex,size_t operatorIndex,const CheckLocation & location)144 void CheckModel(const TfLiteParserImpl::ModelPtr& model,
145                 size_t subgraphIndex,
146                 size_t operatorIndex,
147                 const CheckLocation& location)
148 {
149     if (model.get() == nullptr)
150     {
151         throw ParseException(
152             fmt::format("{} was called with invalid (null) model. "
153                         "Possible reason is that the model is not yet loaded and Unpack(ed). "
154                         "subgraph:{} operator:{} at {}",
155                         location.m_Function,
156                         subgraphIndex,
157                         operatorIndex,
158                         location.FileLine()));
159     }
160     else if (subgraphIndex >= model->subgraphs.size())
161     {
162         throw ParseException(
163             fmt::format("{} was called with an invalid subgraph index. "
164                         "subgraph:{} operator:{} at {}",
165                         location.m_Function,
166                         subgraphIndex,
167                         operatorIndex,
168                         location.FileLine()));
169     }
170     else if (operatorIndex >= model->subgraphs[subgraphIndex]->operators.size() &&
171              operatorIndex != VIRTUAL_OPERATOR_ID)
172     {
173         throw ParseException(
174             fmt::format("{} was called with an invalid operator index. "
175                         "subgraph:{} operator:{} at {}",
176                         location.m_Function,
177                         subgraphIndex,
178                         operatorIndex,
179                         location.FileLine()));
180     }
181 }
182 
183 #define CHECK_MODEL(MODEL, SUBGRAPH_INDEX, OPERATOR_INDEX) \
184     CheckModel(MODEL, SUBGRAPH_INDEX, OPERATOR_INDEX, CHECK_LOCATION())
185 
CheckTensor(const TfLiteParserImpl::ModelPtr & model,size_t subgraphIndex,size_t tensorIndex,const CheckLocation & location)186 void CheckTensor(const TfLiteParserImpl::ModelPtr& model,
187                  size_t subgraphIndex,
188                  size_t tensorIndex,
189                  const CheckLocation& location)
190 {
191     // not checking model, because I assume CHECK_MODEL already run
192     // and checked that. An assert would do.
193     ARMNN_ASSERT_MSG(model.get() != nullptr, "Expecting a valid model in this function");
194 
195     // also subgraph index should be checked by CHECK_MODEL so
196     // I only add an assert here
197     ARMNN_ASSERT_MSG(subgraphIndex < model->subgraphs.size(), "Expecting a valid subgraph index");
198 
199     // the tensor index is the only one to check here
200     if (tensorIndex >= model->subgraphs[subgraphIndex]->tensors.size())
201     {
202         throw ParseException(
203             fmt::format("{} was called with an invalid tensor index. "
204                         "subgraph:{} tensor:{} at {}",
205                         location.m_Function,
206                         subgraphIndex,
207                         tensorIndex,
208                         location.FileLine()));
209     }
210 }
211 
212 #define CHECK_TENSOR(MODEL, SUBGRAPH_INDEX, TENSOR_INDEX) \
213     CheckTensor(MODEL, SUBGRAPH_INDEX, TENSOR_INDEX, CHECK_LOCATION())
214 
CheckTensorPtr(TfLiteParserImpl::TensorRawPtr rawPtr,const CheckLocation & location)215 void CheckTensorPtr(TfLiteParserImpl::TensorRawPtr rawPtr,
216                     const CheckLocation& location)
217 {
218     if (rawPtr == nullptr)
219     {
220         throw ParseException(
221             fmt::format("{} was called with a null tensor pointer at {}", location.m_Function, location.FileLine()));
222     }
223 }
224 
225 #define CHECK_TENSOR_PTR(TENSOR_PTR) \
226     CheckTensorPtr(TENSOR_PTR, CHECK_LOCATION())
227 
CheckBuffer(const TfLiteParserImpl::ModelPtr & model,size_t bufferIndex,const CheckLocation & location)228 void CheckBuffer(const TfLiteParserImpl::ModelPtr& model,
229                  size_t bufferIndex,
230                  const CheckLocation& location)
231 {
232     if (model.get() == nullptr)
233     {
234         throw ParseException(
235             fmt::format("{} was called with invalid (null) model. "
236                         "Possible reason is that the model is not yet loaded and Unpack(ed). "
237                         "buffer:{} at {}",
238                         location.m_Function,
239                         bufferIndex,
240                         location.FileLine()));
241     }
242     else if (bufferIndex >= model->buffers.size())
243     {
244         throw ParseException(
245             fmt::format("{} was called with an invalid buffer index. "
246                         "buffer index:{} at {}",
247                         location.m_Function,
248                         bufferIndex,
249                         location.FileLine()));
250     }
251     else if (model->buffers[bufferIndex].get() == nullptr)
252     {
253         throw ParseException(
254             fmt::format("The buffer #{} is null. {}",
255                         bufferIndex,
256                         location.AsString()));
257     }
258 }
259 
260 #define CHECK_BUFFER(MODEL, BUFFER_INDEX) \
261     CheckBuffer(MODEL, BUFFER_INDEX, CHECK_LOCATION())
262 
CheckBufferSize(TfLiteParserImpl::BufferRawPtr bufferPtr,const armnn::TensorInfo & tensorInfo,uint32_t bufferId,const CheckLocation & location)263 void CheckBufferSize(TfLiteParserImpl::BufferRawPtr bufferPtr,
264                      const armnn::TensorInfo& tensorInfo,
265                      uint32_t bufferId,
266                      const CheckLocation& location)
267 {
268     if (bufferPtr == nullptr)
269     {
270         throw ParseException(
271             fmt::format("BufferPtr is null for buffer:{}. {}",
272                         bufferId,
273                         location.AsString()));
274     }
275     else if(tensorInfo.GetNumElements() > bufferPtr->data.size() ||
276             tensorInfo.GetNumBytes() > bufferPtr->data.size())
277     {
278         std::stringstream ss;
279         ss << "Buffer #" << bufferId << " has " << bufferPtr->data.size() << " bytes. "
280            << "For tensor: " << tensorInfo.GetShape()
281            << " expecting: " << tensorInfo.GetNumBytes() << " bytes and "
282            << tensorInfo.GetNumElements() << " elements. " << location.AsString();
283         throw ParseException(ss.str());
284     }
285 }
286 
287 
GetOpCode(const TfLiteParserImpl::ModelPtr & model,size_t subgraphIndex,size_t operatorIndex)288 tflite::BuiltinOperator GetOpCode(const TfLiteParserImpl::ModelPtr& model, size_t subgraphIndex, size_t operatorIndex)
289 {
290     const auto& operatorPtr = model->subgraphs[subgraphIndex]->operators[operatorIndex];
291     auto opcodeIndex = operatorPtr->opcode_index;
292 
293 // work around the introduction of the deprecated_builtin_code introduced in 2.4 in a backwards compatible manner
294 #if defined(ARMNN_POST_TFLITE_2_3)
295     auto opcode = std::max(model->operator_codes[opcodeIndex]->builtin_code,
296             static_cast<tflite::BuiltinOperator>(model->operator_codes[opcodeIndex]->deprecated_builtin_code));
297 #else
298     auto opcode = model->operator_codes[opcodeIndex]->builtin_code;
299 #endif
300     return opcode;
301 }
302 
GetUIntBuffer(armnn::TensorInfo info,const TfLiteParserImpl::ModelPtr & model,size_t bufferIndex)303 std::vector<unsigned int> GetUIntBuffer(armnn::TensorInfo info,
304                                         const TfLiteParserImpl::ModelPtr& model,
305                                         size_t bufferIndex)
306 {
307     TfLiteParserImpl::BufferRawPtr bufferPtr = TfLiteParserImpl::GetBuffer(model, bufferIndex);
308     std::vector<unsigned int> buffer(info.GetNumElements());
309 
310     if (info.GetDataType() == DataType::Signed32)
311     {
312         ::memcpy(buffer.data(), bufferPtr->data.data(), bufferPtr->data.size());
313     }
314     else if (info.GetDataType() == DataType::Signed64)
315     {
316         std::vector<uint64_t> uint64Buffer(info.GetNumElements());
317         ::memcpy(uint64Buffer.data(), bufferPtr->data.data(), bufferPtr->data.size());
318         buffer.assign(std::begin(uint64Buffer), std::end(uint64Buffer));
319     }
320     else
321     {
322         CheckLocation location = CHECK_LOCATION();
323         throw ParseException(
324                 fmt::format("Unsupported data type for uint buffer {}, only Signed 32 or Signed 64 are supported. {}",
325                             GetDataTypeName(info.GetDataType()),
326                             location.AsString()));
327     }
328     return buffer;
329 }
330 
331 #define CHECK_BUFFER_SIZE(BUFFER_PTR, TENSOR_INFO, BUFFER_ID) \
332     CheckBufferSize(BUFFER_PTR, TENSOR_INFO, BUFFER_ID, CHECK_LOCATION())
333 
IsActivationSupported(tflite::ActivationFunctionType activationType)334 bool IsActivationSupported(tflite::ActivationFunctionType activationType)
335 {
336     switch(activationType)
337     {
338         case tflite::ActivationFunctionType_NONE:
339         case tflite::ActivationFunctionType_RELU:
340         case tflite::ActivationFunctionType_RELU6:
341         case tflite::ActivationFunctionType_TANH:
342         {
343             return true;
344         }
345         default:
346         {
347             return false;
348         }
349     }
350 }
351 
352 #define CHECK_SUPPORTED_FUSED_ACTIVATION(OPTION, SUBGRAPH_INDEX, OPERATOR_INDEX) \
353     do { \
354         if (IsActivationSupported(OPTION->fused_activation_function) == false) \
355         { \
356             throw ParseException( \
357                 fmt::format("TfLite parser doesn't support fused activation: " \
358                             "{}/{} in {} subgraph:{} operator:{} at {}", \
359                             OPTION->fused_activation_function, \
360                             tflite::EnumNameActivationFunctionType(\
361                             OPTION->fused_activation_function), \
362                             __func__, \
363                             SUBGRAPH_INDEX, \
364                             OPERATOR_INDEX, \
365                             CHECK_LOCATION().FileLine())); \
366         } \
367     } while(false)
368 
369 
AsUnsignedVector(const std::vector<int32_t> & in)370 std::vector<unsigned int> AsUnsignedVector(const std::vector<int32_t>& in)
371 {
372     std::vector<unsigned int> result;
373     result.reserve(in.size());
374     for (auto& i : in)
375     {
376         // If the location of the input data is -1 then the input should be ignored.
377         if (i == -1)
378         {
379             continue;
380         }
381         result.push_back(CHECKED_NON_NEGATIVE(i));
382     }
383     return result;
384 }
385 
IsOptionalOperandPresent(int input)386 bool IsOptionalOperandPresent(int input)
387 {
388     return (input >= 0);
389 }
390 
CalcPadding(uint32_t inputSize,uint32_t filterSize,uint32_t stride,uint32_t dilation,uint32_t & paddingFront,uint32_t & paddingBack,tflite::Padding padding)391 void CalcPadding(uint32_t inputSize,
392                  uint32_t filterSize,
393                  uint32_t stride,
394                  uint32_t dilation,
395                  uint32_t& paddingFront,
396                  uint32_t& paddingBack,
397                  tflite::Padding padding)
398 {
399     paddingFront = 0;
400     paddingBack = 0;
401     if (padding == tflite::Padding_SAME)
402     {
403         uint32_t outputSize = (inputSize + stride - 1) / stride;
404         uint32_t dilatedSize = filterSize + (dilation - 1) * (filterSize - 1);
405         uint32_t temp = (outputSize - 1) * stride + dilatedSize;
406         if (temp > inputSize)
407         {
408             paddingFront = (temp - inputSize) / 2;
409             paddingBack = (temp - inputSize) - paddingFront;
410         }
411     }
412 }
413 
ToTensorInfo(TfLiteParserImpl::TensorRawPtr tensorPtr,const std::vector<unsigned int> & shape,const bool outputTensor=false)414 armnn::TensorInfo ToTensorInfo(TfLiteParserImpl::TensorRawPtr tensorPtr,
415                                const std::vector<unsigned int>& shape,
416                                const bool outputTensor = false)
417 {
418     armnn::DataType type;
419     CHECK_TENSOR_PTR(tensorPtr);
420 
421     switch (tensorPtr->type)
422     {
423         case tflite::TensorType_UINT8:
424             type = armnn::DataType::QAsymmU8;
425             break;
426         case tflite::TensorType_FLOAT32:
427             type = armnn::DataType::Float32;
428             break;
429         case tflite::TensorType_FLOAT16:
430             type = armnn::DataType::Float16;
431             break;
432         case tflite::TensorType_INT8:
433             if (tensorPtr->quantization->zero_point.size() == 1)
434             {
435                 // Per-tensor
436                 type = armnn::DataType::QAsymmS8;
437             }
438             else
439             {
440                 // Per-channel
441                 type = armnn::DataType::QSymmS8;
442             }
443             break;
444         case tflite::TensorType_INT16:
445             type = armnn::DataType::QSymmS16;
446             break;
447         case tflite::TensorType_INT32:
448             type = armnn::DataType::Signed32;
449             break;
450         case tflite::TensorType_INT64:
451             type = armnn::DataType::Signed64;
452             break;
453         case tflite::TensorType_BOOL:
454             type = armnn::DataType::Boolean;
455             break;
456         default:
457         {
458             CheckLocation location = CHECK_LOCATION();
459             throw ParseException(
460                 fmt::format("Unsupported data type {} = {} for tensor: {}. {}",
461                             tensorPtr->type,
462                             tflite::EnumNameTensorType(tensorPtr->type),
463                             tensorPtr->name,
464                             location.AsString()));
465         }
466     }
467     TensorShape tensorShape;
468 
469     std::vector<unsigned int> safeShape = shape;
470     if (shape.size() == 0)
471     {
472         safeShape.push_back(1);
473     }
474 
475     if (!outputTensor)
476     {
477         tensorShape = TensorShape(armnn::numeric_cast<unsigned int>(safeShape.size()), safeShape.data());
478     }
479     else
480     {
481         size_t shapeSignatureSize = tensorPtr->shape_signature.size();
482 
483         // If a shape signature exists we will use that to infer dynamic tensors
484         if (shapeSignatureSize != 0)
485         {
486             // If the shape is incompatible with the shape signature override the shape
487             if (shapeSignatureSize != shape.size())
488             {
489                 safeShape = {};
490 
491                 for (unsigned int i = 0; i < shapeSignatureSize; ++i)
492                 {
493                     unsigned int dim = tensorPtr->shape_signature[i] > -1 ?
494                                        static_cast<unsigned int>(tensorPtr->shape_signature[i]) : 0;
495                     safeShape.push_back(dim);
496                 }
497             }
498 
499             std::unique_ptr<bool[]> dimMask = std::make_unique<bool[]>(tensorPtr->shape_signature.size());
500             bool batchOnly = true;
501             for (unsigned int i = 0; i < tensorPtr->shape_signature.size(); ++i)
502             {
503                 dimMask[i] = tensorPtr->shape_signature[i] != -1;
504 
505                 if (i > 0 && !dimMask[i])
506                 {
507                     batchOnly = false;
508                 }
509             }
510             if (batchOnly)
511             {
512                 dimMask[0] = true;
513             }
514             tensorShape = TensorShape(static_cast<unsigned int>(safeShape.size()), safeShape.data(), dimMask.get());
515         }
516         // If there is no shape signature treat the tensor as dynamic if the shape has a size of zero
517         else if (shape.size() == 0)
518         {
519             tensorShape = TensorShape(1, false);
520         }
521         else
522         {
523             tensorShape = TensorShape(armnn::numeric_cast<unsigned int>(shape.size()), shape.data());
524         }
525     }
526 
527     float quantizationScale = 1.0f;
528     int32_t quantizationOffset = 0;
529 
530     if (tensorPtr->quantization.get())
531     {
532         if (tensorPtr->quantization->scale.size() <= 1)
533         {
534             CHECK_VALID_SIZE(tensorPtr->quantization->zero_point.size(), 0, 1);
535             CHECK_VALID_SIZE(tensorPtr->quantization->zero_point.size(), 0, 1);
536 
537             if (tensorPtr->quantization->scale.size() == 1)
538             {
539                 quantizationScale = tensorPtr->quantization->scale[0];
540             }
541             if (tensorPtr->quantization->zero_point.size() == 1)
542             {
543                 // NOTE: we lose precision here when converting from 64 bit to 32
544                 //       but this is what we support at the moment in ArmNN
545                 quantizationOffset = armnn::numeric_cast<int32_t>(tensorPtr->quantization->zero_point[0]);
546             }
547 
548             armnn::TensorInfo result(tensorShape,
549                                      type,
550                                      quantizationScale,
551                                      quantizationOffset);
552             return result;
553         }
554         else
555         {
556             std::vector<float> quantizationScales;
557             std::vector<int32_t> quantizationOffsets;
558 
559             // Scale
560             std::copy(tensorPtr->quantization->scale.begin(),
561                       tensorPtr->quantization->scale.end(),
562                       std::back_inserter(quantizationScales));
563 
564             // QSymmS8 Per-axis
565             armnn::TensorInfo result(tensorShape,
566                                      type,
567                                      quantizationScales,
568                                      armnn::numeric_cast<unsigned int>(tensorPtr->quantization->quantized_dimension));
569             return result;
570         }
571     }
572     else
573     {
574         armnn::TensorInfo result(tensorShape,
575                                  type,
576                                  quantizationScale,
577                                  quantizationOffset);
578         return result;
579     }
580 }
581 
ToTensorInfo(TfLiteParserImpl::TensorRawPtr tensorPtr,const bool outputTensor=false)582 armnn::TensorInfo ToTensorInfo(TfLiteParserImpl::TensorRawPtr tensorPtr,
583                                const bool outputTensor = false)
584 {
585     auto const& dimensions = AsUnsignedVector(tensorPtr->shape);
586     return ToTensorInfo(tensorPtr, dimensions, outputTensor);
587 }
588 
589 template<typename T>
590 std::pair<armnn::ConstTensor, std::unique_ptr<T[]>>
CreateConstTensorImpl(TfLiteParserImpl::BufferRawPtr bufferPtr,TfLiteParserImpl::TensorRawPtr tensorPtr,armnn::TensorInfo & tensorInfo,armnn::Optional<armnn::PermutationVector &> permutationVector)591 CreateConstTensorImpl(TfLiteParserImpl::BufferRawPtr bufferPtr,
592                       TfLiteParserImpl::TensorRawPtr tensorPtr,
593                       armnn::TensorInfo& tensorInfo,
594                       armnn::Optional<armnn::PermutationVector&> permutationVector)
595 {
596     IgnoreUnused(tensorPtr);
597     ARMNN_ASSERT_MSG(tensorPtr != nullptr, "tensorPtr is null");
598     ARMNN_ASSERT_MSG(bufferPtr != nullptr,
599         fmt::format("Buffer for buffer:{} is null", tensorPtr->buffer).c_str());
600 
601     std::unique_ptr<T[]> data(new T[tensorInfo.GetNumElements()]);
602 
603     if (permutationVector.has_value() && permutationVector.value().GetSize() > 0)
604     {
605         tensorInfo = armnnUtils::Permuted(tensorInfo, permutationVector.value());
606         armnnUtils::Permute(tensorInfo.GetShape(), permutationVector.value(),
607                             reinterpret_cast<const T*>(bufferPtr->data.data()), data.get(), sizeof(T));
608     }
609     else
610     {
611         ::memcpy(data.get(), bufferPtr->data.data(), tensorInfo.GetNumBytes());
612     }
613 
614     // Make sure isConstant flag is set.
615     tensorInfo.SetConstant();
616 
617     return std::make_pair(ConstTensor(tensorInfo, data.get()), std::move(data));
618 }
619 
GenerateLayerBindingId(size_t subgraphIndex,size_t tensorIndex)620 armnn::LayerBindingId GenerateLayerBindingId(size_t subgraphIndex, size_t tensorIndex)
621 {
622     // generate the binding id by shifting the tensor id by 8 bit
623     // and add the subgraph id, which allows 256 subgraphs
624     return static_cast<armnn::LayerBindingId>((tensorIndex<<8)+subgraphIndex);
625 }
626 
CheckShape(const armnn::TensorShape & actual,const std::vector<int32_t> & expected)627 bool CheckShape(const armnn::TensorShape& actual, const std::vector<int32_t>& expected)
628 {
629     const unsigned int actualSize = actual.GetNumDimensions();
630     if (actualSize != expected.size())
631     {
632         return false;
633     }
634 
635     for (unsigned int i = 0u; i < actualSize; i++)
636     {
637         if (expected[i] < 0 ||
638             actual[i] != static_cast<unsigned int>(expected[i]))
639         {
640             return false;
641         }
642     }
643 
644     return true;
645 }
646 
CheckShape(const armnn::TensorShape & actual,const armnn::TensorShape & expected)647 bool CheckShape(const armnn::TensorShape& actual, const armnn::TensorShape& expected)
648 {
649     std::vector<int32_t> expectedVec;
650     for (uint32_t i = 0; i < expected.GetNumDimensions(); i++)
651     {
652         expectedVec.push_back(expected[i]);
653     }
654     return CheckShape(actual, expectedVec);
655 }
656 
CheckMatchingQuantization(const TensorInfo & first,const TensorInfo & second,const std::string & descName,std::string const & firstName,std::string const & secondName)657 void CheckMatchingQuantization(const TensorInfo& first,
658                                const TensorInfo& second,
659                                const std::string& descName,
660                                std::string const& firstName,
661                                std::string const& secondName)
662 {
663     if (!first.IsQuantized() ||
664         !second.IsQuantized())
665     {
666         // Not a quantized type, ignore the validation
667         return;
668     }
669 
670     DataType firstDataType  = first.GetDataType();
671     DataType secondDataType = second.GetDataType();
672 
673     if (firstDataType != secondDataType)
674     {
675         throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
676                                        " must be of the same quantized type, " +
677                                        firstName + " is " + GetDataTypeName(firstDataType) + ", " +
678                                        secondName + " is " + GetDataTypeName(secondDataType));
679     }
680 
681     if (!first.IsTypeSpaceMatch(second))
682     {
683         throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
684                                        " must have the same quantization space, " +
685                                        firstName + " has offset " + std::to_string(first.GetQuantizationOffset()) +
686                                        " and scale " + std::to_string(first.GetQuantizationScale()) + ", " +
687                                        secondName + " has offset " + std::to_string(second.GetQuantizationOffset()) +
688                                        " and scale " + std::to_string(second.GetQuantizationScale()));
689     }
690 }
691 
IsDynamic(TfLiteParserImpl::TensorRawPtr tensorPtr)692 bool IsDynamic(TfLiteParserImpl::TensorRawPtr tensorPtr)
693 {
694     auto shape = tensorPtr->shape;
695 
696     if (shape.empty())
697     {
698         return true;
699     }
700     auto shapeSig = tensorPtr->shape_signature;
701 
702     if (shapeSig.empty())
703     {
704         return false;
705     }
706 
707     for (unsigned int i = 0; i < shapeSig.size() ; ++i)
708     {
709         if (shapeSig[i] == -1)
710         {
711             return true;
712         }
713     }
714     return false;
715 }
716 
717 } // <anonymous>
718 
TfLiteParserImpl(const Optional<ITfLiteParser::TfLiteParserOptions> & options)719 TfLiteParserImpl::TfLiteParserImpl(const Optional<ITfLiteParser::TfLiteParserOptions>& options)
720 : m_Options(options)
721 , m_Network(nullptr, nullptr)
722 , m_ParserFunctions(tflite::BuiltinOperator_MAX+1, &TfLiteParserImpl::ParseUnsupportedOperator)
723 {
724     // register supported operators
725     m_ParserFunctions[tflite::BuiltinOperator_ABS]                     = &TfLiteParserImpl::ParseAbs;
726     m_ParserFunctions[tflite::BuiltinOperator_ADD]                     = &TfLiteParserImpl::ParseAdd;
727     m_ParserFunctions[tflite::BuiltinOperator_ARG_MIN]                 = &TfLiteParserImpl::ParseArgMin;
728     m_ParserFunctions[tflite::BuiltinOperator_ARG_MAX]                 = &TfLiteParserImpl::ParseArgMax;
729     m_ParserFunctions[tflite::BuiltinOperator_AVERAGE_POOL_2D]         = &TfLiteParserImpl::ParseAveragePool2D;
730     m_ParserFunctions[tflite::BuiltinOperator_BATCH_TO_SPACE_ND]       = &TfLiteParserImpl::ParseBatchToSpaceND;
731     m_ParserFunctions[tflite::BuiltinOperator_BATCH_MATMUL]            = &TfLiteParserImpl::ParseBatchMatMul;
732     m_ParserFunctions[tflite::BuiltinOperator_CEIL]                    = &TfLiteParserImpl::ParseCeil;
733     m_ParserFunctions[tflite::BuiltinOperator_CAST]                    = &TfLiteParserImpl::ParseCast;
734     m_ParserFunctions[tflite::BuiltinOperator_CONCATENATION]           = &TfLiteParserImpl::ParseConcatenation;
735     m_ParserFunctions[tflite::BuiltinOperator_CONV_2D]                 = &TfLiteParserImpl::ParseConv2D;
736     // Conv3D support was added in TF 2.5, so for backwards compatibility a hash define is needed.
737     #if defined(ARMNN_POST_TFLITE_2_4)
738     m_ParserFunctions[tflite::BuiltinOperator_CONV_3D]                 = &TfLiteParserImpl::ParseConv3D;
739     #endif
740     m_ParserFunctions[tflite::BuiltinOperator_CUSTOM]                  = &TfLiteParserImpl::ParseCustomOperator;
741     m_ParserFunctions[tflite::BuiltinOperator_DEPTH_TO_SPACE]          = &TfLiteParserImpl::ParseDepthToSpace;
742     m_ParserFunctions[tflite::BuiltinOperator_DEPTHWISE_CONV_2D]       = &TfLiteParserImpl::ParseDepthwiseConv2D;
743     m_ParserFunctions[tflite::BuiltinOperator_DEQUANTIZE]              = &TfLiteParserImpl::ParseDequantize;
744     m_ParserFunctions[tflite::BuiltinOperator_DIV]                     = &TfLiteParserImpl::ParseDiv;
745     m_ParserFunctions[tflite::BuiltinOperator_ELU]                     = &TfLiteParserImpl::ParseElu;
746     m_ParserFunctions[tflite::BuiltinOperator_EQUAL]                   = &TfLiteParserImpl::ParseEqual;
747     m_ParserFunctions[tflite::BuiltinOperator_EXP]                     = &TfLiteParserImpl::ParseExp;
748     m_ParserFunctions[tflite::BuiltinOperator_EXPAND_DIMS]             = &TfLiteParserImpl::ParseExpandDims;
749     m_ParserFunctions[tflite::BuiltinOperator_FLOOR_DIV]               = &TfLiteParserImpl::ParseFloorDiv;
750     m_ParserFunctions[tflite::BuiltinOperator_FULLY_CONNECTED]         = &TfLiteParserImpl::ParseFullyConnected;
751     m_ParserFunctions[tflite::BuiltinOperator_GATHER]                  = &TfLiteParserImpl::ParseGather;
752     m_ParserFunctions[tflite::BuiltinOperator_GATHER_ND]               = &TfLiteParserImpl::ParseGatherNd;
753     m_ParserFunctions[tflite::BuiltinOperator_GREATER]                 = &TfLiteParserImpl::ParseGreater;
754     m_ParserFunctions[tflite::BuiltinOperator_GREATER_EQUAL]           = &TfLiteParserImpl::ParseGreaterOrEqual;
755     m_ParserFunctions[tflite::BuiltinOperator_HARD_SWISH]              = &TfLiteParserImpl::ParseHardSwish;
756     m_ParserFunctions[tflite::BuiltinOperator_LEAKY_RELU]              = &TfLiteParserImpl::ParseLeakyRelu;
757     m_ParserFunctions[tflite::BuiltinOperator_LESS]                    = &TfLiteParserImpl::ParseLess;
758     m_ParserFunctions[tflite::BuiltinOperator_LESS_EQUAL]              = &TfLiteParserImpl::ParseLessOrEqual;
759     m_ParserFunctions[tflite::BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION]
760             = &TfLiteParserImpl::ParseLocalResponseNormalization;
761     m_ParserFunctions[tflite::BuiltinOperator_LOG]                     = &TfLiteParserImpl::ParseLog;
762     m_ParserFunctions[tflite::BuiltinOperator_LOGICAL_NOT]             = &TfLiteParserImpl::ParseLogicalNot;
763     m_ParserFunctions[tflite::BuiltinOperator_LOGISTIC]                = &TfLiteParserImpl::ParseLogistic;
764     m_ParserFunctions[tflite::BuiltinOperator_LOG_SOFTMAX]             = &TfLiteParserImpl::ParseLogSoftmax;
765     m_ParserFunctions[tflite::BuiltinOperator_L2_NORMALIZATION]        = &TfLiteParserImpl::ParseL2Normalization;
766     m_ParserFunctions[tflite::BuiltinOperator_MAX_POOL_2D]             = &TfLiteParserImpl::ParseMaxPool2D;
767     m_ParserFunctions[tflite::BuiltinOperator_MAXIMUM]                 = &TfLiteParserImpl::ParseMaximum;
768     m_ParserFunctions[tflite::BuiltinOperator_MEAN]                    = &TfLiteParserImpl::ParseMean;
769     m_ParserFunctions[tflite::BuiltinOperator_MINIMUM]                 = &TfLiteParserImpl::ParseMinimum;
770     m_ParserFunctions[tflite::BuiltinOperator_MIRROR_PAD]              = &TfLiteParserImpl::ParseMirrorPad;
771     m_ParserFunctions[tflite::BuiltinOperator_MUL]                     = &TfLiteParserImpl::ParseMul;
772     m_ParserFunctions[tflite::BuiltinOperator_NEG]                     = &TfLiteParserImpl::ParseNeg;
773     m_ParserFunctions[tflite::BuiltinOperator_NOT_EQUAL]               = &TfLiteParserImpl::ParseNotEqual;
774     m_ParserFunctions[tflite::BuiltinOperator_PACK]                    = &TfLiteParserImpl::ParsePack;
775     m_ParserFunctions[tflite::BuiltinOperator_PAD]                     = &TfLiteParserImpl::ParsePad;
776     m_ParserFunctions[tflite::BuiltinOperator_PADV2]                   = &TfLiteParserImpl::ParsePad;
777     m_ParserFunctions[tflite::BuiltinOperator_PRELU]                   = &TfLiteParserImpl::ParsePrelu;
778     m_ParserFunctions[tflite::BuiltinOperator_QUANTIZE]                = &TfLiteParserImpl::ParseQuantize;
779     m_ParserFunctions[tflite::BuiltinOperator_RELU]                    = &TfLiteParserImpl::ParseRelu;
780     m_ParserFunctions[tflite::BuiltinOperator_RELU6]                   = &TfLiteParserImpl::ParseRelu6;
781     m_ParserFunctions[tflite::BuiltinOperator_REDUCE_MAX]              = &TfLiteParserImpl::ParseReduceMax;
782     m_ParserFunctions[tflite::BuiltinOperator_REDUCE_MIN]              = &TfLiteParserImpl::ParseReduceMin;
783     m_ParserFunctions[tflite::BuiltinOperator_REDUCE_PROD]             = &TfLiteParserImpl::ParseReduceProd;
784     m_ParserFunctions[tflite::BuiltinOperator_RESHAPE]                 = &TfLiteParserImpl::ParseReshape;
785     m_ParserFunctions[tflite::BuiltinOperator_RESIZE_BILINEAR]         = &TfLiteParserImpl::ParseResizeBilinear;
786     m_ParserFunctions[tflite::BuiltinOperator_RESIZE_NEAREST_NEIGHBOR] = &TfLiteParserImpl::ParseResizeNearestNeighbor;
787     m_ParserFunctions[tflite::BuiltinOperator_RSQRT]                   = &TfLiteParserImpl::ParseRsqrt;
788     m_ParserFunctions[tflite::BuiltinOperator_SQRT]                    = &TfLiteParserImpl::ParseSqrt;
789     m_ParserFunctions[tflite::BuiltinOperator_SHAPE]                   = &TfLiteParserImpl::ParseShape;
790     m_ParserFunctions[tflite::BuiltinOperator_SIN]                     = &TfLiteParserImpl::ParseSin;
791     m_ParserFunctions[tflite::BuiltinOperator_SLICE]                   = &TfLiteParserImpl::ParseSlice;
792     m_ParserFunctions[tflite::BuiltinOperator_SOFTMAX]                 = &TfLiteParserImpl::ParseSoftmax;
793     m_ParserFunctions[tflite::BuiltinOperator_SPACE_TO_BATCH_ND]       = &TfLiteParserImpl::ParseSpaceToBatchND;
794     m_ParserFunctions[tflite::BuiltinOperator_SPACE_TO_DEPTH]          = &TfLiteParserImpl::ParseSpaceToDepth;
795     m_ParserFunctions[tflite::BuiltinOperator_SPLIT]                   = &TfLiteParserImpl::ParseSplit;
796     m_ParserFunctions[tflite::BuiltinOperator_SPLIT_V]                 = &TfLiteParserImpl::ParseSplitV;
797     m_ParserFunctions[tflite::BuiltinOperator_SQUEEZE]                 = &TfLiteParserImpl::ParseSqueeze;
798     m_ParserFunctions[tflite::BuiltinOperator_STRIDED_SLICE]           = &TfLiteParserImpl::ParseStridedSlice;
799     m_ParserFunctions[tflite::BuiltinOperator_SUB]                     = &TfLiteParserImpl::ParseSub;
800     m_ParserFunctions[tflite::BuiltinOperator_SUM]                     = &TfLiteParserImpl::ParseSum;
801     m_ParserFunctions[tflite::BuiltinOperator_TANH]                    = &TfLiteParserImpl::ParseTanH;
802     m_ParserFunctions[tflite::BuiltinOperator_TRANSPOSE]               = &TfLiteParserImpl::ParseTranspose;
803     m_ParserFunctions[tflite::BuiltinOperator_TRANSPOSE_CONV]          = &TfLiteParserImpl::ParseTransposeConv;
804     m_ParserFunctions[tflite::BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM]
805             = &TfLiteParserImpl::ParseUnidirectionalSequenceLSTM;
806     m_ParserFunctions[tflite::BuiltinOperator_UNPACK]                  = &TfLiteParserImpl::ParseUnpack;
807 
808     // register supported custom operators
809     m_CustomParserFunctions["TFLite_Detection_PostProcess"]      = &TfLiteParserImpl::ParseDetectionPostProcess;
810 }
811 
InputTensorInfo(size_t subgraphIndex,size_t operatorIndex,int input)812 armnn::TensorInfo TfLiteParserImpl::InputTensorInfo(size_t subgraphIndex,
813                                     size_t operatorIndex,
814                                     int input)
815 {
816     const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex];
817     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
818 
819     uint32_t inputId = CHECKED_NON_NEGATIVE(operatorPtr->inputs[input]);
820     auto search = armnnTfLiteParser::TfLiteParserImpl::m_TensorInfos.find(inputId);
821 
822     if (search != m_TensorInfos.end())
823     {
824         return m_TensorInfos[inputId];
825     }
826     else
827     {
828         auto tensorInfo = ::armnnTfLiteParser::ToTensorInfo(subgraphPtr->tensors[inputId].get());
829         m_TensorInfos.insert({ inputId, tensorInfo });
830         return tensorInfo;
831     }
832 }
833 
OutputTensorInfoFromInputs(size_t subgraphIndex,size_t operatorIndex,armnn::IConnectableLayer * layer,int output,std::vector<int> inputs)834 armnn::TensorInfo TfLiteParserImpl::OutputTensorInfoFromInputs(size_t subgraphIndex,
835                                                                size_t operatorIndex,
836                                                                armnn::IConnectableLayer* layer,
837                                                                int output,
838                                                                std::vector<int> inputs)
839 {
840     const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex];
841     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
842 
843     uint32_t outputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[output]);
844 
845     auto outputSearch = armnnTfLiteParser::TfLiteParserImpl::m_TensorInfos.find(outputId);
846 
847     if (outputSearch != m_TensorInfos.end())
848     {
849         return m_TensorInfos[outputId];
850     }
851 
852     const auto& outputTensorPtr = subgraphPtr->tensors[outputId].get();
853     TensorInfo tensor = ::armnnTfLiteParser::ToTensorInfo(outputTensorPtr, true);
854 
855     if (IsDynamic(outputTensorPtr))
856     {
857         if (inputs.empty())
858         {
859             for (unsigned int i = 0; i < layer->GetNumInputSlots(); ++i)
860             {
861                 inputs.emplace_back(i);
862             }
863         }
864         auto inputTensorIds = GetInputTensorIds(m_Model, subgraphIndex, operatorIndex);
865         std::vector<armnn::TensorShape> inputShapes;
866 
867         for (unsigned int i = 0; i < inputs.size(); ++i)
868         {
869             uint32_t inputId = CHECKED_NON_NEGATIVE(operatorPtr->inputs[inputs[i]]);
870             auto search = armnnTfLiteParser::TfLiteParserImpl::m_TensorInfos.find(inputId);
871 
872             if (search != m_TensorInfos.end())
873             {
874                 auto &inputTensorInfo = m_TensorInfos[inputId];
875                 inputShapes.push_back(inputTensorInfo.GetShape());
876             }
877             else
878             {
879                 m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
880                 auto inputTensorInfo = ::armnnTfLiteParser::ToTensorInfo(subgraphPtr->tensors[inputId].get());
881                 m_TensorInfos.insert({ inputId, inputTensorInfo});
882                 inputShapes.push_back(inputTensorInfo.GetShape());
883             }
884         }
885         const auto outputShape = layer->InferOutputShapes(inputShapes)[output];
886         tensor.SetShape(outputShape);
887     }
888     m_TensorInfos.insert({ outputId, tensor});
889     return tensor;
890 }
891 
OutputTensorInfoFromShapes(size_t subgraphIndex,size_t operatorIndex,armnn::IConnectableLayer * layer,int output,std::vector<armnn::TensorShape> inputShapes)892 armnn::TensorInfo TfLiteParserImpl::OutputTensorInfoFromShapes(size_t subgraphIndex,
893                                                                size_t operatorIndex,
894                                                                armnn::IConnectableLayer* layer,
895                                                                int output,
896                                                                std::vector<armnn::TensorShape> inputShapes)
897 {
898     const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex];
899     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
900 
901     uint32_t outputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[output]);
902     const auto& outputTensorPtr = subgraphPtr->tensors[outputId].get();
903     TensorInfo tensor = ::armnnTfLiteParser::ToTensorInfo(outputTensorPtr, true);
904 
905     if (IsDynamic(outputTensorPtr))
906     {
907         const auto outputShape = layer->InferOutputShapes(inputShapes)[output];
908         tensor.SetShape(outputShape);
909     }
910     m_TensorInfos.insert({ outputId, tensor});
911     return tensor;
912 }
913 
ResetParser()914 void TfLiteParserImpl::ResetParser()
915 {
916     m_Network = armnn::INetworkPtr(nullptr, nullptr);
917     m_Model = nullptr;
918     m_SubgraphConnections.clear();
919     m_OverriddenOutputShapes.clear();
920     m_ConstantsToDequantize.clear();
921     m_ConstantsToBeCreated.clear();
922     m_TensorInfos.clear();
923 }
924 
CreateNetworkFromBinaryFile(const char * graphFile)925 INetworkPtr TfLiteParserImpl::CreateNetworkFromBinaryFile(const char* graphFile)
926 {
927     ResetParser();
928     m_Model = LoadModelFromFile(graphFile);
929     return CreateNetworkFromModel();
930 }
931 
CreateNetworkFromBinary(const std::vector<uint8_t> & binaryContent)932 INetworkPtr TfLiteParserImpl::CreateNetworkFromBinary(const std::vector<uint8_t>& binaryContent)
933 {
934     ResetParser();
935     m_Model = LoadModelFromBinary(binaryContent.data(), binaryContent.size());
936     return CreateNetworkFromModel();
937 }
938 
939 
LoadModel(std::unique_ptr<tflite::ModelT> model)940 armnn::INetworkPtr TfLiteParserImpl::LoadModel(std::unique_ptr<tflite::ModelT> model)
941 {
942     ResetParser();
943     m_Model = std::move(model);
944 
945     return CreateNetworkFromModel();
946 }
947 
CreateNetworkFromModel()948 INetworkPtr TfLiteParserImpl::CreateNetworkFromModel()
949 {
950 
951     using NetworkOptions = std::vector<BackendOptions>;
952     NetworkOptions networkOptions = {};
953     if (m_Options)
954     {
955         if (m_Options.value().m_InferAndValidate)
956         {
957             BackendOptions shapeInferenceMethodOption("ShapeInferenceMethod",
958                                                       {
959                                                           { "InferAndValidate", true }
960                                                       });
961 
962             networkOptions.push_back(shapeInferenceMethodOption);
963         }
964         if (m_Options.value().m_AllowExpandedDims)
965         {
966             BackendOptions shapeInferenceMethodOption("AllowExpandedDims",
967                                                       {
968                                                           { "AllowExpandedDims", true }
969                                                       });
970 
971             networkOptions.push_back(shapeInferenceMethodOption);
972         }
973     }
974     m_Network = INetwork::Create(networkOptions);
975     ARMNN_ASSERT(m_Model.get() != nullptr);
976 
977     if (m_Model->subgraphs.size() != 1)
978     {
979         throw ParseException(
980                 fmt::format("Current TfLite parser only supports 1 subgraph. Current one has: {} {}",
981                             m_Model->subgraphs.size(),
982                             CHECK_LOCATION().AsString()));
983     }
984 
985     size_t subgraphIndex = 0;
986     size_t operatorIndex = 0;
987     try
988     {
989         for (SubgraphPtr const& subgraph : m_Model->subgraphs)
990         {
991             SetupInputLayerTensorInfos(subgraphIndex);
992             SetupConstantLayerTensorInfos(subgraphIndex);
993 
994             m_SubgraphConnections.emplace_back(subgraph->tensors.size());
995             for (OperatorPtr const& op : subgraph->operators)
996             {
997                 auto const& opCodePtr = m_Model->operator_codes[op->opcode_index];
998 
999 // work around the introduction of the deprecated_builtin_code introduced in 2.4 in a backwards compatible manner
1000 #if defined(ARMNN_POST_TFLITE_2_3)
1001                 auto builtinCode = std::max(opCodePtr->builtin_code,
1002                         static_cast<tflite::BuiltinOperator>(opCodePtr->deprecated_builtin_code));
1003 #else
1004                 auto builtinCode = opCodePtr->builtin_code;
1005 #endif
1006 
1007                 if (builtinCode > tflite::BuiltinOperator_MAX)
1008                 {
1009                     throw ParseException(fmt::format("Operator code {} is out of range 0-{}. "
1010                                                      "subgraph:{} operator idx:{}. {}",
1011                                                      builtinCode, tflite::BuiltinOperator_MAX, subgraphIndex,
1012                                                      operatorIndex, CHECK_LOCATION().AsString()));
1013                 }
1014 
1015                 // lookup and call the parser function
1016                 auto& parserFunction = m_ParserFunctions[builtinCode];
1017                 (this->*parserFunction)(subgraphIndex, operatorIndex);
1018                 ++operatorIndex;
1019             }
1020 
1021             SetupInputLayers(subgraphIndex);
1022             SetupOutputLayers(subgraphIndex);
1023             SetupConstantLayers(subgraphIndex);
1024 
1025             ++subgraphIndex;
1026             operatorIndex = 0;
1027         }
1028     }
1029     catch (const ParseException& e)
1030     {
1031         std::stringstream errorString;
1032         errorString << "Failed to parse operator #" << operatorIndex << " within subgraph #"
1033                     << subgraphIndex << " error: " << e.what();
1034         ARMNN_LOG(error) << errorString.str();
1035         std::stringstream errors;
1036         errors << errorString.str() << "\n";
1037         throw ParseException(errors.str());
1038     }
1039 
1040     // establish the connections from the layer outputs to the inputs of the subsequent layers
1041     for (subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex)
1042     {
1043         for (size_t tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex)
1044         {
1045             if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot != nullptr)
1046             {
1047                 for (size_t inputSlotIdx = 0;
1048                     inputSlotIdx < m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size();
1049                     ++inputSlotIdx)
1050                 {
1051                     m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot->Connect(
1052                         *(m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots[inputSlotIdx]));
1053                 }
1054             }
1055         }
1056     }
1057     return std::move(m_Network);
1058 }
1059 
ShouldConstantTensorBeConverted(TfLiteParserImpl::TensorRawPtr tensorPtr,armnn::DataType inputDataType,armnn::DataType tensorDataType)1060 bool TfLiteParserImpl::ShouldConstantTensorBeConverted(TfLiteParserImpl::TensorRawPtr tensorPtr,
1061                                                        armnn::DataType inputDataType,
1062                                                        armnn::DataType tensorDataType)
1063 {
1064     return (TfLiteParserImpl::IsConstTensor(tensorPtr) && inputDataType == DataType::Float32 &&
1065             (tensorDataType == DataType::QAsymmU8 ||
1066              tensorDataType == DataType::QAsymmS8 ||
1067              tensorDataType == DataType::QSymmS8 ||
1068              tensorDataType == DataType::Signed32 ||
1069              tensorDataType == DataType::Signed64));
1070 }
1071 
RegisterProducerOfTensor(size_t subgraphIndex,size_t tensorIndex,armnn::IOutputSlot * slot)1072 void TfLiteParserImpl::RegisterProducerOfTensor(size_t subgraphIndex,
1073                                                 size_t tensorIndex,
1074                                                 armnn::IOutputSlot* slot)
1075 {
1076     CHECK_TENSOR(m_Model, subgraphIndex, tensorIndex);
1077     ARMNN_ASSERT(m_SubgraphConnections.size() > subgraphIndex);
1078     ARMNN_ASSERT(m_SubgraphConnections[subgraphIndex].size() > tensorIndex);
1079 
1080     TensorSlots & tensorSlots = m_SubgraphConnections[subgraphIndex][tensorIndex];
1081 
1082     if (slot->GetOwningIConnectableLayer().GetType() != LayerType::Constant)
1083     {
1084 
1085         // assuming there is only one producer for that tensor
1086         if (tensorSlots.outputSlot != nullptr)
1087         {
1088             throw ParseException(fmt::format("Another layer has already registered itself as the producer of "
1089                                              "subgraph:{} tensor:{} {}",
1090                                              subgraphIndex,
1091                                              tensorIndex,
1092                                              CHECK_LOCATION().AsString()));
1093         }
1094     }
1095     tensorSlots.outputSlot = slot;
1096 }
1097 
RegisterConsumerOfTensor(size_t subgraphIndex,size_t tensorIndex,armnn::IInputSlot * slot)1098 void TfLiteParserImpl::RegisterConsumerOfTensor(size_t subgraphIndex,
1099                                                 size_t tensorIndex,
1100                                                 armnn::IInputSlot* slot)
1101 {
1102     CHECK_TENSOR(m_Model, subgraphIndex, tensorIndex);
1103     ARMNN_ASSERT(m_SubgraphConnections.size() > subgraphIndex);
1104     ARMNN_ASSERT(m_SubgraphConnections[subgraphIndex].size() > tensorIndex);
1105 
1106     TensorSlots& tensorSlots = m_SubgraphConnections[subgraphIndex][tensorIndex];
1107     tensorSlots.inputSlots.push_back(slot);
1108 }
1109 
ParseCustomOperator(size_t subgraphIndex,size_t operatorIndex)1110 void TfLiteParserImpl::ParseCustomOperator(size_t subgraphIndex, size_t operatorIndex)
1111 {
1112     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1113 
1114     // NOTE: By default we presume the custom operator is not supported
1115     auto customParserFunction = &TfLiteParserImpl::ParseUnsupportedOperator;
1116 
1117     // Identify custom code defined for custom operator
1118     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1119     const auto& customCode  = m_Model->operator_codes[operatorPtr->opcode_index]->custom_code;
1120 
1121     // Find parser function that corresponds to custom code (if any)
1122     auto iterator = m_CustomParserFunctions.find(customCode);
1123     if (iterator != m_CustomParserFunctions.end())
1124     {
1125         customParserFunction = iterator->second;
1126     }
1127 
1128     // Run parser function
1129     (this->*customParserFunction)(subgraphIndex, operatorIndex);
1130 }
1131 
ParseUnsupportedOperator(size_t subgraphIndex,size_t operatorIndex)1132 void TfLiteParserImpl::ParseUnsupportedOperator(size_t subgraphIndex, size_t operatorIndex)
1133 {
1134     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1135 
1136     const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1137 
1138     auto opcodeIndex = operatorPtr->opcode_index;
1139 
1140 // work around the introduction of the deprecated_builtin_code introduced in 2.4 in a backwards compatible manner
1141 #if defined(ARMNN_POST_TFLITE_2_3)
1142     auto opcode      = std::max(m_Model->operator_codes[opcodeIndex]->builtin_code,
1143             static_cast<tflite::BuiltinOperator>(m_Model->operator_codes[opcodeIndex]->deprecated_builtin_code));
1144 #else
1145     auto opcode      = m_Model->operator_codes[opcodeIndex]->builtin_code;
1146 #endif
1147 
1148     if (!m_Options || !m_Options.value().m_StandInLayerForUnsupported)
1149     {
1150         // Do not add StandInLayer, throw ParseException instead
1151         throw ParseException(
1152             fmt::format("Operator not supported. "
1153                         "subgraph:{} operator:{} "
1154                         "opcode_index:{} opcode:{} / {} {}",
1155                         subgraphIndex,
1156                         operatorIndex,
1157                         opcodeIndex,
1158                         opcode,
1159                         tflite::EnumNameBuiltinOperator(opcode),
1160                         CHECK_LOCATION().AsString()));
1161     }
1162 
1163     auto inputs  = GetInputs(m_Model, subgraphIndex, operatorIndex);
1164     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1165 
1166     const unsigned int numInputs  = armnn::numeric_cast<unsigned int>(inputs.size());
1167     const unsigned int numOutputs = armnn::numeric_cast<unsigned int>(outputs.size());
1168 
1169     StandInDescriptor descriptor(numInputs, numOutputs);
1170     auto layerName = fmt::format("StandIn:{}:{}:{}", subgraphIndex, operatorIndex, opcode);
1171 
1172     // Add a non-executable StandInLayer as a placeholder for any unsupported operator
1173     IConnectableLayer* layer = m_Network->AddStandInLayer(descriptor, layerName.c_str());
1174     ARMNN_ASSERT(layer != nullptr);
1175 
1176     for (unsigned int i = 0u; i < numOutputs; ++i)
1177     {
1178         layer->GetOutputSlot(i).SetTensorInfo(ToTensorInfo(outputs[0], true));
1179     }
1180 
1181     auto inputTensorIds  = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1182     auto outputTensorIds = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1183 
1184     RegisterInputSlots(subgraphIndex, operatorIndex, layer, inputTensorIds);
1185     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIds);
1186 }
1187 
ParseCast(size_t subgraphIndex,size_t operatorIndex)1188 void TfLiteParserImpl::ParseCast(size_t subgraphIndex, size_t operatorIndex)
1189 {
1190     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1191 
1192     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1193     CHECK_VALID_SIZE(inputs.size(), 1);
1194     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1195     CHECK_VALID_SIZE(outputs.size(), 1);
1196 
1197     auto layerName = fmt::format("Cast:{}:{}", subgraphIndex, operatorIndex);
1198 
1199     IConnectableLayer* layer = m_Network->AddCastLayer(layerName.c_str());
1200     ARMNN_ASSERT(layer != nullptr);
1201 
1202     TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
1203     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1204 
1205     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1206     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1207 
1208     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1209     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
1210 }
1211 
ParseConv2D(size_t subgraphIndex,size_t operatorIndex)1212 void TfLiteParserImpl::ParseConv2D(size_t subgraphIndex, size_t operatorIndex)
1213 {
1214     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1215 
1216     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1217     const auto* options = operatorPtr->builtin_options.AsConv2DOptions();
1218 
1219     CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1220 
1221     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1222     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1223     CHECK_VALID_SIZE(outputs.size(), 1);
1224 
1225     Convolution2dDescriptor desc;
1226     inputs.size() == 3 ?
1227         desc.m_BiasEnabled = true : desc.m_BiasEnabled = false;
1228     desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1229     desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1230     desc.m_DataLayout = armnn::DataLayout::NHWC;
1231     desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
1232     desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
1233 
1234     armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1235     armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
1236 
1237     // assuming input is NHWC
1238     unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1239     unsigned int inputWidth = inputTensorInfo.GetShape()[2];
1240 
1241     // assuming the filter is OHWI : Output, H, W, Input
1242     // which is essentially the same as NHWC
1243     unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1244     unsigned int filterWidth = filterTensorInfo.GetShape()[2];
1245 
1246     CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
1247                 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
1248     CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
1249                 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
1250 
1251     // Add the first input and weights tensor to the registration list.
1252     // The constant weights will be added by SetupConstantLayers.
1253     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1254     std::vector<unsigned int> tensorIndexesToRegister = { inputTensorIndexes[0], inputTensorIndexes[1] };
1255 
1256     auto layerName = fmt::format("Conv2D:{}:{}", subgraphIndex, operatorIndex);
1257     armnn::IConnectableLayer* layer = m_Network->AddConvolution2dLayer(desc, layerName.c_str());
1258 
1259     if (ShouldConstantTensorBeConverted(inputs[1], inputTensorInfo.GetDataType(), filterTensorInfo.GetDataType()))
1260     {
1261         m_ConstantsToDequantize.emplace_back(inputs[1]->buffer);
1262     }
1263 
1264     if (desc.m_BiasEnabled)
1265     {
1266         armnn::TensorInfo biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
1267 
1268         // Add the biases input to the registration list, a constant layer will be added by SetupConstantLayers.
1269         tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
1270 
1271         if (ShouldConstantTensorBeConverted(inputs[2], inputTensorInfo.GetDataType(), biasTensorInfo.GetDataType()))
1272         {
1273             m_ConstantsToDequantize.emplace_back(inputs[2]->buffer);
1274         }
1275     }
1276 
1277     ARMNN_ASSERT(layer != nullptr);
1278 
1279     armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
1280     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1281 
1282     // register the input connection slots for the layer, connections are made after all layers have been created
1283     // only the tensors for the inputs are relevant, exclude the const tensors
1284     RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister);
1285 
1286     layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
1287     // register the output connection slots for the layer, connections are made after all layers have been created
1288     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1289     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, { outputTensorIndexes[0] });
1290 }
1291 
1292 // Conv3D support was added in TF 2.5, so for backwards compatibility a hash define is needed.
1293 #if defined(ARMNN_POST_TFLITE_2_4)
ParseConv3D(size_t subgraphIndex,size_t operatorIndex)1294 void TfLiteParserImpl::ParseConv3D(size_t subgraphIndex, size_t operatorIndex)
1295 {
1296     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1297 
1298     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1299     const auto* options = operatorPtr->builtin_options.AsConv3DOptions();
1300 
1301     CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1302 
1303     Convolution3dDescriptor desc;
1304     desc.m_BiasEnabled = false;
1305     desc.m_DataLayout = armnn::DataLayout::NDHWC;
1306     desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1307     desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1308     desc.m_StrideZ = CHECKED_NON_NEGATIVE(options->stride_d);
1309     desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
1310     desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
1311     desc.m_DilationZ = CHECKED_NON_NEGATIVE(options->dilation_d_factor);
1312 
1313     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1314     CHECK_VALID_SIZE(inputs.size(), 2, 3);
1315 
1316     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1317     CHECK_VALID_SIZE(outputs.size(), 1);
1318 
1319     armnn::TensorInfo inputTensorInfo  = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1320     armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
1321 
1322     // Assuming input is NDHWC
1323     unsigned int inputDepth  = inputTensorInfo.GetShape()[1];
1324     unsigned int inputHeight = inputTensorInfo.GetShape()[2];
1325     unsigned int inputWidth  = inputTensorInfo.GetShape()[3];
1326 
1327     // Assuming the filter is DHWIO : Depth, Height, Width, OutputChannels, InputChannels
1328     unsigned int filterDepth  = filterTensorInfo.GetShape()[0];
1329     unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1330     unsigned int filterWidth  = filterTensorInfo.GetShape()[2];
1331 
1332     CalcPadding(inputDepth, filterDepth, desc.m_StrideZ,
1333                 desc.m_DilationZ, desc.m_PadFront, desc.m_PadBack, options->padding);
1334     CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
1335                 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
1336     CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
1337                 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
1338 
1339     auto filterTensorAndData = CreateConstTensorNonPermuted(inputs[1], filterTensorInfo, inputTensorInfo.GetDataType());
1340 
1341     auto layerName = fmt::format("Conv3D:{}:{}", subgraphIndex, operatorIndex);
1342 
1343     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1344     // Add the first input and weights tensor to the registration list.
1345     // The constant weights will be added by SetupConstantLayers.
1346     std::vector<unsigned int> tensorIndexesToRegister = {inputTensorIndexes[0], inputTensorIndexes[1]};
1347 
1348     if (inputs.size() == 3)
1349     {
1350         desc.m_BiasEnabled = true;
1351 
1352         // Add the biases input to the registration list, a constant layer will be added by SetupConstantLayers.
1353         tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
1354     }
1355 
1356     armnn::IConnectableLayer* layer = m_Network->AddConvolution3dLayer(desc, layerName.c_str());
1357     ARMNN_ASSERT(layer != nullptr);
1358 
1359     armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
1360     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1361 
1362     // Register the input connection slots for the layer, connections are made after all layers have been created
1363     RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister);
1364 
1365     layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
1366     // Register the output connection slots for the layer, connections are made after all layers have been created
1367     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1368     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1369 }
1370 #endif
1371 
ParseDepthwiseConv2D(size_t subgraphIndex,size_t operatorIndex)1372 void TfLiteParserImpl::ParseDepthwiseConv2D(size_t subgraphIndex, size_t operatorIndex)
1373 {
1374     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1375 
1376     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1377     const auto* options = operatorPtr->builtin_options.AsDepthwiseConv2DOptions();
1378 
1379     CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1380 
1381     DepthwiseConvolution2dDescriptor desc;
1382     desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1383     desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1384     desc.m_DataLayout = armnn::DataLayout::NHWC;
1385     CHECKED_NON_NEGATIVE(options->depth_multiplier);
1386 
1387     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1388     CHECK_VALID_SIZE(inputs.size(), 2, 3);
1389     if (inputs.size() == 3)
1390     {
1391         desc.m_BiasEnabled = true;
1392     }
1393 
1394     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1395     CHECK_VALID_SIZE(outputs.size(), 1);
1396     desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
1397     desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
1398 
1399     armnn::TensorInfo inputTensorInfo  = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1400     armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
1401 
1402     // Assuming input is NHWC
1403     unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1404     unsigned int inputWidth  = inputTensorInfo.GetShape()[2];
1405 
1406     // TensorflowLite weights come in the format [1, H, W, I * M]
1407     unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1408     unsigned int filterWidth  = filterTensorInfo.GetShape()[2];
1409 
1410     CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
1411                 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
1412     CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
1413                 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
1414 
1415     // ArmNN uses the same filter tensor layout at TfLite [1, H, W, O] no need for any permutation
1416     auto layerName = fmt::format("DepthwiseConv2D:{}:{}", subgraphIndex, operatorIndex);
1417 
1418     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1419     // Add the first input and weights tensor to the registration list.
1420     // The constant weights will be added by SetupConstantLayers.
1421     std::vector<unsigned int> tensorIndexesToRegister = {inputTensorIndexes[0], inputTensorIndexes[1]};
1422 
1423     armnn::IConnectableLayer* layer = m_Network->AddDepthwiseConvolution2dLayer(desc, layerName.c_str());
1424 
1425     if (desc.m_BiasEnabled)
1426     {
1427         desc.m_BiasEnabled = true;
1428         TensorInfo biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
1429 
1430         // Add the biases input to the registration list, a constant layer will be added by SetupConstantLayers.
1431         tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
1432     }
1433     ARMNN_ASSERT(layer != nullptr);
1434 
1435     armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
1436     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1437 
1438     // register the input connection slots for the layer, connections are made after all layers have been created
1439     // only the tensors for the inputs are relevant, exclude the const tensors
1440     RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister);
1441 
1442     layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
1443     // register the output connection slots for the layer, connections are made after all layers have been created
1444     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1445     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1446 }
1447 
ParseDequantize(size_t subgraphIndex,size_t operatorIndex)1448 void TfLiteParserImpl::ParseDequantize(size_t subgraphIndex, size_t operatorIndex)
1449 {
1450     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1451 
1452     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1453     CHECK_VALID_SIZE(inputs.size(), 1);
1454 
1455     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1456     CHECK_VALID_SIZE(outputs.size(), 1);
1457 
1458     auto layerName = fmt::format("Dequantize:{}:{}", subgraphIndex, operatorIndex);
1459 
1460     IConnectableLayer* layer = m_Network->AddDequantizeLayer(layerName.c_str());
1461     ARMNN_ASSERT(layer != nullptr);
1462 
1463     TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
1464     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1465 
1466     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1467     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1468 
1469     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1470     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
1471 }
1472 
ParseExpandDims(size_t subgraphIndex,size_t operatorIndex)1473 void TfLiteParserImpl::ParseExpandDims(size_t subgraphIndex, size_t operatorIndex)
1474 {
1475     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1476 
1477     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1478     CHECK_VALID_SIZE(inputs.size(), 2);
1479 
1480     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1481     CHECK_VALID_SIZE(outputs.size(), 1);
1482 
1483     auto layerName = fmt::format("ExpandDims:{}:{}", subgraphIndex, operatorIndex);
1484 
1485     armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1486     armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1487 
1488     CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1489 
1490     ReshapeDescriptor reshapeDesc;
1491 
1492     if (outputTensorInfo.GetShape().AreAllDimensionsSpecified())
1493     {
1494         reshapeDesc.m_TargetShape = outputTensorInfo.GetShape();
1495     }
1496     else
1497     {
1498         int32_t axis = inputs[1]->shape[0];
1499 
1500         int32_t inputDimSize = static_cast<int32_t>(inputTensorInfo.GetShape().GetNumDimensions());
1501 
1502         if (axis > inputDimSize || axis < 0 - (inputDimSize + 1))
1503         {
1504             throw ParseException("axis must be in range [0 - (inputDimSize + 1), inputDimSize] inclusive");
1505         }
1506 
1507         if(axis < 0)
1508         {
1509             axis = inputDimSize + axis + 1;
1510         }
1511 
1512         std::vector<unsigned int> shape(static_cast<unsigned int>(inputDimSize) + 1);
1513         unsigned int inputShapeIndex = 0;
1514         for (unsigned int i = 0; i < static_cast<unsigned int>(inputDimSize + 1); ++i)
1515         {
1516             if (i == static_cast<unsigned int>(axis))
1517             {
1518                 shape[i] = 1;
1519             }
1520             else
1521             {
1522                 shape[i] = inputTensorInfo.GetShape()[inputShapeIndex];
1523                 ++inputShapeIndex;
1524             }
1525         }
1526 
1527         reshapeDesc.m_TargetShape = TensorShape(static_cast<unsigned int>(inputDimSize + 1), shape.data());
1528     }
1529 
1530     IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
1531     ARMNN_ASSERT(layer != nullptr);
1532 
1533     reshapeDesc.m_TargetShape = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0}).GetShape();
1534     outputTensorInfo.SetShape(reshapeDesc.m_TargetShape);
1535 
1536     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1537 
1538     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1539     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1540 
1541     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1542     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1543 }
1544 
ParseTranspose(size_t subgraphIndex,size_t operatorIndex)1545 void TfLiteParserImpl::ParseTranspose(size_t subgraphIndex, size_t operatorIndex)
1546 {
1547     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1548 
1549     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1550     CHECK_VALID_SIZE(inputs.size(), 1, 2);
1551 
1552     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1553     CHECK_VALID_SIZE(outputs.size(), 1);
1554 
1555     auto layerName = fmt::format("Transpose:{}:{}", subgraphIndex, operatorIndex);
1556     TransposeDescriptor desc;
1557 
1558     if (inputs.size() == 2)
1559     {
1560         armnn::TensorInfo permuteTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
1561         BufferRawPtr permuteBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1562         auto numPermVecElements = permuteTensorInfo.GetNumElements();
1563         std::vector<unsigned int> permuteShape(numPermVecElements);
1564         ::memcpy(permuteShape.data(), permuteBufferPtr->data.data(), permuteTensorInfo.GetNumBytes());
1565         PermutationVector permutationVector(permuteShape.data(), permuteTensorInfo.GetNumElements());
1566 
1567         desc = TransposeDescriptor(permutationVector);
1568     }
1569     TensorInfo inputTensorInfo  = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1570 
1571     IConnectableLayer* layer = m_Network->AddTransposeLayer(desc, layerName.c_str());
1572     ARMNN_ASSERT(layer != nullptr);
1573 
1574     TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
1575     CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1576     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1577 
1578     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1579     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1580 
1581     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1582     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1583 }
1584 
ParseTransposeConv(size_t subgraphIndex,size_t operatorIndex)1585 void TfLiteParserImpl::ParseTransposeConv(size_t subgraphIndex, size_t operatorIndex)
1586 {
1587     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1588 
1589     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1590     const auto* options = operatorPtr->builtin_options.AsTransposeConvOptions();
1591 
1592     TransposeConvolution2dDescriptor desc;
1593     desc.m_BiasEnabled = false;
1594     desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1595     desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1596     desc.m_DataLayout = armnn::DataLayout::NHWC;
1597 
1598     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1599     if (inputs.size() == 4)
1600     {
1601         desc.m_BiasEnabled = true;
1602     }
1603     else
1604     {
1605         CHECK_VALID_SIZE(inputs.size(), 3);
1606     }
1607 
1608     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1609     CHECK_VALID_SIZE(outputs.size(), 1);
1610 
1611     // This block determines the output shape of the transpose convolution. If the output shape tensor ptr is not null
1612     // And the tensor is a constant, we can access the data at load time and set the output shape of the
1613     // layer. If this is not constant, We do not have access to the shape data, so we have to use
1614     // infer output shape and skip this code block.
1615     if (inputs[0] && IsConstTensor(inputs[0]))
1616     {
1617         armnn::TensorInfo tensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1618         std::vector<int> output_shape(tensorInfo.GetNumElements());
1619 
1620         if (tensorInfo.GetDataType() == DataType::Signed32)
1621         {
1622             ::memcpy(output_shape.data(), GetBuffer(m_Model, inputs[0]->buffer)->data.data(), tensorInfo.GetNumBytes());
1623         }
1624         if (tensorInfo.GetDataType() == DataType::QAsymmU8)
1625         {
1626             for(unsigned int i=0; i < tensorInfo.GetNumElements(); i++)
1627             {
1628                 output_shape[i] = GetBuffer(m_Model, inputs[0]->buffer)->data.data()[i];
1629             }
1630         }
1631         // Change from signed to unsigned int to store in TransposeConvolution2dDescriptor.
1632         for (int dimension : output_shape)
1633         {
1634             desc.m_OutputShape.push_back(static_cast<unsigned int>(dimension));
1635         }
1636         desc.m_OutputShapeEnabled = true;
1637     }
1638     armnn::TensorInfo inputTensorInfo  = InputTensorInfo(subgraphIndex, operatorIndex, 2);
1639     armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
1640 
1641     // TfLite uses NHWC tensors
1642     const unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1643     const unsigned int inputWidth  = inputTensorInfo.GetShape()[2];
1644 
1645     const unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1646     const unsigned int filterWidth  = filterTensorInfo.GetShape()[2];
1647 
1648     CalcPadding(inputHeight,
1649                 filterHeight,
1650                 desc.m_StrideY,
1651                 1, // DilationY
1652                 desc.m_PadTop,
1653                 desc.m_PadBottom,
1654                 options->padding);
1655 
1656     CalcPadding(inputWidth,
1657                 filterWidth,
1658                 desc.m_StrideX,
1659                 1, // DilationX
1660                 desc.m_PadLeft,
1661                 desc.m_PadRight,
1662                 options->padding);
1663 
1664     auto filterTensorAndData = CreateConstTensorNonPermuted(inputs[1], filterTensorInfo, inputTensorInfo.GetDataType());
1665 
1666     armnn::IConnectableLayer* layer = nullptr;
1667     auto layerName = fmt::format("TransposeConv:{}:{}", subgraphIndex, operatorIndex);
1668 
1669     if (desc.m_BiasEnabled)
1670     {
1671         auto biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 3);
1672         auto biasConstTensor = CreateConstTensorNonPermuted(inputs[3], biasTensorInfo, inputTensorInfo.GetDataType());
1673         layer = m_Network->AddTransposeConvolution2dLayer(desc,
1674                                                           filterTensorAndData.first,
1675                                                           biasConstTensor.first,
1676                                                           layerName.c_str());
1677     }
1678     else
1679     {
1680         layer = m_Network->AddTransposeConvolution2dLayer(desc,
1681                                                           filterTensorAndData.first,
1682                                                           EmptyOptional(),
1683                                                           layerName.c_str());
1684     }
1685 
1686     ARMNN_ASSERT(layer != nullptr);
1687 
1688     armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0 , { 2, 1 });
1689     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1690 
1691     // only the tensors for the inputs are relevant, exclude the const (filter) tensor
1692     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1693     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[2]});
1694 
1695     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1696     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1697 }
1698 
ParseAveragePool2D(size_t subgraphIndex,size_t operatorIndex)1699 void TfLiteParserImpl::ParseAveragePool2D(size_t subgraphIndex, size_t operatorIndex)
1700 {
1701     ParsePool(subgraphIndex, operatorIndex, PoolingAlgorithm::Average);
1702 }
1703 
ParseBatchMatMul(size_t subgraphIndex,size_t operatorIndex)1704 void TfLiteParserImpl::ParseBatchMatMul(size_t subgraphIndex, size_t operatorIndex)
1705 {
1706     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1707 
1708     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1709     CHECK_VALID_SIZE(inputs.size(), 2);
1710 
1711     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1712     CHECK_VALID_SIZE(outputs.size(), 1);
1713 
1714     auto layerName = fmt::format("BatchMatMul:{}:{}", subgraphIndex, operatorIndex);
1715 
1716     TensorInfo inputXTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1717     TensorInfo inputYTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
1718 
1719     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1720     const auto* options = operatorPtr->builtin_options.AsBatchMatMulOptions();
1721 
1722     // Adjoint in tensorflow lite performs transpose operation
1723     BatchMatMulDescriptor descriptor(options->adj_x,
1724                                      options->adj_y,
1725                                      false,
1726                                      false);
1727                                      // Arbitrary DataLayout
1728 
1729     IConnectableLayer* layer = m_Network->AddBatchMatMulLayer(descriptor, layerName.c_str());
1730     ARMNN_ASSERT(layer != nullptr);
1731 
1732     TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
1733     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1734 
1735     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1736     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
1737 
1738     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1739     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1740 }
1741 
ParseBatchToSpaceND(size_t subgraphIndex,size_t operatorIndex)1742 void TfLiteParserImpl::ParseBatchToSpaceND(size_t subgraphIndex, size_t operatorIndex)
1743 {
1744     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1745 
1746     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1747     CHECK_VALID_SIZE(inputs.size(), 3);
1748 
1749     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1750     CHECK_VALID_SIZE(outputs.size(), 1);
1751 
1752     armnn::TensorInfo blockShapeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
1753     BufferRawPtr blockShapeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1754 
1755     armnn::TensorInfo cropsTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
1756     BufferRawPtr cropsBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
1757 
1758     std::vector<unsigned int> blockShape(blockShapeTensorInfo.GetNumElements());
1759     ::memcpy(blockShape.data(), blockShapeBufferPtr->data.data(), blockShapeTensorInfo.GetNumBytes());
1760 
1761     std::vector<unsigned int> cropsVector(cropsTensorInfo.GetNumElements());
1762     ::memcpy(cropsVector.data(), cropsBufferPtr->data.data(), cropsTensorInfo.GetNumBytes());
1763 
1764     size_t step = 2;
1765     std::vector<std::pair<unsigned int, unsigned int>> crops;
1766     for (unsigned int i = 0; i < cropsTensorInfo.GetNumElements() / step; ++i)
1767     {
1768         crops.emplace_back(cropsVector[i * step], cropsVector[i * step + 1]);
1769     }
1770 
1771     armnn::BatchToSpaceNdDescriptor desc;
1772     desc.m_BlockShape = blockShape;
1773     desc.m_Crops = crops;
1774     desc.m_DataLayout = armnn::DataLayout::NHWC;
1775 
1776     auto layerName = fmt::format("BatchToSpaceND:{}:{}", subgraphIndex, operatorIndex);
1777 
1778     TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1779 
1780     IConnectableLayer* layer = m_Network->AddBatchToSpaceNdLayer(desc, layerName.c_str());
1781     ARMNN_ASSERT(layer != nullptr);
1782 
1783     TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
1784     CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1785     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1786 
1787     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1788     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1789 
1790     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1791     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1792 }
1793 
ParseL2Normalization(size_t subgraphIndex,size_t operatorIndex)1794 void TfLiteParserImpl::ParseL2Normalization(size_t subgraphIndex, size_t operatorIndex)
1795 {
1796     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1797 
1798     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1799     CHECK_VALID_SIZE(inputs.size(), 1);
1800 
1801     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1802     CHECK_VALID_SIZE(outputs.size(), 1);
1803 
1804     L2NormalizationDescriptor desc;
1805     desc.m_DataLayout = armnn::DataLayout::NHWC;
1806     auto layerName = fmt::format("L2Normalization:{}:{}", subgraphIndex, operatorIndex);
1807     IConnectableLayer* layer = m_Network->AddL2NormalizationLayer(desc, layerName.c_str());
1808 
1809     ARMNN_ASSERT(layer != nullptr);
1810 
1811     armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
1812     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1813 
1814     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1815     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1816 
1817     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1818     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1819 }
1820 
ParseMaxPool2D(size_t subgraphIndex,size_t operatorIndex)1821 void TfLiteParserImpl::ParseMaxPool2D(size_t subgraphIndex, size_t operatorIndex)
1822 {
1823     ParsePool(subgraphIndex, operatorIndex, PoolingAlgorithm::Max);
1824 }
1825 
ParseMaximum(size_t subgraphIndex,size_t operatorIndex)1826 void TfLiteParserImpl::ParseMaximum(size_t subgraphIndex, size_t operatorIndex)
1827 {
1828     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1829 
1830     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1831     CHECK_VALID_SIZE(inputs.size(), 2);
1832 
1833     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1834     CHECK_VALID_SIZE(outputs.size(), 1);
1835 
1836     auto layerName = fmt::format("Maximum:{}:{}", subgraphIndex, operatorIndex);
1837 
1838     TensorInfo inputTensorInfo  = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1839     TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
1840     CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
1841 
1842     IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Maximum, layerName.c_str());
1843     ARMNN_ASSERT(layer != nullptr);
1844 
1845     TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
1846     CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1847     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1848 
1849     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1850     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
1851 
1852     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1853     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1854 }
1855 
ParseMinimum(size_t subgraphIndex,size_t operatorIndex)1856 void TfLiteParserImpl::ParseMinimum(size_t subgraphIndex, size_t operatorIndex)
1857 {
1858     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1859 
1860     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1861     CHECK_VALID_SIZE(inputs.size(), 2);
1862 
1863     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1864     CHECK_VALID_SIZE(outputs.size(), 1);
1865 
1866     auto layerName = fmt::format("Minimum:{}:{}", subgraphIndex, operatorIndex);
1867 
1868     TensorInfo inputTensorInfo  = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1869     TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
1870     CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
1871 
1872     IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Minimum, layerName.c_str());
1873     ARMNN_ASSERT(layer != nullptr);
1874 
1875     TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
1876     CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1877     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1878 
1879     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1880     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
1881 
1882     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1883     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1884 }
1885 
ParsePool(size_t subgraphIndex,size_t operatorIndex,PoolingAlgorithm algorithm)1886 void TfLiteParserImpl::ParsePool(size_t subgraphIndex,
1887                                  size_t operatorIndex,
1888                                  PoolingAlgorithm algorithm)
1889 {
1890     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1891 
1892     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1893     const auto* options = operatorPtr->builtin_options.AsPool2DOptions();
1894 
1895     CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1896 
1897     std::string layerName;
1898 
1899     switch (algorithm)
1900     {
1901         case PoolingAlgorithm::Average:
1902             layerName =
1903                 fmt::format("AveragePool2D:{}:{}", subgraphIndex, operatorIndex);
1904             break;
1905         case PoolingAlgorithm::Max:
1906             layerName =
1907                 fmt::format("MaxPool2D:{}:{}", subgraphIndex, operatorIndex);
1908             break;
1909         default:
1910             ARMNN_ASSERT_MSG(false, "Unsupported Pooling Algorithm");
1911     }
1912 
1913     Pooling2dDescriptor desc;
1914 
1915     desc.m_PoolType = algorithm;
1916     desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1917     desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1918     desc.m_PoolWidth = CHECKED_NON_NEGATIVE(options->filter_width);
1919     desc.m_PoolHeight = CHECKED_NON_NEGATIVE(options->filter_height);
1920     desc.m_PaddingMethod = PaddingMethod::Exclude;
1921     desc.m_OutputShapeRounding = OutputShapeRounding::Floor;
1922     desc.m_DataLayout = armnn::DataLayout::NHWC;
1923 
1924     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1925     CHECK_VALID_SIZE(inputs.size(), 1);
1926     armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1927 
1928     // assuming input is NHWC
1929     unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1930     unsigned int inputWidth  = inputTensorInfo.GetShape()[2];
1931 
1932     CalcPadding(inputHeight, desc.m_PoolHeight, desc.m_StrideY, 1u,
1933                 desc.m_PadTop, desc.m_PadBottom, options->padding);
1934     CalcPadding(inputWidth, desc.m_PoolWidth, desc.m_StrideX, 1u,
1935                 desc.m_PadLeft, desc.m_PadRight, options->padding);
1936 
1937     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1938     CHECK_VALID_SIZE(outputs.size(), 1);
1939 
1940     IConnectableLayer* layer = m_Network->AddPooling2dLayer(desc, layerName.c_str());
1941     ARMNN_ASSERT(layer != nullptr);
1942 
1943     armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
1944     CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1945     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1946 
1947     // register the input connection slots for the layer, connections are made after all layers have been created
1948     // only the tensors for the inputs are relevant, exclude the const tensors
1949     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1950     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1951 
1952     layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
1953     // register the output connection slots for the layer, connections are made after all layers have been created
1954     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1955     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1956 }
1957 
ParseSlice(size_t subgraphIndex,size_t operatorIndex)1958 void TfLiteParserImpl::ParseSlice(size_t subgraphIndex, size_t operatorIndex)
1959 {
1960     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1961 
1962     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1963     CHECK_VALID_SIZE(inputs.size(), 3);
1964     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1965     CHECK_VALID_SIZE(outputs.size(), 1);
1966 
1967     SliceDescriptor desc;
1968 
1969     // set begin tensor info for slice descriptor
1970     armnn::TensorInfo beginTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
1971     BufferRawPtr beginBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1972 
1973     std::vector<unsigned int> begin(beginTensorInfo.GetNumElements());
1974     ::memcpy(begin.data(), beginBufferPtr->data.data(), beginTensorInfo.GetNumBytes());
1975 
1976     // set size tensor info for slice descriptor
1977     armnn::TensorInfo sizeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
1978     BufferRawPtr sizeBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
1979 
1980     std::vector<int> signedSize(sizeTensorInfo.GetNumElements(), 1);
1981 
1982     // if size buffer data is not specified, all contents of size vector remain as values of 1
1983     if (sizeBufferPtr->data.data())
1984     {
1985         ::memcpy(signedSize.data(), sizeBufferPtr->data.data(), sizeTensorInfo.GetNumBytes());
1986     }
1987 
1988     std::vector<unsigned int> size(sizeTensorInfo.GetNumElements());
1989     TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1990 
1991     for (unsigned int i = 0; i < signedSize.size(); ++i)
1992     {
1993         int signedValue = signedSize[i];
1994 
1995         if (signedValue < -1 || signedValue > static_cast<int>(inputTensorInfo.GetShape()[i] - begin[i]))
1996         {
1997             throw ParseException(fmt::format("Invalid value for size {} size must be in range "
1998                                              "[-1, inputDimSize - begin] [-1, {}] inclusive {}",
1999                                              signedValue,
2000                                              inputTensorInfo.GetShape()[i] - begin[i],
2001                                              CHECK_LOCATION().AsString()));
2002         }
2003 
2004         if (signedValue == -1)
2005         {
2006             size[i] = inputTensorInfo.GetShape()[i] - begin[i];
2007         }
2008         else
2009         {
2010             size[i] = static_cast<unsigned int>(signedValue);
2011         }
2012     }
2013 
2014     desc = SliceDescriptor(begin, size);
2015 
2016     auto layerName = fmt::format("Slice:{}:{}", subgraphIndex, operatorIndex);
2017 
2018     IConnectableLayer* const layer = m_Network->AddSliceLayer(desc, layerName.c_str());
2019 
2020     TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
2021     CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
2022     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2023 
2024     // register the input connection slots for the layer, connections are made after all layers have been created
2025     // only the tensors for the inputs are relevant, exclude the const tensors
2026     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2027     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2028 
2029     // register the output connection slots for the layer, connections are made after all layers have been created
2030     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2031     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2032 }
2033 
ParseSoftmax(size_t subgraphIndex,size_t operatorIndex)2034 void TfLiteParserImpl::ParseSoftmax(size_t subgraphIndex, size_t operatorIndex)
2035 {
2036     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2037     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2038     const auto* options = operatorPtr->builtin_options.AsSoftmaxOptions();
2039 
2040     SoftmaxDescriptor desc;
2041     desc.m_Beta = options->beta;
2042 
2043     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2044     CHECK_VALID_SIZE(inputs.size(), 1);
2045     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2046     CHECK_VALID_SIZE(outputs.size(), 1);
2047 
2048     auto layerName = fmt::format("Softmax:{}:{}", subgraphIndex, operatorIndex);
2049     IConnectableLayer* const layer = m_Network->AddSoftmaxLayer(desc, layerName.c_str());
2050 
2051     armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
2052     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2053 
2054     // register the input connection slots for the layer, connections are made after all layers have been created
2055     // only the tensors for the inputs are relevant, exclude the const tensors
2056     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2057     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2058 
2059     // register the output connection slots for the layer, connections are made after all layers have been created
2060     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2061     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2062 }
2063 
ParseLogSoftmax(size_t subgraphIndex,size_t operatorIndex)2064 void TfLiteParserImpl::ParseLogSoftmax(size_t subgraphIndex, size_t operatorIndex)
2065 {
2066     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2067 
2068     LogSoftmaxDescriptor desc;
2069 
2070     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2071     CHECK_VALID_SIZE(inputs.size(), 1);
2072     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2073     CHECK_VALID_SIZE(outputs.size(), 1);
2074 
2075     auto layerName = fmt::format("LogSoftmax:{}:{}", subgraphIndex, operatorIndex);
2076     IConnectableLayer* const layer = m_Network->AddLogSoftmaxLayer(desc, layerName.c_str());
2077 
2078     armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
2079     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2080 
2081     // register the input connection slots for the layer, connections are made after all layers have been created
2082     // only the tensors for the inputs are relevant, exclude the const tensors
2083     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2084     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2085 
2086     // register the output connection slots for the layer, connections are made after all layers have been created
2087     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2088     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2089 }
2090 
ParseSpaceToBatchND(size_t subgraphIndex,size_t operatorIndex)2091 void TfLiteParserImpl::ParseSpaceToBatchND(size_t subgraphIndex, size_t operatorIndex)
2092 {
2093     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2094 
2095     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2096     CHECK_VALID_SIZE(inputs.size(), 3);
2097 
2098     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2099     CHECK_VALID_SIZE(outputs.size(), 1);
2100 
2101     armnn::TensorInfo blockShapeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
2102     BufferRawPtr blockShapeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2103 
2104     armnn::TensorInfo padListTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
2105     BufferRawPtr padListBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
2106 
2107     std::vector<unsigned int> blockShape(blockShapeTensorInfo.GetNumElements());
2108     ::memcpy(blockShape.data(), blockShapeBufferPtr->data.data(), blockShapeTensorInfo.GetNumBytes());
2109 
2110     std::vector<unsigned int> padListVector(padListTensorInfo.GetNumElements());
2111     ::memcpy(padListVector.data(), padListBufferPtr->data.data(), padListTensorInfo.GetNumBytes());
2112 
2113     size_t step = 2;
2114     std::vector<std::pair<unsigned int, unsigned int>> padList;
2115     for (unsigned int i = 0; i < padListTensorInfo.GetNumElements() / step; ++i)
2116     {
2117         padList.emplace_back(padListVector[i * step], padListVector[i * step + 1]);
2118     }
2119 
2120     armnn::SpaceToBatchNdDescriptor desc;
2121     desc.m_BlockShape = blockShape;
2122     desc.m_PadList = padList;
2123     desc.m_DataLayout = armnn::DataLayout::NHWC;
2124 
2125     auto layerName = fmt::format("SpaceToBatchND:{}:{}", subgraphIndex, operatorIndex);
2126 
2127     TensorInfo inputTensorInfo  = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2128 
2129     IConnectableLayer* layer = m_Network->AddSpaceToBatchNdLayer(desc, layerName.c_str());
2130     ARMNN_ASSERT(layer != nullptr);
2131 
2132     TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
2133     CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
2134     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2135 
2136     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2137     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2138 
2139     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2140     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2141 }
2142 
ParseSpaceToDepth(size_t subgraphIndex,size_t operatorIndex)2143 void TfLiteParserImpl::ParseSpaceToDepth(size_t subgraphIndex, size_t operatorIndex)
2144 {
2145     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2146 
2147     TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2148     CHECK_VALID_SIZE(inputs.size(), 1);
2149     TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2150     CHECK_VALID_SIZE(outputs.size(), 1);
2151 
2152     armnn::SpaceToDepthDescriptor descriptor;
2153 
2154     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2155     const auto* options = operatorPtr->builtin_options.AsSpaceToDepthOptions();
2156     auto blockSize = options->block_size;
2157     if (blockSize < 2)
2158     {
2159         throw ParseException(
2160                 fmt::format("Operation has invalid block size: {} Block size should be >= 2 {}",
2161                             blockSize,
2162                             CHECK_LOCATION().AsString()));
2163     }
2164     descriptor.m_BlockSize = armnn::numeric_cast<uint32_t>(blockSize);
2165 
2166     auto layerName = fmt::format("SpaceToDepth:{}:{}", subgraphIndex, operatorIndex);
2167     IConnectableLayer* layer = m_Network->AddSpaceToDepthLayer(descriptor, layerName.c_str());
2168     ARMNN_ASSERT(layer != nullptr);
2169     TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
2170     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2171 
2172     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2173     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2174 
2175     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2176     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2177 }
2178 
OutputShapeOfSqueeze(std::vector<uint32_t> squeezeDims,const armnn::TensorInfo & inputTensorInfo)2179 armnn::TensorInfo TfLiteParserImpl::OutputShapeOfSqueeze(std::vector<uint32_t> squeezeDims,
2180                                                          const armnn::TensorInfo& inputTensorInfo)
2181 {
2182     CHECK_VALID_SIZE(squeezeDims.size(), 0, 1, 2, 3, 4);
2183     static const uint32_t dimensionSequence[] = { 0, 1, 2, 3 };
2184 
2185     if (inputTensorInfo.GetNumDimensions() > 4)
2186     {
2187         std::stringstream ss;
2188         ss << "Input tensor has unexpected number of dimensions:" << inputTensorInfo.GetNumDimensions()
2189            << " shape:" << inputTensorInfo.GetShape() << " "
2190            << CHECK_LOCATION().AsString();
2191         throw ParseException(ss.str());
2192     }
2193 
2194     if (squeezeDims.empty())
2195     {
2196         squeezeDims.assign(dimensionSequence,
2197                            dimensionSequence+inputTensorInfo.GetNumDimensions());
2198     }
2199 
2200     std::vector<uint32_t> outputDims;
2201     for(unsigned int i = 0; i < inputTensorInfo.GetNumDimensions(); i++)
2202     {
2203         bool skipSqueeze = (std::find(squeezeDims.begin(), squeezeDims.end(), i) == squeezeDims.end());
2204         auto currentDimension = inputTensorInfo.GetShape()[i];
2205         if (skipSqueeze || currentDimension != 1)
2206         {
2207             outputDims.push_back(currentDimension);
2208         }
2209     }
2210 
2211     if (outputDims.size() > 4)
2212     {
2213         std::stringstream ss;
2214         ss << "Output tensor has unexpected number of dimensions:" << inputTensorInfo.GetNumDimensions()
2215            << " shape:" << inputTensorInfo.GetShape() << " "
2216            << CHECK_LOCATION().AsString();
2217         throw ParseException(ss.str());
2218     }
2219 
2220     TensorShape outShape = TensorShape(static_cast<unsigned int>(outputDims.size()),
2221                                        outputDims.data());
2222 
2223     // we need to preserve the tensor type and the quantization data as well
2224     TensorInfo outTensorInfo = inputTensorInfo;
2225     outTensorInfo.SetShape(outShape);
2226 
2227     return outTensorInfo;
2228 }
2229 
ParseShape(size_t subgraphIndex,size_t operatorIndex)2230 void TfLiteParserImpl::ParseShape(size_t subgraphIndex, size_t operatorIndex)
2231 {
2232     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2233 
2234     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2235     CHECK_VALID_SIZE(inputs.size(), 1);
2236     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2237     CHECK_VALID_SIZE(outputs.size(), 1);
2238 
2239     auto layerName = fmt::format("Shape:{}:{}", subgraphIndex, operatorIndex);
2240 
2241     IConnectableLayer* layer = m_Network->AddShapeLayer(layerName.c_str());
2242     ARMNN_ASSERT(layer != nullptr);
2243 
2244     TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
2245     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2246 
2247     // Check if output tensor type is Signed32 or Signed64
2248     if (outputTensorInfo.GetDataType() != armnn::DataType::Signed32 &&
2249         outputTensorInfo.GetDataType() != armnn::DataType::Signed64)
2250     {
2251         throw ParseException(
2252             fmt::format(
2253                 "Output tensor data type is not supported. (Supported types: Signed32 & Signed64) {}",
2254                 CHECK_LOCATION().AsString()));
2255     }
2256 
2257     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2258     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2259 
2260     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2261     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2262 }
2263 
ParseSqueeze(size_t subgraphIndex,size_t operatorIndex)2264 void TfLiteParserImpl::ParseSqueeze(size_t subgraphIndex, size_t operatorIndex)
2265 {
2266     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2267 
2268     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2269     CHECK_VALID_SIZE(inputs.size(), 1);
2270 
2271     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2272     CHECK_VALID_SIZE(outputs.size(), 1);
2273 
2274     const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2275     const auto * options = operatorPtr->builtin_options.AsSqueezeOptions();
2276     auto layerName = fmt::format("Squeeze:{}:{}", subgraphIndex, operatorIndex);
2277 
2278     armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2279 
2280     std::vector<uint32_t> squeezeDim;
2281     // A single negative dim index is interpreted as a negative index in python
2282     // Meaning the index will be the shape size plus the negative index value
2283     if (options->squeeze_dims.size() == 1 && options->squeeze_dims[0] < 0)
2284     {
2285         int32_t dim = static_cast<int32_t>(inputTensorInfo.GetShape().GetNumDimensions()) + options->squeeze_dims[0];
2286         squeezeDim.push_back(static_cast<uint32_t>(dim));
2287     }
2288     else
2289     {
2290         squeezeDim = AsUnsignedVector(options->squeeze_dims);
2291     }
2292 
2293     armnn::TensorInfo outputTensorInfo = TfLiteParserImpl::OutputShapeOfSqueeze(squeezeDim, inputTensorInfo);
2294 
2295     CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
2296 
2297     ReshapeDescriptor reshapeDesc;
2298     reshapeDesc.m_TargetShape = outputTensorInfo.GetShape();
2299 
2300     auto outputTensorIds = GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex);
2301     m_TensorInfos[outputTensorIds[0]] = outputTensorInfo;
2302 
2303     IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
2304     ARMNN_ASSERT(layer != nullptr);
2305     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2306 
2307     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2308     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2309 
2310     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2311     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2312 }
2313 
ParseStridedSlice(size_t subgraphIndex,size_t operatorIndex)2314 void TfLiteParserImpl::ParseStridedSlice(size_t subgraphIndex, size_t operatorIndex)
2315 {
2316     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2317 
2318     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2319     CHECK_VALID_SIZE(inputs.size(), 4);
2320 
2321     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2322     CHECK_VALID_SIZE(outputs.size(), 1);
2323 
2324     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2325     const auto* options = operatorPtr->builtin_options.AsStridedSliceOptions();
2326 
2327     StridedSliceDescriptor desc;
2328     desc.m_BeginMask = options->begin_mask;
2329     desc.m_EllipsisMask = options->ellipsis_mask;
2330     desc.m_EndMask = options->end_mask;
2331     desc.m_NewAxisMask = options->new_axis_mask;
2332     desc.m_ShrinkAxisMask = options->shrink_axis_mask;
2333     desc.m_DataLayout = armnn::DataLayout::NHWC;
2334 
2335     armnn::TensorInfo beginTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
2336     BufferRawPtr beginBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2337 
2338     std::vector<int> begin(beginTensorInfo.GetNumElements());
2339     ::memcpy(begin.data(), beginBufferPtr->data.data(), beginTensorInfo.GetNumBytes());
2340 
2341     armnn::TensorInfo endTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
2342     BufferRawPtr endBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
2343 
2344     std::vector<int> end(endTensorInfo.GetNumElements());
2345     ::memcpy(end.data(), endBufferPtr->data.data(), endTensorInfo.GetNumBytes());
2346 
2347     armnn::TensorInfo strideTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 3);
2348     BufferRawPtr strideBufferPtr = GetBuffer(m_Model, inputs[3]->buffer);
2349 
2350     std::vector<int> stride(strideTensorInfo.GetNumElements());
2351     ::memcpy(stride.data(), strideBufferPtr->data.data(), strideTensorInfo.GetNumBytes());
2352 
2353     desc.m_Begin = begin;
2354     desc.m_End = end;
2355     desc.m_Stride = stride;
2356 
2357     auto layerName = fmt::format("StridedSlice:{}:{}", subgraphIndex, operatorIndex);
2358     IConnectableLayer* layer = m_Network->AddStridedSliceLayer(desc, layerName.c_str());
2359     ARMNN_ASSERT(layer != nullptr);
2360 
2361     armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
2362     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2363 
2364     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2365     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2366 
2367     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2368     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2369 }
2370 
ParseSub(size_t subgraphIndex,size_t operatorIndex)2371 void TfLiteParserImpl::ParseSub(size_t subgraphIndex, size_t operatorIndex)
2372 {
2373     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2374 
2375     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2376     const auto* options = operatorPtr->builtin_options.AsSubOptions();
2377 
2378     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2379     CHECK_VALID_SIZE(inputs.size(), 2);
2380 
2381     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2382     CHECK_VALID_SIZE(outputs.size(), 1);
2383 
2384     armnn::TensorInfo inputTensorInfo  = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2385     armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
2386 
2387     auto layerName = fmt::format("Sub:{}:{}", subgraphIndex, operatorIndex);
2388     IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Sub, layerName.c_str());
2389     ARMNN_ASSERT(layer != nullptr);
2390 
2391     TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
2392     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2393 
2394     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2395     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
2396 
2397     layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2398 
2399     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2400     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2401 }
2402 
ParseDiv(size_t subgraphIndex,size_t operatorIndex)2403 void TfLiteParserImpl::ParseDiv(size_t subgraphIndex, size_t operatorIndex)
2404 {
2405     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2406 
2407     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2408     const auto* options = operatorPtr->builtin_options.AsDivOptions();
2409 
2410     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2411     CHECK_VALID_SIZE(inputs.size(), 2);
2412 
2413     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2414     CHECK_VALID_SIZE(outputs.size(), 1);
2415 
2416     armnn::TensorInfo inputTensorInfo  = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2417     armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
2418 
2419     auto layerName = fmt::format("Div:{}:{}", subgraphIndex, operatorIndex);
2420     IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Div, layerName.c_str());
2421     ARMNN_ASSERT(layer != nullptr);
2422 
2423     TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
2424     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2425 
2426     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2427     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
2428     layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2429 
2430     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2431     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2432 }
2433 
ParseFloorDiv(size_t subgraphIndex,size_t operatorIndex)2434 void TfLiteParserImpl::ParseFloorDiv(size_t subgraphIndex, size_t operatorIndex)
2435 {
2436     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2437 
2438     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2439     CHECK_VALID_SIZE(inputs.size(), 2);
2440 
2441     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2442     CHECK_VALID_SIZE(outputs.size(), 1);
2443 
2444     armnn::TensorInfo inputTensorInfo  = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2445     armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
2446 
2447     auto layerName = fmt::format("Div:{}:{}", subgraphIndex, operatorIndex);
2448     IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Div, layerName.c_str());
2449     ARMNN_ASSERT(layer != nullptr);
2450 
2451     TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
2452     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2453 
2454     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2455     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
2456     layer = AddFusedFloorLayer(layer, 0);
2457 
2458     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2459     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2460 }
2461 
ParseAdd(size_t subgraphIndex,size_t operatorIndex)2462 void TfLiteParserImpl::ParseAdd(size_t subgraphIndex, size_t operatorIndex)
2463 {
2464     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2465 
2466     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2467     const auto* options = operatorPtr->builtin_options.AsAddOptions();
2468 
2469     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2470     CHECK_VALID_SIZE(inputs.size(), 2);
2471 
2472     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2473     CHECK_VALID_SIZE(outputs.size(), 1);
2474 
2475     armnn::TensorInfo inputTensorInfo  = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2476     armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
2477 
2478     auto layerName = fmt::format("Add:{}:{}", subgraphIndex, operatorIndex);
2479     IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Add, layerName.c_str());
2480     ARMNN_ASSERT(layer != nullptr);
2481 
2482     TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
2483     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2484 
2485     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2486     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
2487     layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2488 
2489     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2490     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2491 }
2492 
ParseMul(size_t subgraphIndex,size_t operatorIndex)2493 void TfLiteParserImpl::ParseMul(size_t subgraphIndex, size_t operatorIndex)
2494 {
2495     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2496 
2497     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2498     const auto* options = operatorPtr->builtin_options.AsMulOptions();
2499 
2500     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2501     CHECK_VALID_SIZE(inputs.size(), 2);
2502 
2503     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2504     CHECK_VALID_SIZE(outputs.size(), 1);
2505 
2506     armnn::TensorInfo inputTensorInfo  = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2507     armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
2508 
2509     auto layerName = fmt::format("Mul:{}:{}", subgraphIndex, operatorIndex);
2510     IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Mul, layerName.c_str());
2511     ARMNN_ASSERT(layer != nullptr);
2512 
2513     TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
2514     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2515 
2516     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2517     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
2518     layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2519 
2520     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2521     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2522 }
2523 
ParseMean(size_t subgraphIndex,size_t operatorIndex)2524 void TfLiteParserImpl::ParseMean(size_t subgraphIndex, size_t operatorIndex)
2525 {
2526     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2527 
2528     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2529 
2530     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2531     CHECK_VALID_SIZE(outputs.size(), 1);
2532 
2533     TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2534     TensorInfo dimTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
2535 
2536     armnn::MeanDescriptor desc;
2537     BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2538     // Get const axis value from model and set it to descriptor.
2539     if (axisBufferPtr != nullptr)
2540     {
2541         std::vector<int32_t> axisData(dimTensorInfo.GetNumElements());
2542         ::memcpy(axisData.data(), axisBufferPtr->data.data(), dimTensorInfo.GetNumBytes());
2543 
2544         // Convert the axis to unsigned int and remove duplicates.
2545         auto rank = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
2546         std::set<unsigned int> uniqueAxis;
2547         std::transform(axisData.begin(),
2548                        axisData.end(),
2549                        std::inserter(uniqueAxis, uniqueAxis.begin()),
2550                        [rank](int i)->unsigned int{
2551                            return static_cast<uint32_t>(((i + rank) % rank)); });
2552         desc.m_Axis.assign(uniqueAxis.begin(), uniqueAxis.end());
2553     }
2554     else
2555     {
2556         for (uint32_t i = 0; i < inputTensorInfo.GetNumDimensions(); ++i)
2557         {
2558             desc.m_Axis.push_back(i);
2559         }
2560     }
2561 
2562     armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
2563 
2564     desc.m_KeepDims = inputTensorInfo.GetNumDimensions() == outputTensorInfo.GetNumDimensions() ? true : false;
2565 
2566     auto layerName = fmt::format("Mean:{}:{}", subgraphIndex, operatorIndex);
2567     IConnectableLayer* layer = m_Network->AddMeanLayer(desc, layerName.c_str());
2568     ARMNN_ASSERT(layer != nullptr);
2569 
2570     outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
2571     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2572 
2573     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2574     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2575 
2576     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2577     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2578 }
2579 
ParsePad(size_t subgraphIndex,size_t operatorIndex)2580 void TfLiteParserImpl::ParsePad(size_t subgraphIndex, size_t operatorIndex)
2581 {
2582     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2583 
2584     TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2585 
2586     TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2587     CHECK_VALID_SIZE(outputs.size(), 1);
2588 
2589     armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2590     armnn::TensorInfo padTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
2591 
2592     std::vector<unsigned int> padBuffer = GetUIntBuffer(padTensorInfo, m_Model, inputs[1]->buffer);
2593 
2594     size_t step = 2;
2595     armnn::PadDescriptor desc;
2596     auto opcode = GetOpCode(m_Model, subgraphIndex, operatorIndex);
2597 
2598     if (opcode == tflite::BuiltinOperator_PAD)
2599     {
2600         CHECK_VALID_SIZE(inputs.size(), 2);
2601 
2602         if (inputTensorInfo.IsQuantized())
2603         {
2604             desc.m_PadValue = static_cast<float>(inputTensorInfo.GetQuantizationOffset());
2605         }
2606     }
2607     else if (opcode == tflite::BuiltinOperator_PADV2)
2608     {
2609         CHECK_VALID_SIZE(inputs.size(), 3);
2610 
2611         armnn::TensorInfo padValueTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
2612 
2613         if (padValueTensorInfo.GetNumElements() != 1)
2614         {
2615             ARMNN_THROW_PARSE_EXCEPTION("Multiple padding values are not supported in PADV2");
2616         }
2617         BufferRawPtr padValueBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
2618 
2619         // Get the pad value from the input tensor
2620         if (padValueBufferPtr->data.size() > 0)
2621         {
2622             switch (padValueTensorInfo.GetDataType())
2623             {
2624                 case armnn::DataType::Float32:
2625                 {
2626                     std::vector<float> padValueBuffer(padValueTensorInfo.GetNumElements());
2627                     ::memcpy(padValueBuffer.data(), padValueBufferPtr->data.data(), padValueBufferPtr->data.size());
2628                     desc.m_PadValue = padValueBuffer[0];
2629                     break;
2630                 }
2631                 case armnn::DataType::QAsymmU8:
2632                 {
2633                     std::vector<uint8_t> padValueBuffer(padValueTensorInfo.GetNumElements());
2634                     ::memcpy(padValueBuffer.data(), padValueBufferPtr->data.data(), padValueBufferPtr->data.size());
2635                     desc.m_PadValue = armnn::Dequantize<uint8_t>(padValueBuffer[0],
2636                                                                  padValueTensorInfo.GetQuantizationScale(),
2637                                                                  padValueTensorInfo.GetQuantizationOffset());
2638                     break;
2639                 }
2640                 case armnn::DataType::QAsymmS8:
2641                 case armnn::DataType::QSymmS8:
2642                 {
2643                     std::vector<int8_t> padValueBuffer(padValueTensorInfo.GetNumElements());
2644                     ::memcpy(padValueBuffer.data(), padValueBufferPtr->data.data(), padValueBufferPtr->data.size());
2645                     desc.m_PadValue = armnn::Dequantize<int8_t>(padValueBuffer[0],
2646                                                                 padValueTensorInfo.GetQuantizationScale(),
2647                                                                 padValueTensorInfo.GetQuantizationOffset());
2648                     break;
2649                 }
2650                 default: ARMNN_THROW_PARSE_EXCEPTION("Unsupported DataType");
2651             }
2652         }
2653         else if (inputTensorInfo.IsQuantized())
2654         {
2655             desc.m_PadValue = static_cast<float>(inputTensorInfo.GetQuantizationOffset());
2656         }
2657     }
2658 
2659     for (unsigned int i = 0; i < padTensorInfo.GetNumElements() / step; ++i)
2660     {
2661         desc.m_PadList.emplace_back(padBuffer[i * step], padBuffer[i * step + 1]);
2662     }
2663 
2664     auto layerName = (opcode == tflite::BuiltinOperator_PAD) ? fmt::format("Pad:{}:{}", subgraphIndex, operatorIndex)
2665             : fmt::format("PadV2:{}:{}", subgraphIndex, operatorIndex);
2666 
2667     IConnectableLayer* layer = m_Network->AddPadLayer(desc, layerName.c_str());
2668     ARMNN_ASSERT(layer != nullptr);
2669     TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
2670     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2671 
2672     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2673     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2674 
2675     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2676     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2677 }
2678 
ParseMirrorPad(size_t subgraphIndex,size_t operatorIndex)2679 void TfLiteParserImpl::ParseMirrorPad(size_t subgraphIndex, size_t operatorIndex)
2680 {
2681     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2682 
2683     TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2684     CHECK_VALID_SIZE(inputs.size(), 2);
2685 
2686     TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2687     CHECK_VALID_SIZE(outputs.size(), 1);
2688 
2689     armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2690 
2691     armnn::TensorInfo padTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
2692     BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2693 
2694     std::vector<unsigned int> padBuffer(padTensorInfo.GetNumElements());
2695     ::memcpy(padBuffer.data(), bufferPtr->data.data(), padTensorInfo.GetNumBytes());
2696 
2697     size_t step = 2;
2698     armnn::PadDescriptor desc;
2699     for (unsigned int i = 0; i < padTensorInfo.GetNumElements() / step; ++i)
2700     {
2701         desc.m_PadList.emplace_back(padBuffer[i * step], padBuffer[i * step + 1]);
2702     }
2703 
2704     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2705     const auto* options = operatorPtr->builtin_options.AsMirrorPadOptions();
2706 
2707     if (options->mode == tflite::MirrorPadMode_REFLECT)
2708     {
2709         desc.m_PaddingMode = PaddingMode::Reflect;
2710     }
2711     else if (options->mode == tflite::MirrorPadMode_SYMMETRIC)
2712     {
2713         desc.m_PaddingMode = PaddingMode::Symmetric;
2714     }
2715     else
2716     {
2717         ARMNN_THROW_PARSE_EXCEPTION("PaddingMode must be either REFLECT or SYMMETRIC");
2718     }
2719 
2720     // If padding mode is Reflect then both paddings must be no greater than inputShape(i) - 1.
2721     // If padding mode is Symmetric then both paddings must be no greater than inputShape(i).
2722     auto inputShape = inputTensorInfo.GetShape();
2723     auto padList = desc.m_PadList;
2724 
2725     const unsigned int isReflect = static_cast<unsigned int>(desc.m_PaddingMode == PaddingMode::Reflect);
2726     for(unsigned int i = 0; i < padList.size(); ++i)
2727     {
2728         if(padList.at(i).first > (inputShape[i] - isReflect) ||
2729            padList.at(i).second > (inputShape[i] - isReflect))
2730         {
2731             ARMNN_THROW_PARSE_EXCEPTION("Padding values must be less (Reflect) or "
2732                                         "equal (Symmetric) to the dimension size.");
2733         }
2734     }
2735 
2736     auto layerName = fmt::format("MirrorPad:{}:{}", subgraphIndex, operatorIndex);
2737 
2738     IConnectableLayer* layer = m_Network->AddPadLayer(desc, layerName.c_str());
2739     ARMNN_ASSERT(layer != nullptr);
2740     TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
2741     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2742 
2743     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2744     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2745 
2746     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2747     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2748 }
2749 
ParsePrelu(size_t subgraphIndex,size_t operatorIndex)2750 void TfLiteParserImpl::ParsePrelu(size_t subgraphIndex, size_t operatorIndex)
2751 {
2752     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2753 
2754     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2755     CHECK_VALID_SIZE(inputs.size(), 2);
2756 
2757     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2758     CHECK_VALID_SIZE(outputs.size(), 1);
2759 
2760     auto layerName = fmt::format("Prelu:{}:{}", subgraphIndex, operatorIndex);
2761 
2762     armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2763     armnn::TensorInfo alphaTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
2764 
2765     IConnectableLayer* layer = m_Network->AddPreluLayer(layerName.c_str());
2766     ARMNN_ASSERT(layer != nullptr);
2767 
2768 
2769     if (IsConstTensor(inputs[1]))
2770     {
2771         auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2772         armnn::IInputSlot* slot = &(layer->GetInputSlot(0));
2773         RegisterConsumerOfTensor(subgraphIndex, inputTensorIndexes[0], slot);
2774 
2775         auto alphaTensorAndData = CreateConstTensorNonPermuted(inputs[1], alphaTensorInfo,
2776                                                                inputTensorInfo.GetDataType());
2777         std::string constLayerName = fmt::format("Constant:{}", inputs[1]->name);
2778         IConnectableLayer* constLayer =
2779                     m_Network->AddConstantLayer(alphaTensorAndData.first, constLayerName.c_str());
2780         ARMNN_ASSERT(constLayer != nullptr);
2781 
2782         constLayer->GetOutputSlot(0).SetTensorInfo(alphaTensorInfo);
2783         constLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1));
2784         RegisterOutputSlots(subgraphIndex,
2785                             VIRTUAL_OPERATOR_ID,
2786                             constLayer,
2787                             { inputTensorIndexes[1] });
2788     }
2789     else
2790     {
2791         auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2792         RegisterInputSlots(subgraphIndex, operatorIndex, layer, inputTensorIndexes);
2793     }
2794 
2795     armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
2796     CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
2797     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2798 
2799     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2800     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2801 }
2802 
ParseQuantize(size_t subgraphIndex,size_t operatorIndex)2803 void TfLiteParserImpl::ParseQuantize(size_t subgraphIndex, size_t operatorIndex)
2804 {
2805     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2806 
2807     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2808     CHECK_VALID_SIZE(inputs.size(), 1);
2809 
2810     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2811     CHECK_VALID_SIZE(outputs.size(), 1);
2812 
2813     auto layerName = fmt::format("Quantize:{}:{}", subgraphIndex, operatorIndex);
2814 
2815     IConnectableLayer* layer = m_Network->AddQuantizeLayer(layerName.c_str());
2816     ARMNN_ASSERT(layer != nullptr);
2817 
2818     TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
2819     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2820 
2821     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2822     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2823 
2824     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2825     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2826 }
2827 
ParseRelu(size_t subgraphIndex,size_t operatorIndex)2828 void TfLiteParserImpl::ParseRelu(size_t subgraphIndex, size_t operatorIndex)
2829 {
2830     ParseActivation(subgraphIndex,operatorIndex, ActivationFunction::ReLu);
2831 }
2832 
ParseRelu6(size_t subgraphIndex,size_t operatorIndex)2833 void TfLiteParserImpl::ParseRelu6(size_t subgraphIndex, size_t operatorIndex)
2834 {
2835     ParseActivation(subgraphIndex,operatorIndex, ActivationFunction::BoundedReLu);
2836 }
2837 
ParseLeakyRelu(size_t subgraphIndex,size_t operatorIndex)2838 void TfLiteParserImpl::ParseLeakyRelu(size_t subgraphIndex, size_t operatorIndex)
2839 {
2840     ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::LeakyReLu);
2841 }
2842 
ParseLogistic(size_t subgraphIndex,size_t operatorIndex)2843 void TfLiteParserImpl::ParseLogistic(size_t subgraphIndex, size_t operatorIndex)
2844 {
2845     ParseActivation(subgraphIndex,operatorIndex,ActivationFunction::Sigmoid);
2846 }
2847 
ParseTanH(size_t subgraphIndex,size_t operatorIndex)2848 void TfLiteParserImpl::ParseTanH(size_t subgraphIndex, size_t operatorIndex)
2849 {
2850     ParseActivation(subgraphIndex,operatorIndex,ActivationFunction::TanH);
2851 }
2852 
ParseElu(size_t subgraphIndex,size_t operatorIndex)2853 void TfLiteParserImpl::ParseElu(size_t subgraphIndex, size_t operatorIndex)
2854 {
2855     ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::Elu);
2856 }
2857 
ParseHardSwish(size_t subgraphIndex,size_t operatorIndex)2858 void TfLiteParserImpl::ParseHardSwish(size_t subgraphIndex, size_t operatorIndex)
2859 {
2860     ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::HardSwish);
2861 }
2862 
ParseActivation(size_t subgraphIndex,size_t operatorIndex,ActivationFunction activationType)2863 void TfLiteParserImpl::ParseActivation(size_t subgraphIndex, size_t operatorIndex, ActivationFunction activationType)
2864 {
2865     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2866     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2867     IgnoreUnused(operatorPtr);
2868 
2869     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2870     CHECK_VALID_SIZE(inputs.size(), 1);
2871 
2872     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2873     CHECK_VALID_SIZE(outputs.size(), 1);
2874 
2875     auto layerName = fmt::format("Activation:");
2876     ActivationDescriptor activationDesc;
2877     activationDesc.m_Function = activationType;
2878 
2879     switch (activationType)
2880     {
2881         case ActivationFunction::ReLu:
2882         {
2883             layerName += fmt::format("RELU:{}:{}", subgraphIndex, operatorIndex);
2884             break;
2885         }
2886         case ActivationFunction::BoundedReLu:
2887         {
2888             layerName += fmt::format("RELU6:{}:{}", subgraphIndex, operatorIndex);
2889             activationDesc.m_A = 6.0f;
2890             activationDesc.m_B = 0.0f;
2891             break;
2892         }
2893         case ActivationFunction::Sigmoid:
2894         {
2895             layerName += fmt::format("SIGMOID:{}:{}", subgraphIndex, operatorIndex);
2896             break;
2897         }
2898         case ActivationFunction::TanH:
2899         {
2900             layerName += fmt::format("TANH:{}:{}", subgraphIndex, operatorIndex);
2901             activationDesc.m_A = 1.0f;
2902             activationDesc.m_B = 1.0f;
2903             break;
2904         }
2905         case ActivationFunction::LeakyReLu:
2906         {
2907             layerName += fmt::format("LEAKYRELU:{}:{}", subgraphIndex, operatorIndex);
2908             const auto* options = operatorPtr->builtin_options.AsLeakyReluOptions();
2909             activationDesc.m_A = options->alpha;
2910             break;
2911         }
2912         case ActivationFunction::Elu:
2913         {
2914             layerName += fmt::format("ELU:{}:{}", subgraphIndex, operatorIndex);
2915             activationDesc.m_A = 1.0f;
2916             break;
2917         }
2918         case ActivationFunction::HardSwish:
2919         {
2920             layerName += fmt::format("HARDSWISH:{}:{}", subgraphIndex, operatorIndex);
2921             break;
2922         }
2923         default:
2924         {
2925             throw ParseException(
2926                 fmt::format("Unexpected ActivationFunction[{}] when creating layerName {} ",
2927                             static_cast<int>(activationType), CHECK_LOCATION().AsString()));
2928         }
2929     }
2930 
2931     IConnectableLayer* const layer = m_Network->AddActivationLayer(activationDesc, layerName.c_str());
2932 
2933     TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
2934     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2935 
2936     // register the input connection slots for the layer, connections are made after all layers have been created
2937     // only the tensors for the inputs are relevant, exclude the const tensors
2938     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2939     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2940 
2941     // register the output connection slots for the layer, connections are made after all layers have been created
2942     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2943     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2944 }
OutputShapeOfReshape(const armnn::TensorInfo & inputTensorInfo,const std::vector<int32_t> & targetDimsIn)2945 armnn::TensorInfo TfLiteParserImpl::OutputShapeOfReshape(const armnn::TensorInfo& inputTensorInfo,
2946                                                          const std::vector<int32_t>& targetDimsIn)
2947 {
2948     std::vector<unsigned int> outputDims(targetDimsIn.begin(), targetDimsIn.end());
2949     const auto stretchDim = std::find(targetDimsIn.begin(), targetDimsIn.end(), -1);
2950 
2951     if (stretchDim != targetDimsIn.end())
2952     {
2953         if (std::find(std::next(stretchDim), targetDimsIn.end(), -1) != targetDimsIn.end())
2954         {
2955             throw ParseException(
2956                 fmt::format("At most one component of shape can be -1 {}", CHECK_LOCATION().AsString()));
2957         }
2958 
2959         auto targetNumElements =
2960             armnn::numeric_cast<unsigned int>(
2961                 std::accumulate(targetDimsIn.begin(), targetDimsIn.end(), -1, std::multiplies<int32_t>()));
2962 
2963         auto stretchIndex = static_cast<size_t>(std::distance(targetDimsIn.begin(), stretchDim));
2964         outputDims[stretchIndex] = inputTensorInfo.GetNumElements() / targetNumElements;
2965     }
2966 
2967     TensorShape outputShape = TensorShape(static_cast<unsigned int>(outputDims.size()), outputDims.data());
2968 
2969     TensorInfo reshapeInfo = inputTensorInfo;
2970     reshapeInfo.SetShape(outputShape);
2971 
2972     return reshapeInfo;
2973 }
2974 
ParseReshape(size_t subgraphIndex,size_t operatorIndex)2975 void TfLiteParserImpl::ParseReshape(size_t subgraphIndex, size_t operatorIndex)
2976 {
2977     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2978 
2979     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2980 
2981     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2982     CHECK_VALID_SIZE(outputs.size(), 1);
2983 
2984     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2985     const auto* options = operatorPtr->builtin_options.AsReshapeOptions();
2986     auto layerName = fmt::format("Reshape:{}:{}", subgraphIndex, operatorIndex);
2987 
2988     armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2989     armnn::TensorInfo actualOutputTensorInfo  = ToTensorInfo(outputs[0]);
2990     CheckMatchingQuantization(inputTensorInfo, actualOutputTensorInfo, layerName, "Input 0", "Output 0");
2991 
2992     // Extracting new shape for the output
2993     // There are two ways it can be passed
2994     //  * First is to define the target shape in the operator built-in options
2995     //  * Second is to pass it as a second input tensor
2996     std::vector<int32_t> targetShape;
2997     bool targetShapeFound = false;
2998     // Check if built-in options were given
2999     if (options != nullptr)
3000     {
3001         // make sure the parameter is given
3002         if (options->new_shape.empty() == false)
3003         {
3004             targetShape = options->new_shape;
3005             targetShapeFound = true;
3006         }
3007     }
3008 
3009     // If there is no built-in option given or if the built-in new_shape parameter was empty
3010     if (!targetShapeFound)
3011     {
3012         // Check for a second input tensor
3013         if (inputs.size() > 1 && inputs[1] != nullptr)
3014         {
3015             if (inputs[1]->is_variable)
3016             {
3017                 ARMNN_THROW_PARSE_EXCEPTION( "Target shapes defined in non-const input tensors is not supported");
3018             }
3019 
3020             if (inputs[1]->shape.size() != 1)
3021             {
3022                 ARMNN_THROW_PARSE_EXCEPTION("Target 'shape' input is not a 1D tensor");
3023             }
3024 
3025             if (inputs[1]->type != tflite::TensorType_INT32)
3026             {
3027                 ARMNN_THROW_PARSE_EXCEPTION("Target 'shape' input is not an int32 type");
3028             }
3029 
3030             // Extract target shape from input
3031             auto bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
3032             auto values = reinterpret_cast<const int32_t*>(bufferPtr->data.data());
3033             if (values)
3034             {
3035                 for (int i = 0; i < inputs[1]->shape[0]; ++i)
3036                 {
3037                     targetShape.push_back(values[i]);
3038                 }
3039             }
3040             else
3041             {
3042                 try
3043                 {
3044                     // We attempt to infer during Runtime.
3045                     TensorShape reshapeShapes = ToTensorInfo(inputs[1]).GetShape();
3046 
3047                     if (reshapeShapes[0] == actualOutputTensorInfo.GetNumDimensions())
3048                     {
3049                         for (unsigned int i = 0; i < actualOutputTensorInfo.GetShape().GetNumDimensions(); ++i)
3050                         {
3051                             targetShape.push_back(actualOutputTensorInfo.GetShape()[i]);
3052                         }
3053                     }
3054                     // The parser only supports shape (batch, -1) or (-1) for non-constant shape input.
3055                     else if (reshapeShapes[0] > 2)
3056                     {
3057                         throw ParseException(fmt::format("Invalid input shape '{}' in Reshape layer '{}' {}. "
3058                                                          "When inferring during runtime, the parser only supports "
3059                                                          "shape (batch, -1) or (-1) for target shape input.",
3060                                                          reshapeShapes[0],
3061                                                          layerName,
3062                                                          CHECK_LOCATION().AsString()));
3063                     }
3064                     else
3065                     {
3066                         const int32_t numInputElements = inputTensorInfo.GetNumElements();
3067                         const int32_t inputTensorShape = inputTensorInfo.GetShape()[0];
3068                         if (reshapeShapes[0] == 1)
3069                         {
3070                             targetShape = {numInputElements};
3071                         }
3072                         else if (reshapeShapes[0] == 2)
3073                         {
3074                             targetShape = {inputTensorShape, numInputElements / inputTensorShape};
3075                         }
3076                     }
3077                 }
3078                 catch (const std::exception& exc)
3079                 {
3080                     ARMNN_THROW_PARSE_EXCEPTION("Failed attempt to infer during runtime the target shape input for "
3081                                                 "Reshape operation. Reshape operator target shape input buffer data "
3082                                                 "is null. " << exc.what());
3083                 }
3084             }
3085         }
3086         else
3087         {
3088             ARMNN_THROW_PARSE_EXCEPTION("Target shape not defined in reshape parameters or input tensor. "
3089                                         "At least one method required");
3090         }
3091     }
3092 
3093     armnn::TensorInfo reshapeOutputTensorInfo =
3094         TfLiteParserImpl::OutputShapeOfReshape(inputTensorInfo, targetShape);
3095 
3096     // Check for valid input size and that reshape parameters equal output shape
3097     // The output shape can be provided to us in 2 ways:
3098     // 1. through the normal 'shape' parameter given by outputs[indx]->shape
3099     // 2. through additional parameter 'shape_signature' given by outputs[indx]->buffer.
3100     //    This parameter can sometimes contain -1 value not visible in the 'shape' parameter.
3101     const armnn::TensorShape& reshapeOutputTensorShape = reshapeOutputTensorInfo.GetShape();
3102     if (inputs.size() > 1 && !CheckShape(reshapeOutputTensorShape, outputs[0]->shape))
3103     {
3104         // Attempt to extract output shape from secondary 'shape_signature'
3105         // parameter and try to CheckShape() with this param.
3106         std::vector<int32_t> secondaryOutputTargetShape = outputs[0]->shape_signature;
3107 
3108         // if outputs[0]->shape_signature contain a -1 value, we need to compute its actual value
3109         // from reshape input in order to correctly verify reshape parameters equal output shape
3110         armnn::TensorInfo secondaryReshapeOutputTensorInfo =
3111             TfLiteParserImpl::OutputShapeOfReshape(inputTensorInfo, secondaryOutputTargetShape);
3112 
3113         if (!CheckShape(reshapeOutputTensorShape, secondaryReshapeOutputTensorInfo.GetShape()))
3114         {
3115             std::stringstream ss;
3116             ss << "New shape defined in reshape parameters "
3117                << reshapeOutputTensorShape
3118                << " does not equal output shape "
3119                << actualOutputTensorInfo.GetShape()
3120                << ": "
3121                << CHECK_LOCATION().AsString();
3122             throw ParseException(ss.str());
3123         }
3124     }
3125     auto outputTensorIds = GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex);
3126 
3127     ReshapeDescriptor reshapeDesc;
3128     reshapeDesc.m_TargetShape = reshapeOutputTensorInfo.GetShape();
3129     m_TensorInfos[outputTensorIds[0]] = reshapeOutputTensorInfo;
3130 
3131     IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
3132     ARMNN_ASSERT(layer != nullptr);
3133     layer->GetOutputSlot(0).SetTensorInfo(reshapeOutputTensorInfo);
3134 
3135     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3136     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3137 
3138     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3139     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3140 }
3141 
ParseResizeBilinear(size_t subgraphIndex,size_t operatorIndex)3142 void TfLiteParserImpl::ParseResizeBilinear(size_t subgraphIndex, size_t operatorIndex)
3143 {
3144     ParseResize(subgraphIndex, operatorIndex, ResizeMethod::Bilinear);
3145 }
3146 
ParseResizeNearestNeighbor(size_t subgraphIndex,size_t operatorIndex)3147 void TfLiteParserImpl::ParseResizeNearestNeighbor(size_t subgraphIndex, size_t operatorIndex)
3148 {
3149     ParseResize(subgraphIndex, operatorIndex, ResizeMethod::NearestNeighbor);
3150 }
3151 
ParseResize(size_t subgraphIndex,size_t operatorIndex,ResizeMethod resizeMethod)3152 void TfLiteParserImpl::ParseResize(size_t subgraphIndex, size_t operatorIndex, ResizeMethod resizeMethod)
3153 {
3154     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3155 
3156     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3157     CHECK_VALID_SIZE(inputs.size(), 2);
3158 
3159     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3160     CHECK_VALID_SIZE(outputs.size(), 1);
3161 
3162     armnn::TensorInfo sizeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
3163 
3164     // Data for the parsed tensor args (size) must be stored locally.
3165     std::vector<int32_t> sizeTensorData(sizeTensorInfo.GetNumElements());
3166 
3167     BufferRawPtr sizeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
3168     ::memcpy(sizeTensorData.data(), sizeBufferPtr->data.data(), sizeTensorInfo.GetNumBytes());
3169 
3170     ResizeDescriptor desc;
3171     desc.m_Method       = resizeMethod;
3172     desc.m_TargetHeight = static_cast<uint32_t> (sizeTensorData[0]);
3173     desc.m_TargetWidth  = static_cast<uint32_t> (sizeTensorData[1]);
3174     desc.m_DataLayout   = armnn::DataLayout::NHWC;
3175 
3176     auto layerName = fmt::format("Resize:");
3177 
3178     switch (resizeMethod)
3179     {
3180         case ResizeMethod::Bilinear:
3181         {
3182             layerName += fmt::format("BILINEAR:{}:{}", subgraphIndex, operatorIndex);
3183 
3184             const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3185             const auto * options     = operatorPtr->builtin_options.AsResizeBilinearOptions();
3186 
3187             desc.m_AlignCorners = options->align_corners;
3188             break;
3189         }
3190         case ResizeMethod::NearestNeighbor:
3191         {
3192             layerName += fmt::format("NEARESTNEIGHBOR:{}:{}", subgraphIndex, operatorIndex);
3193             break;
3194         }
3195         default:
3196         {
3197             throw ParseException(
3198                 fmt::format("Unexpected ResizeMethod[{}] when creating layerName {} ",
3199                             static_cast<int>(resizeMethod), CHECK_LOCATION().AsString()));
3200         }
3201     }
3202 
3203     TensorInfo inputTensorInfo  = InputTensorInfo(subgraphIndex, operatorIndex, 0);
3204 
3205     IConnectableLayer* layer = m_Network->AddResizeLayer(desc, layerName.c_str());
3206     ARMNN_ASSERT(layer != nullptr);
3207     TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
3208     CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
3209     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3210 
3211     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3212     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3213 
3214     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3215     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
3216 }
3217 
ParseConcatenation(size_t subgraphIndex,size_t operatorIndex)3218 void TfLiteParserImpl::ParseConcatenation(size_t subgraphIndex, size_t operatorIndex)
3219 {
3220     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3221 
3222     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3223     const auto* options = operatorPtr->builtin_options.AsConcatenationOptions();
3224 
3225     CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
3226 
3227     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3228     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3229     auto inputTensorIds = GetInputTensorIds(m_Model, subgraphIndex, operatorIndex);
3230 
3231     CHECK_VALID_SIZE(outputs.size(), 1);
3232 
3233     unsigned int numConcatView = static_cast<unsigned int>(inputs.size());
3234     uint32_t inputRank = InputTensorInfo(subgraphIndex, operatorIndex, 0).GetNumDimensions();
3235 
3236     const unsigned int concatDimInput = static_cast<unsigned int>(
3237             (static_cast<int>(inputRank) + options->axis) % static_cast<int>(inputRank));
3238 
3239     OriginsDescriptor concatDescriptor(static_cast<uint32_t>(numConcatView), inputRank);
3240     concatDescriptor.SetConcatAxis(concatDimInput);
3241     unsigned int mergeDimOrigin = 0;
3242 
3243     for (unsigned int viewIndex = 0; viewIndex < numConcatView; ++viewIndex)
3244     {
3245         TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, viewIndex);
3246 
3247         // This set up concatDescriptor view origin
3248         armnnUtils::ProcessConcatInputTensorInfo(
3249                 inputTensorInfo, concatDescriptor, concatDimInput, viewIndex, mergeDimOrigin);
3250     }
3251 
3252     auto layerName = fmt::format("Concatenation:{}:{}", subgraphIndex, operatorIndex);
3253 
3254     IConnectableLayer* layer = m_Network->AddConcatLayer(concatDescriptor, layerName.c_str());
3255     ARMNN_ASSERT(layer != nullptr);
3256     TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {});
3257     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3258 
3259     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3260     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes});
3261 
3262     // add fused activation layer
3263     layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
3264 
3265     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3266     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3267 }
3268 
ParseFullyConnected(size_t subgraphIndex,size_t operatorIndex)3269 void TfLiteParserImpl::ParseFullyConnected(size_t subgraphIndex, size_t operatorIndex)
3270 {
3271     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3272 
3273     const auto& operatorRfr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3274     const auto options = operatorRfr->builtin_options.AsFullyConnectedOptions();
3275 
3276     CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
3277 
3278     FullyConnectedDescriptor desc;
3279     desc.m_BiasEnabled = false;
3280     desc.m_TransposeWeightMatrix = true;
3281 
3282     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3283     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3284     CHECK_VALID_SIZE(outputs.size(), 1);
3285 
3286     armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
3287 
3288     // Fully Connected Layer accepts two dimensional weights input
3289     int32_t weightsDimension = static_cast<int32_t>(filterTensorInfo.GetNumDimensions());
3290     if (weightsDimension != 2)
3291     {
3292         throw ParseException(
3293             fmt::format("Dimension {} for Fully Connected weights is not supported by Armnn. "
3294                         "Node {}",
3295                         weightsDimension,
3296                         CHECK_LOCATION().AsString()));
3297     }
3298 
3299     armnn::IConnectableLayer* layer = nullptr;
3300     auto layerName = fmt::format("FullyConnected:{}:{}", subgraphIndex, operatorIndex);
3301 
3302     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3303     // Add the first input tensor to the registration list
3304     std::vector<unsigned int> tensorIndexesToRegister = {inputTensorIndexes[0]};
3305     armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
3306 
3307     desc.m_ConstantWeights = IsConstTensor(inputs[1]);
3308 
3309     // Add the weights input to the registration list, constant layers will be added by SetupConstantLayers if constant.
3310     tensorIndexesToRegister.emplace_back(inputTensorIndexes[1]);
3311 
3312     if (ShouldConstantTensorBeConverted(inputs[1], inputTensorInfo.GetDataType(), filterTensorInfo.GetDataType()))
3313     {
3314         m_ConstantsToDequantize.emplace_back(inputs[1]->buffer);
3315     }
3316 
3317     if (inputs.size() == 3)
3318     {
3319         desc.m_BiasEnabled = true;
3320         armnn::TensorInfo biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
3321 
3322         // Add the biases input to the registration list, constant layer will be added by SetupConstantLayers.
3323         tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
3324 
3325         if (ShouldConstantTensorBeConverted(inputs[2], inputTensorInfo.GetDataType(), biasTensorInfo.GetDataType()))
3326         {
3327             m_ConstantsToDequantize.emplace_back(inputs[2]->buffer);
3328         }
3329     }
3330 
3331     // Filters and biases are always passed to fully connected as inputs
3332     layer = m_Network->AddFullyConnectedLayer(desc, layerName.c_str());
3333 
3334     ARMNN_ASSERT(layer != nullptr);
3335 
3336     unsigned int startingSlotIndex = 0;
3337     if (inputTensorInfo.GetNumDimensions() > 2)
3338     {
3339         // Add reshape to flatten to 2D [batch_size, input_size],
3340         // where "input_size" corresponds to the number of inputs to the layer,
3341         // matching the second dimension of weights,
3342         // and "batch_size" is calculated by dividing the number of elements by "input_size".
3343         std::vector<unsigned int> reshapedDimensions(2);
3344         reshapedDimensions[1] = filterTensorInfo.GetShape()[1];
3345         reshapedDimensions[0] = inputTensorInfo.GetNumElements() / reshapedDimensions[1];
3346 
3347         if (inputTensorInfo.GetNumElements() % reshapedDimensions[1] != 0)
3348         {
3349             throw ParseException(
3350                     fmt::format("Failed to deduce input tensor shape from filter size {} {}",
3351                                 reshapedDimensions[1],
3352                                 CHECK_LOCATION().AsString()));
3353         }
3354 
3355         armnn::TensorInfo reshapedTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
3356         reshapedTensorInfo.SetShape(armnn::TensorShape{ 2, reshapedDimensions.data() });
3357         inputTensorInfo = reshapedTensorInfo;
3358 
3359         std::string reshapeLayerName = fmt::format("Reshape_for:{}", layer->GetName());
3360         armnn::ReshapeDescriptor reshapeDescriptor;
3361         reshapeDescriptor.m_TargetShape = reshapedTensorInfo.GetShape();
3362         armnn::IConnectableLayer* reshapeLayer = m_Network->AddReshapeLayer(reshapeDescriptor,
3363                                                                             reshapeLayerName.c_str());
3364 
3365         reshapeLayer->GetOutputSlot(0).SetTensorInfo(reshapedTensorInfo);
3366         reshapeLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
3367 
3368         RegisterInputSlots(subgraphIndex, operatorIndex, reshapeLayer, {inputTensorIndexes[0]});
3369         // Fc layer connects to the reshape layer, so we skip the first input slot when registering fc's input slots
3370         tensorIndexesToRegister.erase(tensorIndexesToRegister.begin());
3371         startingSlotIndex = 1;
3372     }
3373 
3374     RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister, startingSlotIndex);
3375 
3376     armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromShapes(subgraphIndex, operatorIndex, layer, 0,
3377                                                                     { inputTensorInfo.GetShape(),
3378                                                                       filterTensorInfo.GetShape() });
3379 
3380     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3381 
3382     if (outputTensorInfo.GetNumDimensions() > 2)
3383     {
3384         // Calculate reshape to flatten to 2D [batch_size, input_size]
3385         std::vector<unsigned int> reshapedDimensions(2);
3386         reshapedDimensions[1] = filterTensorInfo.GetShape()[0];
3387         reshapedDimensions[0] = outputTensorInfo.GetNumElements() / reshapedDimensions[1];
3388         armnn::TensorInfo reshapedOutputTensorInfo = outputTensorInfo;
3389         if (outputTensorInfo.GetNumElements() % reshapedDimensions[1] != 0)
3390         {
3391             throw ParseException(
3392                     fmt::format("Failed to deduce output tensor shape from filter size {} {}",
3393                                 reshapedDimensions[1],
3394                                 CHECK_LOCATION().AsString()));
3395         }
3396         reshapedOutputTensorInfo.SetShape(armnn::TensorShape{ 2, reshapedDimensions.data() });
3397         layer->GetOutputSlot(0).SetTensorInfo(reshapedOutputTensorInfo);
3398 
3399         std::string reshapeLayerName = fmt::format("ExpandDims:{}:{}", subgraphIndex, operatorIndex);
3400         layer = AddReshapeLayer(layer, 0, reshapeLayerName, outputTensorInfo);
3401     }
3402 
3403     // we need to add the activation layer and fortunately we don't need to care about the data layout
3404     armnn::IConnectableLayer* fusedActivationLayer = AddFusedActivationLayer(layer, 0,
3405                                                                              options->fused_activation_function);
3406 
3407     // register the output connection slots for the layer, connections are made after all layers have been created
3408     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3409     RegisterOutputSlots(subgraphIndex, operatorIndex, fusedActivationLayer, {outputTensorIndexes[0]});
3410 
3411     m_TensorInfos[outputTensorIndexes[0]] = layer->GetOutputSlot(0).GetTensorInfo();
3412 }
3413 
ParseDetectionPostProcess(size_t subgraphIndex,size_t operatorIndex)3414 void TfLiteParserImpl::ParseDetectionPostProcess(size_t subgraphIndex, size_t operatorIndex)
3415 {
3416     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3417 
3418     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3419 
3420     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3421     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3422     CHECK_VALID_SIZE(outputs.size(), 4);
3423 
3424     // Obtain custom options from flexbuffers
3425     auto custom_options = operatorPtr->custom_options;
3426     const flexbuffers::Map& m = flexbuffers::GetRoot(custom_options.data(), custom_options.size()).AsMap();
3427 
3428     // Obtain descriptor information from tf lite
3429     DetectionPostProcessDescriptor desc;
3430     desc.m_MaxDetections           = m["max_detections"].AsUInt32();
3431     desc.m_MaxClassesPerDetection  = m["max_classes_per_detection"].AsUInt32();
3432     desc.m_NmsScoreThreshold       = m["nms_score_threshold"].AsFloat();
3433     desc.m_NmsIouThreshold         = m["nms_iou_threshold"].AsFloat();
3434     desc.m_NumClasses              = m["num_classes"].AsUInt32();
3435     desc.m_ScaleH                  = m["h_scale"].AsFloat();
3436     desc.m_ScaleW                  = m["w_scale"].AsFloat();
3437     desc.m_ScaleX                  = m["x_scale"].AsFloat();
3438     desc.m_ScaleY                  = m["y_scale"].AsFloat();
3439 
3440     if (!(m["use_regular_nms"].IsNull()))
3441     {
3442         desc.m_UseRegularNms       = m["use_regular_nms"].AsBool();
3443     }
3444     if (!(m["detections_per_class"].IsNull()))
3445     {
3446         desc.m_DetectionsPerClass  = m["detections_per_class"].AsUInt32();
3447     }
3448 
3449     if (desc.m_NmsIouThreshold <= 0.0f || desc.m_NmsIouThreshold > 1.0f)
3450     {
3451         throw InvalidArgumentException("DetectionPostProcessTFLiteParser: Intersection over union threshold "
3452                                        "must be positive and less than or equal to 1.");
3453     }
3454 
3455     armnn::TensorInfo anchorTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
3456     auto anchorTensorAndData = CreateConstTensorNonPermuted(inputs[2], anchorTensorInfo);
3457 
3458     auto layerName = fmt::format("DetectionPostProcess:{}:{}", subgraphIndex, operatorIndex);
3459     IConnectableLayer* layer = m_Network->AddDetectionPostProcessLayer(desc, anchorTensorAndData,
3460                                                                        layerName.c_str());
3461 
3462     ARMNN_ASSERT(layer != nullptr);
3463 
3464     // The model does not specify the output shapes.
3465     // The output shapes are calculated from the max_detection and max_classes_per_detection.
3466     unsigned int numDetectedBox = desc.m_MaxDetections * desc.m_MaxClassesPerDetection;
3467     m_OverriddenOutputShapes.push_back({ 1, numDetectedBox, 4 });
3468     m_OverriddenOutputShapes.push_back({ 1, numDetectedBox });
3469     m_OverriddenOutputShapes.push_back({ 1, numDetectedBox });
3470     m_OverriddenOutputShapes.push_back({ 1 });
3471 
3472     for (unsigned int i = 0 ; i < outputs.size() ; ++i)
3473     {
3474         armnn::TensorInfo detectionBoxOutputTensorInfo = ToTensorInfo(outputs[i], m_OverriddenOutputShapes[i]);
3475         layer->GetOutputSlot(i).SetTensorInfo(detectionBoxOutputTensorInfo);
3476     }
3477 
3478     // Register the input connection slots for the layer, connections are made after all layers have been created
3479     // only the tensors for the inputs are relevant, exclude the const tensors
3480     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3481     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
3482 
3483     // Register the output connection slots for the layer, connections are made after all layers have been created
3484     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3485     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0],
3486                                                               outputTensorIndexes[1],
3487                                                               outputTensorIndexes[2],
3488                                                               outputTensorIndexes[3]});
3489 }
3490 
3491 /// The TfLite Pack operator is equivalent to the ArmNN Stack operator
ParsePack(size_t subgraphIndex,size_t operatorIndex)3492 void TfLiteParserImpl::ParsePack(size_t subgraphIndex, size_t operatorIndex)
3493 {
3494     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3495 
3496     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3497     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3498     CHECK_VALID_SIZE(outputs.size(), 1);
3499 
3500     if (inputs.size() < 1)
3501     {
3502         throw ParseException("Pack must have at least one input.");
3503     }
3504 
3505     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3506     const auto* options = operatorPtr->builtin_options.AsPackOptions();
3507 
3508     StackDescriptor desc;
3509     desc.m_Axis = static_cast<uint32_t>(options->axis);
3510     desc.m_NumInputs = static_cast<uint32_t>(inputs.size());
3511 
3512     // Use the tensor shape of the first input as the "correct" input shape in the descriptor
3513     armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
3514     desc.m_InputShape = inputTensorInfo.GetShape();
3515 
3516     auto layerName = fmt::format("Pack:{}:{}", subgraphIndex, operatorIndex);
3517     IConnectableLayer* layer = m_Network->AddStackLayer(desc, layerName.c_str());
3518 
3519     ARMNN_ASSERT(layer != nullptr);
3520 
3521     armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {});
3522     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3523 
3524     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3525     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes});
3526 
3527     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3528     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3529 }
3530 
ParseUnidirectionalSequenceLSTM(size_t subgraphIndex,size_t operatorIndex)3531 void TfLiteParserImpl::ParseUnidirectionalSequenceLSTM(size_t subgraphIndex, size_t operatorIndex)
3532 {
3533     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3534 
3535     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3536     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3537 
3538     if (inputs.size() < 2)
3539     {
3540         throw ParseException("UnidirectionalSequenceLSTM must have at least 2 input.");
3541     }
3542 
3543     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3544     const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex];
3545     const auto nodeParams = operatorPtr->builtin_options.AsUnidirectionalSequenceLSTMOptions();
3546     CHECK_SUPPORTED_FUSED_ACTIVATION(nodeParams, subgraphIndex, operatorIndex);
3547     auto inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
3548     auto outputTensorInfo = ToTensorInfo(outputs[0]);
3549 
3550     // Set the params structure for the AddUnidirectionalSequenceLstmLayer call
3551     // Please refer to each operand at
3552     // https://www.tensorflow.org/mlir/tfl_ops#tflunidirectional_sequence_lstm_tflunidirectionalsequencelstmop
3553     armnn::LstmInputParams params;
3554 
3555     if (IsOptionalOperandPresent(operatorPtr->inputs[1]))
3556     {
3557         params.m_InputToInputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[1]].get(),
3558                                                             inputTensorInfo).first;
3559     }
3560 
3561     params.m_InputToForgetWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[2]].get(),
3562                                                          inputTensorInfo).first;
3563     params.m_InputToCellWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[3]].get(),
3564                                                        inputTensorInfo).first;
3565     params.m_InputToOutputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[4]].get(),
3566                                                          inputTensorInfo).first;
3567 
3568     // Recurrent weight tensors of size {n_cell, n_output}
3569     if (IsOptionalOperandPresent(operatorPtr->inputs[5]))
3570     {
3571         params.m_RecurrentToInputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[5]].get(),
3572                                                                 inputTensorInfo).first;
3573     }
3574 
3575     params.m_RecurrentToForgetWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[6]].get(),
3576                                                              inputTensorInfo).first;
3577     params.m_RecurrentToCellWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[7]].get(),
3578                                                            inputTensorInfo).first;
3579     params.m_RecurrentToOutputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[8]].get(),
3580                                                              inputTensorInfo).first;
3581 
3582     // Peephole weights tensors of size {n_cell}, representing a diagonal matrix.
3583     if (IsOptionalOperandPresent(operatorPtr->inputs[9]))
3584     {
3585         params.m_CellToInputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[9]].get(),
3586                                                            inputTensorInfo).first;
3587     }
3588 
3589     if (IsOptionalOperandPresent(operatorPtr->inputs[10]))
3590     {
3591         params.m_CellToForgetWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[10]].get(),
3592                                                             inputTensorInfo).first;
3593     }
3594 
3595     if (IsOptionalOperandPresent(operatorPtr->inputs[11]))
3596     {
3597         params.m_CellToOutputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[11]].get(),
3598                                                             inputTensorInfo).first;
3599     }
3600 
3601     // Gates bias tensors of size {n_cell}
3602     if (IsOptionalOperandPresent(operatorPtr->inputs[12]))
3603     {
3604         params.m_InputGateBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[12]].get(),
3605                                                       inputTensorInfo).first;
3606     }
3607 
3608     params.m_ForgetGateBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[13]].get(),
3609                                                    inputTensorInfo).first;
3610     params.m_CellBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[14]].get(),
3611                                              inputTensorInfo).first;
3612     params.m_OutputGateBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[15]].get(),
3613                                                    inputTensorInfo).first;
3614 
3615     // Projection weight tensor of size {n_output, n_cell}
3616     if (IsOptionalOperandPresent(operatorPtr->inputs[16]))
3617     {
3618         params.m_ProjectionWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[16]].get(),
3619                                                           inputTensorInfo).first;
3620     }
3621     // Projection bias tensor of size {n_output}
3622     if (IsOptionalOperandPresent(operatorPtr->inputs[17]))
3623     {
3624         params.m_ProjectionBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[17]].get(),
3625                                                        inputTensorInfo).first;
3626     }
3627 
3628     // These state tensors are defined as variable tensors, and will be modified by this op.
3629     armnn::TensorInfo outputStateInInfo = ToTensorInfo(subgraphPtr->tensors[operatorPtr->inputs[18]].get());
3630     m_ConstantsToBeCreated.push_back(operatorPtr->inputs[18]);
3631     armnn::TensorInfo cellStateInInfo = ToTensorInfo(subgraphPtr->tensors[operatorPtr->inputs[19]].get());
3632     m_ConstantsToBeCreated.push_back(operatorPtr->inputs[19]);
3633 
3634     // Layer norm coefficient tensors of size {n_cell}, representing a diagonal matrix.
3635     if (inputs.size() >= 21 && IsOptionalOperandPresent(operatorPtr->inputs[20]))
3636     {
3637         params.m_InputLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[20]].get(),
3638                                                               inputTensorInfo).first;
3639     }
3640 
3641     if (inputs.size() >= 22 && IsOptionalOperandPresent(operatorPtr->inputs[21]))
3642     {
3643         params.m_ForgetLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[21]].get(),
3644                                                                inputTensorInfo).first;
3645     }
3646 
3647     if (inputs.size() >= 23 && IsOptionalOperandPresent(operatorPtr->inputs[22]))
3648     {
3649         params.m_CellLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[22]].get(),
3650                                                              inputTensorInfo).first;
3651     }
3652 
3653     if (inputs.size() >= 24 && IsOptionalOperandPresent(operatorPtr->inputs[23]))
3654     {
3655         params.m_OutputLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[23]].get(),
3656                                                                inputTensorInfo).first;
3657     }
3658 
3659     // set the layer descriptor
3660     armnn::UnidirectionalSequenceLstmDescriptor desc;
3661     desc.m_ActivationFunc    = nodeParams->fused_activation_function;
3662     desc.m_ClippingThresCell = nodeParams->cell_clip;
3663     desc.m_ClippingThresProj = nodeParams->proj_clip;
3664     desc.m_CifgEnabled       = (params.m_InputToInputWeights == nullptr
3665                                 || params.m_RecurrentToInputWeights == nullptr
3666                                 || params.m_InputGateBias == nullptr);
3667     desc.m_PeepholeEnabled   = (params.m_CellToForgetWeights != nullptr || params.m_CellToOutputWeights != nullptr);
3668     desc.m_ProjectionEnabled = (params.m_ProjectionWeights != nullptr);
3669     desc.m_LayerNormEnabled  = (params.m_InputLayerNormWeights != nullptr
3670                                 || params.m_ForgetLayerNormWeights != nullptr
3671                                 || params.m_CellLayerNormWeights != nullptr
3672                                 || params.m_OutputLayerNormWeights != nullptr);
3673     desc.m_TimeMajor         = nodeParams->time_major;
3674 
3675     if (operatorPtr->intermediates.size() > 3 && desc.m_LayerNormEnabled)
3676     {
3677         auto inputIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[0]].get(),
3678                                                       inputTensorInfo).first;
3679         auto inputIntermediateTensorInfo = inputIntermediate->GetInfo();
3680         desc.m_InputIntermediateScale = inputIntermediateTensorInfo.GetQuantizationScale();
3681 
3682         auto forgetIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[1]].get(),
3683                                                       inputTensorInfo).first;
3684         auto forgetIntermediateTensorInfo = forgetIntermediate->GetInfo();
3685         desc.m_ForgetIntermediateScale = forgetIntermediateTensorInfo.GetQuantizationScale();
3686 
3687         auto cellIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[2]].get(),
3688                                                       inputTensorInfo).first;
3689         auto cellIntermediateTensorInfo = cellIntermediate->GetInfo();
3690         desc.m_CellIntermediateScale = cellIntermediateTensorInfo.GetQuantizationScale();
3691 
3692         auto outputIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[3]].get(),
3693                                                       inputTensorInfo).first;
3694         auto outputIntermediateTensorInfo = outputIntermediate->GetInfo();
3695         desc.m_OutputIntermediateScale = outputIntermediateTensorInfo.GetQuantizationScale();
3696     }
3697     else
3698     {
3699         float defaultIntermediate = std::pow(2, -12);
3700         desc.m_InputIntermediateScale = defaultIntermediate;
3701         desc.m_ForgetIntermediateScale = defaultIntermediate;
3702         desc.m_CellIntermediateScale = defaultIntermediate;
3703         desc.m_OutputIntermediateScale = defaultIntermediate;
3704     }
3705 
3706     if (operatorPtr->intermediates.size() > 4)
3707     {
3708         auto hiddentensor = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[4]].get(),
3709                                                  inputTensorInfo).first;
3710 
3711         desc.m_HiddenStateScale = hiddentensor->GetInfo().GetQuantizationScale();
3712         desc.m_HiddenStateZeroPoint = hiddentensor->GetInfo().GetQuantizationOffset();
3713     }
3714     unsigned int batchSize  = inputTensorInfo.GetShape()[0];
3715     unsigned int outputSize = outputTensorInfo.GetShape()[2];
3716     unsigned int numUnits   = cellStateInInfo.GetShape()[1];
3717 
3718     armnn::DataType dataType = inputTensorInfo.GetDataType();
3719     float qScale = inputTensorInfo.GetQuantizationScale();
3720     float qOffset = inputTensorInfo.GetQuantizationOffset();
3721 
3722     armnn::TensorInfo scratchBufferTensorInfo({batchSize, numUnits * 3}, dataType, qScale, qOffset);
3723     if (!desc.m_CifgEnabled)
3724     {
3725         scratchBufferTensorInfo = armnn::TensorInfo({batchSize, numUnits * 4}, dataType, qScale, qOffset);
3726     }
3727     armnn::TensorInfo cellStateOutTensorInfo({batchSize, numUnits},
3728                                              cellStateInInfo.GetDataType(),
3729                                              cellStateInInfo.GetQuantizationScale(),
3730                                              cellStateInInfo.GetQuantizationOffset());
3731     armnn::TensorInfo outputStateOutTensorInfo({batchSize, outputSize}, dataType, qScale, qOffset);
3732 
3733     armnn::LstmInputParamsInfo paramsInfo;
3734     paramsInfo.m_InputToForgetWeights     = &(params.m_InputToForgetWeights->GetInfo());
3735     paramsInfo.m_InputToCellWeights       = &(params.m_InputToCellWeights->GetInfo());
3736     paramsInfo.m_InputToOutputWeights     = &(params.m_InputToOutputWeights->GetInfo());
3737     paramsInfo.m_RecurrentToForgetWeights = &(params.m_RecurrentToForgetWeights->GetInfo());
3738     paramsInfo.m_RecurrentToCellWeights   = &(params.m_RecurrentToCellWeights->GetInfo());
3739     paramsInfo.m_RecurrentToOutputWeights = &(params.m_RecurrentToOutputWeights->GetInfo());
3740     paramsInfo.m_ForgetGateBias           = &(params.m_ForgetGateBias->GetInfo());
3741     paramsInfo.m_CellBias                 = &(params.m_CellBias->GetInfo());
3742     paramsInfo.m_OutputGateBias           = &(params.m_OutputGateBias->GetInfo());
3743 
3744     if (!desc.m_CifgEnabled)
3745     {
3746         paramsInfo.m_InputToInputWeights = &(params.m_InputToInputWeights->GetInfo());
3747         paramsInfo.m_RecurrentToInputWeights = &(params.m_RecurrentToInputWeights->GetInfo());
3748         if (params.m_CellToInputWeights != nullptr)
3749         {
3750             paramsInfo.m_CellToInputWeights = &(params.m_CellToInputWeights->GetInfo());
3751         }
3752         paramsInfo.m_InputGateBias = &(params.m_InputGateBias->GetInfo());
3753     }
3754 
3755     if (desc.m_ProjectionEnabled)
3756     {
3757         paramsInfo.m_ProjectionWeights = &(params.m_ProjectionWeights->GetInfo());
3758         if (params.m_ProjectionBias != nullptr)
3759         {
3760             paramsInfo.m_ProjectionBias = &(params.m_ProjectionBias->GetInfo());
3761         }
3762     }
3763 
3764     if (desc.m_PeepholeEnabled)
3765     {
3766         paramsInfo.m_CellToForgetWeights = &(params.m_CellToForgetWeights->GetInfo());
3767         paramsInfo.m_CellToOutputWeights = &(params.m_CellToOutputWeights->GetInfo());
3768     }
3769 
3770     if (desc.m_LayerNormEnabled)
3771     {
3772         if(!desc.m_CifgEnabled)
3773         {
3774             paramsInfo.m_InputLayerNormWeights = &(params.m_InputLayerNormWeights->GetInfo());
3775         }
3776         paramsInfo.m_ForgetLayerNormWeights = &(params.m_ForgetLayerNormWeights->GetInfo());
3777         paramsInfo.m_CellLayerNormWeights = &(params.m_CellLayerNormWeights->GetInfo());
3778         paramsInfo.m_OutputLayerNormWeights = &(params.m_OutputLayerNormWeights->GetInfo());
3779     }
3780 
3781     auto layerName = fmt::format("UnidirectionalSequenceLSTM:{}:{}", subgraphIndex, operatorIndex);
3782     armnn::IConnectableLayer* layer = m_Network->AddUnidirectionalSequenceLstmLayer(desc, params);
3783     ARMNN_ASSERT(layer != nullptr);
3784 
3785     // register the input connection slots for the layer, connections are made after all layers have been created
3786     // only the tensors for the inputs are relevant, exclude the const tensors
3787     auto inputTensorIndexes = AsUnsignedVector({operatorPtr->inputs[0],
3788                                operatorPtr->inputs[18],
3789                                operatorPtr->inputs[19]});
3790     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0],
3791                                                              inputTensorIndexes[1],
3792                                                              inputTensorIndexes[2]});
3793 
3794     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3795 
3796     layer->GetOutputSlot(0).SetTensorInfo(outputStateOutTensorInfo);
3797     layer->GetOutputSlot(1).SetTensorInfo(cellStateOutTensorInfo);
3798     layer->GetOutputSlot(2).SetTensorInfo(outputTensorInfo);
3799 
3800     unsigned int tensorIndex = outputTensorIndexes[0];
3801     armnn::IOutputSlot* slot = &(layer->GetOutputSlot(2));
3802     RegisterProducerOfTensor(subgraphIndex, tensorIndex, slot);
3803 }
3804 
ParseUnpack(size_t subgraphIndex,size_t operatorIndex)3805 void TfLiteParserImpl::ParseUnpack(size_t subgraphIndex, size_t operatorIndex)
3806 {
3807     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3808 
3809     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3810     const auto* options = operatorPtr->builtin_options.AsUnpackOptions();
3811 
3812     // This unpackAxis indicates the axis to unpack
3813     const unsigned int unpackAxis = CHECKED_NON_NEGATIVE(options->axis);
3814 
3815     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3816     CHECK_VALID_SIZE(inputs.size(), 1);
3817 
3818     armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
3819 
3820     if (unpackAxis >= inputTensorInfo.GetNumDimensions())
3821     {
3822         throw ParseException(
3823                 fmt::format("The unpack axis: {} cannot be greater than or equal to "
3824                             "the number of input dimension {} {}",
3825                             unpackAxis,
3826                             inputTensorInfo.GetNumDimensions(),
3827                             CHECK_LOCATION().AsString()));
3828     }
3829 
3830     unsigned int unpackNum = CHECKED_NON_NEGATIVE(options->num);
3831     // If num is not defined, automatically infer from the length of the dimension axis.
3832     if(unpackNum == 0)
3833     {
3834         unpackNum = inputTensorInfo.GetShape()[unpackAxis];
3835     }
3836 
3837     // If unpack number cannot be inferred and is still zero, throw ParseException.
3838     if(unpackNum == 0)
3839     {
3840         throw ParseException("Number to unpack must greater than zero.");
3841     }
3842 
3843     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3844     CHECK_VALID_SIZE(outputs.size(), unpackNum);
3845 
3846     auto inputDimSize = inputTensorInfo.GetNumDimensions();
3847     std::vector<unsigned int> unpackDimSizes(inputDimSize);
3848 
3849     // Add current input shape to unpackDimSizes
3850     for (unsigned int i = 0; i < inputDimSize; ++i)
3851     {
3852         unpackDimSizes[i] = inputTensorInfo.GetShape()[i];
3853     }
3854 
3855     if (unpackDimSizes[unpackAxis] != unpackNum)
3856     {
3857         throw ParseException("Number to unpack must be the same as length of the dimension to "
3858                              "unpack along.");
3859     }
3860 
3861     unpackDimSizes[unpackAxis] /= unpackNum;
3862 
3863     SplitterDescriptor splitDesc(unpackNum, static_cast<unsigned int>(unpackDimSizes.size()));
3864     for (unsigned int j = 0; j < unpackNum; ++j)
3865     {
3866         // Set the size of the views.
3867         for (unsigned int dimIdx = 0; dimIdx < unpackDimSizes.size(); ++dimIdx)
3868         {
3869             splitDesc.SetViewSize(j, dimIdx, unpackDimSizes[dimIdx]);
3870         }
3871         splitDesc.SetViewOriginCoord(j, unpackAxis, unpackDimSizes[unpackAxis] * j);
3872     }
3873 
3874     auto layerName = fmt::format("Unpack:{}:{}", subgraphIndex, operatorIndex);
3875     IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
3876     ARMNN_ASSERT(layer != nullptr);
3877 
3878     TensorShape splitOutShape = TensorShape(static_cast<unsigned int>(unpackDimSizes.size()),
3879                                             unpackDimSizes.data());
3880 
3881     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3882     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3883 
3884     std::vector<unsigned int> reshapeDims;
3885     for (unsigned int axis = 0; axis < splitOutShape.GetNumDimensions(); ++axis)
3886     {
3887         if (axis != unpackAxis)
3888         {
3889             reshapeDims.push_back(splitOutShape[axis]);
3890         }
3891     }
3892 
3893     TensorShape reshapeOutputShape(splitOutShape.GetNumDimensions() -1, reshapeDims.data());
3894 
3895     // Create reshape to remove the unpacked dimension for unpack operator of each output from Splitter.
3896     for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
3897     {
3898         armnn::TensorInfo outputTensorInfo  = ToTensorInfo(outputs[k], true);
3899         std::string reshapeLayerName = fmt::format("Reshape_for:{}", layer->GetName());
3900         armnn::ReshapeDescriptor desc;
3901         desc.m_TargetShape = reshapeOutputShape;
3902         armnn::IConnectableLayer* reshapeLayer = m_Network->AddReshapeLayer(desc, layerName.c_str());
3903 
3904         layer->GetOutputSlot(k).SetTensorInfo(armnn::TensorInfo(splitOutShape,
3905                                                                 outputTensorInfo.GetDataType(),
3906                                                                 outputTensorInfo.GetQuantizationScale(),
3907                                                                 outputTensorInfo.GetQuantizationOffset()));
3908         layer->GetOutputSlot(k).Connect(reshapeLayer->GetInputSlot(0));
3909 
3910         reshapeLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3911 
3912         uint32_t reshapedOutputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[k]);
3913         armnn::IOutputSlot* slot = &(reshapeLayer->GetOutputSlot(0));
3914         RegisterProducerOfTensor(subgraphIndex, reshapedOutputId, slot);
3915     }
3916 }
3917 
ParseSplit(size_t subgraphIndex,size_t operatorIndex)3918 void TfLiteParserImpl::ParseSplit(size_t subgraphIndex, size_t operatorIndex)
3919 {
3920     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3921 
3922     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3923     const auto* options = operatorPtr->builtin_options.AsSplitOptions();
3924 
3925     const unsigned int numSplits = CHECKED_NON_NEGATIVE(options->num_splits);
3926 
3927     // If number of splits cannot be inferred and is zero, throw ParseException.
3928     if(numSplits == 0)
3929     {
3930         throw ParseException("Number to splits must greater than zero.");
3931     }
3932 
3933     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3934     CHECK_VALID_SIZE(inputs.size(), 2);
3935     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3936     CHECK_VALID_SIZE(outputs.size(), numSplits);
3937 
3938     armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
3939     armnn::TensorInfo axisTensorInfo  = InputTensorInfo(subgraphIndex, operatorIndex, 0);
3940     ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
3941 
3942     BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[0]->buffer);
3943     if (axisBufferPtr == nullptr)
3944     {
3945         throw ParseException(
3946                 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
3947                             CHECK_LOCATION().AsString()));
3948     }
3949 
3950     std::vector<int32_t> axisData(axisTensorInfo.GetNumElements());
3951     ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
3952     int32_t axis = axisData[0];
3953 
3954     auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
3955     if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
3956     {
3957         // Square bracket denotes inclusive n while parenthesis denotes exclusive n
3958         // E.g. Rank 4 tensor can have axis in range [-4, 3)
3959         // -1 == 3, -2 == 2, -3 == 1, -4 == 0
3960         throw ParseException(
3961                 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
3962                             axis,
3963                             CHECK_LOCATION().AsString()));
3964     }
3965 
3966     const unsigned int splitDim = armnnUtils::GetUnsignedAxis(inputTensorInfo.GetNumDimensions(), axis);
3967 
3968     auto inputDimSize = inputTensorInfo.GetNumDimensions();
3969     if (inputDimSize > MaxNumOfTensorDimensions)
3970     {
3971         throw ParseException(
3972             fmt::format("The number of dimensions: {} for input tensors of the split op cannot be greater than {} {}",
3973                         inputTensorInfo.GetNumDimensions(),
3974                         MaxNumOfTensorDimensions,
3975                         CHECK_LOCATION().AsString()));
3976     }
3977 
3978     std::vector<unsigned int> splitterDimSizes(inputDimSize);
3979 
3980     // Add current input shape to splitterDimSizes
3981     for (unsigned int i = 0; i < inputDimSize; ++i)
3982     {
3983         splitterDimSizes[i] = inputTensorInfo.GetShape()[i];
3984     }
3985 
3986     if (splitterDimSizes[splitDim] % numSplits != 0)
3987     {
3988         throw ParseException("Number of splits must evenly divide the dimension");
3989     }
3990     splitterDimSizes[splitDim] /= numSplits;
3991 
3992     SplitterDescriptor splitDesc(numSplits, inputDimSize);
3993     for (unsigned int j = 0; j < numSplits; ++j)
3994     {
3995         // Set the size of the views.
3996         for (unsigned int dimIdx = 0; dimIdx < splitterDimSizes.size(); ++dimIdx)
3997         {
3998             splitDesc.SetViewSize(j, dimIdx, splitterDimSizes[dimIdx]);
3999         }
4000         splitDesc.SetViewOriginCoord(j, splitDim, splitterDimSizes[splitDim] * j);
4001     }
4002 
4003     auto layerName = fmt::format("Split:{}:{}", subgraphIndex, operatorIndex);
4004     IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
4005     ARMNN_ASSERT(layer != nullptr);
4006 
4007     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4008     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[1]});
4009 
4010     for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
4011     {
4012         armnn::TensorInfo tensorInfo = ToTensorInfo(outputs[k], true);
4013         layer->GetOutputSlot(k).SetTensorInfo(tensorInfo);
4014     }
4015 
4016     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4017     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4018 }
4019 
ComputeWrappedIndex(int idx,unsigned int numDimsIn)4020 unsigned int ComputeWrappedIndex(int idx, unsigned int numDimsIn)
4021 {
4022     int numDims = armnn::numeric_cast<int>(numDimsIn);
4023     int v = idx < 0 ? numDims + idx : idx;
4024     ARMNN_ASSERT(v >= 0);
4025     ARMNN_ASSERT(v < numDims);
4026 
4027     return static_cast<unsigned int>(v);
4028 }
4029 
ParseSplitV(size_t subgraphIndex,size_t operatorIndex)4030 void TfLiteParserImpl::ParseSplitV(size_t subgraphIndex, size_t operatorIndex)
4031 {
4032     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4033 
4034     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4035     const auto* options = operatorPtr->builtin_options.AsSplitVOptions();
4036 
4037     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4038     CHECK_VALID_SIZE(inputs.size(), 3);
4039 
4040     auto& inputTensor = inputs[0];
4041     auto& splitsTensor = inputs[1];
4042     auto& axisTensor = inputs[2];
4043 
4044     armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputTensor);
4045     armnn::TensorInfo splitsInfo      = ToTensorInfo(splitsTensor);
4046     armnn::TensorInfo axisTensorInfo  = ToTensorInfo(axisTensor);
4047     ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
4048 
4049     // Inputs
4050     auto inputDimSize = inputTensorInfo.GetNumDimensions();
4051     if (inputDimSize > MaxNumOfTensorDimensions)
4052     {
4053         throw ParseException(
4054             fmt::format("The number of dimensions: {} for input tensors of the "
4055                         "SplitV op cannot be greater than {} {}",
4056                         inputTensorInfo.GetNumDimensions(),
4057                         MaxNumOfTensorDimensions,
4058                         CHECK_LOCATION().AsString()));
4059     }
4060 
4061     // Get split axis
4062     BufferRawPtr axisBufferPtr = GetBuffer(m_Model, axisTensor->buffer);
4063     if (axisBufferPtr == nullptr)
4064     {
4065         throw ParseException(
4066                 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
4067                             CHECK_LOCATION().AsString()));
4068     }
4069 
4070     std::vector<int> axisData(axisTensorInfo.GetNumElements());
4071     ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
4072     int32_t axis = axisData[0];
4073 
4074     auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
4075     if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
4076     {
4077         // Square bracket denotes inclusive n while parenthesis denotes exclusive n
4078         // E.g. Rank 4 tensor can have axis in range [-4, 3)
4079         // -1 == 3, -2 == 2, -3 == 1, -4 == 0
4080         throw ParseException(
4081                 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
4082                             axis,
4083                             CHECK_LOCATION().AsString()));
4084     }
4085     const unsigned int splitDim = ComputeWrappedIndex(axis, inputTensorInfo.GetNumDimensions());
4086 
4087     // Set split sizes
4088     CHECK_VALID_SIZE(splitsInfo.GetNumDimensions(), 1);
4089     unsigned int numSplits{0};
4090 
4091     if(options)
4092     {
4093         numSplits = CHECKED_NON_NEGATIVE(options->num_splits);
4094     }
4095     else
4096     {
4097         numSplits = splitsInfo.GetNumElements();
4098     }
4099 
4100     if (numSplits <=0)
4101     {
4102         throw ParseException("SplitV has invalid number of splits");
4103     }
4104 
4105     std::vector<int> splitsData(numSplits);
4106     BufferRawPtr splitsBufferPtr = GetBuffer(m_Model, splitsTensor->buffer);
4107     ::memcpy(splitsData.data(), splitsBufferPtr->data.data(), splitsInfo.GetNumBytes());
4108 
4109     unsigned int idx = 0;
4110     int numInferred{0};
4111     unsigned int inferIdx{0};
4112     int splitSum{0};
4113     for (auto split : splitsData)
4114     {
4115         if (split < 0)
4116         {
4117             numInferred++;
4118             inferIdx = idx;
4119         }
4120         else
4121         {
4122             splitSum += split;
4123         }
4124         idx++;
4125     }
4126     // Check for inferred Axis
4127     if (numInferred == 0)
4128     {
4129         if (splitSum != armnn::numeric_cast<int>(inputTensorInfo.GetShape()[splitDim]))
4130         {
4131             throw ParseException("SplitV split_sizes does not sum to the dimension of value along split_dim.");
4132         }
4133     }
4134     else if (numInferred == 1)
4135     {
4136         splitsData[inferIdx] = armnn::numeric_cast<int>(inputTensorInfo.GetShape()[splitDim]) - splitSum;
4137     }
4138     else
4139     {
4140         throw ParseException("Cannot infer split size for more than one split");
4141     }
4142 
4143     //Ouput size validation
4144     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4145     CHECK_VALID_SIZE(outputs.size(), numSplits);
4146 
4147     // Setup Armnn descriptor
4148     SplitterDescriptor splitDesc(numSplits, inputDimSize);
4149     unsigned int accumSplit = 0;
4150     for (unsigned int j = 0; j < numSplits; ++j)
4151     {
4152         unsigned int splitSize = armnn::numeric_cast<unsigned int>(splitsData[j]);
4153 
4154         // Set the size of the views.
4155         for (unsigned int dimIdx = 0; dimIdx < inputTensorInfo.GetNumDimensions(); ++dimIdx)
4156         {
4157             unsigned int dimSize = inputTensorInfo.GetShape()[dimIdx];
4158             if (dimIdx == splitDim)
4159             {
4160                 dimSize = splitSize;
4161             }
4162             splitDesc.SetViewSize(j, dimIdx, dimSize);
4163         }
4164 
4165         splitDesc.SetViewOriginCoord(j, splitDim, accumSplit);
4166         accumSplit += splitSize;
4167     }
4168 
4169     auto layerName = fmt::format("SplitV:{}:{}", subgraphIndex, operatorIndex);
4170     IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
4171     ARMNN_ASSERT(layer != nullptr);
4172 
4173     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4174     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4175 
4176     for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
4177     {
4178         armnn::TensorInfo tensorInfo = ToTensorInfo(outputs[k], true);
4179         layer->GetOutputSlot(k).SetTensorInfo(tensorInfo);
4180     }
4181 
4182     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4183     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4184 }
4185 
ParseArgMin(size_t subgraphIndex,size_t operatorIndex)4186 void TfLiteParserImpl::ParseArgMin(size_t subgraphIndex, size_t operatorIndex)
4187 {
4188     ParseArgMinMax(subgraphIndex, operatorIndex, armnn::ArgMinMaxFunction::Min);
4189 }
4190 
ParseArgMax(size_t subgraphIndex,size_t operatorIndex)4191 void TfLiteParserImpl::ParseArgMax(size_t subgraphIndex, size_t operatorIndex)
4192 {
4193     ParseArgMinMax(subgraphIndex, operatorIndex, armnn::ArgMinMaxFunction::Max);
4194 }
4195 
ParseArgMinMax(size_t subgraphIndex,size_t operatorIndex,ArgMinMaxFunction argMinMaxFunction)4196 void TfLiteParserImpl::ParseArgMinMax(size_t subgraphIndex, size_t operatorIndex, ArgMinMaxFunction argMinMaxFunction)
4197 {
4198     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4199     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4200     CHECK_VALID_SIZE(inputs.size(), 2);
4201 
4202     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4203     CHECK_VALID_SIZE(outputs.size(), 1);
4204 
4205     armnn::TensorInfo inputTensorInfo  = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4206     armnn::TensorInfo axisTensorInfo   = InputTensorInfo(subgraphIndex, operatorIndex, 1);
4207     armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
4208     ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
4209 
4210     // Check if output tensor type is Signed32 or Signed64
4211     if (outputTensorInfo.GetDataType() != armnn::DataType::Signed32 &&
4212         outputTensorInfo.GetDataType() != armnn::DataType::Signed64)
4213     {
4214         throw ParseException(
4215                 fmt::format(
4216                         "Output tensor data type is not supported. (Supported types: Signed32 & Signed64) {}",
4217                                 CHECK_LOCATION().AsString()));
4218     }
4219 
4220     // Get const axis value from model and set it to descriptor.
4221     BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
4222     if (axisBufferPtr == nullptr)
4223     {
4224         throw ParseException(
4225                 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
4226                             CHECK_LOCATION().AsString()));
4227     }
4228 
4229     std::vector<int32_t> axisData(axisTensorInfo.GetNumElements());
4230     ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
4231     int32_t axis = axisData.front();
4232 
4233     auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
4234     if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
4235     {
4236         // Square bracket denotes inclusive n while parenthesis denotes exclusive n
4237         // E.g. Rank 4 tensor can have axis in range [-4, 3)
4238         // -1 == 3, -2 == 2, -3 == 1, -4 == 0
4239         throw ParseException(
4240                 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
4241                                     axis,
4242                                     CHECK_LOCATION().AsString()));
4243     }
4244 
4245     ArgMinMaxDescriptor desc;
4246     desc.m_Axis = axis;
4247     desc.m_Function = argMinMaxFunction;
4248 
4249     // Register a ArgMin/ArgMax layer.
4250     auto layerName = argMinMaxFunction == ArgMinMaxFunction::Max ? "ArgMax:{}:{}" : "ArgMin:{}:{}";
4251     auto layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4252     IConnectableLayer *layer = m_Network->AddArgMinMaxLayer(desc, layerNameFormatted.c_str());
4253     ARMNN_ASSERT(layer != nullptr);
4254     outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
4255     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4256 
4257     // Register input tensor to the layer.
4258     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4259     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4260 
4261     // Register output tensor to the layer.
4262     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4263     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4264 }
4265 
ParseGather(size_t subgraphIndex,size_t operatorIndex)4266 void TfLiteParserImpl::ParseGather(size_t subgraphIndex, size_t operatorIndex)
4267 {
4268     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4269 
4270     TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4271     CHECK_VALID_SIZE(inputs.size(), 2);
4272     TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4273     CHECK_VALID_SIZE(outputs.size(), 1);
4274 
4275     armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4276     armnn::TensorInfo indicesTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
4277     armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
4278 
4279     armnn::GatherDescriptor gatherDescriptor;
4280 
4281     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4282     const auto* options = operatorPtr->builtin_options.AsGatherOptions();
4283     auto axis = options->axis;
4284 
4285     auto layerName = fmt::format("Gather:{}:{}", subgraphIndex, operatorIndex);
4286 
4287     auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
4288     auto indicesDimensions = indicesTensorInfo.GetNumDimensions();
4289     auto outputDimensions = outputTensorInfo.GetNumDimensions();
4290     if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
4291     {
4292         throw ParseException(
4293             fmt::format("Operation has invalid axis: {} It is out of bounds [ -{}, {} ) {}",
4294                         axis,
4295                         inputDimensions, inputDimensions,
4296                         CHECK_LOCATION().AsString()));
4297     }
4298     if (outputDimensions != static_cast<unsigned int>(inputDimensions) + indicesDimensions - 1)
4299     {
4300         throw ParseException(
4301             fmt::format("Operation has invalid output dimensions: {} Output must be an ({} + {} - 1) -D tensor {}",
4302                         outputDimensions,
4303                         inputDimensions, indicesDimensions,
4304                         CHECK_LOCATION().AsString()));
4305     }
4306 
4307     gatherDescriptor.m_Axis = axis;
4308 
4309     IConnectableLayer* layer = m_Network->AddGatherLayer(gatherDescriptor, layerName.c_str());
4310     ARMNN_ASSERT(layer != nullptr);
4311     outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
4312     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4313 
4314     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4315     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4316 
4317     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4318     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4319 }
4320 
ParseGatherNd(size_t subgraphIndex,size_t operatorIndex)4321 void TfLiteParserImpl::ParseGatherNd(size_t subgraphIndex, size_t operatorIndex)
4322 {
4323     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4324 
4325     TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4326     CHECK_VALID_SIZE(inputs.size(), 2);
4327     TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4328     CHECK_VALID_SIZE(outputs.size(), 1);
4329 
4330     armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4331     armnn::TensorInfo indicesTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
4332 
4333     auto layerName = fmt::format("GatherNd:{}:{}", subgraphIndex, operatorIndex);
4334     IConnectableLayer* layer = m_Network->AddGatherNdLayer(layerName.c_str());
4335     ARMNN_ASSERT(layer != nullptr);
4336     TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
4337     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4338 
4339     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4340     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4341 
4342     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4343     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4344 }
4345 
ParseDepthToSpace(size_t subgraphIndex,size_t operatorIndex)4346 void TfLiteParserImpl::ParseDepthToSpace(size_t subgraphIndex, size_t operatorIndex)
4347 {
4348     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4349 
4350     TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4351     CHECK_VALID_SIZE(inputs.size(), 1);
4352     TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4353     CHECK_VALID_SIZE(outputs.size(), 1);
4354 
4355     armnn::DepthToSpaceDescriptor descriptor;
4356 
4357     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4358     const auto* options = operatorPtr->builtin_options.AsDepthToSpaceOptions();
4359     auto blockSize = options->block_size;
4360     if (blockSize < 2)
4361     {
4362         throw ParseException(
4363             fmt::format("Operation has invalid block size: {} Block size should be >= 2 {}",
4364                         blockSize,
4365                         CHECK_LOCATION().AsString()));
4366     }
4367     descriptor.m_BlockSize = armnn::numeric_cast<uint32_t>(blockSize);
4368 
4369     auto layerName = fmt::format("DepthToSpace:{}:{}", subgraphIndex, operatorIndex);
4370     IConnectableLayer* layer = m_Network->AddDepthToSpaceLayer(descriptor, layerName.c_str());
4371     ARMNN_ASSERT(layer != nullptr);
4372     TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
4373     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4374 
4375     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4376     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4377 
4378     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4379     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4380 }
4381 
ParseSum(size_t subgraphIndex,size_t operatorIndex)4382 void TfLiteParserImpl::ParseSum(size_t subgraphIndex, size_t operatorIndex)
4383 {
4384     ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Sum);
4385 }
4386 
ParseReduceProd(size_t subgraphIndex,size_t operatorIndex)4387 void TfLiteParserImpl::ParseReduceProd(size_t subgraphIndex, size_t operatorIndex)
4388 {
4389     ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Prod);
4390 }
4391 
ParseReduceMax(size_t subgraphIndex,size_t operatorIndex)4392 void TfLiteParserImpl::ParseReduceMax(size_t subgraphIndex, size_t operatorIndex)
4393 {
4394     ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Max);
4395 }
4396 
ParseReduceMin(size_t subgraphIndex,size_t operatorIndex)4397 void TfLiteParserImpl::ParseReduceMin(size_t subgraphIndex, size_t operatorIndex)
4398 {
4399     ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Min);
4400 }
4401 
ParseReduce(size_t subgraphIndex,size_t operatorIndex,ReduceOperation reduceOperation)4402 void TfLiteParserImpl::ParseReduce(size_t subgraphIndex, size_t operatorIndex, ReduceOperation reduceOperation)
4403 {
4404     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4405 
4406     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4407     const auto* options = operatorPtr->builtin_options.AsReducerOptions();
4408 
4409     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4410     CHECK_VALID_SIZE(inputs.size(), 2);
4411 
4412     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4413     CHECK_VALID_SIZE(outputs.size(), 1);
4414 
4415     auto layerName = fmt::format("Reduce:{}:{}", subgraphIndex, operatorIndex);
4416 
4417     armnn::TensorInfo inputTensorInfo0 = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4418     armnn::TensorInfo inputTensorInfo1 = InputTensorInfo(subgraphIndex, operatorIndex, 1);
4419 
4420     ReduceDescriptor desc;
4421     BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
4422     // Get const axis value from model and set it to descriptor.
4423     if (axisBufferPtr != nullptr)
4424     {
4425         std::vector<int32_t> axisData(inputTensorInfo1.GetNumElements());
4426         ::memcpy(axisData.data(), axisBufferPtr->data.data(), inputTensorInfo1.GetNumBytes());
4427 
4428         // Convert the axis to unsigned int and remove duplicates.
4429         auto rank = static_cast<int32_t>(inputTensorInfo0.GetNumDimensions());
4430         std::set<unsigned int> uniqueAxis;
4431         std::transform(axisData.begin(),
4432                        axisData.end(),
4433                        std::inserter(uniqueAxis, uniqueAxis.begin()),
4434                        [rank](int i)->unsigned int{
4435                                return static_cast<uint32_t>(((i + rank) % rank)); });
4436         desc.m_vAxis.assign(uniqueAxis.begin(), uniqueAxis.end());
4437     }
4438     else
4439     {
4440         for (uint32_t i = 0; i < inputTensorInfo0.GetNumDimensions(); ++i)
4441         {
4442             desc.m_vAxis.push_back(i);
4443         }
4444     }
4445 
4446     desc.m_KeepDims        = options->keep_dims;
4447     desc.m_ReduceOperation = reduceOperation;
4448 
4449     // Register a new layer object, Sum.
4450     IConnectableLayer* layer = m_Network->AddReduceLayer(desc, layerName.c_str());
4451 
4452     armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
4453     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4454 
4455     // Register input tensor to the layer.
4456     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4457     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4458 
4459     // Register output tensor to the layer.
4460     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4461     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4462 }
4463 
ParseLocalResponseNormalization(size_t subgraphIndex,size_t operatorIndex)4464 void TfLiteParserImpl::ParseLocalResponseNormalization(size_t subgraphIndex, size_t operatorIndex)
4465 {
4466     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4467 
4468     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4469     CHECK_VALID_SIZE(inputs.size(), 1);
4470 
4471     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4472     CHECK_VALID_SIZE(outputs.size(), 1);
4473 
4474     auto layerName = fmt::format("LRN:{}:{}", subgraphIndex, operatorIndex);
4475     std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4476 
4477     armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4478 
4479     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4480     const auto* options = operatorPtr->builtin_options.AsLocalResponseNormalizationOptions();
4481 
4482     armnn::NormalizationDescriptor descriptor;
4483     descriptor.m_DataLayout      = armnn::DataLayout::NHWC;
4484     descriptor.m_NormChannelType = armnn::NormalizationAlgorithmChannel::Across;
4485     descriptor.m_NormMethodType  = armnn::NormalizationAlgorithmMethod::LocalBrightness;
4486     descriptor.m_NormSize = static_cast<uint32_t>(options->radius);
4487     descriptor.m_K = options->bias;
4488     descriptor.m_Alpha = options->alpha;
4489     descriptor.m_Beta = options->beta;
4490 
4491     // ArmNN expects normSize to be the full size of the normalization
4492     // window rather than the radius as in TfLite.
4493     descriptor.m_NormSize = 1 + (2 * descriptor.m_NormSize);
4494 
4495     IConnectableLayer* layer = m_Network->AddNormalizationLayer(descriptor, layerNameFormatted.c_str());
4496     ARMNN_ASSERT(layer != nullptr);
4497 
4498     TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
4499     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4500 
4501     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4502     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4503 
4504     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4505     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4506 }
4507 
ParseAbs(size_t subgraphIndex,size_t operatorIndex)4508 void TfLiteParserImpl::ParseAbs(size_t subgraphIndex, size_t operatorIndex)
4509 {
4510     ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Abs);
4511 }
4512 
ParseCeil(size_t subgraphIndex,size_t operatorIndex)4513 void TfLiteParserImpl::ParseCeil(size_t subgraphIndex, size_t operatorIndex)
4514 {
4515     ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Ceil);
4516 }
4517 
ParseExp(size_t subgraphIndex,size_t operatorIndex)4518 void TfLiteParserImpl::ParseExp(size_t subgraphIndex, size_t operatorIndex)
4519 {
4520     ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Exp);
4521 }
4522 
ParseLog(size_t subgraphIndex,size_t operatorIndex)4523 void TfLiteParserImpl::ParseLog(size_t subgraphIndex, size_t operatorIndex)
4524 {
4525     ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Log);
4526 }
4527 
ParseLogicalNot(size_t subgraphIndex,size_t operatorIndex)4528 void TfLiteParserImpl::ParseLogicalNot(size_t subgraphIndex, size_t operatorIndex)
4529 {
4530     ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::LogicalNot);
4531 }
4532 
ParseNeg(size_t subgraphIndex,size_t operatorIndex)4533 void TfLiteParserImpl::ParseNeg(size_t subgraphIndex, size_t operatorIndex)
4534 {
4535     ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Neg);
4536 }
4537 
ParseRsqrt(size_t subgraphIndex,size_t operatorIndex)4538 void TfLiteParserImpl::ParseRsqrt(size_t subgraphIndex, size_t operatorIndex)
4539 {
4540     ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Rsqrt);
4541 }
4542 
ParseSin(size_t subgraphIndex,size_t operatorIndex)4543 void TfLiteParserImpl::ParseSin(size_t subgraphIndex, size_t operatorIndex)
4544 {
4545     ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Sin);
4546 }
4547 
ParseSqrt(size_t subgraphIndex,size_t operatorIndex)4548 void TfLiteParserImpl::ParseSqrt(size_t subgraphIndex, size_t operatorIndex)
4549 {
4550     ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Sqrt);
4551 }
4552 
ParseElementwiseUnary(size_t subgraphIndex,size_t operatorIndex,UnaryOperation unaryOperation)4553 void TfLiteParserImpl::ParseElementwiseUnary(size_t subgraphIndex, size_t operatorIndex, UnaryOperation unaryOperation)
4554 {
4555     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4556 
4557     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4558     CHECK_VALID_SIZE(inputs.size(), 1);
4559 
4560     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4561     CHECK_VALID_SIZE(outputs.size(), 1);
4562 
4563     std::string layerName = std::string(GetUnaryOperationAsCString(unaryOperation)) + ":{}:{}";
4564     std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4565 
4566     ElementwiseUnaryDescriptor desc;
4567     desc.m_Operation = unaryOperation;
4568     IConnectableLayer* layer = m_Network->AddElementwiseUnaryLayer(desc, layerNameFormatted.c_str());
4569     ARMNN_ASSERT(layer != nullptr);
4570 
4571     TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
4572     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4573 
4574     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4575     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4576 
4577     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4578     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4579 }
4580 
ParseEqual(size_t subgraphIndex,size_t operatorIndex)4581 void TfLiteParserImpl::ParseEqual(size_t subgraphIndex, size_t operatorIndex)
4582 {
4583     ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::Equal);
4584 }
4585 
ParseNotEqual(size_t subgraphIndex,size_t operatorIndex)4586 void TfLiteParserImpl::ParseNotEqual(size_t subgraphIndex, size_t operatorIndex)
4587 {
4588     ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::NotEqual);
4589 }
4590 
ParseGreater(size_t subgraphIndex,size_t operatorIndex)4591 void TfLiteParserImpl::ParseGreater(size_t subgraphIndex, size_t operatorIndex)
4592 {
4593     ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::Greater);
4594 }
4595 
ParseGreaterOrEqual(size_t subgraphIndex,size_t operatorIndex)4596 void TfLiteParserImpl::ParseGreaterOrEqual(size_t subgraphIndex, size_t operatorIndex)
4597 {
4598     ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::GreaterOrEqual);
4599 }
4600 
ParseLess(size_t subgraphIndex,size_t operatorIndex)4601 void TfLiteParserImpl::ParseLess(size_t subgraphIndex, size_t operatorIndex)
4602 {
4603     ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::Less);
4604 }
4605 
ParseLessOrEqual(size_t subgraphIndex,size_t operatorIndex)4606 void TfLiteParserImpl::ParseLessOrEqual(size_t subgraphIndex, size_t operatorIndex)
4607 {
4608     ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::LessOrEqual);
4609 }
4610 
ParseComparison(size_t subgraphIndex,size_t operatorIndex,ComparisonOperation comparisonOperation)4611 void TfLiteParserImpl::ParseComparison(size_t subgraphIndex, size_t operatorIndex,
4612                                        ComparisonOperation comparisonOperation)
4613 {
4614     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4615 
4616     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4617     CHECK_VALID_SIZE(inputs.size(), 2);
4618 
4619     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4620     CHECK_VALID_SIZE(outputs.size(), 1);
4621 
4622     auto layerName = std::string(GetComparisonOperationAsCString(comparisonOperation)) + ":{}:{}";
4623     std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4624 
4625     armnn::TensorInfo inputTensorInfo  = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4626     armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
4627     CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerNameFormatted, "Input 0", "Input 1");
4628 
4629     ComparisonDescriptor desc;
4630     desc.m_Operation = comparisonOperation;
4631     IConnectableLayer* layer = m_Network->AddComparisonLayer(desc, layerNameFormatted.c_str());
4632     ARMNN_ASSERT(layer != nullptr);
4633 
4634     TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
4635     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4636 
4637     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4638     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4639 
4640     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4641     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4642 }
4643 
AddReshapeLayer(armnn::IConnectableLayer * layer,unsigned int outputSlot,std::string reshapeLayerName,armnn::TensorInfo outputShape)4644 armnn::IConnectableLayer* TfLiteParserImpl::AddReshapeLayer(armnn::IConnectableLayer* layer,
4645                                                             unsigned int outputSlot,
4646                                                             std::string reshapeLayerName,
4647                                                             armnn::TensorInfo outputShape)
4648 {
4649     ReshapeDescriptor desc;
4650     desc.m_TargetShape = outputShape.GetShape();
4651 
4652     IConnectableLayer* reshapeLayer =
4653             m_Network->AddReshapeLayer(desc, reshapeLayerName.c_str());
4654 
4655     auto & prevOutputSlot = layer->GetOutputSlot(outputSlot);
4656     prevOutputSlot.Connect(reshapeLayer->GetInputSlot(0));
4657     reshapeLayer->GetOutputSlot(0).SetTensorInfo(outputShape);
4658     return reshapeLayer;
4659 }
4660 
AddFusedActivationLayer(armnn::IConnectableLayer * prevLayer,unsigned int outputSlot,tflite::ActivationFunctionType activationType)4661 armnn::IConnectableLayer* TfLiteParserImpl::AddFusedActivationLayer(armnn::IConnectableLayer* prevLayer,
4662                                                                     unsigned int outputSlot,
4663                                                                     tflite::ActivationFunctionType activationType)
4664 {
4665     ActivationDescriptor activationDesc;
4666     std::string layerName = prevLayer->GetName();
4667 
4668     switch(activationType)
4669     {
4670         case tflite::ActivationFunctionType_NONE:
4671         {
4672             // this is a no-op: return previous layer
4673             return prevLayer;
4674         }
4675         case tflite::ActivationFunctionType_RELU:
4676         {
4677             activationDesc.m_Function = ActivationFunction::ReLu;
4678             layerName += ":RELU";
4679             break;
4680         }
4681         case tflite::ActivationFunctionType_RELU6:
4682         {
4683             activationDesc.m_Function = ActivationFunction::BoundedReLu;
4684             activationDesc.m_A = 6.0f;
4685             activationDesc.m_B = 0.0f;
4686             layerName += ":RELU6";
4687             break;
4688         }
4689         case tflite::ActivationFunctionType_TANH:
4690         {
4691             activationDesc.m_Function = ActivationFunction::TanH;
4692             activationDesc.m_A = 1.0f;
4693             activationDesc.m_B = 1.0f;
4694             layerName += ":TANH";
4695             break;
4696         }
4697 
4698         // I only put these here as a reminder what others we could support
4699         case tflite::ActivationFunctionType_RELU_N1_TO_1:
4700         case tflite::ActivationFunctionType_SIGN_BIT:
4701         default:
4702         {
4703             throw ParseException(
4704                 fmt::format("TfLite parser doesn't support fused activation: "
4705                             "{}/{} {} ",
4706                             activationType,
4707                             tflite::EnumNameActivationFunctionType(activationType),
4708                             CHECK_LOCATION().AsString()));
4709 
4710         }
4711     }
4712 
4713     IConnectableLayer* activationLayer =
4714         m_Network->AddActivationLayer(activationDesc, layerName.c_str());
4715 
4716     auto & prevOutputSlot = prevLayer->GetOutputSlot(outputSlot);
4717     prevOutputSlot.Connect(activationLayer->GetInputSlot(0));
4718     activationLayer->GetOutputSlot(0).SetTensorInfo(prevOutputSlot.GetTensorInfo());
4719     return activationLayer;
4720 }
4721 
AddFusedFloorLayer(armnn::IConnectableLayer * prevLayer,unsigned int outputSlot)4722 armnn::IConnectableLayer* TfLiteParserImpl::AddFusedFloorLayer(armnn::IConnectableLayer* prevLayer,
4723                                                                unsigned int outputSlot)
4724 {
4725 
4726     auto& prevOutputSlot = prevLayer->GetOutputSlot(outputSlot);
4727     DataType dataType = prevOutputSlot.GetTensorInfo().GetDataType();
4728 
4729     if (dataType == DataType::Signed32)
4730     {
4731         return prevLayer;
4732     }
4733 
4734     std::string layerName = prevLayer->GetName();
4735     IConnectableLayer* floorLayer = m_Network->AddFloorLayer(layerName.c_str());
4736 
4737     prevOutputSlot.Connect(floorLayer->GetInputSlot(0));
4738     floorLayer->GetOutputSlot(0).SetTensorInfo(prevOutputSlot.GetTensorInfo());
4739 
4740     return floorLayer;
4741 }
4742 
LoadModelFromFile(const char * fileName)4743 TfLiteParserImpl::ModelPtr TfLiteParserImpl::LoadModelFromFile(const char* fileName)
4744 {
4745     if (fileName == nullptr)
4746     {
4747         throw InvalidArgumentException(fmt::format("Invalid (null) file name {}",
4748                                        CHECK_LOCATION().AsString()));
4749     }
4750     std::error_code errorCode;
4751     fs::path pathToFile(fileName);
4752     if (!fs::exists(pathToFile, errorCode))
4753     {
4754         //fmt::format() could not be used here (format error)
4755         std::stringstream msg;
4756         msg << "Cannot find the file (" << fileName << ") errorCode: " << errorCode
4757             << " " << CHECK_LOCATION().AsString();
4758 
4759         throw FileNotFoundException(msg.str());
4760     }
4761     std::ifstream file(fileName, std::ios::binary);
4762     std::string fileContent((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
4763     return LoadModelFromBinary(reinterpret_cast<const uint8_t *>(fileContent.c_str()),
4764                                fileContent.size());
4765 }
4766 
LoadModelFromBinary(const uint8_t * binaryContent,size_t len)4767 TfLiteParserImpl::ModelPtr TfLiteParserImpl::LoadModelFromBinary(const uint8_t* binaryContent, size_t len)
4768 {
4769     if (binaryContent == nullptr)
4770      {
4771         throw InvalidArgumentException(fmt::format("Invalid (null) binary content {}",
4772                                        CHECK_LOCATION().AsString()));
4773      }
4774     flatbuffers::Verifier verifier(binaryContent, len);
4775     if (verifier.VerifyBuffer<tflite::Model>() == false)
4776     {
4777         throw ParseException(
4778             fmt::format("Buffer doesn't conform to the expected Tensorflow Lite "
4779                         "flatbuffers format. size:{} {}",
4780                         len,
4781                         CHECK_LOCATION().AsString()));
4782     }
4783     return tflite::UnPackModel(binaryContent);
4784 }
4785 
GetInputs(const ModelPtr & model,size_t subgraphIndex,size_t operatorIndex)4786 TfLiteParserImpl::TensorRawPtrVector TfLiteParserImpl::GetInputs(const ModelPtr& model,
4787                                                                  size_t subgraphIndex,
4788                                                                  size_t operatorIndex)
4789 {
4790     CHECK_MODEL(model, subgraphIndex, operatorIndex);
4791 
4792     const auto& subgraphPtr = model->subgraphs[subgraphIndex];
4793     const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
4794 
4795     size_t inputCount = operatorPtr->inputs.size();
4796     TensorRawPtrVector result;
4797     for (size_t i = 0; i < inputCount; ++i)
4798     {
4799         // If the input location is -1 then assume input is turned off.
4800         if (operatorPtr->inputs[i] == -1)
4801         {
4802             continue;
4803         }
4804         else
4805         {
4806             uint32_t inputId = CHECKED_NON_NEGATIVE(operatorPtr->inputs[i]);
4807             result.push_back(subgraphPtr->tensors[inputId].get());
4808         }
4809     }
4810     return result;
4811 }
4812 
GetOutputs(const ModelPtr & model,size_t subgraphIndex,size_t operatorIndex)4813 TfLiteParserImpl::TensorRawPtrVector TfLiteParserImpl::GetOutputs(const ModelPtr& model,
4814                                                                   size_t subgraphIndex,
4815                                                                   size_t operatorIndex)
4816 {
4817     CHECK_MODEL(model, subgraphIndex, operatorIndex);
4818 
4819     const auto& subgraphPtr = model->subgraphs[subgraphIndex];
4820     const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
4821 
4822     size_t outputCount = operatorPtr->outputs.size();
4823     TensorRawPtrVector result(outputCount);
4824     for (size_t i = 0; i < outputCount; ++i)
4825     {
4826         uint32_t outputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[i]);
4827         CHECK_TENSOR(model, subgraphIndex, outputId);
4828         result[i] = subgraphPtr->tensors[outputId].get();
4829     }
4830     return result;
4831 }
4832 
GetSubgraphInputs(const ModelPtr & model,size_t subgraphIndex)4833 TfLiteParserImpl::TensorIdRawPtrVector TfLiteParserImpl::GetSubgraphInputs(const ModelPtr& model,
4834                                                                            size_t subgraphIndex)
4835 {
4836     CHECK_SUBGRAPH(model, subgraphIndex);
4837     const auto& subgraphPtr = model->subgraphs[subgraphIndex];
4838 
4839     size_t inputCount = subgraphPtr->inputs.size();
4840     TensorIdRawPtrVector result(inputCount);
4841     for (size_t i = 0; i < inputCount; ++i)
4842     {
4843         uint32_t inputId = CHECKED_NON_NEGATIVE(subgraphPtr->inputs[i]);
4844         CHECK_TENSOR(model, subgraphIndex, inputId);
4845         result[i] = std::make_pair(inputId, subgraphPtr->tensors[inputId].get());
4846     }
4847     return result;
4848 }
4849 
GetSubgraphOutputs(const ModelPtr & model,size_t subgraphIndex)4850 TfLiteParserImpl::TensorIdRawPtrVector TfLiteParserImpl::GetSubgraphOutputs(const ModelPtr& model,
4851                                                                             size_t subgraphIndex)
4852 {
4853     CHECK_SUBGRAPH(model, subgraphIndex);
4854     const auto& subgraphPtr = model->subgraphs[subgraphIndex];
4855 
4856     size_t outputCount = subgraphPtr->outputs.size();
4857     TensorIdRawPtrVector result(outputCount);
4858     for (size_t i = 0; i < outputCount; ++i)
4859     {
4860         uint32_t outputId = CHECKED_NON_NEGATIVE(subgraphPtr->outputs[i]);
4861         result[i] = std::make_pair(outputId, subgraphPtr->tensors[outputId].get());
4862     }
4863     return result;
4864 }
4865 
GetInputTensorIds(const ModelPtr & model,size_t subgraphIndex,size_t operatorIndex)4866 std::vector<int32_t>& TfLiteParserImpl::GetInputTensorIds(const ModelPtr& model,
4867                                                           size_t subgraphIndex,
4868                                                           size_t operatorIndex)
4869 {
4870     CHECK_MODEL(model, subgraphIndex, operatorIndex);
4871     const auto& subgraphPtr = model->subgraphs[subgraphIndex];
4872     const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
4873     return operatorPtr->inputs;
4874 }
4875 
GetOutputTensorIds(const ModelPtr & model,size_t subgraphIndex,size_t operatorIndex)4876 std::vector<int32_t>& TfLiteParserImpl::GetOutputTensorIds(const ModelPtr& model,
4877                                                            size_t subgraphIndex,
4878                                                            size_t operatorIndex)
4879 {
4880     CHECK_MODEL(model, subgraphIndex, operatorIndex);
4881     const auto& subgraphPtr = model->subgraphs[subgraphIndex];
4882     const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
4883     return operatorPtr->outputs;
4884 }
4885 
RegisterInputSlots(size_t subgraphIndex,size_t operatorIndex,IConnectableLayer * layer,const std::vector<unsigned int> & tensorIndexes,unsigned int startingSlotIndex)4886 void TfLiteParserImpl::RegisterInputSlots(size_t subgraphIndex,
4887                                           size_t operatorIndex,
4888                                           IConnectableLayer* layer,
4889                                           const std::vector<unsigned int>& tensorIndexes,
4890                                           unsigned int startingSlotIndex)
4891 {
4892     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4893     ARMNN_ASSERT(layer != nullptr);
4894 
4895     if (tensorIndexes.size() + startingSlotIndex != layer->GetNumInputSlots())
4896     {
4897         throw ParseException(
4898             fmt::format("The number of tensor inputs ({}) does not match the number expected ({})"
4899                         " for subgraph:{} operator index:{} {}",
4900                         tensorIndexes.size(),
4901                         layer->GetNumInputSlots(),
4902                         subgraphIndex,
4903                         operatorIndex,
4904                         CHECK_LOCATION().AsString()));
4905     }
4906 
4907     for (unsigned int index = 0; index < tensorIndexes.size() ; ++index)
4908     {
4909         unsigned int tensorIndex = tensorIndexes[index];
4910         armnn::IInputSlot* slot = &(layer->GetInputSlot(startingSlotIndex + index));
4911         RegisterConsumerOfTensor(subgraphIndex, tensorIndex, slot);
4912     }
4913 }
4914 
RegisterOutputSlots(size_t subgraphIndex,size_t operatorIndex,IConnectableLayer * layer,const std::vector<unsigned int> & tensorIndexes)4915 void TfLiteParserImpl::RegisterOutputSlots(size_t subgraphIndex,
4916                                            size_t operatorIndex,
4917                                            IConnectableLayer* layer,
4918                                            const std::vector<unsigned int>& tensorIndexes)
4919 {
4920     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4921     ARMNN_ASSERT(layer != nullptr);
4922     if (tensorIndexes.size() != layer->GetNumOutputSlots())
4923     {
4924         throw ParseException(
4925             fmt::format("The number of tensor outputs ({}) does not match the number expected ({})"
4926                         " for subgraph:{} operator index:{} {}",
4927                         tensorIndexes.size(),
4928                         layer->GetNumOutputSlots(),
4929                         subgraphIndex,
4930                         operatorIndex,
4931                         CHECK_LOCATION().AsString()));
4932     }
4933 
4934     for (unsigned int slotIndex = 0; slotIndex < layer->GetNumOutputSlots(); ++slotIndex)
4935     {
4936         unsigned int tensorIndex = tensorIndexes[slotIndex];
4937         armnn::IOutputSlot* slot = &(layer->GetOutputSlot(slotIndex));
4938         RegisterProducerOfTensor(subgraphIndex, tensorIndex, slot);
4939     }
4940 }
4941 
SetupInputLayerTensorInfos(size_t subgraphIndex)4942 void TfLiteParserImpl::SetupInputLayerTensorInfos(size_t subgraphIndex)
4943 {
4944     CHECK_SUBGRAPH(m_Model, subgraphIndex);
4945 
4946     auto inputs = GetSubgraphInputs(m_Model, subgraphIndex);
4947     for (auto const& tensorIdAndPtr : inputs)
4948     {
4949         auto tensorInfo = ToTensorInfo(tensorIdAndPtr.second);
4950         m_TensorInfos.insert({tensorIdAndPtr.first, tensorInfo});
4951     }
4952 }
4953 
SetupInputLayers(size_t subgraphIndex)4954 void TfLiteParserImpl::SetupInputLayers(size_t subgraphIndex)
4955 {
4956     CHECK_SUBGRAPH(m_Model, subgraphIndex);
4957 
4958     auto inputs = GetSubgraphInputs(m_Model, subgraphIndex);
4959     for (auto const& tensorIdAndPtr : inputs)
4960     {
4961         auto bindingId = GenerateLayerBindingId(subgraphIndex, tensorIdAndPtr.first);
4962         IConnectableLayer* layer =
4963             m_Network->AddInputLayer(bindingId, tensorIdAndPtr.second->name.c_str());
4964 
4965         auto tensorInfo = ToTensorInfo(tensorIdAndPtr.second);
4966         layer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
4967 
4968         RegisterOutputSlots(subgraphIndex,
4969                             VIRTUAL_OPERATOR_ID,
4970                             layer,
4971                             { static_cast<uint32_t>(tensorIdAndPtr.first) });
4972     }
4973 }
4974 
SetupOutputLayers(size_t subgraphIndex)4975 void TfLiteParserImpl::SetupOutputLayers(size_t subgraphIndex)
4976 {
4977     CHECK_SUBGRAPH(m_Model, subgraphIndex);
4978 
4979     auto outputs = GetSubgraphOutputs(m_Model, subgraphIndex);
4980     for (auto const& tensorIdAndPtr : outputs)
4981     {
4982         auto bindingId = GenerateLayerBindingId(subgraphIndex, tensorIdAndPtr.first);
4983         IConnectableLayer* layer =
4984             m_Network->AddOutputLayer(bindingId, tensorIdAndPtr.second->name.c_str());
4985 
4986         RegisterInputSlots(subgraphIndex,
4987                            VIRTUAL_OPERATOR_ID,
4988                            layer,
4989                            { static_cast<uint32_t>(tensorIdAndPtr.first) });
4990     }
4991 }
4992 
SetupConstantLayerTensorInfos(size_t subgraph)4993 void TfLiteParserImpl::SetupConstantLayerTensorInfos(size_t subgraph)
4994 {
4995     CHECK_SUBGRAPH(m_Model, subgraph);
4996 
4997     const auto & subgraphPtr = m_Model->subgraphs[subgraph];
4998     for (unsigned int subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex)
4999     {
5000         for (unsigned int tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex)
5001         {
5002             if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot == nullptr &&
5003                 m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size() > 0)
5004             {
5005                 TensorRawPtr tensorPtr = subgraphPtr->tensors[tensorIndex].get();
5006 
5007                 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
5008 
5009                 m_TensorInfos.insert({tensorIndex, tensorInfo});
5010             }
5011         }
5012     }
5013 }
5014 
SetupConstantLayers(size_t subgraph)5015 void TfLiteParserImpl::SetupConstantLayers(size_t subgraph)
5016 {
5017     CHECK_SUBGRAPH(m_Model, subgraph);
5018 
5019     const auto & subgraphPtr = m_Model->subgraphs[subgraph];
5020     for (unsigned int subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex)
5021     {
5022         for (unsigned int tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex)
5023         {
5024             if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot == nullptr &&
5025                 m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size() > 0)
5026             {
5027                 TensorRawPtr tensorPtr = subgraphPtr->tensors[tensorIndex].get();
5028 
5029                 if (IsConstTensor(tensorPtr))
5030                 {
5031                     armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
5032                     armnn::DataType dataType = tensorInfo.GetDataType();
5033 
5034                     if (std::find(m_ConstantsToDequantize.begin(), m_ConstantsToDequantize.end(), tensorPtr->buffer)
5035                         != m_ConstantsToDequantize.end())
5036                     {
5037                         dataType = DataType::Float32;
5038                     }
5039                     auto tensorAndData = CreateConstTensorNonPermuted(tensorPtr, tensorInfo, dataType);
5040 
5041                     std::string layerName = fmt::format("Constant:{}", tensorPtr->name);
5042                     IConnectableLayer *layer = m_Network->AddConstantLayer(tensorAndData.first, layerName.c_str());
5043 
5044                     layer->GetOutputSlot(0).SetTensorInfo(tensorAndData.first.GetInfo());
5045                     RegisterOutputSlots(subgraphIndex,
5046                                         VIRTUAL_OPERATOR_ID,
5047                                         layer,
5048                                         { tensorIndex });
5049                 }
5050                 else if (ShouldConstantTensorBeCreated(tensorIndex))
5051                 {
5052                     armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
5053                     armnn::DataType dataType = tensorInfo.GetDataType();
5054 
5055                     if (std::find(m_ConstantsToDequantize.begin(), m_ConstantsToDequantize.end(), tensorPtr->buffer)
5056                         != m_ConstantsToDequantize.end())
5057                     {
5058                         dataType = DataType::Float32;
5059                     }
5060                     // Make sure isConstant flag is set.
5061                     tensorInfo.SetConstant();
5062                     tensorInfo.SetDataType(dataType);
5063 
5064                     auto tensorAndData = ConstTensor(tensorInfo, std::vector<uint8_t>(tensorInfo.GetNumBytes()));
5065 
5066                     std::string layerName = fmt::format("Constant:{}", tensorPtr->name);
5067                     IConnectableLayer* layer = m_Network->AddConstantLayer(tensorAndData, layerName.c_str());
5068 
5069                     layer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
5070                     RegisterOutputSlots(subgraphIndex,
5071                                         VIRTUAL_OPERATOR_ID,
5072                                         layer,
5073                                         {tensorIndex});
5074                 }
5075                 else
5076                 {
5077                     throw ParseException(
5078                             fmt::format("Invalid Tensor: Tensor should be constant. {}",
5079                                         CHECK_LOCATION().AsString()));
5080                 }
5081             }
5082         }
5083     }
5084 }
5085 
5086 // example usage: BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[0]->buffer);
GetBuffer(const ModelPtr & model,size_t bufferIndex)5087 TfLiteParserImpl::BufferRawPtr TfLiteParserImpl::GetBuffer(const ModelPtr& model, size_t bufferIndex)
5088 {
5089     CHECK_BUFFER(model, bufferIndex);
5090     return model->buffers[bufferIndex].get();
5091 }
5092 
5093 template<typename T>
5094 std::pair<armnn::ConstTensor, TfLiteParserImpl::SupportedDataStorage>
CreateConstTensorAndStoreData(TfLiteParserImpl::BufferRawPtr bufferPtr,TfLiteParserImpl::TensorRawPtr tensorPtr,armnn::TensorInfo & tensorInfo,armnn::Optional<armnn::PermutationVector &> permutationVector)5095 TfLiteParserImpl::CreateConstTensorAndStoreData(TfLiteParserImpl::BufferRawPtr bufferPtr,
5096                                             TfLiteParserImpl::TensorRawPtr tensorPtr,
5097                                             armnn::TensorInfo& tensorInfo,
5098                                             armnn::Optional<armnn::PermutationVector&> permutationVector)
5099 {
5100     // Make sure isConstant flag is set.
5101     tensorInfo.SetConstant();
5102 
5103     auto constData = CreateConstTensorImpl<T>(bufferPtr,
5104                                               tensorPtr,
5105                                               tensorInfo,
5106                                               permutationVector);
5107     TfLiteParserImpl::SupportedDataStorage storage(std::move(constData.second));
5108     return std::make_pair(constData.first, std::move(storage));
5109 }
5110 
ShouldConstantTensorBeCreated(unsigned int tensorIndex)5111 bool TfLiteParserImpl::ShouldConstantTensorBeCreated(unsigned int tensorIndex)
5112 {
5113     // If the TensorIndex appears in the list of ConstantsToBeCreated then return true
5114     return (std::find(m_ConstantsToBeCreated.begin(), m_ConstantsToBeCreated.end(), tensorIndex)
5115             != m_ConstantsToBeCreated.end());
5116 }
5117 
IsConstTensor(TensorRawPtr tensorPtr)5118 bool TfLiteParserImpl::IsConstTensor(TensorRawPtr tensorPtr)
5119 {
5120     CHECK_TENSOR_PTR(tensorPtr);
5121     bool isConst = true;
5122 
5123     auto buffer = GetBuffer(m_Model, tensorPtr->buffer);
5124     if (buffer->data.size() == 0)
5125     {
5126         isConst = false;
5127     }
5128 
5129     return isConst;
5130 }
5131 
5132 std::pair<armnn::ConstTensor, TfLiteParserImpl::SupportedDataStorage>
CreateConstTensorPermuted(TensorRawPtr tensorPtr,armnn::TensorInfo & tensorInfo,armnn::Optional<armnn::PermutationVector &> permutationVector)5133 TfLiteParserImpl::CreateConstTensorPermuted(TensorRawPtr tensorPtr,
5134                                             armnn::TensorInfo& tensorInfo,
5135                                             armnn::Optional<armnn::PermutationVector&> permutationVector)
5136 {
5137     CHECK_TENSOR_PTR(tensorPtr);
5138     auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5139     CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5140 
5141     // Make sure isConstant flag is set.
5142     tensorInfo.SetConstant();
5143 
5144     switch (tensorInfo.GetDataType())
5145     {
5146         case armnn::DataType::Float32:
5147             return CreateConstTensorAndStoreData<float>(bufferPtr,
5148                                                         tensorPtr,
5149                                                         tensorInfo,
5150                                                         permutationVector);
5151         case armnn::DataType::QAsymmU8:
5152             return CreateConstTensorAndStoreData<uint8_t>(bufferPtr,
5153                                                           tensorPtr,
5154                                                           tensorInfo,
5155                                                           permutationVector);
5156         case armnn::DataType::QSymmS8:
5157             return CreateConstTensorAndStoreData<int8_t>(bufferPtr,
5158                                                          tensorPtr,
5159                                                          tensorInfo,
5160                                                          permutationVector);
5161         case armnn::DataType::QAsymmS8:
5162             return CreateConstTensorAndStoreData<int8_t>(bufferPtr,
5163                                                          tensorPtr,
5164                                                          tensorInfo,
5165                                                          permutationVector);
5166         case armnn::DataType::Signed32:
5167             return CreateConstTensorAndStoreData<int32_t>(bufferPtr,
5168                                                           tensorPtr,
5169                                                           tensorInfo,
5170                                                           permutationVector);
5171         default:
5172         {
5173             std::stringstream errString;
5174             errString << "Unexpected datatype when creating const tensor: "
5175                         << armnn::GetDataTypeName(tensorInfo.GetDataType())
5176                         << " shape:" << tensorInfo.GetShape()
5177                         << CHECK_LOCATION().AsString();
5178             throw ParseException(errString.str());
5179         }
5180     }
5181 }
5182 
CreateConstTensorNonPermuted(TensorRawPtr tensorPtr,armnn::TensorInfo & tensorInfo)5183 armnn::ConstTensor TfLiteParserImpl::CreateConstTensorNonPermuted(TensorRawPtr tensorPtr,
5184                                                                   armnn::TensorInfo& tensorInfo)
5185 {
5186     CHECK_TENSOR_PTR(tensorPtr);
5187     auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5188     CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5189 
5190     // Make sure isConstant flag is set.
5191     tensorInfo.SetConstant();
5192 
5193     return ConstTensor(tensorInfo, bufferPtr->data.data());
5194 }
5195 
5196 std::pair<armnn::ConstTensor, std::unique_ptr<float[]>>
CreateConstTensorNonPermuted(TensorRawPtr tensorPtr,armnn::TensorInfo & tensorInfo,armnn::DataType inputDataType)5197 TfLiteParserImpl::CreateConstTensorNonPermuted(TensorRawPtr tensorPtr,
5198                                                armnn::TensorInfo& tensorInfo,
5199                                                armnn::DataType inputDataType)
5200 {
5201     CHECK_TENSOR_PTR(tensorPtr);
5202     auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5203     CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5204 
5205     // Make sure isConstant flag is set.
5206     tensorInfo.SetConstant();
5207 
5208     if (inputDataType == DataType::Float32 && tensorInfo.GetDataType() != DataType::Float32)
5209     {
5210         try
5211         {
5212             TensorInfo constTensorInfo(tensorInfo.GetShape(), DataType::Float32, 0.0f, 0, true);
5213             std::unique_ptr<float[]> data = armnnUtils::ToFloatArray(bufferPtr->data, tensorInfo);
5214             return std::make_pair(ConstTensor(constTensorInfo, data.get()), std::move(data));
5215         }
5216         catch (InvalidArgumentException&)
5217         {
5218             throw ParseException(
5219                     fmt::format("Unsupported input/weights combination:  Input {} not supported with Weights {}",
5220                                 GetDataTypeName(DataType::Float32),
5221                                 GetDataTypeName(tensorInfo.GetDataType()),
5222                                 CHECK_LOCATION().AsString()));
5223         }
5224     }
5225     else
5226     {
5227         return std::make_pair(ConstTensor(tensorInfo, bufferPtr->data.data()), std::unique_ptr<float[]>());
5228     }
5229 }
5230 
5231 std::pair<armnn::ConstTensor*, std::unique_ptr<float[]>>
CreateConstTensorPtr(TensorRawPtr tensorPtr,armnn::TensorInfo & inputTensorInfo)5232 TfLiteParserImpl::CreateConstTensorPtr(TensorRawPtr tensorPtr, armnn::TensorInfo& inputTensorInfo)
5233 {
5234     CHECK_TENSOR_PTR(tensorPtr);
5235     armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
5236     auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5237     CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5238 
5239     // Make sure isConstant flag is set.
5240     tensorInfo.SetConstant();
5241 
5242     if (inputTensorInfo.GetDataType() == DataType::Float32 && tensorInfo.GetDataType() != DataType::Float32)
5243     {
5244         try
5245         {
5246             TensorInfo constTensorInfo(tensorInfo.GetShape(), DataType::Float32, 0.0f, 0, true);
5247             std::unique_ptr<float[]> data = armnnUtils::ToFloatArray(bufferPtr->data, tensorInfo);
5248             return std::make_pair(new ConstTensor(constTensorInfo, data.get()), std::move(data));
5249         }
5250         catch (InvalidArgumentException&)
5251         {
5252             throw ParseException(
5253                     fmt::format("Unsupported input/weights combination:  Input {} not supported with Weights {}",
5254                                 GetDataTypeName(DataType::Float32),
5255                                 GetDataTypeName(tensorInfo.GetDataType()),
5256                                 CHECK_LOCATION().AsString()));
5257         }
5258     }
5259     else
5260     {
5261         return std::make_pair(new ConstTensor(tensorInfo, bufferPtr->data.data()), std::unique_ptr<float[]>());
5262     }
5263 }
5264 
GetNetworkInputBindingInfo(size_t subgraphId,const std::string & name) const5265 BindingPointInfo TfLiteParserImpl::GetNetworkInputBindingInfo(size_t subgraphId,
5266                                                               const std::string& name) const
5267 {
5268     CHECK_SUBGRAPH(m_Model, subgraphId);
5269     auto inputs = GetSubgraphInputs(m_Model, subgraphId);
5270     for (auto const& input : inputs)
5271     {
5272         if (input.second->name == name)
5273         {
5274             auto bindingId = GenerateLayerBindingId(subgraphId, input.first);
5275             auto inputTensorInfo = ToTensorInfo(input.second);
5276             // Input tensors are always treated as constant tensors during network execution.
5277             inputTensorInfo.SetConstant(true);
5278             return std::make_pair(bindingId, inputTensorInfo);
5279         }
5280     }
5281 
5282     std::stringstream bindings;
5283     for (auto const& input : inputs)
5284     {
5285         bindings << "'" << input.second->name << "' ";
5286     }
5287 
5288     throw ParseException(
5289         fmt::format("No input binding found for subgraph:{} and name:{}. "
5290                     "Possible inputs are: [{}] {}",
5291                     subgraphId,
5292                     name,
5293                     bindings.str(),
5294                     CHECK_LOCATION().AsString()));
5295 }
5296 
GetNetworkOutputBindingInfo(size_t subgraphId,const std::string & name) const5297 BindingPointInfo TfLiteParserImpl::GetNetworkOutputBindingInfo(size_t subgraphId,
5298                                                                const std::string& name) const
5299 {
5300     CHECK_SUBGRAPH(m_Model, subgraphId);
5301     auto outputs = GetSubgraphOutputs(m_Model, subgraphId);
5302     for (unsigned int i = 0; i < outputs.size(); ++i)
5303     {
5304         auto const output = outputs[i];
5305         if (output.second->name == name)
5306         {
5307             auto bindingId = GenerateLayerBindingId(subgraphId, output.first);
5308             std::vector<unsigned int> shape = m_OverriddenOutputShapes.size() > 0 ?
5309                                                 m_OverriddenOutputShapes[i] : AsUnsignedVector(output.second->shape);
5310             return std::make_pair(bindingId, ToTensorInfo(output.second, shape));
5311         }
5312     }
5313 
5314     std::stringstream bindings;
5315     for (auto const& output : outputs)
5316     {
5317         bindings << "'" << output.second->name << "' ";
5318     }
5319 
5320     throw ParseException(
5321         fmt::format("No output binding found for subgraph:{} and name:{}. "
5322                     "Possible outputs are: [{}] {}",
5323                     subgraphId,
5324                     name,
5325                     bindings.str(),
5326                     CHECK_LOCATION().AsString()));
5327 }
5328 
GetSubgraphCount() const5329 size_t TfLiteParserImpl::GetSubgraphCount() const
5330 {
5331     return m_Model->subgraphs.size();
5332 }
5333 
GetSubgraphInputTensorNames(size_t subgraphId) const5334 std::vector<std::string> TfLiteParserImpl::GetSubgraphInputTensorNames(size_t subgraphId) const
5335 {
5336     CHECK_SUBGRAPH(m_Model, subgraphId);
5337     auto inputs = GetSubgraphInputs(m_Model, subgraphId);
5338     std::vector<std::string> result;
5339     result.reserve(inputs.size());
5340     for (auto const& input : inputs)
5341     {
5342         result.push_back(input.second->name);
5343     }
5344     return result;
5345 }
5346 
GetSubgraphOutputTensorNames(size_t subgraphId) const5347 std::vector<std::string> TfLiteParserImpl::GetSubgraphOutputTensorNames(size_t subgraphId) const
5348 {
5349     CHECK_SUBGRAPH(m_Model, subgraphId);
5350     auto outputs = GetSubgraphOutputs(m_Model, subgraphId);
5351     std::vector<std::string> result;
5352     result.reserve(outputs.size());
5353     for (auto const& output : outputs)
5354     {
5355         result.push_back(output.second->name);
5356     }
5357     return result;
5358 }
5359 
GetVersion()5360 const std::string TfLiteParserImpl::GetVersion()
5361 {
5362     return TFLITE_PARSER_VERSION;
5363 }
5364 
SupportedDataStorage(std::unique_ptr<float[]> && data)5365 TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<float[]>&& data)
5366 : m_FloatData(std::move(data))
5367 , m_Uint8Data(nullptr)
5368 , m_Int8Data(nullptr)
5369 , m_Int32Data(nullptr)
5370 {
5371 }
5372 
SupportedDataStorage(std::unique_ptr<uint8_t[]> && data)5373 TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<uint8_t[]>&& data)
5374 : m_FloatData(nullptr)
5375 , m_Uint8Data(std::move(data))
5376 , m_Int8Data(nullptr)
5377 , m_Int32Data(nullptr)
5378 {
5379 }
5380 
SupportedDataStorage(std::unique_ptr<int8_t[]> && data)5381 TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<int8_t[]>&& data)
5382 : m_FloatData(nullptr)
5383 , m_Uint8Data(nullptr)
5384 , m_Int8Data(std::move(data))
5385 , m_Int32Data(nullptr)
5386 {
5387 }
5388 
SupportedDataStorage(std::unique_ptr<int32_t[]> && data)5389 TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<int32_t[]>&& data)
5390 : m_FloatData(nullptr)
5391 , m_Uint8Data(nullptr)
5392 , m_Int8Data(nullptr)
5393 , m_Int32Data(std::move(data))
5394 {
5395 }
5396 
5397 } // armnnTfLiteParser
5398