• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include "TfLiteParser.hpp"
7 
8 #include <armnn/BackendOptions.hpp>
9 #include <armnn/Descriptors.hpp>
10 #include <armnn/Exceptions.hpp>
11 #include <armnn/Logging.hpp>
12 #include <armnn/Tensor.hpp>
13 #include <armnn/TypesUtils.hpp>
14 #include <armnn/utility/Assert.hpp>
15 #include <armnn/utility/IgnoreUnused.hpp>
16 #include <armnn/utility/NumericCast.hpp>
17 
18 // armnnUtils:
19 #include <armnnUtils/Permute.hpp>
20 #include <Filesystem.hpp>
21 
22 #include <ParserHelper.hpp>
23 #include <VerificationHelpers.hpp>
24 
25 // The generated code based on the Tf Lite schema:
26 #include <schema_generated.h>
27 
28 #include <flatbuffers/flexbuffers.h>
29 
30 #include <fmt/format.h>
31 
32 #include <fstream>
33 #include <algorithm>
34 #include <limits>
35 #include <numeric>
36 #include <sstream>
37 
38 #define ARMNN_THROW_PARSE_EXCEPTION(msg) \
39           { \
40             throw armnn::ParseException( static_cast<const std::stringstream&>( std::stringstream() << msg \
41                << ": " \
42                << CHECK_LOCATION().AsString()).str()); \
43           }
44 
45 using namespace armnn;
46 using armnn::CheckLocation;
47 namespace armnnTfLiteParser
48 {
49 namespace
50 {
51 
52 const uint32_t VIRTUAL_OPERATOR_ID = std::numeric_limits<uint32_t>::max();
53 
CheckSubgraph(const TfLiteParser::ModelPtr & model,size_t subgraphIndex,const CheckLocation & location)54 void CheckSubgraph(const TfLiteParser::ModelPtr & model,
55                    size_t subgraphIndex,
56                    const CheckLocation & location)
57 {
58     if (model.get() == nullptr)
59     {
60         throw ParseException(
61             fmt::format("{} was called with invalid (null) model. "
62                         "Possible reason is that the model is not yet loaded and Unpack(ed). "
63                         "subgraph:{} at {}",
64                         location.m_Function,
65                         subgraphIndex,
66                         location.FileLine()));
67     }
68     else if (subgraphIndex >= model->subgraphs.size())
69     {
70         throw ParseException(
71             fmt::format("{} was called with an invalid subgraph index. "
72                         "subgraph:{} at {}",
73                         location.m_Function,
74                         subgraphIndex,
75                         location.FileLine()));
76     }
77 }
78 
79 #define CHECK_SUBGRAPH(MODEL, SUBGRAPH_INDEX) \
80     CheckSubgraph(MODEL, SUBGRAPH_INDEX, CHECK_LOCATION())
81 
CheckModel(const TfLiteParser::ModelPtr & model,size_t subgraphIndex,size_t operatorIndex,const CheckLocation & location)82 void CheckModel(const TfLiteParser::ModelPtr & model,
83                 size_t subgraphIndex,
84                 size_t operatorIndex,
85                 const CheckLocation & location)
86 {
87     if (model.get() == nullptr)
88     {
89         throw ParseException(
90             fmt::format("{} was called with invalid (null) model. "
91                         "Possible reason is that the model is not yet loaded and Unpack(ed). "
92                         "subgraph:{} operator:{} at {}",
93                         location.m_Function,
94                         subgraphIndex,
95                         operatorIndex,
96                         location.FileLine()));
97     }
98     else if (subgraphIndex >= model->subgraphs.size())
99     {
100         throw ParseException(
101             fmt::format("{} was called with an invalid subgraph index. "
102                         "subgraph:{} operator:{} at {}",
103                         location.m_Function,
104                         subgraphIndex,
105                         operatorIndex,
106                         location.FileLine()));
107     }
108     else if (operatorIndex >= model->subgraphs[subgraphIndex]->operators.size() &&
109              operatorIndex != VIRTUAL_OPERATOR_ID)
110     {
111         throw ParseException(
112             fmt::format("{} was called with an invalid operator index. "
113                         "subgraph:{} operator:{} at {}",
114                         location.m_Function,
115                         subgraphIndex,
116                         operatorIndex,
117                         location.FileLine()));
118     }
119 }
120 
121 #define CHECK_MODEL(MODEL, SUBGRAPH_INDEX, OPERATOR_INDEX) \
122     CheckModel(MODEL, SUBGRAPH_INDEX, OPERATOR_INDEX, CHECK_LOCATION())
123 
CheckTensor(const TfLiteParser::ModelPtr & model,size_t subgraphIndex,size_t tensorIndex,const CheckLocation & location)124 void CheckTensor(const TfLiteParser::ModelPtr & model,
125                  size_t subgraphIndex,
126                  size_t tensorIndex,
127                  const CheckLocation & location)
128 {
129     // not checking model, because I assume CHECK_MODEL already run
130     // and checked that. An assert would do.
131     ARMNN_ASSERT_MSG(model.get() != nullptr, "Expecting a valid model in this function");
132 
133     // also subgraph index should be checked by CHECK_MODEL so
134     // I only add an assert here
135     ARMNN_ASSERT_MSG(subgraphIndex < model->subgraphs.size(), "Expecting a valid subgraph index");
136 
137     // the tensor index is the only one to check here
138     if (tensorIndex >= model->subgraphs[subgraphIndex]->tensors.size())
139     {
140         throw ParseException(
141             fmt::format("{} was called with an invalid tensor index. "
142                         "subgraph:{} tensor:{} at {}",
143                         location.m_Function,
144                         subgraphIndex,
145                         tensorIndex,
146                         location.FileLine()));
147     }
148 }
149 
150 #define CHECK_TENSOR(MODEL, SUBGRAPH_INDEX, TENSOR_INDEX) \
151     CheckTensor(MODEL, SUBGRAPH_INDEX, TENSOR_INDEX, CHECK_LOCATION())
152 
CheckTensorPtr(TfLiteParser::TensorRawPtr rawPtr,const CheckLocation & location)153 void CheckTensorPtr(TfLiteParser::TensorRawPtr rawPtr,
154                     const CheckLocation & location)
155 {
156     if (rawPtr == nullptr)
157     {
158         throw ParseException(
159             fmt::format("{} was called with a null tensor pointer at {}", location.m_Function, location.FileLine()));
160     }
161 }
162 
163 #define CHECK_TENSOR_PTR(TENSOR_PTR) \
164     CheckTensorPtr(TENSOR_PTR, CHECK_LOCATION())
165 
CheckBuffer(const TfLiteParser::ModelPtr & model,size_t bufferIndex,const CheckLocation & location)166 void CheckBuffer(const TfLiteParser::ModelPtr & model,
167                  size_t bufferIndex,
168                  const CheckLocation & location)
169 {
170     if (model.get() == nullptr)
171     {
172         throw ParseException(
173             fmt::format("{} was called with invalid (null) model. "
174                         "Possible reason is that the model is not yet loaded and Unpack(ed). "
175                         "buffer:{} at {}",
176                         location.m_Function,
177                         bufferIndex,
178                         location.FileLine()));
179     }
180     else if (bufferIndex >= model->buffers.size())
181     {
182         throw ParseException(
183             fmt::format("{} was called with an invalid buffer index. "
184                         "buffer index:{} at {}",
185                         location.m_Function,
186                         bufferIndex,
187                         location.FileLine()));
188     }
189     else if (model->buffers[bufferIndex].get() == nullptr)
190     {
191         throw ParseException(
192             fmt::format("The buffer #{} is null. {}",
193                         bufferIndex,
194                         location.AsString()));
195     }
196 }
197 
198 #define CHECK_BUFFER(MODEL, BUFFER_INDEX) \
199     CheckBuffer(MODEL, BUFFER_INDEX, CHECK_LOCATION())
200 
CheckBufferSize(TfLiteParser::BufferRawPtr bufferPtr,const armnn::TensorInfo & tensorInfo,uint32_t bufferId,const CheckLocation & location)201 void CheckBufferSize(TfLiteParser::BufferRawPtr bufferPtr,
202                      const armnn::TensorInfo & tensorInfo,
203                      uint32_t bufferId,
204                      const CheckLocation & location)
205 {
206     if (bufferPtr == nullptr)
207     {
208         throw ParseException(
209             fmt::format("BufferPtr is null for buffer:{}. {}",
210                         bufferId,
211                         location.AsString()));
212     }
213     else if(tensorInfo.GetNumElements() > bufferPtr->data.size() ||
214             tensorInfo.GetNumBytes() > bufferPtr->data.size())
215     {
216         std::stringstream ss;
217         ss << "Buffer #" << bufferId << " has " << bufferPtr->data.size() << " bytes. "
218            << "For tensor: " << tensorInfo.GetShape()
219            << " expecting: " << tensorInfo.GetNumBytes() << " bytes and "
220            << tensorInfo.GetNumElements() << " elements. " << location.AsString();
221         throw ParseException(ss.str());
222     }
223 }
224 
225 #define CHECK_BUFFER_SIZE(BUFFER_PTR, TENSOR_INFO, BUFFER_ID) \
226     CheckBufferSize(BUFFER_PTR, TENSOR_INFO, BUFFER_ID, CHECK_LOCATION())
227 
IsActivationSupported(tflite::ActivationFunctionType activationType)228 bool IsActivationSupported(tflite::ActivationFunctionType activationType)
229 {
230     switch(activationType)
231     {
232         case tflite::ActivationFunctionType_NONE:
233         case tflite::ActivationFunctionType_RELU:
234         case tflite::ActivationFunctionType_RELU6:
235         case tflite::ActivationFunctionType_TANH:
236         {
237             return true;
238         }
239         default:
240         {
241             return false;
242         }
243     }
244 }
245 
246 #define CHECK_SUPPORTED_FUSED_ACTIVATION(OPTION, SUBGRAPH_INDEX, OPERATOR_INDEX) \
247     do { \
248         if (IsActivationSupported(OPTION->fused_activation_function) == false) \
249         { \
250             throw ParseException( \
251                 fmt::format("TfLite parser doesn't suppport fused activation: " \
252                             "{}/{} in {} subgraph:{} operator:{} at {}", \
253                             OPTION->fused_activation_function, \
254                             tflite::EnumNameActivationFunctionType(\
255                             OPTION->fused_activation_function), \
256                             __func__, \
257                             SUBGRAPH_INDEX, \
258                             OPERATOR_INDEX, \
259                             CHECK_LOCATION().FileLine())); \
260         } \
261     } while(false)
262 
263 
AsUnsignedVector(const std::vector<int32_t> & in)264 std::vector<unsigned int> AsUnsignedVector(const std::vector<int32_t> & in)
265 {
266     std::vector<unsigned int> result;
267     result.reserve(in.size());
268     for (auto & i : in)
269     {
270         result.push_back(CHECKED_NON_NEGATIVE(i));
271     }
272     return result;
273 }
274 
CalcPadding(uint32_t inputSize,uint32_t filterSize,uint32_t stride,uint32_t dilation,uint32_t & paddingFront,uint32_t & paddingBack,tflite::Padding padding)275 void CalcPadding(uint32_t inputSize,
276                  uint32_t filterSize,
277                  uint32_t stride,
278                  uint32_t dilation,
279                  uint32_t& paddingFront,
280                  uint32_t& paddingBack,
281                  tflite::Padding padding)
282 {
283     paddingFront = 0;
284     paddingBack = 0;
285     if (padding == tflite::Padding_SAME)
286     {
287         uint32_t outputSize = (inputSize + stride - 1) / stride;
288         uint32_t dilatedSize = filterSize + (dilation - 1) * (filterSize - 1);
289         uint32_t temp = (outputSize - 1) * stride + dilatedSize;
290         if (temp > inputSize)
291         {
292             paddingFront = (temp - inputSize) / 2;
293             paddingBack = (temp - inputSize) - paddingFront;
294         }
295     }
296 }
297 
ToTensorInfo(TfLiteParser::TensorRawPtr tensorPtr,const std::vector<unsigned int> & shapes,const armnn::PermutationVector & dimensionMappings={0, 1, 2, 3},const bool outputTensor=false)298 armnn::TensorInfo ToTensorInfo(TfLiteParser::TensorRawPtr tensorPtr,
299                                const std::vector<unsigned int>& shapes,
300                                const armnn::PermutationVector& dimensionMappings = {0, 1, 2, 3},
301                                const bool outputTensor = false)
302 {
303     armnn::DataType type;
304     CHECK_TENSOR_PTR(tensorPtr);
305 
306     switch (tensorPtr->type)
307     {
308         case tflite::TensorType_UINT8:
309             type = armnn::DataType::QAsymmU8;
310             break;
311         case tflite::TensorType_FLOAT32:
312             type = armnn::DataType::Float32;
313             break;
314         case tflite::TensorType_INT8:
315             if (tensorPtr->quantization->zero_point.size() == 1)
316             {
317                 // Per-tensor
318                 type = armnn::DataType::QAsymmS8;
319             }
320             else
321             {
322                 // Per-channel
323                 type = armnn::DataType::QSymmS8;
324             }
325             break;
326         case tflite::TensorType_INT16:
327             type = armnn::DataType::QSymmS16;
328             break;
329         case tflite::TensorType_INT32:
330             type = armnn::DataType::Signed32;
331             break;
332         case tflite::TensorType_INT64:
333             type = armnn::DataType::Signed64;
334             break;
335         default:
336         {
337             CheckLocation location = CHECK_LOCATION();
338             throw ParseException(
339                 fmt::format("Unsupported data type {} = {} for tensor: {}. {}",
340                             tensorPtr->type,
341                             tflite::EnumNameTensorType(tensorPtr->type),
342                             tensorPtr->name,
343                             location.AsString()));
344         }
345     }
346     std::vector<unsigned int> safeShape = shapes;
347     bool isDynamic = false;
348     if (safeShape.size() == 0)
349     {
350         safeShape.push_back(1);
351         if (outputTensor)
352         {
353             isDynamic = true;
354         }
355     }
356 
357     float quantizationScale = 0.0f;
358     int32_t quantizationOffset = 0;
359 
360     if (tensorPtr->quantization.get())
361     {
362         if (tensorPtr->quantization->scale.size() <= 1)
363         {
364             CHECK_VALID_SIZE(tensorPtr->quantization->zero_point.size(), 0, 1);
365             CHECK_VALID_SIZE(tensorPtr->quantization->zero_point.size(), 0, 1);
366 
367             if (tensorPtr->quantization->scale.size() == 1)
368             {
369                 quantizationScale = tensorPtr->quantization->scale[0];
370             }
371             if (tensorPtr->quantization->zero_point.size() == 1)
372             {
373                 // NOTE: we lose precision here when converting from 64 bit to 32
374                 //       but this is what we support at the moment in ArmNN
375                 quantizationOffset = armnn::numeric_cast<int32_t>(tensorPtr->quantization->zero_point[0]);
376             }
377 
378             TensorShape tensorShape(armnn::numeric_cast<unsigned int>(safeShape.size()),
379                                     safeShape.data());
380             if (isDynamic)
381             {
382                 tensorShape = TensorShape(1, false);
383             }
384             armnn::TensorInfo result(tensorShape,
385                                      type,
386                                      quantizationScale,
387                                      quantizationOffset);
388             return result;
389         }
390         else
391         {
392             std::vector<float> quantizationScales;
393             std::vector<int32_t> quantizationOffsets;
394 
395             // Scale
396             std::copy(tensorPtr->quantization->scale.begin(),
397                       tensorPtr->quantization->scale.end(),
398                       std::back_inserter(quantizationScales));
399 
400             // QSymmS8 Per-axis
401             TensorShape tensorShape(armnn::numeric_cast<unsigned int>(safeShape.size()),
402                                     safeShape.data());
403             if (isDynamic)
404             {
405                 tensorShape = TensorShape(1, false);
406             }
407             armnn::TensorInfo result(tensorShape,
408                                      type,
409                                      quantizationScales,
410                                      dimensionMappings[armnn::numeric_cast<unsigned int>(
411                                          tensorPtr->quantization->quantized_dimension)]);
412             return result;
413         }
414     }
415     else
416     {
417         TensorShape tensorShape(armnn::numeric_cast<unsigned int>(safeShape.size()),
418                                 safeShape.data());
419         if (isDynamic)
420         {
421             tensorShape = TensorShape(1, false);
422         }
423         armnn::TensorInfo result(tensorShape,
424                                  type,
425                                  quantizationScale,
426                                  quantizationOffset);
427         return result;
428     }
429 }
430 
ToTensorInfo(TfLiteParser::TensorRawPtr tensorPtr,const armnn::PermutationVector & dimensionMappings={0, 1, 2, 3})431 armnn::TensorInfo ToTensorInfo(TfLiteParser::TensorRawPtr tensorPtr,
432                                const armnn::PermutationVector& dimensionMappings = {0, 1, 2, 3})
433 {
434     auto const & dimensions = AsUnsignedVector(tensorPtr->shape);
435     return ToTensorInfo(tensorPtr, dimensions, dimensionMappings);
436 }
437 
ToTensorInfo(TfLiteParser::TensorRawPtr tensorPtr,const bool outputTensor)438 armnn::TensorInfo ToTensorInfo(TfLiteParser::TensorRawPtr tensorPtr,
439                                const bool outputTensor)
440 {
441     auto const & dimensions = AsUnsignedVector(tensorPtr->shape);
442     const armnn::PermutationVector& dimensionMappings = {0, 1, 2, 3};
443     return ToTensorInfo(tensorPtr, dimensions, dimensionMappings, outputTensor);
444 }
445 
446 template<typename T>
447 std::pair<armnn::ConstTensor, std::unique_ptr<T[]>>
CreateConstTensorImpl(TfLiteParser::BufferRawPtr bufferPtr,TfLiteParser::TensorRawPtr tensorPtr,armnn::TensorInfo & tensorInfo,armnn::Optional<armnn::PermutationVector &> permutationVector)448 CreateConstTensorImpl(TfLiteParser::BufferRawPtr bufferPtr,
449                       TfLiteParser::TensorRawPtr tensorPtr,
450                       armnn::TensorInfo& tensorInfo,
451                       armnn::Optional<armnn::PermutationVector&> permutationVector)
452 {
453     IgnoreUnused(tensorPtr);
454     ARMNN_ASSERT_MSG(tensorPtr != nullptr, "tensorPtr is null");
455     ARMNN_ASSERT_MSG(bufferPtr != nullptr,
456         fmt::format("Buffer for buffer:{} is null", tensorPtr->buffer).c_str());
457 
458     std::unique_ptr<T[]> data(new T[tensorInfo.GetNumElements()]);
459 
460     if (permutationVector.has_value() && permutationVector.value().GetSize() > 0)
461     {
462         tensorInfo = armnnUtils::Permuted(tensorInfo, permutationVector.value());
463         armnnUtils::Permute(tensorInfo.GetShape(), permutationVector.value(),
464                             reinterpret_cast<const T*>(bufferPtr->data.data()), data.get(), sizeof(T));
465     }
466     else
467     {
468         ::memcpy(data.get(), bufferPtr->data.data(), tensorInfo.GetNumBytes());
469     }
470 
471     return std::make_pair(ConstTensor(tensorInfo, data.get()), std::move(data));
472 }
473 
GenerateLayerBindingId(size_t subgraphIndex,size_t tensorIndex)474 armnn::LayerBindingId GenerateLayerBindingId(size_t subgraphIndex, size_t tensorIndex)
475 {
476     // generate the binding id by shifting the tensor id by 8 bit
477     // and add the subgraph id, which allows 256 subgraphs
478     return static_cast<armnn::LayerBindingId>((tensorIndex<<8)+subgraphIndex);
479 }
480 
CheckShape(const armnn::TensorShape & actual,const std::vector<int32_t> & expected)481 bool CheckShape(const armnn::TensorShape& actual, const std::vector<int32_t>& expected)
482 {
483     const unsigned int actualSize = actual.GetNumDimensions();
484     if (actualSize != expected.size())
485     {
486         return false;
487     }
488 
489     for (unsigned int i = 0u; i < actualSize; i++)
490     {
491         if (expected[i] < 0 ||
492             actual[i] != static_cast<unsigned int>(expected[i]))
493         {
494             return false;
495         }
496     }
497 
498     return true;
499 }
500 
CheckMatchingQuantization(const TensorInfo & first,const TensorInfo & second,const std::string & descName,std::string const & firstName,std::string const & secondName)501 void CheckMatchingQuantization(const TensorInfo& first,
502                                const TensorInfo& second,
503                                const std::string& descName,
504                                std::string const& firstName,
505                                std::string const& secondName)
506 {
507     if (!first.IsQuantized() ||
508         !second.IsQuantized())
509     {
510         // Not a quantized type, ignore the validation
511         return;
512     }
513 
514     DataType firstDataType  = first.GetDataType();
515     DataType secondDataType = second.GetDataType();
516 
517     if (firstDataType != secondDataType)
518     {
519         throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
520                                        " must be of the same quantized type, " +
521                                        firstName + " is " + GetDataTypeName(firstDataType) + ", " +
522                                        secondName + " is " + GetDataTypeName(secondDataType));
523     }
524 
525     if (!first.IsTypeSpaceMatch(second))
526     {
527         throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
528                                        " must have the same quantization space, " +
529                                        firstName + " has offset " + std::to_string(first.GetQuantizationOffset()) +
530                                        " and scale " + std::to_string(first.GetQuantizationScale()) + ", " +
531                                        secondName + " has offset " + std::to_string(second.GetQuantizationOffset()) +
532                                        " and scale " + std::to_string(second.GetQuantizationScale()));
533     }
534 }
535 
536 } // <anonymous>
537 
TfLiteParser(const Optional<ITfLiteParser::TfLiteParserOptions> & options)538 TfLiteParser::TfLiteParser(const Optional<ITfLiteParser::TfLiteParserOptions>& options)
539 : m_Options(options)
540 , m_Network(nullptr, nullptr)
541 , m_ParserFunctions(tflite::BuiltinOperator_MAX+1, &TfLiteParser::ParseUnsupportedOperator)
542 {
543     // register supported operators
544     m_ParserFunctions[tflite::BuiltinOperator_ADD]                     = &TfLiteParser::ParseAdd;
545     m_ParserFunctions[tflite::BuiltinOperator_AVERAGE_POOL_2D]         = &TfLiteParser::ParseAveragePool2D;
546     m_ParserFunctions[tflite::BuiltinOperator_BATCH_TO_SPACE_ND]       = &TfLiteParser::ParseBatchToSpaceND;
547     m_ParserFunctions[tflite::BuiltinOperator_CONCATENATION]           = &TfLiteParser::ParseConcatenation;
548     m_ParserFunctions[tflite::BuiltinOperator_CONV_2D]                 = &TfLiteParser::ParseConv2D;
549     m_ParserFunctions[tflite::BuiltinOperator_CUSTOM]                  = &TfLiteParser::ParseCustomOperator;
550     m_ParserFunctions[tflite::BuiltinOperator_DEPTHWISE_CONV_2D]       = &TfLiteParser::ParseDepthwiseConv2D;
551     m_ParserFunctions[tflite::BuiltinOperator_DEQUANTIZE]              = &TfLiteParser::ParseDequantize;
552     m_ParserFunctions[tflite::BuiltinOperator_EXP]                     = &TfLiteParser::ParseExp;
553     m_ParserFunctions[tflite::BuiltinOperator_FULLY_CONNECTED]         = &TfLiteParser::ParseFullyConnected;
554     m_ParserFunctions[tflite::BuiltinOperator_HARD_SWISH]              = &TfLiteParser::ParseHardSwish;
555     m_ParserFunctions[tflite::BuiltinOperator_LEAKY_RELU]              = &TfLiteParser::ParseLeakyRelu;
556     m_ParserFunctions[tflite::BuiltinOperator_LOGISTIC]                = &TfLiteParser::ParseLogistic;
557     m_ParserFunctions[tflite::BuiltinOperator_L2_NORMALIZATION]        = &TfLiteParser::ParseL2Normalization;
558     m_ParserFunctions[tflite::BuiltinOperator_MAX_POOL_2D]             = &TfLiteParser::ParseMaxPool2D;
559     m_ParserFunctions[tflite::BuiltinOperator_MAXIMUM]                 = &TfLiteParser::ParseMaximum;
560     m_ParserFunctions[tflite::BuiltinOperator_MEAN]                    = &TfLiteParser::ParseMean;
561     m_ParserFunctions[tflite::BuiltinOperator_MINIMUM]                 = &TfLiteParser::ParseMinimum;
562     m_ParserFunctions[tflite::BuiltinOperator_MUL]                     = &TfLiteParser::ParseMul;
563     m_ParserFunctions[tflite::BuiltinOperator_NEG]                     = &TfLiteParser::ParseNeg;
564     m_ParserFunctions[tflite::BuiltinOperator_PACK]                    = &TfLiteParser::ParsePack;
565     m_ParserFunctions[tflite::BuiltinOperator_PAD]                     = &TfLiteParser::ParsePad;
566     m_ParserFunctions[tflite::BuiltinOperator_QUANTIZE]                = &TfLiteParser::ParseQuantize;
567     m_ParserFunctions[tflite::BuiltinOperator_RELU]                    = &TfLiteParser::ParseRelu;
568     m_ParserFunctions[tflite::BuiltinOperator_RELU6]                   = &TfLiteParser::ParseRelu6;
569     m_ParserFunctions[tflite::BuiltinOperator_RESHAPE]                 = &TfLiteParser::ParseReshape;
570     m_ParserFunctions[tflite::BuiltinOperator_RESIZE_BILINEAR]         = &TfLiteParser::ParseResizeBilinear;
571     m_ParserFunctions[tflite::BuiltinOperator_RESIZE_NEAREST_NEIGHBOR] = &TfLiteParser::ParseResizeNearestNeighbor;
572     m_ParserFunctions[tflite::BuiltinOperator_SLICE]                   = &TfLiteParser::ParseSlice;
573     m_ParserFunctions[tflite::BuiltinOperator_SOFTMAX]                 = &TfLiteParser::ParseSoftmax;
574     m_ParserFunctions[tflite::BuiltinOperator_SPACE_TO_BATCH_ND]       = &TfLiteParser::ParseSpaceToBatchND;
575     m_ParserFunctions[tflite::BuiltinOperator_SPLIT]                   = &TfLiteParser::ParseSplit;
576     m_ParserFunctions[tflite::BuiltinOperator_SPLIT_V]                 = &TfLiteParser::ParseSplitV;
577     m_ParserFunctions[tflite::BuiltinOperator_SQUEEZE]                 = &TfLiteParser::ParseSqueeze;
578     m_ParserFunctions[tflite::BuiltinOperator_STRIDED_SLICE]           = &TfLiteParser::ParseStridedSlice;
579     m_ParserFunctions[tflite::BuiltinOperator_SUB]                     = &TfLiteParser::ParseSub;
580     m_ParserFunctions[tflite::BuiltinOperator_TANH]                    = &TfLiteParser::ParseTanH;
581     m_ParserFunctions[tflite::BuiltinOperator_TRANSPOSE]               = &TfLiteParser::ParseTranspose;
582     m_ParserFunctions[tflite::BuiltinOperator_TRANSPOSE_CONV]          = &TfLiteParser::ParseTransposeConv;
583     m_ParserFunctions[tflite::BuiltinOperator_UNPACK]                  = &TfLiteParser::ParseUnpack;
584     m_ParserFunctions[tflite::BuiltinOperator_DIV]                     = &TfLiteParser::ParseDiv;
585     m_ParserFunctions[tflite::BuiltinOperator_ARG_MAX]                 = &TfLiteParser::ParseArgMax;
586     // register supported custom operators
587     m_CustomParserFunctions["TFLite_Detection_PostProcess"]      = &TfLiteParser::ParseDetectionPostProcess;
588 }
589 
ResetParser()590 void TfLiteParser::ResetParser()
591 {
592     m_Network = armnn::INetworkPtr(nullptr, nullptr);
593     m_Model = nullptr;
594     m_SubgraphConnections.clear();
595 }
596 
CreateNetworkFromBinaryFile(const char * graphFile)597 INetworkPtr TfLiteParser::CreateNetworkFromBinaryFile(const char* graphFile)
598 {
599     ResetParser();
600     m_Model = LoadModelFromFile(graphFile);
601     return CreateNetworkFromModel();
602 }
603 
CreateNetworkFromBinary(const std::vector<uint8_t> & binaryContent)604 INetworkPtr TfLiteParser::CreateNetworkFromBinary(const std::vector<uint8_t> & binaryContent)
605 {
606     ResetParser();
607     m_Model = LoadModelFromBinary(binaryContent.data(), binaryContent.size());
608     return CreateNetworkFromModel();
609 }
610 
CreateNetworkFromModel()611 INetworkPtr TfLiteParser::CreateNetworkFromModel()
612 {
613 
614     using NetworkOptions = std::vector<BackendOptions>;
615     NetworkOptions networkOptions = {};
616     if (m_Options && m_Options.value().m_InferAndValidate)
617     {
618         BackendOptions shapeInferenceMethodOption("ShapeInferenceMethod",
619                                                   {
620                                                       { "InferAndValidate", true }
621                                                   });
622 
623         networkOptions.push_back(shapeInferenceMethodOption);
624     }
625 
626     m_Network = INetwork::Create(networkOptions);
627     ARMNN_ASSERT(m_Model.get() != nullptr);
628 
629     if (m_Model->subgraphs.size() != 1)
630     {
631         throw ParseException(
632                 fmt::format("Current TfLite parser only supports 1 subgraph. Current one has: {} {}",
633                             m_Model->subgraphs.size(),
634                             CHECK_LOCATION().AsString()));
635     }
636 
637     size_t subgraphIndex = 0;
638     size_t operatorIndex = 0;
639     try
640     {
641         for (SubgraphPtr const& subgraph : m_Model->subgraphs)
642         {
643             m_SubgraphConnections.emplace_back(subgraph->tensors.size());
644             for (OperatorPtr const& op : subgraph->operators)
645             {
646                 auto const& opCodePtr = m_Model->operator_codes[op->opcode_index];
647                 auto builtinCode = opCodePtr->builtin_code;
648 
649                 if (builtinCode > tflite::BuiltinOperator_MAX)
650                 {
651                     throw ParseException(fmt::format("Operator code {} is out of range 0-{}. "
652                                                      "subgraph:{} operator idx:{}. {}",
653                                                      builtinCode, tflite::BuiltinOperator_MAX, subgraphIndex,
654                                                      operatorIndex, CHECK_LOCATION().AsString()));
655                 }
656 
657                 // lookup and call the parser function
658                 auto& parserFunction = m_ParserFunctions[builtinCode];
659                 (this->*parserFunction)(subgraphIndex, operatorIndex);
660                 ++operatorIndex;
661             }
662 
663             SetupInputLayers(subgraphIndex);
664             SetupOutputLayers(subgraphIndex);
665             SetupConstantLayers(subgraphIndex);
666 
667             ++subgraphIndex;
668             operatorIndex = 0;
669         }
670     }
671     catch (const ParseException& e)
672     {
673         std::stringstream errorString;
674         errorString << "Failed to parse operator #" << operatorIndex << " within subgraph #"
675                     << subgraphIndex << " error: " << e.what();
676         ARMNN_LOG(error) << errorString.str();
677         std::stringstream errors;
678         errors << errorString.str() << "\n";
679         throw ParseException(errors.str());
680     }
681 
682     // establish the connections from the layer outputs to the inputs of the subsequent layers
683     for (subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex)
684     {
685         for (size_t tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex)
686         {
687             if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot != nullptr)
688             {
689                 for (size_t inputSlotIdx = 0;
690                     inputSlotIdx < m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size();
691                     ++inputSlotIdx)
692                 {
693                     m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot->Connect(
694                         *(m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots[inputSlotIdx]));
695                 }
696             }
697         }
698     }
699 
700     return std::move(m_Network);
701 }
702 
RegisterProducerOfTensor(size_t subgraphIndex,size_t tensorIndex,armnn::IOutputSlot * slot)703 void TfLiteParser::RegisterProducerOfTensor(size_t subgraphIndex,
704                                             size_t tensorIndex,
705                                             armnn::IOutputSlot* slot)
706 {
707     CHECK_TENSOR(m_Model, subgraphIndex, tensorIndex);
708     ARMNN_ASSERT(m_SubgraphConnections.size() > subgraphIndex);
709     ARMNN_ASSERT(m_SubgraphConnections[subgraphIndex].size() > tensorIndex);
710 
711     TensorSlots & tensorSlots = m_SubgraphConnections[subgraphIndex][tensorIndex];
712 
713     // assuming there is only one producer for that tensor
714     if (tensorSlots.outputSlot != nullptr)
715     {
716         throw ParseException(fmt::format("Another layer has already registered itself as the producer of "
717                                          "subgraph:{} tensor:{} {}",
718                                          subgraphIndex,
719                                          tensorIndex,
720                                          CHECK_LOCATION().AsString()));
721     }
722 
723     tensorSlots.outputSlot = slot;
724 }
725 
RegisterConsumerOfTensor(size_t subgraphIndex,size_t tensorIndex,armnn::IInputSlot * slot)726 void TfLiteParser::RegisterConsumerOfTensor(size_t subgraphIndex,
727                                             size_t tensorIndex,
728                                             armnn::IInputSlot* slot)
729 {
730     CHECK_TENSOR(m_Model, subgraphIndex, tensorIndex);
731     ARMNN_ASSERT(m_SubgraphConnections.size() > subgraphIndex);
732     ARMNN_ASSERT(m_SubgraphConnections[subgraphIndex].size() > tensorIndex);
733 
734     TensorSlots & tensorSlots = m_SubgraphConnections[subgraphIndex][tensorIndex];
735     tensorSlots.inputSlots.push_back(slot);
736 }
737 
ParseCustomOperator(size_t subgraphIndex,size_t operatorIndex)738 void TfLiteParser::ParseCustomOperator(size_t subgraphIndex, size_t operatorIndex)
739 {
740     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
741 
742     // NOTE: By default we presume the custom operator is not supported
743     auto customParserFunction = &TfLiteParser::ParseUnsupportedOperator;
744 
745     // Identify custom code defined for custom operator
746     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
747     const auto& customCode  = m_Model->operator_codes[operatorPtr->opcode_index]->custom_code;
748 
749     // Find parser function that correspondes to custom code (if any)
750     auto iterator = m_CustomParserFunctions.find(customCode);
751     if (iterator != m_CustomParserFunctions.end())
752     {
753         customParserFunction = iterator->second;
754     }
755 
756     // Run parser function
757     (this->*customParserFunction)(subgraphIndex, operatorIndex);
758 }
759 
ParseUnsupportedOperator(size_t subgraphIndex,size_t operatorIndex)760 void TfLiteParser::ParseUnsupportedOperator(size_t subgraphIndex, size_t operatorIndex)
761 {
762     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
763 
764     const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
765 
766     auto opcodeIndex = operatorPtr->opcode_index;
767     auto opcode      = m_Model->operator_codes[opcodeIndex]->builtin_code;
768 
769     if (!m_Options || !m_Options.value().m_StandInLayerForUnsupported)
770     {
771         // Do not add StandInLayer, throw ParseException instead
772         throw ParseException(
773             fmt::format("Operator not supported. "
774                         "subgraph:{} operator:{} "
775                         "opcode_index:{} opcode:{} / {} {}",
776                         subgraphIndex,
777                         operatorIndex,
778                         opcodeIndex,
779                         opcode,
780                         tflite::EnumNameBuiltinOperator(opcode),
781                         CHECK_LOCATION().AsString()));
782     }
783 
784     auto inputs  = GetInputs(m_Model, subgraphIndex, operatorIndex);
785     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
786 
787     const unsigned int numInputs  = armnn::numeric_cast<unsigned int>(inputs.size());
788     const unsigned int numOutputs = armnn::numeric_cast<unsigned int>(outputs.size());
789 
790     StandInDescriptor descriptor(numInputs, numOutputs);
791     auto layerName = fmt::format("StandIn:{}:{}:{}", subgraphIndex, operatorIndex, opcode);
792 
793     // Add a non-executable StandInLayer as a placeholder for any unsupported operator
794     IConnectableLayer* layer = m_Network->AddStandInLayer(descriptor, layerName.c_str());
795     ARMNN_ASSERT(layer != nullptr);
796 
797     for (unsigned int i = 0u; i < numOutputs; ++i)
798     {
799         layer->GetOutputSlot(i).SetTensorInfo(ToTensorInfo(outputs[i], true));
800     }
801 
802     auto inputTensorIds  = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
803     auto outputTensorIds = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
804 
805     RegisterInputSlots(subgraphIndex, operatorIndex, layer, inputTensorIds);
806     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIds);
807 }
808 
ParseConv2D(size_t subgraphIndex,size_t operatorIndex)809 void TfLiteParser::ParseConv2D(size_t subgraphIndex, size_t operatorIndex)
810 {
811     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
812 
813     const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
814     const auto * options = operatorPtr->builtin_options.AsConv2DOptions();
815 
816     CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
817 
818     Convolution2dDescriptor desc;
819     desc.m_BiasEnabled = false;
820     desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
821     desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
822     desc.m_DataLayout = armnn::DataLayout::NHWC;
823     desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
824     desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
825 
826     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
827     CHECK_VALID_SIZE(inputs.size(), 2, 3);
828 
829     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
830     CHECK_VALID_SIZE(outputs.size(), 1);
831 
832     armnn::TensorInfo inputTensorInfo  = ToTensorInfo(inputs[0]);
833     armnn::TensorInfo filterTensorInfo = ToTensorInfo(inputs[1]);
834 
835     // assuming input is NHWC
836     unsigned int inputHeight = inputTensorInfo.GetShape()[1];
837     unsigned int inputWidth  = inputTensorInfo.GetShape()[2];
838 
839     // assuming the filter is OHWI : Output, H, W, Input
840     // which is essentially the same as NHWC
841     unsigned int filterHeight = filterTensorInfo.GetShape()[1];
842     unsigned int filterWidth  = filterTensorInfo.GetShape()[2];
843 
844     CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
845                 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
846     CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
847                 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
848 
849     auto filterTensorAndData = CreateConstTensor(inputs[1],
850                                                  filterTensorInfo,
851                                                  armnn::Optional<armnn::PermutationVector&>());
852     armnn::IConnectableLayer* layer = nullptr;
853 
854     auto layerName = fmt::format("Conv2D:{}:{}", subgraphIndex, operatorIndex);
855 
856     if (inputs.size() == 3)
857     {
858         desc.m_BiasEnabled = true;
859         armnn::TensorInfo biasTensorInfo = ToTensorInfo(inputs[2]);
860         auto biasTensorAndData = CreateConstTensor(inputs[2],
861                                                    biasTensorInfo,
862                                                    armnn::Optional<armnn::PermutationVector&>());
863         layer = m_Network->AddConvolution2dLayer(desc,
864                                                  filterTensorAndData.first,
865                                                  Optional<ConstTensor>(biasTensorAndData.first),
866                                                  layerName.c_str());
867     }
868     else
869     {
870         layer = m_Network->AddConvolution2dLayer(desc,
871                                                  filterTensorAndData.first,
872                                                  EmptyOptional(),
873                                                  layerName.c_str());
874     }
875 
876     ARMNN_ASSERT(layer != nullptr);
877 
878     armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
879     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
880 
881     // register the input connection slots for the layer, connections are made after all layers have been created
882     // only the tensors for the inputs are relevant, exclude the const tensors
883     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
884     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
885 
886     layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
887     // register the output connection slots for the layer, connections are made after all layers have been created
888     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
889     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
890 }
891 
ParseDepthwiseConv2D(size_t subgraphIndex,size_t operatorIndex)892 void TfLiteParser::ParseDepthwiseConv2D(size_t subgraphIndex, size_t operatorIndex)
893 {
894     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
895 
896     const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
897     const auto * options = operatorPtr->builtin_options.AsDepthwiseConv2DOptions();
898 
899     CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
900 
901     DepthwiseConvolution2dDescriptor desc;
902     desc.m_BiasEnabled = false;
903     desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
904     desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
905     desc.m_DataLayout = armnn::DataLayout::NHWC;
906     CHECKED_NON_NEGATIVE(options->depth_multiplier);
907 
908     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
909     CHECK_VALID_SIZE(inputs.size(), 2, 3);
910     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
911     CHECK_VALID_SIZE(outputs.size(), 1);
912     desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
913     desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
914 
915     // Mappings from TensorflowLite filter tensors to the ArmNN filter tensors (ArmNN weights have to be [M, I, H, W])
916     PermutationVector permutationVector{ 2, 3, 1, 0 }; // [H, W, I, M] -> [M, I, H, W]
917 
918     armnn::TensorInfo inputTensorInfo  = ToTensorInfo(inputs[0]);
919     armnn::TensorInfo filterTensorInfo = ToTensorInfo(inputs[1], permutationVector);
920 
921     // Assuming input is NHWC
922     unsigned int inputHeight = inputTensorInfo.GetShape()[1];
923     unsigned int inputWidth  = inputTensorInfo.GetShape()[2];
924 
925     // TensorflowLite weights come in the format [1, H, W, I * M]
926     unsigned int filterHeight = filterTensorInfo.GetShape()[1];
927     unsigned int filterWidth  = filterTensorInfo.GetShape()[2];
928 
929     // Reshape weights as [ H, W, I, M ]
930     filterTensorInfo.SetShape({ filterHeight,
931                                 filterWidth,
932                                 inputTensorInfo.GetShape()[3],
933                                 filterTensorInfo.GetShape()[3] / inputTensorInfo.GetShape()[3] });
934 
935     CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
936                 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
937     CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
938                 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
939 
940     auto filterTensorAndData = CreateConstTensor(inputs[1], filterTensorInfo, permutationVector);
941     armnn::IConnectableLayer* layer = nullptr;
942     auto layerName = fmt::format("DepthwiseConv2D:{}:{}", subgraphIndex, operatorIndex);
943 
944     if (inputs.size() == 3)
945     {
946         desc.m_BiasEnabled = true;
947         TensorInfo biasTensorInfo = ToTensorInfo(inputs[2]);
948         auto biasTensorAndData = CreateConstTensor(inputs[2],
949                                                    biasTensorInfo,
950                                                    armnn::Optional<armnn::PermutationVector&>());
951         layer = m_Network->AddDepthwiseConvolution2dLayer(desc,
952                                                           filterTensorAndData.first,
953                                                           Optional<ConstTensor>(biasTensorAndData.first),
954                                                           layerName.c_str());
955     }
956     else
957     {
958         layer = m_Network->AddDepthwiseConvolution2dLayer(desc,
959                                                           filterTensorAndData.first,
960                                                           EmptyOptional(),
961                                                           layerName.c_str());
962     }
963     ARMNN_ASSERT(layer != nullptr);
964 
965     armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
966     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
967 
968     // register the input connection slots for the layer, connections are made after all layers have been created
969     // only the tensors for the inputs are relevant, exclude the const tensors
970     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
971     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
972 
973     layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
974     // register the output connection slots for the layer, connections are made after all layers have been created
975     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
976     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
977 }
978 
ParseDequantize(size_t subgraphIndex,size_t operatorIndex)979 void TfLiteParser::ParseDequantize(size_t subgraphIndex, size_t operatorIndex)
980 {
981     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
982 
983     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
984     CHECK_VALID_SIZE(inputs.size(), 1);
985 
986     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
987     CHECK_VALID_SIZE(outputs.size(), 1);
988 
989     auto layerName = fmt::format("Dequantize:{}:{}", subgraphIndex, operatorIndex);
990 
991     IConnectableLayer* layer = m_Network->AddDequantizeLayer(layerName.c_str());
992     ARMNN_ASSERT(layer != nullptr);
993 
994     TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
995     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
996 
997     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
998     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
999 
1000     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1001     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
1002 }
1003 
ParseExp(size_t subgraphIndex,size_t operatorIndex)1004 void TfLiteParser::ParseExp(size_t subgraphIndex, size_t operatorIndex)
1005 {
1006     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1007 
1008     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1009     CHECK_VALID_SIZE(inputs.size(), 1);
1010 
1011     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1012     CHECK_VALID_SIZE(outputs.size(), 1);
1013 
1014     auto layerName = fmt::format("Exp:{}:{}", subgraphIndex, operatorIndex);
1015 
1016     ElementwiseUnaryDescriptor desc;
1017     desc.m_Operation = UnaryOperation::Exp;
1018     IConnectableLayer* layer = m_Network->AddElementwiseUnaryLayer(desc, layerName.c_str());
1019     ARMNN_ASSERT(layer != nullptr);
1020 
1021     TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1022     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1023 
1024     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1025     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1026 
1027     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1028     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
1029 }
1030 
ParseTranspose(size_t subgraphIndex,size_t operatorIndex)1031 void TfLiteParser::ParseTranspose(size_t subgraphIndex, size_t operatorIndex)
1032 {
1033     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1034 
1035     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1036     CHECK_VALID_SIZE(inputs.size(), 1, 2);
1037 
1038     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1039     CHECK_VALID_SIZE(outputs.size(), 1);
1040 
1041     auto layerName = fmt::format("Transpose:{}:{}", subgraphIndex, operatorIndex);
1042     TransposeDescriptor desc;
1043 
1044     if (inputs.size() == 2)
1045     {
1046         armnn::TensorInfo permuteTensorInfo = ToTensorInfo(inputs[1]);
1047         BufferRawPtr permuteBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1048         auto numPermVecElements = permuteTensorInfo.GetNumElements();
1049         std::vector<unsigned int> permuteShape(numPermVecElements);
1050         ::memcpy(permuteShape.data(), permuteBufferPtr->data.data(), permuteTensorInfo.GetNumBytes());
1051         PermutationVector permutationVector(permuteShape.data(), permuteTensorInfo.GetNumElements());
1052 
1053         desc = TransposeDescriptor(permutationVector);
1054     }
1055 
1056     TensorInfo inputTensorInfo  = ToTensorInfo(inputs[0]);
1057     TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1058     CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1059 
1060     IConnectableLayer* layer = m_Network->AddTransposeLayer(desc, layerName.c_str());
1061     ARMNN_ASSERT(layer != nullptr);
1062     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1063 
1064     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1065     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1066 
1067     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1068     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1069 }
1070 
ParseTransposeConv(size_t subgraphIndex,size_t operatorIndex)1071 void TfLiteParser::ParseTransposeConv(size_t subgraphIndex, size_t operatorIndex)
1072 {
1073     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1074 
1075     const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1076     const auto * options = operatorPtr->builtin_options.AsTransposeConvOptions();
1077 
1078     TransposeConvolution2dDescriptor desc;
1079     desc.m_BiasEnabled = false;
1080     desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1081     desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1082     desc.m_DataLayout = armnn::DataLayout::NHWC;
1083 
1084     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1085     CHECK_VALID_SIZE(inputs.size(), 3);
1086 
1087     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1088     CHECK_VALID_SIZE(outputs.size(), 1);
1089 
1090     if (inputs[0])
1091     {
1092         armnn::TensorInfo tensorInfo = ToTensorInfo(inputs[0]);
1093         std::vector<int> output_shape(tensorInfo.GetNumElements());
1094         if (tensorInfo.GetDataType() == DataType::Signed32)
1095         {
1096             ::memcpy(output_shape.data(), GetBuffer(m_Model, inputs[0]->buffer)->data.data(), tensorInfo.GetNumBytes());
1097         }
1098         if (tensorInfo.GetDataType() == DataType::QAsymmU8)
1099         {
1100             for(unsigned int i=0; i < tensorInfo.GetNumElements(); i++)
1101             {
1102                 output_shape[i] = GetBuffer(m_Model, inputs[0]->buffer)->data.data()[i];
1103             }
1104         }
1105         // Change from signed to unsigned int to store in TransposeConvolution2dDescriptor.
1106         for (int dimension : output_shape)
1107         {
1108             desc.m_OutputShape.push_back(static_cast<unsigned int>(dimension));
1109         }
1110         desc.m_OutputShapeEnabled = true;
1111     }
1112     armnn::TensorInfo inputTensorInfo  = ToTensorInfo(inputs[2]);
1113     armnn::TensorInfo filterTensorInfo = ToTensorInfo(inputs[1]);
1114 
1115     // TfLite uses NHWC tensors
1116     const unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1117     const unsigned int inputWidth  = inputTensorInfo.GetShape()[2];
1118 
1119     const unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1120     const unsigned int filterWidth  = filterTensorInfo.GetShape()[2];
1121 
1122     CalcPadding(inputHeight,
1123                 filterHeight,
1124                 desc.m_StrideY,
1125                 1, // DilationY
1126                 desc.m_PadTop,
1127                 desc.m_PadBottom,
1128                 options->padding);
1129 
1130     CalcPadding(inputWidth,
1131                 filterWidth,
1132                 desc.m_StrideX,
1133                 1, // DilationX
1134                 desc.m_PadLeft,
1135                 desc.m_PadRight,
1136                 options->padding);
1137 
1138     auto filterTensorAndData = CreateConstTensor(inputs[1],
1139                                                  filterTensorInfo,
1140                                                  armnn::Optional<armnn::PermutationVector&>());
1141 
1142     armnn::IConnectableLayer* layer = nullptr;
1143     auto layerName = fmt::format("TransposeConv:{}:{}", subgraphIndex, operatorIndex);
1144 
1145     layer = m_Network->AddTransposeConvolution2dLayer(desc,
1146                                                       filterTensorAndData.first,
1147                                                       EmptyOptional(),
1148                                                       layerName.c_str());
1149 
1150     ARMNN_ASSERT(layer != nullptr);
1151 
1152     armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1153     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1154 
1155     // only the tensors for the inputs are relevant, exclude the const (filter) tensor
1156     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1157     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[2]});
1158 
1159     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1160     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1161 }
1162 
ParseAveragePool2D(size_t subgraphIndex,size_t operatorIndex)1163 void TfLiteParser::ParseAveragePool2D(size_t subgraphIndex, size_t operatorIndex)
1164 {
1165     ParsePool(subgraphIndex, operatorIndex, PoolingAlgorithm::Average);
1166 }
1167 
ParseBatchToSpaceND(size_t subgraphIndex,size_t operatorIndex)1168 void TfLiteParser::ParseBatchToSpaceND(size_t subgraphIndex, size_t operatorIndex)
1169 {
1170     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1171 
1172     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1173     CHECK_VALID_SIZE(inputs.size(), 3);
1174 
1175     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1176     CHECK_VALID_SIZE(outputs.size(), 1);
1177 
1178     armnn::TensorInfo blockShapeTensorInfo = ToTensorInfo(inputs[1]);
1179     BufferRawPtr blockShapeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1180 
1181     armnn::TensorInfo cropsTensorInfo = ToTensorInfo(inputs[2]);
1182     BufferRawPtr cropsBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
1183 
1184     std::vector<unsigned int> blockShape(blockShapeTensorInfo.GetNumElements());
1185     ::memcpy(blockShape.data(), blockShapeBufferPtr->data.data(), blockShapeTensorInfo.GetNumBytes());
1186 
1187     std::vector<unsigned int> cropsVector(cropsTensorInfo.GetNumElements());
1188     ::memcpy(cropsVector.data(), cropsBufferPtr->data.data(), cropsTensorInfo.GetNumBytes());
1189 
1190     size_t step = 2;
1191     std::vector<std::pair<unsigned int, unsigned int>> crops;
1192     for (unsigned int i = 0; i < cropsTensorInfo.GetNumElements() / step; ++i)
1193     {
1194         crops.emplace_back(cropsVector[i * step], cropsVector[i * step + 1]);
1195     }
1196 
1197     armnn::BatchToSpaceNdDescriptor desc;
1198     desc.m_BlockShape = blockShape;
1199     desc.m_Crops = crops;
1200     desc.m_DataLayout = armnn::DataLayout::NHWC;
1201 
1202     auto layerName = fmt::format("BatchToSpaceND:{}:{}", subgraphIndex, operatorIndex);
1203 
1204     TensorInfo inputTensorInfo  = ToTensorInfo(inputs[0]);
1205     TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1206     CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1207 
1208     IConnectableLayer* layer = m_Network->AddBatchToSpaceNdLayer(desc, layerName.c_str());
1209     ARMNN_ASSERT(layer != nullptr);
1210     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1211 
1212     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1213     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1214 
1215     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1216     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1217 }
1218 
ParseL2Normalization(size_t subgraphIndex,size_t operatorIndex)1219 void TfLiteParser::ParseL2Normalization(size_t subgraphIndex, size_t operatorIndex)
1220 {
1221     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1222 
1223     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1224     CHECK_VALID_SIZE(inputs.size(), 1);
1225 
1226     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1227     CHECK_VALID_SIZE(outputs.size(), 1);
1228 
1229     L2NormalizationDescriptor desc;
1230     desc.m_DataLayout = armnn::DataLayout::NHWC;
1231     auto layerName = fmt::format("L2Normalization:{}:{}", subgraphIndex, operatorIndex);
1232     IConnectableLayer* layer = m_Network->AddL2NormalizationLayer(desc, layerName.c_str());
1233 
1234     ARMNN_ASSERT(layer != nullptr);
1235 
1236     armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1237     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1238 
1239     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1240     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1241 
1242     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1243     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1244 }
1245 
ParseMaxPool2D(size_t subgraphIndex,size_t operatorIndex)1246 void TfLiteParser::ParseMaxPool2D(size_t subgraphIndex, size_t operatorIndex)
1247 {
1248     ParsePool(subgraphIndex, operatorIndex, PoolingAlgorithm::Max);
1249 }
1250 
ParseMaximum(size_t subgraphIndex,size_t operatorIndex)1251 void TfLiteParser::ParseMaximum(size_t subgraphIndex, size_t operatorIndex)
1252 {
1253     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1254 
1255     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1256     CHECK_VALID_SIZE(inputs.size(), 2);
1257 
1258     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1259     CHECK_VALID_SIZE(outputs.size(), 1);
1260 
1261     auto layerName = fmt::format("Maximum:{}:{}", subgraphIndex, operatorIndex);
1262 
1263     TensorInfo inputTensorInfo  = ToTensorInfo(inputs[0]);
1264     TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]);
1265     CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
1266 
1267     TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1268     CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1269 
1270     IConnectableLayer* layer = m_Network->AddMaximumLayer(layerName.c_str());
1271     ARMNN_ASSERT(layer != nullptr);
1272     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1273 
1274     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1275     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
1276 
1277     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1278     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1279 }
1280 
ParseMinimum(size_t subgraphIndex,size_t operatorIndex)1281 void TfLiteParser::ParseMinimum(size_t subgraphIndex, size_t operatorIndex)
1282 {
1283     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1284 
1285     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1286     CHECK_VALID_SIZE(inputs.size(), 2);
1287 
1288     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1289     CHECK_VALID_SIZE(outputs.size(), 1);
1290 
1291     auto layerName = fmt::format("Minimum:{}:{}", subgraphIndex, operatorIndex);
1292 
1293     TensorInfo inputTensorInfo  = ToTensorInfo(inputs[0]);
1294     TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]);
1295     CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
1296 
1297     TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1298     CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1299 
1300     IConnectableLayer* layer = m_Network->AddMinimumLayer(layerName.c_str());
1301     ARMNN_ASSERT(layer != nullptr);
1302     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1303 
1304     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1305     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
1306 
1307     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1308     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1309 }
1310 
ParsePool(size_t subgraphIndex,size_t operatorIndex,PoolingAlgorithm algorithm)1311 void TfLiteParser::ParsePool(size_t subgraphIndex,
1312                              size_t operatorIndex,
1313                              PoolingAlgorithm algorithm)
1314 {
1315     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1316 
1317     const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1318     const auto * options = operatorPtr->builtin_options.AsPool2DOptions();
1319 
1320     CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1321 
1322     std::string layerName;
1323 
1324     switch (algorithm)
1325     {
1326         case PoolingAlgorithm::Average:
1327             layerName =
1328                 fmt::format("AveragePool2D:{}:{}", subgraphIndex, operatorIndex);
1329             break;
1330         case PoolingAlgorithm::Max:
1331             layerName =
1332                 fmt::format("MaxPool2D:{}:{}", subgraphIndex, operatorIndex);
1333             break;
1334         default:
1335             ARMNN_ASSERT_MSG(false, "Unsupported Pooling Algorithm");
1336     }
1337 
1338     Pooling2dDescriptor desc;
1339 
1340     desc.m_PoolType = algorithm;
1341     desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1342     desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1343     desc.m_PoolWidth = CHECKED_NON_NEGATIVE(options->filter_width);
1344     desc.m_PoolHeight = CHECKED_NON_NEGATIVE(options->filter_height);
1345     desc.m_PaddingMethod = PaddingMethod::Exclude;
1346     desc.m_OutputShapeRounding = OutputShapeRounding::Floor;
1347     desc.m_DataLayout = armnn::DataLayout::NHWC;
1348 
1349     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1350     CHECK_VALID_SIZE(inputs.size(), 1);
1351     armnn::TensorInfo inputTensorInfo  = ToTensorInfo(inputs[0]);
1352 
1353     // assuming input is NHWC
1354     unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1355     unsigned int inputWidth  = inputTensorInfo.GetShape()[2];
1356 
1357     CalcPadding(inputHeight, desc.m_PoolHeight, desc.m_StrideY, 1u,
1358                 desc.m_PadTop, desc.m_PadBottom, options->padding);
1359     CalcPadding(inputWidth, desc.m_PoolWidth, desc.m_StrideX, 1u,
1360                 desc.m_PadLeft, desc.m_PadRight, options->padding);
1361 
1362     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1363     CHECK_VALID_SIZE(outputs.size(), 1);
1364 
1365     armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1366     CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1367 
1368     IConnectableLayer* layer = m_Network->AddPooling2dLayer(desc, layerName.c_str());
1369     ARMNN_ASSERT(layer != nullptr);
1370     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1371 
1372     // register the input connection slots for the layer, connections are made after all layers have been created
1373     // only the tensors for the inputs are relevant, exclude the const tensors
1374     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1375     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1376 
1377     layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
1378     // register the output connection slots for the layer, connections are made after all layers have been created
1379     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1380     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1381 }
1382 
ParseSlice(size_t subgraphIndex,size_t operatorIndex)1383 void TfLiteParser::ParseSlice(size_t subgraphIndex, size_t operatorIndex)
1384 {
1385     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1386 
1387     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1388     CHECK_VALID_SIZE(inputs.size(), 3);
1389     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1390     CHECK_VALID_SIZE(outputs.size(), 1);
1391 
1392     SliceDescriptor desc;
1393 
1394     // set begin tensor info for slice descriptor
1395     armnn::TensorInfo beginTensorInfo = ToTensorInfo(inputs[1]);
1396     BufferRawPtr beginBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1397 
1398     std::vector<unsigned int> begin(beginTensorInfo.GetNumElements());
1399     ::memcpy(begin.data(), beginBufferPtr->data.data(), beginTensorInfo.GetNumBytes());
1400 
1401     // set size tensor info for slice descriptor
1402     armnn::TensorInfo sizeTensorInfo = ToTensorInfo(inputs[2]);
1403     BufferRawPtr sizeBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
1404 
1405     std::vector<unsigned int> size(sizeTensorInfo.GetNumElements());
1406     ::memcpy(size.data(), sizeBufferPtr->data.data(), sizeTensorInfo.GetNumBytes());
1407     desc = SliceDescriptor(begin, size);
1408 
1409     auto layerName = fmt::format("Slice:{}:{}", subgraphIndex, operatorIndex);
1410 
1411     TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
1412     TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1413     CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1414 
1415     IConnectableLayer* const layer = m_Network->AddSliceLayer(desc, layerName.c_str());
1416     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1417 
1418     // register the input connection slots for the layer, connections are made after all layers have been created
1419     // only the tensors for the inputs are relevant, exclude the const tensors
1420     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1421     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1422 
1423     // register the output connection slots for the layer, connections are made after all layers have been created
1424     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1425     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1426 }
1427 
ParseSoftmax(size_t subgraphIndex,size_t operatorIndex)1428 void TfLiteParser::ParseSoftmax(size_t subgraphIndex, size_t operatorIndex)
1429 {
1430     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1431     const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1432     const auto * options = operatorPtr->builtin_options.AsSoftmaxOptions();
1433 
1434     SoftmaxDescriptor desc;
1435     desc.m_Beta = options->beta;
1436 
1437     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1438     CHECK_VALID_SIZE(inputs.size(), 1);
1439     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1440     CHECK_VALID_SIZE(outputs.size(), 1);
1441 
1442     auto layerName = fmt::format("Softmax:{}:{}", subgraphIndex, operatorIndex);
1443     IConnectableLayer* const layer = m_Network->AddSoftmaxLayer(desc, layerName.c_str());
1444 
1445     armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1446     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1447 
1448     // register the input connection slots for the layer, connections are made after all layers have been created
1449     // only the tensors for the inputs are relevant, exclude the const tensors
1450     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1451     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1452 
1453     // register the output connection slots for the layer, connections are made after all layers have been created
1454     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1455     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1456 }
1457 
ParseSpaceToBatchND(size_t subgraphIndex,size_t operatorIndex)1458 void TfLiteParser::ParseSpaceToBatchND(size_t subgraphIndex, size_t operatorIndex)
1459 {
1460     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1461 
1462     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1463     CHECK_VALID_SIZE(inputs.size(), 3);
1464 
1465     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1466     CHECK_VALID_SIZE(outputs.size(), 1);
1467 
1468     armnn::TensorInfo blockShapeTensorInfo = ToTensorInfo(inputs[1]);
1469     BufferRawPtr blockShapeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1470 
1471     armnn::TensorInfo padListTensorInfo = ToTensorInfo(inputs[2]);
1472     BufferRawPtr padListBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
1473 
1474     std::vector<unsigned int> blockShape(blockShapeTensorInfo.GetNumElements());
1475     ::memcpy(blockShape.data(), blockShapeBufferPtr->data.data(), blockShapeTensorInfo.GetNumBytes());
1476 
1477     std::vector<unsigned int> padListVector(padListTensorInfo.GetNumElements());
1478     ::memcpy(padListVector.data(), padListBufferPtr->data.data(), padListTensorInfo.GetNumBytes());
1479 
1480     size_t step = 2;
1481     std::vector<std::pair<unsigned int, unsigned int>> padList;
1482     for (unsigned int i = 0; i < padListTensorInfo.GetNumElements() / step; ++i)
1483     {
1484         padList.emplace_back(padListVector[i * step], padListVector[i * step + 1]);
1485     }
1486 
1487     armnn::SpaceToBatchNdDescriptor desc;
1488     desc.m_BlockShape = blockShape;
1489     desc.m_PadList = padList;
1490     desc.m_DataLayout = armnn::DataLayout::NHWC;
1491 
1492     auto layerName = fmt::format("SpaceToBatchND:{}:{}", subgraphIndex, operatorIndex);
1493 
1494     TensorInfo inputTensorInfo  = ToTensorInfo(inputs[0]);
1495     TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1496     CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1497 
1498     IConnectableLayer* layer = m_Network->AddSpaceToBatchNdLayer(desc, layerName.c_str());
1499     ARMNN_ASSERT(layer != nullptr);
1500     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1501 
1502     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1503     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1504 
1505     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1506     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1507 }
1508 
OutputShapeOfSqueeze(const std::vector<uint32_t> & squeezeDimsIn,const armnn::TensorInfo & inputTensorInfo)1509 armnn::TensorInfo TfLiteParser::OutputShapeOfSqueeze(const std::vector<uint32_t> & squeezeDimsIn,
1510                                                      const armnn::TensorInfo & inputTensorInfo)
1511 {
1512     CHECK_VALID_SIZE(squeezeDimsIn.size(), 0, 1, 2, 3, 4);
1513     std::vector<uint32_t> squeezeDims = squeezeDimsIn;
1514     static const uint32_t dimensionSequence[] = { 0, 1, 2, 3 };
1515 
1516     if (inputTensorInfo.GetNumDimensions() > 4)
1517     {
1518         std::stringstream ss;
1519         ss << "Input tensor has unexpected number of dimensions:" << inputTensorInfo.GetNumDimensions()
1520            << " shape:" << inputTensorInfo.GetShape() << " "
1521            << CHECK_LOCATION().AsString();
1522         throw ParseException(ss.str());
1523     }
1524 
1525     if (squeezeDims.empty())
1526     {
1527         squeezeDims.assign(dimensionSequence,
1528                            dimensionSequence+inputTensorInfo.GetNumDimensions());
1529     }
1530 
1531     std::vector<uint32_t> outputDims;
1532     for(unsigned int i = 0; i < inputTensorInfo.GetNumDimensions(); i++)
1533     {
1534         bool skipSqueeze = (std::find(squeezeDims.begin(), squeezeDims.end(), i) == squeezeDims.end());
1535         auto currentDimension = inputTensorInfo.GetShape()[i];
1536         if (skipSqueeze || currentDimension != 1)
1537         {
1538             outputDims.push_back(currentDimension);
1539         }
1540     }
1541 
1542     if (outputDims.size() > 4)
1543     {
1544         std::stringstream ss;
1545         ss << "Output tensor has unexpected number of dimensions:" << inputTensorInfo.GetNumDimensions()
1546            << " shape:" << inputTensorInfo.GetShape() << " "
1547            << CHECK_LOCATION().AsString();
1548         throw ParseException(ss.str());
1549     }
1550 
1551     TensorShape outShape = TensorShape(static_cast<unsigned int>(outputDims.size()),
1552                                        outputDims.data());
1553 
1554     // we need to preserve the tensor type and the quantization data as well
1555     TensorInfo outTensorInfo = inputTensorInfo;
1556     outTensorInfo.SetShape(outShape);
1557 
1558     return outTensorInfo;
1559 }
1560 
ParseSqueeze(size_t subgraphIndex,size_t operatorIndex)1561 void TfLiteParser::ParseSqueeze(size_t subgraphIndex, size_t operatorIndex)
1562 {
1563     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1564 
1565     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1566     CHECK_VALID_SIZE(inputs.size(), 1);
1567 
1568     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1569     CHECK_VALID_SIZE(outputs.size(), 1);
1570 
1571     const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1572     const auto * options = operatorPtr->builtin_options.AsSqueezeOptions();
1573     auto layerName = fmt::format("Squeeze:{}:{}", subgraphIndex, operatorIndex);
1574 
1575     armnn::TensorInfo inputTensorInfo  = ToTensorInfo(inputs[0]);
1576     armnn::TensorInfo outputTensorInfo =
1577         TfLiteParser::OutputShapeOfSqueeze(AsUnsignedVector(options->squeeze_dims),
1578                                            inputTensorInfo);
1579     CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1580 
1581     ReshapeDescriptor reshapeDesc;
1582     reshapeDesc.m_TargetShape = outputTensorInfo.GetShape();
1583 
1584     IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
1585     ARMNN_ASSERT(layer != nullptr);
1586     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1587 
1588     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1589     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1590 
1591     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1592     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1593 }
1594 
ParseStridedSlice(size_t subgraphIndex,size_t operatorIndex)1595 void TfLiteParser::ParseStridedSlice(size_t subgraphIndex, size_t operatorIndex)
1596 {
1597     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1598 
1599     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1600     CHECK_VALID_SIZE(inputs.size(), 4);
1601 
1602     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1603     CHECK_VALID_SIZE(outputs.size(), 1);
1604 
1605     const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1606     const auto * options = operatorPtr->builtin_options.AsStridedSliceOptions();
1607 
1608     StridedSliceDescriptor desc;
1609     desc.m_BeginMask = options->begin_mask;
1610     desc.m_EllipsisMask = options->ellipsis_mask;
1611     desc.m_EndMask = options->end_mask;
1612     desc.m_NewAxisMask = options->new_axis_mask;
1613     desc.m_ShrinkAxisMask = options->shrink_axis_mask;
1614     desc.m_DataLayout = armnn::DataLayout::NHWC;
1615 
1616     armnn::TensorInfo beginTensorInfo = ToTensorInfo(inputs[1]);
1617     BufferRawPtr beginBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1618 
1619     std::vector<int> begin(beginTensorInfo.GetNumElements());
1620     ::memcpy(begin.data(), beginBufferPtr->data.data(), beginTensorInfo.GetNumBytes());
1621 
1622     armnn::TensorInfo endTensorInfo = ToTensorInfo(inputs[2]);
1623     BufferRawPtr endBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
1624 
1625     std::vector<int> end(endTensorInfo.GetNumElements());
1626     ::memcpy(end.data(), endBufferPtr->data.data(), endTensorInfo.GetNumBytes());
1627 
1628     armnn::TensorInfo strideTensorInfo = ToTensorInfo(inputs[3]);
1629     BufferRawPtr strideBufferPtr = GetBuffer(m_Model, inputs[3]->buffer);
1630 
1631     std::vector<int> stride(strideTensorInfo.GetNumElements());
1632     ::memcpy(stride.data(), strideBufferPtr->data.data(), strideTensorInfo.GetNumBytes());
1633 
1634     desc.m_Begin = begin;
1635     desc.m_End = end;
1636     desc.m_Stride = stride;
1637 
1638     auto layerName = fmt::format("StridedSlice:{}:{}", subgraphIndex, operatorIndex);
1639     IConnectableLayer* layer = m_Network->AddStridedSliceLayer(desc, layerName.c_str());
1640     ARMNN_ASSERT(layer != nullptr);
1641 
1642     armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1643     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1644 
1645     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1646     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1647 
1648     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1649     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1650 }
1651 
ParseSub(size_t subgraphIndex,size_t operatorIndex)1652 void TfLiteParser::ParseSub(size_t subgraphIndex, size_t operatorIndex)
1653 {
1654     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1655 
1656     const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1657     const auto * options = operatorPtr->builtin_options.AsSubOptions();
1658 
1659     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1660     CHECK_VALID_SIZE(inputs.size(), 2);
1661 
1662     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1663     CHECK_VALID_SIZE(outputs.size(), 1);
1664 
1665     armnn::TensorInfo inputTensorInfo  = ToTensorInfo(inputs[0]);
1666     armnn::TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]);
1667 
1668     auto layerName = fmt::format("Sub:{}:{}", subgraphIndex, operatorIndex);
1669     IConnectableLayer* layer = m_Network->AddSubtractionLayer(layerName.c_str());
1670     ARMNN_ASSERT(layer != nullptr);
1671 
1672     TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1673     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1674 
1675     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1676     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
1677 
1678     layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
1679 
1680     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1681     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1682 }
1683 
ParseDiv(size_t subgraphIndex,size_t operatorIndex)1684 void TfLiteParser::ParseDiv(size_t subgraphIndex, size_t operatorIndex)
1685 {
1686     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1687 
1688     const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1689     const auto * options = operatorPtr->builtin_options.AsDivOptions();
1690 
1691     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1692     CHECK_VALID_SIZE(inputs.size(), 2);
1693 
1694     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1695     CHECK_VALID_SIZE(outputs.size(), 1);
1696 
1697     armnn::TensorInfo inputTensorInfo  = ToTensorInfo(inputs[0]);
1698     armnn::TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]);
1699 
1700     auto layerName = fmt::format("Div:{}:{}", subgraphIndex, operatorIndex);
1701     IConnectableLayer* layer = m_Network->AddDivisionLayer(layerName.c_str());
1702     ARMNN_ASSERT(layer != nullptr);
1703 
1704     TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1705     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1706 
1707     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1708     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
1709     layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
1710 
1711     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1712     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1713 }
1714 
ParseAdd(size_t subgraphIndex,size_t operatorIndex)1715 void TfLiteParser::ParseAdd(size_t subgraphIndex, size_t operatorIndex)
1716 {
1717     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1718 
1719     const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1720     const auto * options = operatorPtr->builtin_options.AsAddOptions();
1721 
1722     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1723     CHECK_VALID_SIZE(inputs.size(), 2);
1724 
1725     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1726     CHECK_VALID_SIZE(outputs.size(), 1);
1727 
1728     armnn::TensorInfo inputTensorInfo  = ToTensorInfo(inputs[0]);
1729     armnn::TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]);
1730 
1731     auto layerName = fmt::format("Add:{}:{}", subgraphIndex, operatorIndex);
1732     IConnectableLayer* layer = m_Network->AddAdditionLayer(layerName.c_str());
1733     ARMNN_ASSERT(layer != nullptr);
1734 
1735     TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1736     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1737 
1738     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1739     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
1740     layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
1741 
1742     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1743     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1744 }
1745 
ParseMul(size_t subgraphIndex,size_t operatorIndex)1746 void TfLiteParser::ParseMul(size_t subgraphIndex, size_t operatorIndex)
1747 {
1748     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1749 
1750     const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1751     const auto * options = operatorPtr->builtin_options.AsMulOptions();
1752 
1753     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1754     CHECK_VALID_SIZE(inputs.size(), 2);
1755 
1756     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1757     CHECK_VALID_SIZE(outputs.size(), 1);
1758 
1759     armnn::TensorInfo inputTensorInfo  = ToTensorInfo(inputs[0]);
1760     armnn::TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]);
1761 
1762     auto layerName = fmt::format("Mul:{}:{}", subgraphIndex, operatorIndex);
1763     IConnectableLayer* layer = m_Network->AddMultiplicationLayer(layerName.c_str());
1764     ARMNN_ASSERT(layer != nullptr);
1765 
1766     TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1767     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1768 
1769     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1770     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
1771     layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
1772 
1773     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1774     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1775 }
1776 
ParseMean(size_t subgraphIndex,size_t operatorIndex)1777 void TfLiteParser::ParseMean(size_t subgraphIndex, size_t operatorIndex)
1778 {
1779     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1780 
1781     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1782 
1783     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1784     CHECK_VALID_SIZE(outputs.size(), 1);
1785 
1786     armnn::TensorInfo dimTensorInfo = ToTensorInfo(inputs[1]);
1787     BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1788 
1789     armnn::MeanDescriptor desc;
1790     std::vector<unsigned int> axis(dimTensorInfo.GetNumElements());
1791     ::memcpy(axis.data(), bufferPtr->data.data(), dimTensorInfo.GetNumBytes());
1792     desc.m_Axis = axis;
1793 
1794     armnn::TensorInfo inputTensorInfo  = ToTensorInfo(inputs[0]);
1795     armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1796 
1797     desc.m_KeepDims =
1798         inputTensorInfo.GetNumDimensions() == outputTensorInfo.GetNumDimensions() ?
1799             true : false;
1800 
1801     auto layerName = fmt::format("Mean:{}:{}", subgraphIndex, operatorIndex);
1802     IConnectableLayer* layer = m_Network->AddMeanLayer(desc, layerName.c_str());
1803     ARMNN_ASSERT(layer != nullptr);
1804 
1805     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1806 
1807     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1808     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1809 
1810     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1811     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1812 }
1813 
ParseNeg(size_t subgraphIndex,size_t operatorIndex)1814 void TfLiteParser::ParseNeg(size_t subgraphIndex, size_t operatorIndex)
1815 {
1816   CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1817 
1818   auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1819   CHECK_VALID_SIZE(inputs.size(), 1);
1820 
1821   auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1822   CHECK_VALID_SIZE(outputs.size(), 1);
1823 
1824   auto layerName = fmt::format("Neg:{}:{}", subgraphIndex, operatorIndex);
1825   armnn::ElementwiseUnaryDescriptor descriptor(armnn::UnaryOperation::Neg);
1826   IConnectableLayer* layer = m_Network->AddElementwiseUnaryLayer(descriptor, layerName.c_str());
1827   ARMNN_ASSERT(layer != nullptr);
1828 
1829   TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1830   layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1831 
1832   auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1833   RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1834 
1835   auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1836   RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
1837 }
1838 
ParsePad(size_t subgraphIndex,size_t operatorIndex)1839 void TfLiteParser::ParsePad(size_t subgraphIndex, size_t operatorIndex)
1840 {
1841     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1842 
1843     TfLiteParser::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1844 
1845     TfLiteParser::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1846     CHECK_VALID_SIZE(outputs.size(), 1);
1847 
1848     armnn::TensorInfo padTensorInfo = ToTensorInfo(inputs[1]);
1849     BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1850 
1851     std::vector<unsigned int> padBuffer(padTensorInfo.GetNumElements());
1852     ::memcpy(padBuffer.data(), bufferPtr->data.data(), padTensorInfo.GetNumBytes());
1853 
1854     size_t step = 2;
1855     armnn::PadDescriptor desc;
1856     for (unsigned int i = 0; i < padTensorInfo.GetNumElements() / step; ++i)
1857     {
1858         desc.m_PadList.emplace_back(padBuffer[i * step], padBuffer[i * step + 1]);
1859     }
1860 
1861     auto layerName = fmt::format("Pad:{}:{}", subgraphIndex, operatorIndex);
1862     TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1863 
1864     IConnectableLayer* layer = m_Network->AddPadLayer(desc, layerName.c_str());
1865     ARMNN_ASSERT(layer != nullptr);
1866     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1867 
1868     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1869     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1870 
1871     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1872     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1873 }
1874 
ParseQuantize(size_t subgraphIndex,size_t operatorIndex)1875 void TfLiteParser::ParseQuantize(size_t subgraphIndex, size_t operatorIndex)
1876 {
1877     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1878 
1879     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1880     CHECK_VALID_SIZE(inputs.size(), 1);
1881 
1882     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1883     CHECK_VALID_SIZE(outputs.size(), 1);
1884 
1885     auto layerName = fmt::format("Quantize:{}:{}", subgraphIndex, operatorIndex);
1886 
1887     IConnectableLayer* layer = m_Network->AddQuantizeLayer(layerName.c_str());
1888     ARMNN_ASSERT(layer != nullptr);
1889 
1890     TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1891     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1892 
1893     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1894     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1895 
1896     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1897     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
1898 }
1899 
ParseRelu(size_t subgraphIndex,size_t operatorIndex)1900 void TfLiteParser::ParseRelu(size_t subgraphIndex, size_t operatorIndex)
1901 {
1902     ParseActivation(subgraphIndex,operatorIndex, ActivationFunction::ReLu);
1903 }
1904 
ParseRelu6(size_t subgraphIndex,size_t operatorIndex)1905 void TfLiteParser::ParseRelu6(size_t subgraphIndex, size_t operatorIndex)
1906 {
1907     ParseActivation(subgraphIndex,operatorIndex, ActivationFunction::BoundedReLu);
1908 }
1909 
ParseLeakyRelu(size_t subgraphIndex,size_t operatorIndex)1910 void TfLiteParser::ParseLeakyRelu(size_t subgraphIndex, size_t operatorIndex)
1911 {
1912     ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::LeakyReLu);
1913 }
1914 
ParseLogistic(size_t subgraphIndex,size_t operatorIndex)1915 void TfLiteParser::ParseLogistic(size_t subgraphIndex, size_t operatorIndex)
1916 {
1917     ParseActivation(subgraphIndex,operatorIndex,ActivationFunction::Sigmoid);
1918 }
1919 
ParseTanH(size_t subgraphIndex,size_t operatorIndex)1920 void TfLiteParser::ParseTanH(size_t subgraphIndex, size_t operatorIndex)
1921 {
1922     ParseActivation(subgraphIndex,operatorIndex,ActivationFunction::TanH);
1923 }
1924 
ParseHardSwish(size_t subgraphIndex,size_t operatorIndex)1925 void TfLiteParser::ParseHardSwish(size_t subgraphIndex, size_t operatorIndex)
1926 {
1927     ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::HardSwish);
1928 }
1929 
ParseActivation(size_t subgraphIndex,size_t operatorIndex,ActivationFunction activationType)1930 void TfLiteParser::ParseActivation(size_t subgraphIndex, size_t operatorIndex, ActivationFunction activationType)
1931 {
1932     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1933     const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1934     IgnoreUnused(operatorPtr);
1935 
1936     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1937     CHECK_VALID_SIZE(inputs.size(), 1);
1938 
1939     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1940     CHECK_VALID_SIZE(outputs.size(), 1);
1941 
1942     auto layerName = fmt::format("Activation:");
1943     ActivationDescriptor activationDesc;
1944     activationDesc.m_Function = activationType;
1945 
1946     switch (activationType)
1947     {
1948         case ActivationFunction::ReLu:
1949         {
1950             layerName += fmt::format("RELU:{}:{}", subgraphIndex, operatorIndex);
1951             break;
1952         }
1953         case ActivationFunction::BoundedReLu:
1954         {
1955             layerName += fmt::format("RELU6:{}:{}", subgraphIndex, operatorIndex);
1956             activationDesc.m_A = 6.0f;
1957             activationDesc.m_B = 0.0f;
1958             break;
1959         }
1960         case ActivationFunction::Sigmoid:
1961         {
1962             layerName += fmt::format("SIGMOID:{}:{}", subgraphIndex, operatorIndex);
1963             break;
1964         }
1965         case ActivationFunction::TanH:
1966         {
1967             layerName += fmt::format("TANH:{}:{}", subgraphIndex, operatorIndex);
1968             activationDesc.m_A = 1.0f;
1969             activationDesc.m_B = 1.0f;
1970             break;
1971         }
1972         case ActivationFunction::LeakyReLu:
1973         {
1974             layerName += fmt::format("LEAKYRELU:{}:{}", subgraphIndex, operatorIndex);
1975             const auto * options = operatorPtr->builtin_options.AsLeakyReluOptions();
1976             activationDesc.m_A = options->alpha;
1977             break;
1978         }
1979         case ActivationFunction::HardSwish:
1980             layerName += fmt::format("HARDSWISH:{}:{}", subgraphIndex, operatorIndex);
1981             break;
1982         default:
1983         {
1984             throw ParseException(
1985                 fmt::format("Unexpected ActivationFunction[{}] when creating layerName {} ",
1986                             static_cast<int>(activationType), CHECK_LOCATION().AsString()));
1987         }
1988     }
1989 
1990     IConnectableLayer* const layer = m_Network->AddActivationLayer(activationDesc, layerName.c_str());
1991 
1992     TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1993     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1994 
1995     // register the input connection slots for the layer, connections are made after all layers have been created
1996     // only the tensors for the inputs are relevant, exclude the const tensors
1997     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1998     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1999 
2000     // register the output connection slots for the layer, connections are made after all layers have been created
2001     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2002     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2003 }
OutputShapeOfReshape(const armnn::TensorInfo & inputTensorInfo,const std::vector<int32_t> & targetDimsIn)2004 armnn::TensorInfo TfLiteParser::OutputShapeOfReshape(const armnn::TensorInfo & inputTensorInfo,
2005                                                      const std::vector<int32_t> & targetDimsIn)
2006 {
2007     std::vector<unsigned int> outputDims(targetDimsIn.begin(), targetDimsIn.end());
2008     const auto stretchDim = std::find(targetDimsIn.begin(), targetDimsIn.end(), -1);
2009 
2010     if (stretchDim != targetDimsIn.end())
2011     {
2012         if (std::find(std::next(stretchDim), targetDimsIn.end(), -1) != targetDimsIn.end())
2013         {
2014             throw ParseException(
2015                 fmt::format("At most one component of shape can be -1 {}", CHECK_LOCATION().AsString()));
2016         }
2017 
2018         auto targetNumElements =
2019             armnn::numeric_cast<unsigned int>(
2020                 std::accumulate(targetDimsIn.begin(), targetDimsIn.end(), -1, std::multiplies<int32_t>()));
2021 
2022         auto stretchIndex = static_cast<size_t>(std::distance(targetDimsIn.begin(), stretchDim));
2023         outputDims[stretchIndex] = inputTensorInfo.GetNumElements() / targetNumElements;
2024     }
2025 
2026     TensorShape outputShape = TensorShape(static_cast<unsigned int>(outputDims.size()), outputDims.data());
2027 
2028     TensorInfo reshapeInfo = inputTensorInfo;
2029     reshapeInfo.SetShape(outputShape);
2030 
2031     return reshapeInfo;
2032 }
2033 
ParseReshape(size_t subgraphIndex,size_t operatorIndex)2034 void TfLiteParser::ParseReshape(size_t subgraphIndex, size_t operatorIndex)
2035 {
2036     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2037 
2038     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2039 
2040     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2041     CHECK_VALID_SIZE(outputs.size(), 1);
2042 
2043     const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2044     const auto * options = operatorPtr->builtin_options.AsReshapeOptions();
2045     auto layerName = fmt::format("Reshape:{}:{}", subgraphIndex, operatorIndex);
2046 
2047     armnn::TensorInfo inputTensorInfo  = ToTensorInfo(inputs[0]);
2048     armnn::TensorInfo actualOutputTensorInfo  = ToTensorInfo(outputs[0]);
2049     CheckMatchingQuantization(inputTensorInfo, actualOutputTensorInfo, layerName, "Input 0", "Output 0");
2050 
2051     // Extracting new shape for the output
2052     // There are two ways it can be passed
2053     //  * First is to define the target shape in the operator built-in options
2054     //  * Second is to pass it as a second input tensor
2055     std::vector<int32_t> targetShape;
2056     bool targetShapeFound = false;
2057     // Check if built-in options were given
2058     if (options != nullptr)
2059     {
2060         // make sure the parameter is given
2061         if (options->new_shape.empty() == false)
2062         {
2063             targetShape = options->new_shape;
2064             targetShapeFound = true;
2065         }
2066     }
2067 
2068     // If there is no built-in option given or if the built-in new_shape parameter was empty
2069     if (!targetShapeFound)
2070     {
2071         // Check for a second input tensor
2072         if (inputs.size() > 1 && inputs[1] != nullptr)
2073         {
2074             if (inputs[1]->is_variable)
2075             {
2076                 ARMNN_THROW_PARSE_EXCEPTION( "Target shapes defined in non-const input tensors is not supported");
2077             }
2078 
2079             if (inputs[1]->shape.size() != 1)
2080             {
2081                 ARMNN_THROW_PARSE_EXCEPTION("Target 'shape' input is not a 1D tensor");
2082             }
2083 
2084             if (inputs[1]->type != tflite::TensorType_INT32)
2085             {
2086                 ARMNN_THROW_PARSE_EXCEPTION("Target 'shape' input is not an int32 type");
2087             }
2088 
2089             // Extract target shape from input
2090             auto bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2091             auto values = reinterpret_cast<const int32_t*>(bufferPtr->data.data());
2092             for (int i=0; i < inputs[1]->shape[0]; ++i)
2093             {
2094                 targetShape.push_back(values[i]);
2095             }
2096         }
2097         else
2098         {
2099             ARMNN_THROW_PARSE_EXCEPTION("Target shape not defined in reshape parameters or input tensor. "
2100                                         "At least one method required");
2101         }
2102     }
2103 
2104     armnn::TensorInfo reshapeOutputTensorInfo =
2105         TfLiteParser::OutputShapeOfReshape(inputTensorInfo, targetShape);
2106 
2107     // Check for valid input size and that reshape parameters equal output shape
2108     const armnn::TensorShape& reshapeOutputTensorShape = reshapeOutputTensorInfo.GetShape();
2109     if (inputs.size() > 1 && !CheckShape(reshapeOutputTensorShape, outputs[0]->shape))
2110     {
2111         std::stringstream ss;
2112         ss << "New shape defined in reshape parameters "
2113            << reshapeOutputTensorShape
2114            << " does not equal output shape "
2115            << actualOutputTensorInfo.GetShape()
2116            << ": "
2117            << CHECK_LOCATION().AsString();
2118         throw ParseException(ss.str());
2119     }
2120 
2121     ReshapeDescriptor reshapeDesc;
2122     reshapeDesc.m_TargetShape = reshapeOutputTensorInfo.GetShape();
2123 
2124     IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
2125     ARMNN_ASSERT(layer != nullptr);
2126     layer->GetOutputSlot(0).SetTensorInfo(reshapeOutputTensorInfo);
2127 
2128     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2129     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2130 
2131     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2132     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2133 }
2134 
ParseResizeBilinear(size_t subgraphIndex,size_t operatorIndex)2135 void TfLiteParser::ParseResizeBilinear(size_t subgraphIndex, size_t operatorIndex)
2136 {
2137     ParseResize(subgraphIndex, operatorIndex, ResizeMethod::Bilinear);
2138 }
2139 
ParseResizeNearestNeighbor(size_t subgraphIndex,size_t operatorIndex)2140 void TfLiteParser::ParseResizeNearestNeighbor(size_t subgraphIndex, size_t operatorIndex)
2141 {
2142     ParseResize(subgraphIndex, operatorIndex, ResizeMethod::NearestNeighbor);
2143 }
2144 
ParseResize(size_t subgraphIndex,size_t operatorIndex,ResizeMethod resizeMethod)2145 void TfLiteParser::ParseResize(size_t subgraphIndex, size_t operatorIndex, ResizeMethod resizeMethod)
2146 {
2147     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2148 
2149     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2150     CHECK_VALID_SIZE(inputs.size(), 2);
2151 
2152     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2153     CHECK_VALID_SIZE(outputs.size(), 1);
2154 
2155     armnn::TensorInfo sizeTensorInfo = ToTensorInfo(inputs[1]);
2156 
2157     // Data for the parsed tensor args (size) must be stored locally.
2158     std::vector<int32_t> sizeTensorData(sizeTensorInfo.GetNumElements());
2159 
2160     BufferRawPtr sizeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2161     ::memcpy(sizeTensorData.data(), sizeBufferPtr->data.data(), sizeTensorInfo.GetNumBytes());
2162 
2163     ResizeDescriptor desc;
2164     desc.m_Method       = resizeMethod;
2165     desc.m_TargetHeight = static_cast<uint32_t> (sizeTensorData[0]);
2166     desc.m_TargetWidth  = static_cast<uint32_t> (sizeTensorData[1]);
2167     desc.m_DataLayout   = armnn::DataLayout::NHWC;
2168 
2169     auto layerName = fmt::format("Resize:");
2170 
2171     switch (resizeMethod)
2172     {
2173         case ResizeMethod::Bilinear:
2174         {
2175             layerName += fmt::format("BILINEAR:{}:{}", subgraphIndex, operatorIndex);
2176 
2177             const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2178             const auto * options     = operatorPtr->builtin_options.AsResizeBilinearOptions();
2179 
2180             desc.m_AlignCorners = options->align_corners;
2181             break;
2182         }
2183         case ResizeMethod::NearestNeighbor:
2184         {
2185             layerName += fmt::format("NEARESTNEIGHBOR:{}:{}", subgraphIndex, operatorIndex);
2186             break;
2187         }
2188         default:
2189         {
2190             throw ParseException(
2191                 fmt::format("Unexpected ResizeMethod[{}] when creating layerName {} ",
2192                             static_cast<int>(resizeMethod), CHECK_LOCATION().AsString()));
2193         }
2194     }
2195 
2196     TensorInfo inputTensorInfo  = ToTensorInfo(inputs[0]);
2197     TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
2198     CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
2199 
2200     IConnectableLayer* layer = m_Network->AddResizeLayer(desc, layerName.c_str());
2201     ARMNN_ASSERT(layer != nullptr);
2202     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2203 
2204     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2205     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2206 
2207     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2208     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2209 }
2210 
ParseConcatenation(size_t subgraphIndex,size_t operatorIndex)2211 void TfLiteParser::ParseConcatenation(size_t subgraphIndex, size_t operatorIndex)
2212 {
2213     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2214 
2215     const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2216     const auto * options = operatorPtr->builtin_options.AsConcatenationOptions();
2217 
2218     CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
2219 
2220     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2221     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2222     CHECK_VALID_SIZE(outputs.size(), 1);
2223 
2224     unsigned int numConcatView = static_cast<unsigned int>(inputs.size());
2225     uint32_t inputRank = ToTensorInfo(inputs[0]).GetNumDimensions();
2226 
2227     const unsigned int concatDimInput = static_cast<unsigned int>(
2228         (static_cast<int>(inputRank) + options->axis) % static_cast<int>(inputRank));
2229 
2230     OriginsDescriptor concatDescriptor(static_cast<uint32_t>(numConcatView), inputRank);
2231     concatDescriptor.SetConcatAxis(concatDimInput);
2232 
2233     unsigned int mergeDimOrigin = 0;
2234 
2235     for (unsigned int viewIndex = 0; viewIndex < numConcatView; ++viewIndex)
2236     {
2237         TensorInfo inputTensorInfo = ToTensorInfo(inputs[viewIndex]);
2238 
2239         // This set up concatDescriptor view origin
2240         armnnUtils::ProcessConcatInputTensorInfo(
2241             inputTensorInfo, concatDescriptor, concatDimInput, viewIndex, mergeDimOrigin);
2242     }
2243 
2244     auto layerName = fmt::format("Concatenation:{}:{}", subgraphIndex, operatorIndex);
2245     TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
2246 
2247     IConnectableLayer* layer = m_Network->AddConcatLayer(concatDescriptor, layerName.c_str());
2248     ARMNN_ASSERT(layer != nullptr);
2249     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2250 
2251     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2252     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes});
2253 
2254     // add fused activation layer
2255     layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2256 
2257     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2258     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2259 }
2260 
ParseFullyConnected(size_t subgraphIndex,size_t operatorIndex)2261 void TfLiteParser::ParseFullyConnected(size_t subgraphIndex, size_t operatorIndex)
2262 {
2263     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2264 
2265     const auto & operatorRfr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2266     const auto options = operatorRfr->builtin_options.AsFullyConnectedOptions();
2267 
2268     CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
2269 
2270     FullyConnectedDescriptor desc;
2271     desc.m_BiasEnabled = false;
2272     desc.m_TransposeWeightMatrix = true;
2273 
2274     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2275     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2276     CHECK_VALID_SIZE(outputs.size(), 1);
2277 
2278     armnn::TensorInfo filterTensorInfo = ToTensorInfo(inputs[1]);
2279 
2280     // Fully Connected Layer accepts two dimensional weights input
2281     int32_t weightsDimension = static_cast<int32_t>(filterTensorInfo.GetNumDimensions());
2282     if (weightsDimension != 2)
2283     {
2284         throw ParseException(
2285             fmt::format("Dimension {} for Fully Connected weights is not supported by Armnn. "
2286                         "Node {}",
2287                         weightsDimension,
2288                         CHECK_LOCATION().AsString()));
2289     }
2290 
2291     auto filterTensorAndData = CreateConstTensor(inputs[1],
2292                                                  filterTensorInfo,
2293                                                  armnn::Optional<armnn::PermutationVector&>());
2294     armnn::IConnectableLayer* layer = nullptr;
2295     auto layerName = fmt::format("FullyConnected:{}:{}", subgraphIndex, operatorIndex);
2296 
2297     if (inputs.size() == 3)
2298     {
2299         desc.m_BiasEnabled = true;
2300         TensorInfo biasTensorInfo = ToTensorInfo(inputs[2]);
2301         auto biasTensorAndData = CreateConstTensor(inputs[2],
2302                                                    biasTensorInfo,
2303                                                    armnn::Optional<armnn::PermutationVector&>());
2304         layer = m_Network->AddFullyConnectedLayer(desc,
2305                                                   filterTensorAndData.first,
2306                                                   Optional<ConstTensor>(biasTensorAndData.first),
2307                                                   layerName.c_str());
2308     }
2309     else
2310     {
2311         layer = m_Network->AddFullyConnectedLayer(desc,
2312                                                   filterTensorAndData.first,
2313                                                   EmptyOptional(),
2314                                                   layerName.c_str());
2315     }
2316     ARMNN_ASSERT(layer != nullptr);
2317 
2318     armnn::TensorInfo inputTensorInfo  = ToTensorInfo(inputs[0]);
2319 
2320     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2321 
2322     if (inputTensorInfo.GetNumDimensions() > 2)
2323     {
2324         // Add reshape to flatten to 2D [batch_size, input_size],
2325         // where "input_size" corresponds to the number of inputs to the layer,
2326         // matching the second dimension of weights,
2327         // and "batch_size" is calculated by dividing the number of elements by "input_size".
2328         std::vector<unsigned int> reshapedDimensions(2);
2329         reshapedDimensions[1] = filterTensorInfo.GetShape()[1];
2330         reshapedDimensions[0] = inputTensorInfo.GetNumElements() / reshapedDimensions[1];
2331 
2332         if (inputTensorInfo.GetNumElements() % reshapedDimensions[1] != 0)
2333         {
2334             throw ParseException(
2335                     fmt::format("Failed to deduce input tensor shape from filter size {} {}",
2336                                 reshapedDimensions[1],
2337                                 CHECK_LOCATION().AsString()));
2338         }
2339 
2340         armnn::TensorInfo reshapedTensorInfo = ToTensorInfo(inputs[0]);
2341         reshapedTensorInfo.SetShape(armnn::TensorShape{ 2, reshapedDimensions.data() });
2342 
2343         std::string reshapeLayerName = fmt::format("Reshape_for:{}", layer->GetName());
2344         armnn::ReshapeDescriptor desc;
2345         desc.m_TargetShape = reshapedTensorInfo.GetShape();
2346         armnn::IConnectableLayer* reshapeLayer = m_Network->AddReshapeLayer(desc, layerName.c_str());
2347 
2348         reshapeLayer->GetOutputSlot(0).SetTensorInfo(reshapedTensorInfo);
2349         reshapeLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
2350 
2351         RegisterInputSlots(subgraphIndex, operatorIndex, reshapeLayer, {inputTensorIndexes[0]});
2352     }
2353     else
2354     {
2355         // register the input connection slot for the layer
2356         // only the tensors for the inputs are relevant, exclude the const tensors
2357         RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2358     }
2359 
2360     armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
2361     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2362 
2363     // we need to add the activation layer and fortunately we don't need to care about the data layout
2364     armnn::IConnectableLayer* fusedActivationLayer = AddFusedActivationLayer(layer, 0,
2365                                                                              options->fused_activation_function);
2366 
2367     // register the output connection slots for the layer, connections are made after all layers have been created
2368     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2369     RegisterOutputSlots(subgraphIndex, operatorIndex, fusedActivationLayer, {outputTensorIndexes[0]});
2370 }
2371 
ParseDetectionPostProcess(size_t subgraphIndex,size_t operatorIndex)2372 void TfLiteParser::ParseDetectionPostProcess(size_t subgraphIndex, size_t operatorIndex)
2373 {
2374     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2375 
2376     const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2377 
2378     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2379     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2380     CHECK_VALID_SIZE(outputs.size(), 4);
2381 
2382     // Obtain custom options from flexbuffers
2383     auto custom_options = operatorPtr->custom_options;
2384     const flexbuffers::Map& m = flexbuffers::GetRoot(custom_options.data(), custom_options.size()).AsMap();
2385 
2386     // Obtain descriptor information from tf lite
2387     DetectionPostProcessDescriptor desc;
2388     desc.m_MaxDetections           = m["max_detections"].AsUInt32();
2389     desc.m_MaxClassesPerDetection  = m["max_classes_per_detection"].AsUInt32();
2390     desc.m_NmsScoreThreshold       = m["nms_score_threshold"].AsFloat();
2391     desc.m_NmsIouThreshold         = m["nms_iou_threshold"].AsFloat();
2392     desc.m_NumClasses              = m["num_classes"].AsUInt32();
2393     desc.m_ScaleH                  = m["h_scale"].AsFloat();
2394     desc.m_ScaleW                  = m["w_scale"].AsFloat();
2395     desc.m_ScaleX                  = m["x_scale"].AsFloat();
2396     desc.m_ScaleY                  = m["y_scale"].AsFloat();
2397 
2398     if (!(m["use_regular_nms"].IsNull()))
2399     {
2400         desc.m_UseRegularNms       = m["use_regular_nms"].AsBool();
2401     }
2402     if (!(m["detections_per_class"].IsNull()))
2403     {
2404         desc.m_DetectionsPerClass  = m["detections_per_class"].AsUInt32();
2405     }
2406 
2407     if (desc.m_NmsIouThreshold <= 0.0f || desc.m_NmsIouThreshold > 1.0f)
2408     {
2409         throw InvalidArgumentException("DetectionPostProcessTFLiteParser: Intersection over union threshold "
2410                                        "must be positive and less than or equal to 1.");
2411     }
2412 
2413     armnn::TensorInfo anchorTensorInfo = ToTensorInfo(inputs[2]);
2414     auto anchorTensorAndData = CreateConstTensor(inputs[2], anchorTensorInfo,
2415                                                  armnn::Optional<armnn::PermutationVector&>());
2416 
2417     auto layerName = fmt::format("DetectionPostProcess:{}:{}", subgraphIndex, operatorIndex);
2418     IConnectableLayer* layer = m_Network->AddDetectionPostProcessLayer(desc, anchorTensorAndData.first,
2419                                                                        layerName.c_str());
2420 
2421     ARMNN_ASSERT(layer != nullptr);
2422 
2423     // The model does not specify the output shapes.
2424     // The output shapes are calculated from the max_detection and max_classes_per_detection.
2425     unsigned int numDetectedBox = desc.m_MaxDetections * desc.m_MaxClassesPerDetection;
2426     m_OverridenOutputShapes.push_back({ 1, numDetectedBox, 4 });
2427     m_OverridenOutputShapes.push_back({ 1, numDetectedBox });
2428     m_OverridenOutputShapes.push_back({ 1, numDetectedBox });
2429     m_OverridenOutputShapes.push_back({ 1 });
2430 
2431     for (unsigned int i = 0 ; i < outputs.size() ; ++i)
2432     {
2433         armnn::TensorInfo detectionBoxOutputTensorInfo = ToTensorInfo(outputs[i], m_OverridenOutputShapes[i]);
2434         layer->GetOutputSlot(i).SetTensorInfo(detectionBoxOutputTensorInfo);
2435     }
2436 
2437     // Register the input connection slots for the layer, connections are made after all layers have been created
2438     // only the tensors for the inputs are relevant, exclude the const tensors
2439     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2440     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
2441 
2442     // Register the output connection slots for the layer, connections are made after all layers have been created
2443     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2444     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0],
2445                                                               outputTensorIndexes[1],
2446                                                               outputTensorIndexes[2],
2447                                                               outputTensorIndexes[3]});
2448 }
2449 
2450 /// The TfLite Pack operator is equivalent to the ArmNN Stack operator
ParsePack(size_t subgraphIndex,size_t operatorIndex)2451 void TfLiteParser::ParsePack(size_t subgraphIndex, size_t operatorIndex)
2452 {
2453     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2454 
2455     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2456     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2457     CHECK_VALID_SIZE(outputs.size(), 1);
2458 
2459     if (inputs.size() < 1)
2460     {
2461         throw ParseException("Pack must have at least one input.");
2462     }
2463 
2464     const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2465     const auto* options = operatorPtr->builtin_options.AsPackOptions();
2466 
2467     StackDescriptor desc;
2468     desc.m_Axis = static_cast<uint32_t>(options->axis);
2469     desc.m_NumInputs = static_cast<uint32_t>(inputs.size());
2470 
2471     // Use the tensor shape of the first input as the "correct" input shape in the descriptor
2472     armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
2473     desc.m_InputShape = inputTensorInfo.GetShape();
2474 
2475     auto layerName = fmt::format("Pack:{}:{}", subgraphIndex, operatorIndex);
2476     IConnectableLayer* layer = m_Network->AddStackLayer(desc, layerName.c_str());
2477 
2478     ARMNN_ASSERT(layer != nullptr);
2479 
2480     armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
2481     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2482 
2483     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2484     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes});
2485 
2486     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2487     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2488 }
2489 
ParseUnpack(size_t subgraphIndex,size_t operatorIndex)2490 void TfLiteParser::ParseUnpack(size_t subgraphIndex, size_t operatorIndex)
2491 {
2492     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2493 
2494     const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2495     const auto * options = operatorPtr->builtin_options.AsUnpackOptions();
2496 
2497     // This unpackAxis indicates the axis to unpack
2498     const unsigned int unpackAxis = CHECKED_NON_NEGATIVE(options->axis);
2499 
2500     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2501     CHECK_VALID_SIZE(inputs.size(), 1);
2502 
2503     armnn::TensorInfo inputTensorInfo  = ToTensorInfo(inputs[0]);
2504 
2505     if (unpackAxis >= inputTensorInfo.GetNumDimensions())
2506     {
2507         throw ParseException(
2508                 fmt::format("The unpack axis: {} cannot be greater than or equal to "
2509                             "the number of input dimension {} {}",
2510                             unpackAxis,
2511                             inputTensorInfo.GetNumDimensions(),
2512                             CHECK_LOCATION().AsString()));
2513     }
2514 
2515     unsigned int unpackNum = CHECKED_NON_NEGATIVE(options->num);
2516     // If num is not defined, automatically infer from the length of the dimension axis.
2517     if(unpackNum == 0)
2518     {
2519         unpackNum = inputTensorInfo.GetShape()[unpackAxis];
2520     }
2521 
2522     // If unpack number cannot be inferred and is still zero, throw ParseException.
2523     if(unpackNum == 0)
2524     {
2525         throw ParseException("Number to unpack must greater than zero.");
2526     }
2527 
2528     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2529     CHECK_VALID_SIZE(outputs.size(), unpackNum);
2530 
2531     auto inputDimSize = inputTensorInfo.GetNumDimensions();
2532     std::vector<unsigned int> unpackDimSizes(inputDimSize);
2533 
2534     // Add current input shape to unpackDimSizes
2535     for (unsigned int i = 0; i < inputDimSize; ++i)
2536     {
2537         unpackDimSizes[i] = inputTensorInfo.GetShape()[i];
2538     }
2539 
2540     if (unpackDimSizes[unpackAxis] != unpackNum)
2541     {
2542         throw ParseException("Number to unpack must be the same as length of the dimension to "
2543                              "unpack along.");
2544     }
2545 
2546     unpackDimSizes[unpackAxis] /= unpackNum;
2547 
2548     SplitterDescriptor splitDesc(unpackNum, static_cast<unsigned int>(unpackDimSizes.size()));
2549     for (unsigned int j = 0; j < unpackNum; ++j)
2550     {
2551         // Set the size of the views.
2552         for (unsigned int dimIdx = 0; dimIdx < unpackDimSizes.size(); ++dimIdx)
2553         {
2554             splitDesc.SetViewSize(j, dimIdx, unpackDimSizes[dimIdx]);
2555         }
2556         splitDesc.SetViewOriginCoord(j, unpackAxis, unpackDimSizes[unpackAxis] * j);
2557     }
2558 
2559     auto layerName = fmt::format("Unpack:{}:{}", subgraphIndex, operatorIndex);
2560     IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
2561     ARMNN_ASSERT(layer != nullptr);
2562 
2563     TensorShape splitOutShape = TensorShape(static_cast<unsigned int>(unpackDimSizes.size()),
2564                                             unpackDimSizes.data());
2565 
2566     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2567     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2568 
2569     // Create reshape to remove the unpacked dimension for unpack operator of each output from Splitter.
2570     for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
2571     {
2572         armnn::TensorInfo outputTensorInfo  = ToTensorInfo(outputs[k], true);
2573         std::string reshapeLayerName = fmt::format("Reshape_for:{}", layer->GetName());
2574         armnn::ReshapeDescriptor desc;
2575         desc.m_TargetShape = outputTensorInfo.GetShape();
2576         armnn::IConnectableLayer* reshapeLayer = m_Network->AddReshapeLayer(desc, layerName.c_str());
2577 
2578         layer->GetOutputSlot(k).SetTensorInfo(armnn::TensorInfo(splitOutShape,
2579                                                                 outputTensorInfo.GetDataType(),
2580                                                                 outputTensorInfo.GetQuantizationScale(),
2581                                                                 outputTensorInfo.GetQuantizationOffset()));
2582         layer->GetOutputSlot(k).Connect(reshapeLayer->GetInputSlot(0));
2583 
2584         reshapeLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2585 
2586         uint32_t reshapedOutputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[k]);
2587         armnn::IOutputSlot* slot = &(reshapeLayer->GetOutputSlot(0));
2588         RegisterProducerOfTensor(subgraphIndex, reshapedOutputId, slot);
2589     }
2590 }
2591 
ParseSplit(size_t subgraphIndex,size_t operatorIndex)2592 void TfLiteParser::ParseSplit(size_t subgraphIndex, size_t operatorIndex)
2593 {
2594     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2595 
2596     const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2597     const auto * options = operatorPtr->builtin_options.AsSplitOptions();
2598 
2599     const unsigned int numSplits = CHECKED_NON_NEGATIVE(options->num_splits);
2600 
2601     // If number of splits cannot be inferred and is zero, throw ParseException.
2602     if(numSplits == 0)
2603     {
2604         throw ParseException("Number to splits must greater than zero.");
2605     }
2606 
2607     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2608     CHECK_VALID_SIZE(inputs.size(), 2);
2609     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2610     CHECK_VALID_SIZE(outputs.size(), numSplits);
2611 
2612     armnn::TensorInfo inputTensorInfo  = ToTensorInfo(inputs[1]);
2613     armnn::TensorInfo axisTensorInfo = ToTensorInfo(inputs[0]);
2614 
2615     BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[0]->buffer);
2616     std::vector<unsigned int> axisData(axisTensorInfo.GetNumElements());
2617     ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
2618 
2619     ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
2620     const unsigned int splitDim = axisData[0];
2621 
2622     auto inputDimSize = inputTensorInfo.GetNumDimensions();
2623     if (inputDimSize > MaxNumOfTensorDimensions)
2624     {
2625         throw ParseException(
2626             fmt::format("The number of dimensions: {} for input tensors of the split op cannot be greater than {} {}",
2627                         inputTensorInfo.GetNumDimensions(),
2628                         MaxNumOfTensorDimensions,
2629                         CHECK_LOCATION().AsString()));
2630     }
2631 
2632     std::vector<unsigned int> splitterDimSizes(inputDimSize);
2633 
2634     // Add current input shape to splitterDimSizes
2635     for (unsigned int i = 0; i < inputDimSize; ++i)
2636     {
2637         splitterDimSizes[i] = inputTensorInfo.GetShape()[i];
2638     }
2639 
2640     if (splitterDimSizes[splitDim] % numSplits != 0)
2641     {
2642         throw ParseException("Number of splits must evenly divide the dimension");
2643     }
2644     splitterDimSizes[splitDim] /= numSplits;
2645 
2646     SplitterDescriptor splitDesc(numSplits, inputDimSize);
2647     for (unsigned int j = 0; j < numSplits; ++j)
2648     {
2649         // Set the size of the views.
2650         for (unsigned int dimIdx = 0; dimIdx < splitterDimSizes.size(); ++dimIdx)
2651         {
2652             splitDesc.SetViewSize(j, dimIdx, splitterDimSizes[dimIdx]);
2653         }
2654         splitDesc.SetViewOriginCoord(j, splitDim, splitterDimSizes[splitDim] * j);
2655     }
2656 
2657     auto layerName = fmt::format("Split:{}:{}", subgraphIndex, operatorIndex);
2658     IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
2659     ARMNN_ASSERT(layer != nullptr);
2660 
2661     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2662     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[1]});
2663 
2664     for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
2665     {
2666         armnn::TensorInfo tensorInfo = ToTensorInfo(outputs[k], true);
2667         layer->GetOutputSlot(k).SetTensorInfo(tensorInfo);
2668     }
2669 
2670     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2671     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2672 }
2673 
ComputeWrappedIndex(int idx,unsigned int numDimsIn)2674 unsigned int ComputeWrappedIndex(int idx, unsigned int numDimsIn)
2675 {
2676     int numDims = armnn::numeric_cast<int>(numDimsIn);
2677     int v = idx < 0 ? numDims + idx : idx;
2678     ARMNN_ASSERT(v >= 0);
2679     ARMNN_ASSERT(v < numDims);
2680 
2681     return static_cast<unsigned int>(v);
2682 }
2683 
ParseSplitV(size_t subgraphIndex,size_t operatorIndex)2684 void TfLiteParser::ParseSplitV(size_t subgraphIndex, size_t operatorIndex)
2685 {
2686     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2687 
2688     const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2689     const auto * options = operatorPtr->builtin_options.AsSplitVOptions();
2690 
2691     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2692     CHECK_VALID_SIZE(inputs.size(), 3);
2693 
2694     auto& inputTensor = inputs[0];
2695     auto& splitsTensor = inputs[1];
2696     auto& axisTensor = inputs[2];
2697 
2698     armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputTensor);
2699     armnn::TensorInfo splitsInfo      = ToTensorInfo(splitsTensor);
2700     armnn::TensorInfo axisTensorInfo  = ToTensorInfo(axisTensor);
2701     ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
2702 
2703     // Inputs
2704     auto inputDimSize = inputTensorInfo.GetNumDimensions();
2705     if (inputDimSize > MaxNumOfTensorDimensions)
2706     {
2707         throw ParseException(
2708             fmt::format("The number of dimensions: {} for input tensors of the "
2709                         "SplitV op cannot be greater than {} {}",
2710                         inputTensorInfo.GetNumDimensions(),
2711                         MaxNumOfTensorDimensions,
2712                         CHECK_LOCATION().AsString()));
2713     }
2714 
2715     // Get split axis
2716     BufferRawPtr axisBufferPtr = GetBuffer(m_Model, axisTensor->buffer);
2717     std::vector<int> axisData(axisTensorInfo.GetNumElements());
2718     ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
2719     const unsigned int splitDim = ComputeWrappedIndex(axisData[0], inputTensorInfo.GetNumDimensions());
2720 
2721     // Set split sizes
2722     CHECK_VALID_SIZE(splitsInfo.GetNumDimensions(), 1);
2723     unsigned int numSplits{0};
2724 
2725     if(options)
2726     {
2727         numSplits = CHECKED_NON_NEGATIVE(options->num_splits);
2728     }
2729     else
2730     {
2731         numSplits = splitsInfo.GetNumElements();
2732     }
2733 
2734     if (numSplits <=0)
2735     {
2736         throw ParseException("SplitV has invalid number of splits");
2737     }
2738 
2739     std::vector<int> splitsData(numSplits);
2740     BufferRawPtr splitsBufferPtr = GetBuffer(m_Model, splitsTensor->buffer);
2741     ::memcpy(splitsData.data(), splitsBufferPtr->data.data(), splitsInfo.GetNumBytes());
2742 
2743     unsigned int idx = 0;
2744     int numInferred{0};
2745     unsigned int inferIdx{0};
2746     int splitSum{0};
2747     for (auto split : splitsData)
2748     {
2749         if (split < 0)
2750         {
2751             numInferred++;
2752             inferIdx = idx;
2753         }
2754         else
2755         {
2756             splitSum += split;
2757         }
2758         idx++;
2759     }
2760     // Check for inferred Axis
2761     if (numInferred == 0)
2762     {
2763         if (splitSum != armnn::numeric_cast<int>(inputTensorInfo.GetShape()[splitDim]))
2764         {
2765             throw ParseException("SplitV split_sizes does not sum to the dimension of value along split_dim.");
2766         }
2767     }
2768     else if (numInferred == 1)
2769     {
2770         splitsData[inferIdx] = armnn::numeric_cast<int>(inputTensorInfo.GetShape()[splitDim]) - splitSum;
2771     }
2772     else
2773     {
2774         throw ParseException("Cannot infer split size for more than one split");
2775     }
2776 
2777     //Ouput size validation
2778     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2779     CHECK_VALID_SIZE(outputs.size(), numSplits);
2780 
2781     // Setup Armnn descriptor
2782     SplitterDescriptor splitDesc(numSplits, inputDimSize);
2783     unsigned int accumSplit = 0;
2784     for (unsigned int j = 0; j < numSplits; ++j)
2785     {
2786         unsigned int splitSize = armnn::numeric_cast<unsigned int>(splitsData[j]);
2787 
2788         // Set the size of the views.
2789         for (unsigned int dimIdx = 0; dimIdx < inputTensorInfo.GetNumDimensions(); ++dimIdx)
2790         {
2791             unsigned int dimSize = inputTensorInfo.GetShape()[dimIdx];
2792             if (dimIdx == splitDim)
2793             {
2794                 dimSize = splitSize;
2795             }
2796             splitDesc.SetViewSize(j, dimIdx, dimSize);
2797         }
2798 
2799         splitDesc.SetViewOriginCoord(j, splitDim, accumSplit);
2800         accumSplit += splitSize;
2801     }
2802 
2803     auto layerName = fmt::format("SplitV:{}:{}", subgraphIndex, operatorIndex);
2804     IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
2805     ARMNN_ASSERT(layer != nullptr);
2806 
2807     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2808     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2809 
2810     for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
2811     {
2812         armnn::TensorInfo tensorInfo = ToTensorInfo(outputs[k], true);
2813         layer->GetOutputSlot(k).SetTensorInfo(tensorInfo);
2814     }
2815 
2816     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2817     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2818 }
2819 
ParseArgMax(size_t subgraphIndex,size_t operatorIndex)2820 void TfLiteParser::ParseArgMax(size_t subgraphIndex, size_t operatorIndex)
2821 {
2822     const auto &operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2823     const auto *options = operatorPtr->builtin_options.AsArgMaxOptions();
2824 
2825     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2826     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2827     CHECK_VALID_SIZE(inputs.size(), 2);
2828 
2829     auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2830     CHECK_VALID_SIZE(outputs.size(), 1);
2831 
2832     auto layerName = fmt::format("ArgMax:{}:{}", subgraphIndex, operatorIndex);
2833 
2834     armnn::TensorInfo sizeTensorInfo0 = ToTensorInfo(inputs[0]);
2835     armnn::TensorInfo sizeTensorInfo1 = ToTensorInfo(inputs[1]);
2836 
2837     // Get const axis value from model and set it to descriptor.
2838     BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2839 
2840     ArgMinMaxDescriptor desc;
2841     desc.m_Axis = axisBufferPtr->data.data()[0];
2842     // If output_type is int32 then set Signed32 else Signed64. Default type is Signed64.
2843     desc.m_Output_Type = options->output_type == 3 ? armnn::DataType::Signed32 : armnn::DataType::Signed64;
2844     desc.m_Function = ArgMinMaxFunction::Max;
2845 
2846     // Register a ArgMax layer.
2847     IConnectableLayer *layer = m_Network->AddArgMinMaxLayer(desc, layerName.c_str());
2848 
2849     armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2850     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2851 
2852     // Register input tensor to the layer.
2853     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2854     RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2855 
2856     // Register output tensor to the layer.
2857     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2858     RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2859 }
2860 
AddFusedActivationLayer(armnn::IConnectableLayer * prevLayer,unsigned int outputSlot,tflite::ActivationFunctionType activationType)2861 armnn::IConnectableLayer* TfLiteParser::AddFusedActivationLayer(armnn::IConnectableLayer* prevLayer,
2862                                                                 unsigned int outputSlot,
2863                                                                 tflite::ActivationFunctionType activationType)
2864 {
2865     ActivationDescriptor activationDesc;
2866     std::string layerName = prevLayer->GetName();
2867 
2868     switch(activationType)
2869     {
2870         case tflite::ActivationFunctionType_NONE:
2871         {
2872             // this is a no-op: return previous layer
2873             return prevLayer;
2874         }
2875         case tflite::ActivationFunctionType_RELU:
2876         {
2877             activationDesc.m_Function = ActivationFunction::ReLu;
2878             layerName += ":RELU";
2879             break;
2880         }
2881         case tflite::ActivationFunctionType_RELU6:
2882         {
2883             activationDesc.m_Function = ActivationFunction::BoundedReLu;
2884             activationDesc.m_A = 6.0f;
2885             activationDesc.m_B = 0.0f;
2886             layerName += ":RELU6";
2887             break;
2888         }
2889         case tflite::ActivationFunctionType_TANH:
2890         {
2891             activationDesc.m_Function = ActivationFunction::TanH;
2892             activationDesc.m_A = 1.0f;
2893             activationDesc.m_B = 1.0f;
2894             layerName += ":TANH";
2895             break;
2896         }
2897 
2898         // I only put these here as a reminder what others we could support
2899         case tflite::ActivationFunctionType_RELU_N1_TO_1:
2900         case tflite::ActivationFunctionType_SIGN_BIT:
2901         default:
2902         {
2903             throw ParseException(
2904                 fmt::format("TfLite parser doesn't suppport fused activation: "
2905                             "{}/{} {} ",
2906                             activationType,
2907                             tflite::EnumNameActivationFunctionType(activationType),
2908                             CHECK_LOCATION().AsString()));
2909 
2910         }
2911     }
2912 
2913     IConnectableLayer* activationLayer =
2914         m_Network->AddActivationLayer(activationDesc, layerName.c_str());
2915 
2916     auto & prevOutputSlot = prevLayer->GetOutputSlot(outputSlot);
2917     prevOutputSlot.Connect(activationLayer->GetInputSlot(0));
2918     activationLayer->GetOutputSlot(0).SetTensorInfo(prevOutputSlot.GetTensorInfo());
2919     return activationLayer;
2920 }
2921 
LoadModelFromFile(const char * fileName)2922 TfLiteParser::ModelPtr TfLiteParser::LoadModelFromFile(const char * fileName)
2923 {
2924     if (fileName == nullptr)
2925     {
2926         throw InvalidArgumentException(fmt::format("Invalid (null) file name {}",
2927                                        CHECK_LOCATION().AsString()));
2928     }
2929     std::error_code errorCode;
2930     fs::path pathToFile(fileName);
2931     if (!fs::exists(pathToFile, errorCode))
2932     {
2933         //fmt::format() could not be used here (format error)
2934         std::stringstream msg;
2935         msg << "Cannot find the file (" << fileName << ") errorCode: " << errorCode
2936             << " " << CHECK_LOCATION().AsString();
2937 
2938         throw FileNotFoundException(msg.str());
2939     }
2940     std::ifstream file(fileName, std::ios::binary);
2941     std::string fileContent((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
2942     return LoadModelFromBinary(reinterpret_cast<const uint8_t *>(fileContent.c_str()),
2943                                fileContent.size());
2944 }
2945 
LoadModelFromBinary(const uint8_t * binaryContent,size_t len)2946 TfLiteParser::ModelPtr TfLiteParser::LoadModelFromBinary(const uint8_t * binaryContent, size_t len)
2947 {
2948     if (binaryContent == nullptr)
2949      {
2950         throw InvalidArgumentException(fmt::format("Invalid (null) binary content {}",
2951                                        CHECK_LOCATION().AsString()));
2952      }
2953     flatbuffers::Verifier verifier(binaryContent, len);
2954     if (verifier.VerifyBuffer<tflite::Model>() == false)
2955     {
2956         throw ParseException(
2957             fmt::format("Buffer doesn't conform to the expected Tensorflow Lite "
2958                         "flatbuffers format. size:{} {}",
2959                         len,
2960                         CHECK_LOCATION().AsString()));
2961     }
2962     return tflite::UnPackModel(binaryContent);
2963 }
2964 
GetInputs(const ModelPtr & model,size_t subgraphIndex,size_t operatorIndex)2965 TfLiteParser::TensorRawPtrVector TfLiteParser::GetInputs(const ModelPtr & model,
2966                                                          size_t subgraphIndex,
2967                                                          size_t operatorIndex)
2968 {
2969     CHECK_MODEL(model, subgraphIndex, operatorIndex);
2970 
2971     const auto & subgraphPtr = model->subgraphs[subgraphIndex];
2972     const auto & operatorPtr = subgraphPtr->operators[operatorIndex];
2973 
2974     size_t inputCount = operatorPtr->inputs.size();
2975     TensorRawPtrVector result(inputCount);
2976     for (size_t i=0; i<inputCount; ++i)
2977     {
2978         uint32_t inputId = CHECKED_NON_NEGATIVE(operatorPtr->inputs[i]);
2979         result[i] = subgraphPtr->tensors[inputId].get();
2980     }
2981     return result;
2982 }
2983 
GetOutputs(const ModelPtr & model,size_t subgraphIndex,size_t operatorIndex)2984 TfLiteParser::TensorRawPtrVector TfLiteParser::GetOutputs(const ModelPtr & model,
2985                                                           size_t subgraphIndex,
2986                                                           size_t operatorIndex)
2987 {
2988     CHECK_MODEL(model, subgraphIndex, operatorIndex);
2989 
2990     const auto & subgraphPtr = model->subgraphs[subgraphIndex];
2991     const auto & operatorPtr = subgraphPtr->operators[operatorIndex];
2992 
2993     size_t outputCount = operatorPtr->outputs.size();
2994     TensorRawPtrVector result(outputCount);
2995     for (size_t i=0; i<outputCount; ++i)
2996     {
2997         uint32_t outputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[i]);
2998         CHECK_TENSOR(model, subgraphIndex, outputId);
2999         result[i] = subgraphPtr->tensors[outputId].get();
3000     }
3001     return result;
3002 }
3003 
GetSubgraphInputs(const ModelPtr & model,size_t subgraphIndex)3004 TfLiteParser::TensorIdRawPtrVector TfLiteParser::GetSubgraphInputs(const ModelPtr & model,
3005                                                                    size_t subgraphIndex)
3006 {
3007     CHECK_SUBGRAPH(model, subgraphIndex);
3008     const auto & subgraphPtr = model->subgraphs[subgraphIndex];
3009 
3010     size_t inputCount = subgraphPtr->inputs.size();
3011     TensorIdRawPtrVector result(inputCount);
3012     for (size_t i=0; i<inputCount; ++i)
3013     {
3014         uint32_t inputId = CHECKED_NON_NEGATIVE(subgraphPtr->inputs[i]);
3015         CHECK_TENSOR(model, subgraphIndex, inputId);
3016         result[i] = std::make_pair(inputId, subgraphPtr->tensors[inputId].get());
3017     }
3018     return result;
3019 }
3020 
GetSubgraphOutputs(const ModelPtr & model,size_t subgraphIndex)3021 TfLiteParser::TensorIdRawPtrVector TfLiteParser::GetSubgraphOutputs(const ModelPtr & model,
3022                                                                     size_t subgraphIndex)
3023 {
3024     CHECK_SUBGRAPH(model, subgraphIndex);
3025     const auto & subgraphPtr = model->subgraphs[subgraphIndex];
3026 
3027     size_t outputCount = subgraphPtr->outputs.size();
3028     TensorIdRawPtrVector result(outputCount);
3029     for (size_t i=0; i<outputCount; ++i)
3030     {
3031         uint32_t outputId = CHECKED_NON_NEGATIVE(subgraphPtr->outputs[i]);
3032         result[i] = std::make_pair(outputId, subgraphPtr->tensors[outputId].get());
3033     }
3034     return result;
3035 }
3036 
GetInputTensorIds(const ModelPtr & model,size_t subgraphIndex,size_t operatorIndex)3037 std::vector<int32_t>& TfLiteParser::GetInputTensorIds(const ModelPtr& model,
3038                                                       size_t subgraphIndex,
3039                                                       size_t operatorIndex)
3040 {
3041     CHECK_MODEL(model, subgraphIndex, operatorIndex);
3042     const auto & subgraphPtr = model->subgraphs[subgraphIndex];
3043     const auto & operatorPtr = subgraphPtr->operators[operatorIndex];
3044     return operatorPtr->inputs;
3045 }
3046 
GetOutputTensorIds(const ModelPtr & model,size_t subgraphIndex,size_t operatorIndex)3047 std::vector<int32_t>& TfLiteParser::GetOutputTensorIds(const ModelPtr& model,
3048                                                        size_t subgraphIndex,
3049                                                        size_t operatorIndex)
3050 {
3051     CHECK_MODEL(model, subgraphIndex, operatorIndex);
3052     const auto & subgraphPtr = model->subgraphs[subgraphIndex];
3053     const auto & operatorPtr = subgraphPtr->operators[operatorIndex];
3054     return operatorPtr->outputs;
3055 }
3056 
RegisterInputSlots(size_t subgraphIndex,size_t operatorIndex,IConnectableLayer * layer,const std::vector<unsigned int> & tensorIndexes)3057 void TfLiteParser::RegisterInputSlots(size_t subgraphIndex,
3058                                       size_t operatorIndex,
3059                                       IConnectableLayer* layer,
3060                                       const std::vector<unsigned int>& tensorIndexes)
3061 {
3062     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3063     ARMNN_ASSERT(layer != nullptr);
3064     if (tensorIndexes.size() != layer->GetNumInputSlots())
3065     {
3066         throw ParseException(
3067             fmt::format("The number of tensor inputs ({}) does not match the number expected ({})"
3068                         " for subgraph:{} operator index:{} {}",
3069                         tensorIndexes.size(),
3070                         layer->GetNumInputSlots(),
3071                         subgraphIndex,
3072                         operatorIndex,
3073                         CHECK_LOCATION().AsString()));
3074     }
3075 
3076     for (unsigned int slotIndex = 0; slotIndex < layer->GetNumInputSlots(); ++slotIndex)
3077     {
3078         unsigned int tensorIndex = tensorIndexes[slotIndex];
3079         armnn::IInputSlot* slot = &(layer->GetInputSlot(slotIndex));
3080         RegisterConsumerOfTensor(subgraphIndex, tensorIndex, slot);
3081     }
3082 }
3083 
RegisterOutputSlots(size_t subgraphIndex,size_t operatorIndex,IConnectableLayer * layer,const std::vector<unsigned int> & tensorIndexes)3084 void TfLiteParser::RegisterOutputSlots(size_t subgraphIndex,
3085                                        size_t operatorIndex,
3086                                        IConnectableLayer* layer,
3087                                        const std::vector<unsigned int>& tensorIndexes)
3088 {
3089     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3090     ARMNN_ASSERT(layer != nullptr);
3091     if (tensorIndexes.size() != layer->GetNumOutputSlots())
3092     {
3093         throw ParseException(
3094             fmt::format("The number of tensor outputs ({}) does not match the number expected ({})"
3095                         " for subgraph:{} operator index:{} {}",
3096                         tensorIndexes.size(),
3097                         layer->GetNumOutputSlots(),
3098                         subgraphIndex,
3099                         operatorIndex,
3100                         CHECK_LOCATION().AsString()));
3101     }
3102 
3103     for (unsigned int slotIndex = 0; slotIndex < layer->GetNumOutputSlots(); ++slotIndex)
3104     {
3105         unsigned int tensorIndex = tensorIndexes[slotIndex];
3106         armnn::IOutputSlot* slot = &(layer->GetOutputSlot(slotIndex));
3107         RegisterProducerOfTensor(subgraphIndex, tensorIndex, slot);
3108     }
3109 }
3110 
SetupInputLayers(size_t subgraphIndex)3111 void TfLiteParser::SetupInputLayers(size_t subgraphIndex)
3112 {
3113     CHECK_SUBGRAPH(m_Model, subgraphIndex);
3114 
3115     auto inputs = GetSubgraphInputs(m_Model, subgraphIndex);
3116     for (auto const & tensorIdAndPtr : inputs)
3117     {
3118         auto bindingId = GenerateLayerBindingId(subgraphIndex, tensorIdAndPtr.first);
3119         IConnectableLayer* layer =
3120             m_Network->AddInputLayer(bindingId, tensorIdAndPtr.second->name.c_str());
3121 
3122         auto tensorInfo = ToTensorInfo(tensorIdAndPtr.second);
3123         layer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
3124 
3125         RegisterOutputSlots(subgraphIndex,
3126                             VIRTUAL_OPERATOR_ID,
3127                             layer,
3128                             { static_cast<uint32_t>(tensorIdAndPtr.first) });
3129     }
3130 }
3131 
SetupOutputLayers(size_t subgraphIndex)3132 void TfLiteParser::SetupOutputLayers(size_t subgraphIndex)
3133 {
3134     CHECK_SUBGRAPH(m_Model, subgraphIndex);
3135 
3136     auto outputs = GetSubgraphOutputs(m_Model, subgraphIndex);
3137     for (auto const & tensorIdAndPtr : outputs)
3138     {
3139         auto bindingId = GenerateLayerBindingId(subgraphIndex, tensorIdAndPtr.first);
3140         IConnectableLayer* layer =
3141             m_Network->AddOutputLayer(bindingId, tensorIdAndPtr.second->name.c_str());
3142 
3143         RegisterInputSlots(subgraphIndex,
3144                            VIRTUAL_OPERATOR_ID,
3145                            layer,
3146                            { static_cast<uint32_t>(tensorIdAndPtr.first) });
3147     }
3148 }
3149 
SetupConstantLayers(size_t subgraphIndex)3150 void TfLiteParser::SetupConstantLayers(size_t subgraphIndex)
3151 {
3152     CHECK_SUBGRAPH(m_Model, subgraphIndex);
3153 
3154     const auto & subgraphPtr = m_Model->subgraphs[subgraphIndex];
3155     for (unsigned int subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex)
3156     {
3157         for (unsigned int tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex)
3158         {
3159             if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot == nullptr &&
3160                 m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size() > 0)
3161             {
3162                 TensorRawPtr tensorPtr = subgraphPtr->tensors[tensorIndex].get();
3163                 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
3164                 auto tensorAndData = CreateConstTensor(tensorPtr,
3165                                                        tensorInfo,
3166                                                        armnn::Optional<armnn::PermutationVector&>());
3167 
3168                 std::string layerName = fmt::format("Constant:{}", tensorPtr->name);
3169                 IConnectableLayer *layer =
3170                     m_Network->AddConstantLayer(tensorAndData.first, layerName.c_str());
3171 
3172                 layer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
3173                 RegisterOutputSlots(subgraphIndex,
3174                                     VIRTUAL_OPERATOR_ID,
3175                                     layer,
3176                                     { tensorIndex });
3177 
3178             }
3179         }
3180     }
3181 }
3182 
3183 // example usage: BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[0]->buffer);
GetBuffer(const ModelPtr & model,size_t bufferIndex)3184 TfLiteParser::BufferRawPtr TfLiteParser::GetBuffer(const ModelPtr& model, size_t bufferIndex)
3185 {
3186     CHECK_BUFFER(model, bufferIndex);
3187     return model->buffers[bufferIndex].get();
3188 }
3189 
3190 template<typename T>
3191 std::pair<armnn::ConstTensor, TfLiteParser::SupportedDataStorage>
CreateConstTensorAndStoreData(TfLiteParser::BufferRawPtr bufferPtr,TfLiteParser::TensorRawPtr tensorPtr,armnn::TensorInfo & tensorInfo,armnn::Optional<armnn::PermutationVector &> permutationVector)3192 TfLiteParser::CreateConstTensorAndStoreData(TfLiteParser::BufferRawPtr bufferPtr,
3193                                             TfLiteParser::TensorRawPtr tensorPtr,
3194                                             armnn::TensorInfo& tensorInfo,
3195                                             armnn::Optional<armnn::PermutationVector&> permutationVector)
3196 {
3197     auto constData = CreateConstTensorImpl<T>(bufferPtr,
3198                                               tensorPtr,
3199                                               tensorInfo,
3200                                               permutationVector);
3201     TfLiteParser::SupportedDataStorage storage(std::move(constData.second));
3202     return std::make_pair(constData.first, std::move(storage));
3203 }
3204 
3205 std::pair<armnn::ConstTensor, TfLiteParser::SupportedDataStorage>
CreateConstTensor(TensorRawPtr tensorPtr,armnn::TensorInfo & tensorInfo,armnn::Optional<armnn::PermutationVector &> permutationVector)3206 TfLiteParser::CreateConstTensor(TensorRawPtr tensorPtr,
3207                                 armnn::TensorInfo& tensorInfo,
3208                                 armnn::Optional<armnn::PermutationVector&> permutationVector)
3209 {
3210     CHECK_TENSOR_PTR(tensorPtr);
3211     auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
3212     CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
3213 
3214     switch (tensorInfo.GetDataType())
3215     {
3216         case armnn::DataType::Float32:
3217             return CreateConstTensorAndStoreData<float>(bufferPtr,
3218                                                         tensorPtr,
3219                                                         tensorInfo,
3220                                                         permutationVector);
3221         case armnn::DataType::QAsymmU8:
3222             return CreateConstTensorAndStoreData<uint8_t>(bufferPtr,
3223                                                           tensorPtr,
3224                                                           tensorInfo,
3225                                                           permutationVector);
3226         case armnn::DataType::QSymmS8:
3227             return CreateConstTensorAndStoreData<int8_t>(bufferPtr,
3228                                                          tensorPtr,
3229                                                          tensorInfo,
3230                                                          permutationVector);
3231         case armnn::DataType::QAsymmS8:
3232             return CreateConstTensorAndStoreData<int8_t>(bufferPtr,
3233                                                          tensorPtr,
3234                                                          tensorInfo,
3235                                                          permutationVector);
3236         case armnn::DataType::Signed32:
3237             return CreateConstTensorAndStoreData<int32_t>(bufferPtr,
3238                                                           tensorPtr,
3239                                                           tensorInfo,
3240                                                           permutationVector);
3241         default:
3242         {
3243             std::stringstream errString;
3244             errString << "Unexpected datatype when creating const tensor: "
3245                         << armnn::GetDataTypeName(tensorInfo.GetDataType())
3246                         << " shape:" << tensorInfo.GetShape()
3247                         << CHECK_LOCATION().AsString();
3248             throw ParseException(errString.str());
3249         }
3250     }
3251 }
3252 
GetNetworkInputBindingInfo(size_t subgraphId,const std::string & name) const3253 BindingPointInfo TfLiteParser::GetNetworkInputBindingInfo(size_t subgraphId,
3254                                                           const std::string& name) const
3255 {
3256     CHECK_SUBGRAPH(m_Model, subgraphId);
3257     auto inputs = GetSubgraphInputs(m_Model, subgraphId);
3258     for (auto const & input : inputs)
3259     {
3260         if (input.second->name == name)
3261         {
3262             auto bindingId = GenerateLayerBindingId(subgraphId, input.first);
3263             return std::make_pair(bindingId, ToTensorInfo(input.second));
3264         }
3265     }
3266 
3267     std::stringstream bindings;
3268     for (auto const & input : inputs)
3269     {
3270         bindings << "'" << input.second->name << "' ";
3271     }
3272 
3273     throw ParseException(
3274         fmt::format("No input binding found for subgraph:{} and name:{}. "
3275                     "Possible inputs are: [{}] {}",
3276                     subgraphId,
3277                     name,
3278                     bindings.str(),
3279                     CHECK_LOCATION().AsString()));
3280 }
3281 
GetNetworkOutputBindingInfo(size_t subgraphId,const std::string & name) const3282 BindingPointInfo TfLiteParser::GetNetworkOutputBindingInfo(size_t subgraphId,
3283                                                            const std::string& name) const
3284 {
3285     CHECK_SUBGRAPH(m_Model, subgraphId);
3286     auto outputs = GetSubgraphOutputs(m_Model, subgraphId);
3287     for (unsigned int i = 0; i < outputs.size(); ++i)
3288     {
3289         auto const output = outputs[i];
3290         if (output.second->name == name)
3291         {
3292             auto bindingId = GenerateLayerBindingId(subgraphId, output.first);
3293             std::vector<unsigned int> shape = m_OverridenOutputShapes.size() > 0 ?
3294                                                 m_OverridenOutputShapes[i] : AsUnsignedVector(output.second->shape);
3295             return std::make_pair(bindingId, ToTensorInfo(output.second, shape));
3296         }
3297     }
3298 
3299     std::stringstream bindings;
3300     for (auto const & output : outputs)
3301     {
3302         bindings << "'" << output.second->name << "' ";
3303     }
3304 
3305     throw ParseException(
3306         fmt::format("No output binding found for subgraph:{} and name:{}. "
3307                     "Possible outputs are: [{}] {}",
3308                     subgraphId,
3309                     name,
3310                     bindings.str(),
3311                     CHECK_LOCATION().AsString()));
3312 }
3313 
GetSubgraphCount() const3314 size_t TfLiteParser::GetSubgraphCount() const
3315 {
3316     return m_Model->subgraphs.size();
3317 }
3318 
GetSubgraphInputTensorNames(size_t subgraphId) const3319 std::vector<std::string> TfLiteParser::GetSubgraphInputTensorNames(size_t subgraphId) const
3320 {
3321     CHECK_SUBGRAPH(m_Model, subgraphId);
3322     auto inputs = GetSubgraphInputs(m_Model, subgraphId);
3323     std::vector<std::string> result;
3324     result.reserve(inputs.size());
3325     for (auto const & input : inputs)
3326     {
3327         result.push_back(input.second->name);
3328     }
3329     return result;
3330 }
3331 
GetSubgraphOutputTensorNames(size_t subgraphId) const3332 std::vector<std::string> TfLiteParser::GetSubgraphOutputTensorNames(size_t subgraphId) const
3333 {
3334     CHECK_SUBGRAPH(m_Model, subgraphId);
3335     auto outputs = GetSubgraphOutputs(m_Model, subgraphId);
3336     std::vector<std::string> result;
3337     result.reserve(outputs.size());
3338     for (auto const & output : outputs)
3339     {
3340         result.push_back(output.second->name);
3341     }
3342     return result;
3343 }
3344 
CreateRaw(const Optional<ITfLiteParser::TfLiteParserOptions> & options)3345 ITfLiteParser* ITfLiteParser::CreateRaw(const Optional<ITfLiteParser::TfLiteParserOptions>& options)
3346 {
3347     return new TfLiteParser(options);
3348 }
3349 
Create(const Optional<ITfLiteParser::TfLiteParserOptions> & options)3350 ITfLiteParserPtr ITfLiteParser::Create(const Optional<ITfLiteParser::TfLiteParserOptions>& options)
3351 {
3352     return ITfLiteParserPtr(CreateRaw(options), &ITfLiteParser::Destroy);
3353 }
3354 
Destroy(ITfLiteParser * parser)3355 void ITfLiteParser::Destroy(ITfLiteParser* parser)
3356 {
3357     delete parser;
3358 }
3359 
SupportedDataStorage(std::unique_ptr<float[]> && data)3360 TfLiteParser::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<float[]> && data)
3361 : m_FloatData(std::move(data))
3362 , m_Uint8Data(nullptr)
3363 , m_Int8Data(nullptr)
3364 , m_Int32Data(nullptr)
3365 {
3366 }
3367 
SupportedDataStorage(std::unique_ptr<uint8_t[]> && data)3368 TfLiteParser::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<uint8_t[]> && data)
3369 : m_FloatData(nullptr)
3370 , m_Uint8Data(std::move(data))
3371 , m_Int8Data(nullptr)
3372 , m_Int32Data(nullptr)
3373 {
3374 }
3375 
SupportedDataStorage(std::unique_ptr<int8_t[]> && data)3376 TfLiteParser::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<int8_t[]> && data)
3377 : m_FloatData(nullptr)
3378 , m_Uint8Data(nullptr)
3379 , m_Int8Data(std::move(data))
3380 , m_Int32Data(nullptr)
3381 {
3382 }
3383 
SupportedDataStorage(std::unique_ptr<int32_t[]> && data)3384 TfLiteParser::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<int32_t[]> && data)
3385 : m_FloatData(nullptr)
3386 , m_Uint8Data(nullptr)
3387 , m_Int8Data(nullptr)
3388 , m_Int32Data(std::move(data))
3389 {
3390 }
3391 
3392 } // armnnTfLiteParser
3393