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