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