blob: 880de100c1b5bfbbce31f39d5b706d81ccc9d7a3 [file] [log] [blame]
telsoa01c577f2c2018-08-31 09:22:23 +01001//
Teresa Charlin455172a2022-06-29 15:35:57 +01002// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
David Beckecb56cd2018-09-05 12:52:57 +01003// SPDX-License-Identifier: MIT
telsoa01c577f2c2018-08-31 09:22:23 +01004//
Matteo Martincighe011d202019-11-28 11:35:47 +00005
telsoa01c577f2c2018-08-31 09:22:23 +01006#include "TfLiteParser.hpp"
7
Matthew Sloyanac001ee2021-02-03 10:43:04 +00008#include "armnnTfLiteParser/Version.hpp"
Mike Kelly5880b912022-01-28 16:18:54 +00009#include "armnn/LstmParams.hpp"
Matthew Sloyanac001ee2021-02-03 10:43:04 +000010
Sadik Armagand109a4d2020-07-28 10:42:13 +010011#include <armnn/BackendOptions.hpp>
Matthew Bentham39ef3e52020-01-20 10:09:09 +000012#include <armnn/Descriptors.hpp>
telsoa01c577f2c2018-08-31 09:22:23 +010013#include <armnn/Exceptions.hpp>
Derek Lamberti08446972019-11-26 16:38:31 +000014#include <armnn/Logging.hpp>
James Conroy05102392020-06-24 15:39:55 +010015#include <armnn/Tensor.hpp>
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +000016#include <armnnUtils/TensorUtils.hpp>
telsoa01c577f2c2018-08-31 09:22:23 +010017#include <armnn/TypesUtils.hpp>
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +010018#include <armnn/utility/Assert.hpp>
Jan Eilers8eb25602020-03-09 12:13:48 +000019#include <armnn/utility/IgnoreUnused.hpp>
Derek Lambertif0176992020-04-28 13:37:49 +010020#include <armnn/utility/NumericCast.hpp>
telsoa01c577f2c2018-08-31 09:22:23 +010021
22// armnnUtils:
Matteo Martincighe011d202019-11-28 11:35:47 +000023#include <armnnUtils/Permute.hpp>
Rob Hughes9542f902021-07-14 09:48:54 +010024#include <armnnUtils/Filesystem.hpp>
Matteo Martincighe011d202019-11-28 11:35:47 +000025
Sadik Armagan479045b2018-10-01 11:51:37 +010026#include <ParserHelper.hpp>
telsoa01c577f2c2018-08-31 09:22:23 +010027#include <VerificationHelpers.hpp>
28
29// The generated code based on the Tf Lite schema:
30#include <schema_generated.h>
31
Matteo Martincighe011d202019-11-28 11:35:47 +000032#include <flatbuffers/flexbuffers.h>
33
James Ward58dec6b2020-09-11 17:32:44 +010034#include <fmt/format.h>
telsoa01c577f2c2018-08-31 09:22:23 +010035
telsoa01c577f2c2018-08-31 09:22:23 +010036#include <algorithm>
Matthew Sloyanac001ee2021-02-03 10:43:04 +000037#include <iostream>
telsoa01c577f2c2018-08-31 09:22:23 +010038#include <limits>
Sadikb94967b2018-09-19 15:30:00 +010039#include <numeric>
Derek Lambertic9e52792020-03-11 11:42:26 +000040
41#define ARMNN_THROW_PARSE_EXCEPTION(msg) \
42 { \
43 throw armnn::ParseException( static_cast<const std::stringstream&>( std::stringstream() << msg \
44 << ": " \
45 << CHECK_LOCATION().AsString()).str()); \
46 }
telsoa01c577f2c2018-08-31 09:22:23 +010047
48using namespace armnn;
49using armnn::CheckLocation;
50namespace armnnTfLiteParser
51{
Kevin May7d96b162021-02-03 17:38:41 +000052
53ITfLiteParser::ITfLiteParser(const armnn::Optional<TfLiteParserOptions>& options) :
54 pTfLiteParserImpl(new TfLiteParserImpl(options)) {}
55
56ITfLiteParser::~ITfLiteParser() = default;
57
58ITfLiteParser* ITfLiteParser::CreateRaw(const armnn::Optional<TfLiteParserOptions>& options)
59{
60 return new ITfLiteParser(options);
61}
62
63ITfLiteParserPtr ITfLiteParser::Create(const armnn::Optional<TfLiteParserOptions>& options)
64{
65 return ITfLiteParserPtr(CreateRaw(options), &ITfLiteParser::Destroy);
66}
67
68void ITfLiteParser::Destroy(ITfLiteParser* parser)
69{
70 delete parser;
71}
72
73armnn::INetworkPtr ITfLiteParser::CreateNetworkFromBinaryFile(const char* graphFile)
74{
75 return pTfLiteParserImpl->CreateNetworkFromBinaryFile(graphFile);
76}
77
Mike Kelly0d77ae12022-01-07 17:42:27 +000078armnn::INetworkPtr ITfLiteParser::CreateNetworkFromBinary(const std::vector<uint8_t>& binaryContent)
Kevin May7d96b162021-02-03 17:38:41 +000079{
80 return pTfLiteParserImpl->CreateNetworkFromBinary(binaryContent);
81}
82
83BindingPointInfo ITfLiteParser::GetNetworkInputBindingInfo(size_t subgraphId,
84 const std::string& name) const
85{
86 return pTfLiteParserImpl->GetNetworkInputBindingInfo(subgraphId, name);
87}
88
89BindingPointInfo ITfLiteParser::GetNetworkOutputBindingInfo(size_t subgraphId,
90 const std::string& name) const
91{
92 return pTfLiteParserImpl->GetNetworkOutputBindingInfo(subgraphId, name);
93}
94
95size_t ITfLiteParser::GetSubgraphCount() const
96{
97 return pTfLiteParserImpl->GetSubgraphCount();
98}
99
100std::vector<std::string> ITfLiteParser::GetSubgraphInputTensorNames(size_t subgraphId) const
101{
102 return pTfLiteParserImpl->GetSubgraphInputTensorNames(subgraphId);
103}
104
105std::vector<std::string> ITfLiteParser::GetSubgraphOutputTensorNames(size_t subgraphId) const
106{
107 return pTfLiteParserImpl->GetSubgraphOutputTensorNames(subgraphId);
108}
109
telsoa01c577f2c2018-08-31 09:22:23 +0100110namespace
111{
jimfly01c25411c2018-11-14 17:47:22 +0000112
telsoa01c577f2c2018-08-31 09:22:23 +0100113const uint32_t VIRTUAL_OPERATOR_ID = std::numeric_limits<uint32_t>::max();
114
Mike Kelly0d77ae12022-01-07 17:42:27 +0000115void CheckSubgraph(const TfLiteParserImpl::ModelPtr& model,
telsoa01c577f2c2018-08-31 09:22:23 +0100116 size_t subgraphIndex,
Mike Kelly0d77ae12022-01-07 17:42:27 +0000117 const CheckLocation& location)
telsoa01c577f2c2018-08-31 09:22:23 +0100118{
119 if (model.get() == nullptr)
120 {
121 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100122 fmt::format("{} was called with invalid (null) model. "
123 "Possible reason is that the model is not yet loaded and Unpack(ed). "
124 "subgraph:{} at {}",
125 location.m_Function,
126 subgraphIndex,
127 location.FileLine()));
telsoa01c577f2c2018-08-31 09:22:23 +0100128 }
129 else if (subgraphIndex >= model->subgraphs.size())
130 {
131 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100132 fmt::format("{} was called with an invalid subgraph index. "
133 "subgraph:{} at {}",
134 location.m_Function,
135 subgraphIndex,
136 location.FileLine()));
telsoa01c577f2c2018-08-31 09:22:23 +0100137 }
138}
139
140#define CHECK_SUBGRAPH(MODEL, SUBGRAPH_INDEX) \
141 CheckSubgraph(MODEL, SUBGRAPH_INDEX, CHECK_LOCATION())
142
Mike Kelly0d77ae12022-01-07 17:42:27 +0000143void CheckModel(const TfLiteParserImpl::ModelPtr& model,
telsoa01c577f2c2018-08-31 09:22:23 +0100144 size_t subgraphIndex,
145 size_t operatorIndex,
Mike Kelly0d77ae12022-01-07 17:42:27 +0000146 const CheckLocation& location)
telsoa01c577f2c2018-08-31 09:22:23 +0100147{
148 if (model.get() == nullptr)
149 {
150 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100151 fmt::format("{} was called with invalid (null) model. "
152 "Possible reason is that the model is not yet loaded and Unpack(ed). "
153 "subgraph:{} operator:{} at {}",
154 location.m_Function,
155 subgraphIndex,
156 operatorIndex,
157 location.FileLine()));
telsoa01c577f2c2018-08-31 09:22:23 +0100158 }
159 else if (subgraphIndex >= model->subgraphs.size())
160 {
161 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100162 fmt::format("{} was called with an invalid subgraph index. "
163 "subgraph:{} operator:{} at {}",
164 location.m_Function,
165 subgraphIndex,
166 operatorIndex,
167 location.FileLine()));
telsoa01c577f2c2018-08-31 09:22:23 +0100168 }
169 else if (operatorIndex >= model->subgraphs[subgraphIndex]->operators.size() &&
170 operatorIndex != VIRTUAL_OPERATOR_ID)
171 {
172 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100173 fmt::format("{} was called with an invalid operator index. "
174 "subgraph:{} operator:{} at {}",
175 location.m_Function,
176 subgraphIndex,
177 operatorIndex,
178 location.FileLine()));
telsoa01c577f2c2018-08-31 09:22:23 +0100179 }
180}
181
182#define CHECK_MODEL(MODEL, SUBGRAPH_INDEX, OPERATOR_INDEX) \
183 CheckModel(MODEL, SUBGRAPH_INDEX, OPERATOR_INDEX, CHECK_LOCATION())
184
Mike Kelly0d77ae12022-01-07 17:42:27 +0000185void CheckTensor(const TfLiteParserImpl::ModelPtr& model,
telsoa01c577f2c2018-08-31 09:22:23 +0100186 size_t subgraphIndex,
187 size_t tensorIndex,
Mike Kelly0d77ae12022-01-07 17:42:27 +0000188 const CheckLocation& location)
telsoa01c577f2c2018-08-31 09:22:23 +0100189{
190 // not checking model, because I assume CHECK_MODEL already run
191 // and checked that. An assert would do.
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100192 ARMNN_ASSERT_MSG(model.get() != nullptr, "Expecting a valid model in this function");
telsoa01c577f2c2018-08-31 09:22:23 +0100193
194 // also subgraph index should be checked by CHECK_MODEL so
195 // I only add an assert here
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100196 ARMNN_ASSERT_MSG(subgraphIndex < model->subgraphs.size(), "Expecting a valid subgraph index");
telsoa01c577f2c2018-08-31 09:22:23 +0100197
198 // the tensor index is the only one to check here
199 if (tensorIndex >= model->subgraphs[subgraphIndex]->tensors.size())
200 {
201 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100202 fmt::format("{} was called with an invalid tensor index. "
203 "subgraph:{} tensor:{} at {}",
204 location.m_Function,
205 subgraphIndex,
206 tensorIndex,
207 location.FileLine()));
telsoa01c577f2c2018-08-31 09:22:23 +0100208 }
209}
210
211#define CHECK_TENSOR(MODEL, SUBGRAPH_INDEX, TENSOR_INDEX) \
212 CheckTensor(MODEL, SUBGRAPH_INDEX, TENSOR_INDEX, CHECK_LOCATION())
213
Kevin May7d96b162021-02-03 17:38:41 +0000214void CheckTensorPtr(TfLiteParserImpl::TensorRawPtr rawPtr,
Mike Kelly0d77ae12022-01-07 17:42:27 +0000215 const CheckLocation& location)
telsoa01c577f2c2018-08-31 09:22:23 +0100216{
217 if (rawPtr == nullptr)
218 {
219 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100220 fmt::format("{} was called with a null tensor pointer at {}", location.m_Function, location.FileLine()));
telsoa01c577f2c2018-08-31 09:22:23 +0100221 }
222}
223
224#define CHECK_TENSOR_PTR(TENSOR_PTR) \
225 CheckTensorPtr(TENSOR_PTR, CHECK_LOCATION())
226
Mike Kelly0d77ae12022-01-07 17:42:27 +0000227void CheckBuffer(const TfLiteParserImpl::ModelPtr& model,
telsoa01c577f2c2018-08-31 09:22:23 +0100228 size_t bufferIndex,
Mike Kelly0d77ae12022-01-07 17:42:27 +0000229 const CheckLocation& location)
telsoa01c577f2c2018-08-31 09:22:23 +0100230{
231 if (model.get() == nullptr)
232 {
233 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100234 fmt::format("{} was called with invalid (null) model. "
235 "Possible reason is that the model is not yet loaded and Unpack(ed). "
236 "buffer:{} at {}",
237 location.m_Function,
238 bufferIndex,
239 location.FileLine()));
telsoa01c577f2c2018-08-31 09:22:23 +0100240 }
241 else if (bufferIndex >= model->buffers.size())
242 {
243 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100244 fmt::format("{} was called with an invalid buffer index. "
245 "buffer index:{} at {}",
246 location.m_Function,
247 bufferIndex,
248 location.FileLine()));
telsoa01c577f2c2018-08-31 09:22:23 +0100249 }
250 else if (model->buffers[bufferIndex].get() == nullptr)
251 {
252 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100253 fmt::format("The buffer #{} is null. {}",
254 bufferIndex,
255 location.AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +0100256 }
257}
258
259#define CHECK_BUFFER(MODEL, BUFFER_INDEX) \
260 CheckBuffer(MODEL, BUFFER_INDEX, CHECK_LOCATION())
261
Kevin May7d96b162021-02-03 17:38:41 +0000262void CheckBufferSize(TfLiteParserImpl::BufferRawPtr bufferPtr,
Mike Kelly0d77ae12022-01-07 17:42:27 +0000263 const armnn::TensorInfo& tensorInfo,
telsoa01c577f2c2018-08-31 09:22:23 +0100264 uint32_t bufferId,
Mike Kelly0d77ae12022-01-07 17:42:27 +0000265 const CheckLocation& location)
telsoa01c577f2c2018-08-31 09:22:23 +0100266{
267 if (bufferPtr == nullptr)
268 {
269 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100270 fmt::format("BufferPtr is null for buffer:{}. {}",
271 bufferId,
272 location.AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +0100273 }
274 else if(tensorInfo.GetNumElements() > bufferPtr->data.size() ||
275 tensorInfo.GetNumBytes() > bufferPtr->data.size())
276 {
277 std::stringstream ss;
278 ss << "Buffer #" << bufferId << " has " << bufferPtr->data.size() << " bytes. "
279 << "For tensor: " << tensorInfo.GetShape()
280 << " expecting: " << tensorInfo.GetNumBytes() << " bytes and "
281 << tensorInfo.GetNumElements() << " elements. " << location.AsString();
282 throw ParseException(ss.str());
283 }
284}
285
Mike Kelly0d77ae12022-01-07 17:42:27 +0000286
287tflite::BuiltinOperator GetOpCode(const TfLiteParserImpl::ModelPtr& model, size_t subgraphIndex, size_t operatorIndex)
288{
289 const auto& operatorPtr = model->subgraphs[subgraphIndex]->operators[operatorIndex];
290 auto opcodeIndex = operatorPtr->opcode_index;
291
292// work around the introduction of the deprecated_builtin_code introduced in 2.4 in a backwards compatible manner
293#if defined(ARMNN_POST_TFLITE_2_3)
294 auto opcode = std::max(model->operator_codes[opcodeIndex]->builtin_code,
295 static_cast<tflite::BuiltinOperator>(model->operator_codes[opcodeIndex]->deprecated_builtin_code));
296#else
297 auto opcode = model->operator_codes[opcodeIndex]->builtin_code;
298#endif
299 return opcode;
300}
301
302std::vector<unsigned int> GetUIntBuffer(armnn::TensorInfo info,
303 const TfLiteParserImpl::ModelPtr& model,
304 size_t bufferIndex)
305{
306 TfLiteParserImpl::BufferRawPtr bufferPtr = TfLiteParserImpl::GetBuffer(model, bufferIndex);
307 std::vector<unsigned int> buffer(info.GetNumElements());
308
309 if (info.GetDataType() == DataType::Signed32)
310 {
311 ::memcpy(buffer.data(), bufferPtr->data.data(), bufferPtr->data.size());
312 }
313 else if (info.GetDataType() == DataType::Signed64)
314 {
315 std::vector<uint64_t> uint64Buffer(info.GetNumElements());
316 ::memcpy(uint64Buffer.data(), bufferPtr->data.data(), bufferPtr->data.size());
317 buffer.assign(std::begin(uint64Buffer), std::end(uint64Buffer));
318 }
319 return buffer;
320}
321
telsoa01c577f2c2018-08-31 09:22:23 +0100322#define CHECK_BUFFER_SIZE(BUFFER_PTR, TENSOR_INFO, BUFFER_ID) \
323 CheckBufferSize(BUFFER_PTR, TENSOR_INFO, BUFFER_ID, CHECK_LOCATION())
324
325bool IsActivationSupported(tflite::ActivationFunctionType activationType)
326{
327 switch(activationType)
328 {
329 case tflite::ActivationFunctionType_NONE:
330 case tflite::ActivationFunctionType_RELU:
331 case tflite::ActivationFunctionType_RELU6:
332 case tflite::ActivationFunctionType_TANH:
333 {
334 return true;
335 }
336 default:
337 {
338 return false;
339 }
340 }
341}
342
343#define CHECK_SUPPORTED_FUSED_ACTIVATION(OPTION, SUBGRAPH_INDEX, OPERATOR_INDEX) \
344 do { \
345 if (IsActivationSupported(OPTION->fused_activation_function) == false) \
346 { \
347 throw ParseException( \
James Ward58dec6b2020-09-11 17:32:44 +0100348 fmt::format("TfLite parser doesn't suppport fused activation: " \
349 "{}/{} in {} subgraph:{} operator:{} at {}", \
350 OPTION->fused_activation_function, \
351 tflite::EnumNameActivationFunctionType(\
352 OPTION->fused_activation_function), \
353 __func__, \
354 SUBGRAPH_INDEX, \
355 OPERATOR_INDEX, \
356 CHECK_LOCATION().FileLine())); \
telsoa01c577f2c2018-08-31 09:22:23 +0100357 } \
358 } while(false)
359
360
Mike Kelly0d77ae12022-01-07 17:42:27 +0000361std::vector<unsigned int> AsUnsignedVector(const std::vector<int32_t>& in)
telsoa01c577f2c2018-08-31 09:22:23 +0100362{
363 std::vector<unsigned int> result;
364 result.reserve(in.size());
Mike Kelly0d77ae12022-01-07 17:42:27 +0000365 for (auto& i : in)
telsoa01c577f2c2018-08-31 09:22:23 +0100366 {
mathad01c21025d2021-04-26 10:09:37 +0100367 // If the location of the input data is -1 then the input should be ignored.
368 if (i == -1)
369 {
370 continue;
371 }
telsoa01c577f2c2018-08-31 09:22:23 +0100372 result.push_back(CHECKED_NON_NEGATIVE(i));
373 }
374 return result;
375}
376
Mike Kelly5880b912022-01-28 16:18:54 +0000377bool IsOptionalOperandPresent(int input)
378{
379 return (input >= 0);
380}
381
telsoa01c577f2c2018-08-31 09:22:23 +0100382void CalcPadding(uint32_t inputSize,
383 uint32_t filterSize,
384 uint32_t stride,
Pablo Tellof0bd6832019-04-26 17:58:13 +0100385 uint32_t dilation,
telsoa01c577f2c2018-08-31 09:22:23 +0100386 uint32_t& paddingFront,
387 uint32_t& paddingBack,
388 tflite::Padding padding)
389{
390 paddingFront = 0;
391 paddingBack = 0;
392 if (padding == tflite::Padding_SAME)
393 {
394 uint32_t outputSize = (inputSize + stride - 1) / stride;
Pablo Tellof0bd6832019-04-26 17:58:13 +0100395 uint32_t dilatedSize = filterSize + (dilation - 1) * (filterSize - 1);
396 uint32_t temp = (outputSize - 1) * stride + dilatedSize;
telsoa01c577f2c2018-08-31 09:22:23 +0100397 if (temp > inputSize)
398 {
399 paddingFront = (temp - inputSize) / 2;
400 paddingBack = (temp - inputSize) - paddingFront;
401 }
402 }
403}
404
Kevin May7d96b162021-02-03 17:38:41 +0000405armnn::TensorInfo ToTensorInfo(TfLiteParserImpl::TensorRawPtr tensorPtr,
Finn Williamsb49ed182021-06-29 15:50:08 +0100406 const std::vector<unsigned int>& shape,
Sadik Armagand109a4d2020-07-28 10:42:13 +0100407 const bool outputTensor = false)
telsoa01c577f2c2018-08-31 09:22:23 +0100408{
409 armnn::DataType type;
410 CHECK_TENSOR_PTR(tensorPtr);
411
412 switch (tensorPtr->type)
413 {
414 case tflite::TensorType_UINT8:
Derek Lambertif90c56d2020-01-10 17:14:08 +0000415 type = armnn::DataType::QAsymmU8;
telsoa01c577f2c2018-08-31 09:22:23 +0100416 break;
417 case tflite::TensorType_FLOAT32:
418 type = armnn::DataType::Float32;
419 break;
Keith Davisb4dd5cc2022-04-07 11:32:00 +0100420 case tflite::TensorType_FLOAT16:
421 type = armnn::DataType::Float16;
422 break;
Finn Williamsed66d142019-12-06 09:55:55 +0000423 case tflite::TensorType_INT8:
Keith Davis67e6c542020-02-19 10:08:33 +0000424 if (tensorPtr->quantization->zero_point.size() == 1)
Ryan OShea03181ff2020-02-07 17:22:22 +0000425 {
Keith Davis0c2eeac2020-02-11 16:51:50 +0000426 // Per-tensor
Ryan OShea03181ff2020-02-07 17:22:22 +0000427 type = armnn::DataType::QAsymmS8;
428 }
429 else
430 {
Keith Davis0c2eeac2020-02-11 16:51:50 +0000431 // Per-channel
Ryan OShea03181ff2020-02-07 17:22:22 +0000432 type = armnn::DataType::QSymmS8;
433 }
Finn Williamsed66d142019-12-06 09:55:55 +0000434 break;
435 case tflite::TensorType_INT16:
Derek Lambertif90c56d2020-01-10 17:14:08 +0000436 type = armnn::DataType::QSymmS16;
Finn Williamsed66d142019-12-06 09:55:55 +0000437 break;
telsoa01c577f2c2018-08-31 09:22:23 +0100438 case tflite::TensorType_INT32:
439 type = armnn::DataType::Signed32;
440 break;
Inki Daed4619e22020-09-10 15:33:54 +0900441 case tflite::TensorType_INT64:
442 type = armnn::DataType::Signed64;
443 break;
Matthew Sloyaned7fce42021-04-15 20:46:24 +0100444 case tflite::TensorType_BOOL:
445 type = armnn::DataType::Boolean;
446 break;
telsoa01c577f2c2018-08-31 09:22:23 +0100447 default:
448 {
449 CheckLocation location = CHECK_LOCATION();
450 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100451 fmt::format("Unsupported data type {} = {} for tensor: {}. {}",
452 tensorPtr->type,
453 tflite::EnumNameTensorType(tensorPtr->type),
454 tensorPtr->name,
455 location.AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +0100456 }
457 }
Finn Williamsb49ed182021-06-29 15:50:08 +0100458 TensorShape tensorShape;
459
460 std::vector<unsigned int> safeShape = shape;
461 if (shape.size() == 0)
Narumol Prangnawarat4818d462019-04-17 11:22:38 +0100462 {
463 safeShape.push_back(1);
Finn Williamsb49ed182021-06-29 15:50:08 +0100464 }
465
466 if (!outputTensor)
467 {
468 tensorShape = TensorShape(armnn::numeric_cast<unsigned int>(safeShape.size()), safeShape.data());
469 }
470 else
471 {
Rob Hughesd812a312021-08-06 13:10:53 +0100472 size_t shapeSignatureSize = tensorPtr->shape_signature.size();
Finn Williamsb49ed182021-06-29 15:50:08 +0100473
474 // If a shape signature exists we will use that to infer dynamic tensors
475 if (shapeSignatureSize != 0)
Sadik Armagand109a4d2020-07-28 10:42:13 +0100476 {
Finn Williamsb49ed182021-06-29 15:50:08 +0100477 // If the shape is incompatible with the shape signature override the shape
478 if (shapeSignatureSize != shape.size())
479 {
480 safeShape = {};
481
482 for (unsigned int i = 0; i < shapeSignatureSize; ++i)
483 {
484 unsigned int dim = tensorPtr->shape_signature[i] > -1 ?
485 static_cast<unsigned int>(tensorPtr->shape_signature[i]) : 0;
486 safeShape.push_back(dim);
487 }
488 }
489
Rob Hughesd812a312021-08-06 13:10:53 +0100490 std::unique_ptr<bool[]> dimMask = std::make_unique<bool[]>(tensorPtr->shape_signature.size());
Finn Williamsb49ed182021-06-29 15:50:08 +0100491 for (unsigned int i = 0; i < tensorPtr->shape_signature.size(); ++i)
492 {
493 dimMask[i] = tensorPtr->shape_signature[i] == -1 ? false : true;
494 }
Rob Hughesd812a312021-08-06 13:10:53 +0100495 tensorShape = TensorShape(static_cast<unsigned int>(safeShape.size()), safeShape.data(), dimMask.get());
Finn Williamsb49ed182021-06-29 15:50:08 +0100496 }
497 // If there is no shape signature treat the tensor as dynamic if the shape has a size of zero
498 else if (shape.size() == 0)
499 {
500 tensorShape = TensorShape(1, false);
501 }
502 else
503 {
504 tensorShape = TensorShape(armnn::numeric_cast<unsigned int>(shape.size()), shape.data());
Sadik Armagand109a4d2020-07-28 10:42:13 +0100505 }
Narumol Prangnawarat4818d462019-04-17 11:22:38 +0100506 }
507
Keith Davisd305e1a2020-01-22 11:57:54 +0000508 float quantizationScale = 0.0f;
509 int32_t quantizationOffset = 0;
510
511 if (tensorPtr->quantization.get())
512 {
513 if (tensorPtr->quantization->scale.size() <= 1)
514 {
515 CHECK_VALID_SIZE(tensorPtr->quantization->zero_point.size(), 0, 1);
516 CHECK_VALID_SIZE(tensorPtr->quantization->zero_point.size(), 0, 1);
517
518 if (tensorPtr->quantization->scale.size() == 1)
519 {
520 quantizationScale = tensorPtr->quantization->scale[0];
521 }
522 if (tensorPtr->quantization->zero_point.size() == 1)
523 {
524 // NOTE: we lose precision here when converting from 64 bit to 32
Ryan OShea03181ff2020-02-07 17:22:22 +0000525 // but this is what we support at the moment in ArmNN
Matthew Sloyan589e3e82020-09-11 16:17:48 +0100526 quantizationOffset = armnn::numeric_cast<int32_t>(tensorPtr->quantization->zero_point[0]);
Keith Davisd305e1a2020-01-22 11:57:54 +0000527 }
528
Sadik Armagand109a4d2020-07-28 10:42:13 +0100529 armnn::TensorInfo result(tensorShape,
530 type,
531 quantizationScale,
532 quantizationOffset);
Keith Davisd305e1a2020-01-22 11:57:54 +0000533 return result;
534 }
535 else
536 {
537 std::vector<float> quantizationScales;
538 std::vector<int32_t> quantizationOffsets;
539
540 // Scale
541 std::copy(tensorPtr->quantization->scale.begin(),
542 tensorPtr->quantization->scale.end(),
543 std::back_inserter(quantizationScales));
544
Keith Davis0c2eeac2020-02-11 16:51:50 +0000545 // QSymmS8 Per-axis
Sadik Armagand109a4d2020-07-28 10:42:13 +0100546 armnn::TensorInfo result(tensorShape,
547 type,
548 quantizationScales,
Jan Eilers7612bd62021-04-06 17:29:03 +0100549 armnn::numeric_cast<unsigned int>(tensorPtr->quantization->quantized_dimension));
Keith Davisd305e1a2020-01-22 11:57:54 +0000550 return result;
551 }
552 }
553 else
554 {
Sadik Armagand109a4d2020-07-28 10:42:13 +0100555 armnn::TensorInfo result(tensorShape,
Keith Davisd305e1a2020-01-22 11:57:54 +0000556 type,
557 quantizationScale,
558 quantizationOffset);
559 return result;
560 }
telsoa01c577f2c2018-08-31 09:22:23 +0100561}
562
Jan Eilers7612bd62021-04-06 17:29:03 +0100563armnn::TensorInfo ToTensorInfo(TfLiteParserImpl::TensorRawPtr tensorPtr)
Narumol Prangnawarat4628d052019-02-25 17:26:05 +0000564{
Mike Kelly0d77ae12022-01-07 17:42:27 +0000565 auto const& dimensions = AsUnsignedVector(tensorPtr->shape);
Jan Eilers7612bd62021-04-06 17:29:03 +0100566 return ToTensorInfo(tensorPtr, dimensions);
Narumol Prangnawarat4628d052019-02-25 17:26:05 +0000567}
568
Kevin May7d96b162021-02-03 17:38:41 +0000569armnn::TensorInfo ToTensorInfo(TfLiteParserImpl::TensorRawPtr tensorPtr,
Sadik Armagand109a4d2020-07-28 10:42:13 +0100570 const bool outputTensor)
571{
Mike Kelly0d77ae12022-01-07 17:42:27 +0000572 auto const& dimensions = AsUnsignedVector(tensorPtr->shape);
Jan Eilers7612bd62021-04-06 17:29:03 +0100573 return ToTensorInfo(tensorPtr, dimensions, outputTensor);
Sadik Armagand109a4d2020-07-28 10:42:13 +0100574}
575
telsoa01c577f2c2018-08-31 09:22:23 +0100576template<typename T>
577std::pair<armnn::ConstTensor, std::unique_ptr<T[]>>
Kevin May7d96b162021-02-03 17:38:41 +0000578CreateConstTensorImpl(TfLiteParserImpl::BufferRawPtr bufferPtr,
579 TfLiteParserImpl::TensorRawPtr tensorPtr,
Matteo Martincigh747ef822018-12-18 09:26:39 +0000580 armnn::TensorInfo& tensorInfo,
581 armnn::Optional<armnn::PermutationVector&> permutationVector)
telsoa01c577f2c2018-08-31 09:22:23 +0100582{
Jan Eilers8eb25602020-03-09 12:13:48 +0000583 IgnoreUnused(tensorPtr);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100584 ARMNN_ASSERT_MSG(tensorPtr != nullptr, "tensorPtr is null");
585 ARMNN_ASSERT_MSG(bufferPtr != nullptr,
James Ward58dec6b2020-09-11 17:32:44 +0100586 fmt::format("Buffer for buffer:{} is null", tensorPtr->buffer).c_str());
telsoa01c577f2c2018-08-31 09:22:23 +0100587
588 std::unique_ptr<T[]> data(new T[tensorInfo.GetNumElements()]);
Matteo Martincigh747ef822018-12-18 09:26:39 +0000589
590 if (permutationVector.has_value() && permutationVector.value().GetSize() > 0)
591 {
592 tensorInfo = armnnUtils::Permuted(tensorInfo, permutationVector.value());
Matteo Martincighd5b9e642019-01-04 18:01:21 +0000593 armnnUtils::Permute(tensorInfo.GetShape(), permutationVector.value(),
594 reinterpret_cast<const T*>(bufferPtr->data.data()), data.get(), sizeof(T));
Matteo Martincigh747ef822018-12-18 09:26:39 +0000595 }
596 else
597 {
598 ::memcpy(data.get(), bufferPtr->data.data(), tensorInfo.GetNumBytes());
599 }
600
Matthew Sloyan81beae32021-07-13 19:46:11 +0100601 // Make sure isConstant flag is set.
602 tensorInfo.SetConstant();
603
telsoa01c577f2c2018-08-31 09:22:23 +0100604 return std::make_pair(ConstTensor(tensorInfo, data.get()), std::move(data));
605}
606
telsoa01c577f2c2018-08-31 09:22:23 +0100607armnn::LayerBindingId GenerateLayerBindingId(size_t subgraphIndex, size_t tensorIndex)
608{
609 // generate the binding id by shifting the tensor id by 8 bit
610 // and add the subgraph id, which allows 256 subgraphs
611 return static_cast<armnn::LayerBindingId>((tensorIndex<<8)+subgraphIndex);
612}
613
Aron Virginas-Tar70672f62019-01-23 14:00:00 +0000614bool CheckShape(const armnn::TensorShape& actual, const std::vector<int32_t>& expected)
615{
616 const unsigned int actualSize = actual.GetNumDimensions();
617 if (actualSize != expected.size())
618 {
619 return false;
620 }
621
622 for (unsigned int i = 0u; i < actualSize; i++)
623 {
624 if (expected[i] < 0 ||
625 actual[i] != static_cast<unsigned int>(expected[i]))
626 {
627 return false;
628 }
629 }
630
631 return true;
632}
633
James Conroy05102392020-06-24 15:39:55 +0100634void CheckMatchingQuantization(const TensorInfo& first,
635 const TensorInfo& second,
636 const std::string& descName,
637 std::string const& firstName,
638 std::string const& secondName)
639{
640 if (!first.IsQuantized() ||
641 !second.IsQuantized())
642 {
643 // Not a quantized type, ignore the validation
644 return;
645 }
646
647 DataType firstDataType = first.GetDataType();
648 DataType secondDataType = second.GetDataType();
649
650 if (firstDataType != secondDataType)
651 {
652 throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
653 " must be of the same quantized type, " +
654 firstName + " is " + GetDataTypeName(firstDataType) + ", " +
655 secondName + " is " + GetDataTypeName(secondDataType));
656 }
657
658 if (!first.IsTypeSpaceMatch(second))
659 {
660 throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
661 " must have the same quantization space, " +
662 firstName + " has offset " + std::to_string(first.GetQuantizationOffset()) +
663 " and scale " + std::to_string(first.GetQuantizationScale()) + ", " +
664 secondName + " has offset " + std::to_string(second.GetQuantizationOffset()) +
665 " and scale " + std::to_string(second.GetQuantizationScale()));
666 }
667}
668
telsoa01c577f2c2018-08-31 09:22:23 +0100669} // <anonymous>
670
Kevin May7d96b162021-02-03 17:38:41 +0000671TfLiteParserImpl::TfLiteParserImpl(const Optional<ITfLiteParser::TfLiteParserOptions>& options)
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100672: m_Options(options)
673, m_Network(nullptr, nullptr)
Kevin May7d96b162021-02-03 17:38:41 +0000674, m_ParserFunctions(tflite::BuiltinOperator_MAX+1, &TfLiteParserImpl::ParseUnsupportedOperator)
telsoa01c577f2c2018-08-31 09:22:23 +0100675{
676 // register supported operators
Matthew Sloyaned7fce42021-04-15 20:46:24 +0100677 m_ParserFunctions[tflite::BuiltinOperator_ABS] = &TfLiteParserImpl::ParseAbs;
Kevin May7d96b162021-02-03 17:38:41 +0000678 m_ParserFunctions[tflite::BuiltinOperator_ADD] = &TfLiteParserImpl::ParseAdd;
Matthew Sloyan28f177c2021-04-09 14:38:52 +0100679 m_ParserFunctions[tflite::BuiltinOperator_ARG_MIN] = &TfLiteParserImpl::ParseArgMin;
680 m_ParserFunctions[tflite::BuiltinOperator_ARG_MAX] = &TfLiteParserImpl::ParseArgMax;
Kevin May7d96b162021-02-03 17:38:41 +0000681 m_ParserFunctions[tflite::BuiltinOperator_AVERAGE_POOL_2D] = &TfLiteParserImpl::ParseAveragePool2D;
682 m_ParserFunctions[tflite::BuiltinOperator_BATCH_TO_SPACE_ND] = &TfLiteParserImpl::ParseBatchToSpaceND;
mathad01b392e982021-04-07 12:07:30 +0100683 m_ParserFunctions[tflite::BuiltinOperator_CAST] = &TfLiteParserImpl::ParseCast;
Kevin May7d96b162021-02-03 17:38:41 +0000684 m_ParserFunctions[tflite::BuiltinOperator_CONCATENATION] = &TfLiteParserImpl::ParseConcatenation;
685 m_ParserFunctions[tflite::BuiltinOperator_CONV_2D] = &TfLiteParserImpl::ParseConv2D;
Matthew Sloyan4d217c02021-10-07 11:48:58 +0100686 // Conv3D support was added in TF 2.5, so for backwards compatibility a hash define is needed.
Cathal Corbette126be92022-05-25 11:21:11 +0100687 #if defined(ARMNN_POST_TFLITE_2_4)
Matthew Sloyaneb5f8102021-10-05 17:31:42 +0100688 m_ParserFunctions[tflite::BuiltinOperator_CONV_3D] = &TfLiteParserImpl::ParseConv3D;
Matthew Sloyan4d217c02021-10-07 11:48:58 +0100689 #endif
Kevin May7d96b162021-02-03 17:38:41 +0000690 m_ParserFunctions[tflite::BuiltinOperator_CUSTOM] = &TfLiteParserImpl::ParseCustomOperator;
691 m_ParserFunctions[tflite::BuiltinOperator_DEPTH_TO_SPACE] = &TfLiteParserImpl::ParseDepthToSpace;
692 m_ParserFunctions[tflite::BuiltinOperator_DEPTHWISE_CONV_2D] = &TfLiteParserImpl::ParseDepthwiseConv2D;
693 m_ParserFunctions[tflite::BuiltinOperator_DEQUANTIZE] = &TfLiteParserImpl::ParseDequantize;
Matthew Sloyan28f177c2021-04-09 14:38:52 +0100694 m_ParserFunctions[tflite::BuiltinOperator_DIV] = &TfLiteParserImpl::ParseDiv;
Kevin May7d96b162021-02-03 17:38:41 +0000695 m_ParserFunctions[tflite::BuiltinOperator_ELU] = &TfLiteParserImpl::ParseElu;
Bruno Goncalves2d0eb862021-07-11 14:10:15 -0300696 m_ParserFunctions[tflite::BuiltinOperator_EQUAL] = &TfLiteParserImpl::ParseEqual;
Kevin May7d96b162021-02-03 17:38:41 +0000697 m_ParserFunctions[tflite::BuiltinOperator_EXP] = &TfLiteParserImpl::ParseExp;
Teresa Charlin3ab85482021-06-08 16:59:29 +0100698 m_ParserFunctions[tflite::BuiltinOperator_EXPAND_DIMS] = &TfLiteParserImpl::ParseExpandDims;
Teresa Charlincdbd40b2022-02-25 13:21:55 +0000699 m_ParserFunctions[tflite::BuiltinOperator_FLOOR_DIV] = &TfLiteParserImpl::ParseFloorDiv;
Kevin May7d96b162021-02-03 17:38:41 +0000700 m_ParserFunctions[tflite::BuiltinOperator_FULLY_CONNECTED] = &TfLiteParserImpl::ParseFullyConnected;
701 m_ParserFunctions[tflite::BuiltinOperator_GATHER] = &TfLiteParserImpl::ParseGather;
Teresa Charlin91a53ea2022-04-25 15:47:29 +0100702 m_ParserFunctions[tflite::BuiltinOperator_GATHER_ND] = &TfLiteParserImpl::ParseGatherNd;
Bruno Goncalves2d0eb862021-07-11 14:10:15 -0300703 m_ParserFunctions[tflite::BuiltinOperator_GREATER] = &TfLiteParserImpl::ParseGreater;
704 m_ParserFunctions[tflite::BuiltinOperator_GREATER_EQUAL] = &TfLiteParserImpl::ParseGreaterOrEqual;
Kevin May7d96b162021-02-03 17:38:41 +0000705 m_ParserFunctions[tflite::BuiltinOperator_HARD_SWISH] = &TfLiteParserImpl::ParseHardSwish;
706 m_ParserFunctions[tflite::BuiltinOperator_LEAKY_RELU] = &TfLiteParserImpl::ParseLeakyRelu;
Bruno Goncalves2d0eb862021-07-11 14:10:15 -0300707 m_ParserFunctions[tflite::BuiltinOperator_LESS] = &TfLiteParserImpl::ParseLess;
708 m_ParserFunctions[tflite::BuiltinOperator_LESS_EQUAL] = &TfLiteParserImpl::ParseLessOrEqual;
Mike Kelly31dce2b2021-09-01 21:22:37 +0100709 m_ParserFunctions[tflite::BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION]
710 = &TfLiteParserImpl::ParseLocalResponseNormalization;
Teresa Charlin8b0bee12022-07-12 11:18:44 +0100711 m_ParserFunctions[tflite::BuiltinOperator_LOG] = &TfLiteParserImpl::ParseLog;
Matthew Sloyaned7fce42021-04-15 20:46:24 +0100712 m_ParserFunctions[tflite::BuiltinOperator_LOGICAL_NOT] = &TfLiteParserImpl::ParseLogicalNot;
Kevin May7d96b162021-02-03 17:38:41 +0000713 m_ParserFunctions[tflite::BuiltinOperator_LOGISTIC] = &TfLiteParserImpl::ParseLogistic;
Teresa Charlin455172a2022-06-29 15:35:57 +0100714 m_ParserFunctions[tflite::BuiltinOperator_LOG_SOFTMAX] = &TfLiteParserImpl::ParseLogSoftmax;
Kevin May7d96b162021-02-03 17:38:41 +0000715 m_ParserFunctions[tflite::BuiltinOperator_L2_NORMALIZATION] = &TfLiteParserImpl::ParseL2Normalization;
716 m_ParserFunctions[tflite::BuiltinOperator_MAX_POOL_2D] = &TfLiteParserImpl::ParseMaxPool2D;
717 m_ParserFunctions[tflite::BuiltinOperator_MAXIMUM] = &TfLiteParserImpl::ParseMaximum;
718 m_ParserFunctions[tflite::BuiltinOperator_MEAN] = &TfLiteParserImpl::ParseMean;
719 m_ParserFunctions[tflite::BuiltinOperator_MINIMUM] = &TfLiteParserImpl::ParseMinimum;
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +0100720 m_ParserFunctions[tflite::BuiltinOperator_MIRROR_PAD] = &TfLiteParserImpl::ParseMirrorPad;
Kevin May7d96b162021-02-03 17:38:41 +0000721 m_ParserFunctions[tflite::BuiltinOperator_MUL] = &TfLiteParserImpl::ParseMul;
722 m_ParserFunctions[tflite::BuiltinOperator_NEG] = &TfLiteParserImpl::ParseNeg;
Bruno Goncalves2d0eb862021-07-11 14:10:15 -0300723 m_ParserFunctions[tflite::BuiltinOperator_NOT_EQUAL] = &TfLiteParserImpl::ParseNotEqual;
Kevin May7d96b162021-02-03 17:38:41 +0000724 m_ParserFunctions[tflite::BuiltinOperator_PACK] = &TfLiteParserImpl::ParsePack;
725 m_ParserFunctions[tflite::BuiltinOperator_PAD] = &TfLiteParserImpl::ParsePad;
Mike Kelly0d77ae12022-01-07 17:42:27 +0000726 m_ParserFunctions[tflite::BuiltinOperator_PADV2] = &TfLiteParserImpl::ParsePad;
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +0100727 m_ParserFunctions[tflite::BuiltinOperator_PRELU] = &TfLiteParserImpl::ParsePrelu;
Kevin May7d96b162021-02-03 17:38:41 +0000728 m_ParserFunctions[tflite::BuiltinOperator_QUANTIZE] = &TfLiteParserImpl::ParseQuantize;
729 m_ParserFunctions[tflite::BuiltinOperator_RELU] = &TfLiteParserImpl::ParseRelu;
730 m_ParserFunctions[tflite::BuiltinOperator_RELU6] = &TfLiteParserImpl::ParseRelu6;
Sadik Armagana2747482021-02-09 10:28:54 +0000731 m_ParserFunctions[tflite::BuiltinOperator_REDUCE_MAX] = &TfLiteParserImpl::ParseReduceMax;
732 m_ParserFunctions[tflite::BuiltinOperator_REDUCE_MIN] = &TfLiteParserImpl::ParseReduceMin;
Teresa Charlin4e3e8312021-08-05 12:34:37 +0100733 m_ParserFunctions[tflite::BuiltinOperator_REDUCE_PROD] = &TfLiteParserImpl::ParseReduceProd;
Kevin May7d96b162021-02-03 17:38:41 +0000734 m_ParserFunctions[tflite::BuiltinOperator_RESHAPE] = &TfLiteParserImpl::ParseReshape;
735 m_ParserFunctions[tflite::BuiltinOperator_RESIZE_BILINEAR] = &TfLiteParserImpl::ParseResizeBilinear;
736 m_ParserFunctions[tflite::BuiltinOperator_RESIZE_NEAREST_NEIGHBOR] = &TfLiteParserImpl::ParseResizeNearestNeighbor;
Matthew Sloyaned7fce42021-04-15 20:46:24 +0100737 m_ParserFunctions[tflite::BuiltinOperator_RSQRT] = &TfLiteParserImpl::ParseRsqrt;
Teresa Charlinf0fce5b2022-05-04 17:24:43 +0100738 m_ParserFunctions[tflite::BuiltinOperator_SQRT] = &TfLiteParserImpl::ParseSqrt;
Keith Davis0176fd82021-06-01 17:36:32 +0100739 m_ParserFunctions[tflite::BuiltinOperator_SHAPE] = &TfLiteParserImpl::ParseShape;
Teresa Charlin8b0bee12022-07-12 11:18:44 +0100740 m_ParserFunctions[tflite::BuiltinOperator_SIN] = &TfLiteParserImpl::ParseSin;
Kevin May7d96b162021-02-03 17:38:41 +0000741 m_ParserFunctions[tflite::BuiltinOperator_SLICE] = &TfLiteParserImpl::ParseSlice;
742 m_ParserFunctions[tflite::BuiltinOperator_SOFTMAX] = &TfLiteParserImpl::ParseSoftmax;
743 m_ParserFunctions[tflite::BuiltinOperator_SPACE_TO_BATCH_ND] = &TfLiteParserImpl::ParseSpaceToBatchND;
744 m_ParserFunctions[tflite::BuiltinOperator_SPLIT] = &TfLiteParserImpl::ParseSplit;
745 m_ParserFunctions[tflite::BuiltinOperator_SPLIT_V] = &TfLiteParserImpl::ParseSplitV;
746 m_ParserFunctions[tflite::BuiltinOperator_SQUEEZE] = &TfLiteParserImpl::ParseSqueeze;
747 m_ParserFunctions[tflite::BuiltinOperator_STRIDED_SLICE] = &TfLiteParserImpl::ParseStridedSlice;
748 m_ParserFunctions[tflite::BuiltinOperator_SUB] = &TfLiteParserImpl::ParseSub;
749 m_ParserFunctions[tflite::BuiltinOperator_SUM] = &TfLiteParserImpl::ParseSum;
750 m_ParserFunctions[tflite::BuiltinOperator_TANH] = &TfLiteParserImpl::ParseTanH;
751 m_ParserFunctions[tflite::BuiltinOperator_TRANSPOSE] = &TfLiteParserImpl::ParseTranspose;
752 m_ParserFunctions[tflite::BuiltinOperator_TRANSPOSE_CONV] = &TfLiteParserImpl::ParseTransposeConv;
Mike Kelly5880b912022-01-28 16:18:54 +0000753 m_ParserFunctions[tflite::BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM]
754 = &TfLiteParserImpl::ParseUnidirectionalSequenceLSTM;
Kevin May7d96b162021-02-03 17:38:41 +0000755 m_ParserFunctions[tflite::BuiltinOperator_UNPACK] = &TfLiteParserImpl::ParseUnpack;
Matthew Sloyan28f177c2021-04-09 14:38:52 +0100756
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100757 // register supported custom operators
Kevin May7d96b162021-02-03 17:38:41 +0000758 m_CustomParserFunctions["TFLite_Detection_PostProcess"] = &TfLiteParserImpl::ParseDetectionPostProcess;
telsoa01c577f2c2018-08-31 09:22:23 +0100759}
760
Kevin May7d96b162021-02-03 17:38:41 +0000761void TfLiteParserImpl::ResetParser()
telsoa01c577f2c2018-08-31 09:22:23 +0100762{
763 m_Network = armnn::INetworkPtr(nullptr, nullptr);
764 m_Model = nullptr;
765 m_SubgraphConnections.clear();
Mike Kelly5880b912022-01-28 16:18:54 +0000766 m_OverridenOutputShapes.clear();
767 m_ConstantsToDequantize.clear();
768 m_ConstantsToBeCreated.clear();
telsoa01c577f2c2018-08-31 09:22:23 +0100769}
770
Kevin May7d96b162021-02-03 17:38:41 +0000771INetworkPtr TfLiteParserImpl::CreateNetworkFromBinaryFile(const char* graphFile)
telsoa01c577f2c2018-08-31 09:22:23 +0100772{
773 ResetParser();
774 m_Model = LoadModelFromFile(graphFile);
775 return CreateNetworkFromModel();
776}
777
Mike Kelly0d77ae12022-01-07 17:42:27 +0000778INetworkPtr TfLiteParserImpl::CreateNetworkFromBinary(const std::vector<uint8_t>& binaryContent)
telsoa01c577f2c2018-08-31 09:22:23 +0100779{
780 ResetParser();
781 m_Model = LoadModelFromBinary(binaryContent.data(), binaryContent.size());
782 return CreateNetworkFromModel();
783}
784
Finn Williamsb49ed182021-06-29 15:50:08 +0100785
786armnn::INetworkPtr TfLiteParserImpl::LoadModel(std::unique_ptr<tflite::ModelT> model)
787{
788 ResetParser();
789 m_Model = std::move(model);
790
791 return CreateNetworkFromModel();
792}
793
Kevin May7d96b162021-02-03 17:38:41 +0000794INetworkPtr TfLiteParserImpl::CreateNetworkFromModel()
telsoa01c577f2c2018-08-31 09:22:23 +0100795{
Sadik Armagand109a4d2020-07-28 10:42:13 +0100796
797 using NetworkOptions = std::vector<BackendOptions>;
798 NetworkOptions networkOptions = {};
Mike Kelly80512b02022-05-16 23:10:42 +0100799 if (m_Options)
Sadik Armagand109a4d2020-07-28 10:42:13 +0100800 {
Mike Kelly80512b02022-05-16 23:10:42 +0100801 if (m_Options.value().m_InferAndValidate)
802 {
803 BackendOptions shapeInferenceMethodOption("ShapeInferenceMethod",
804 {
805 { "InferAndValidate", true }
806 });
Sadik Armagand109a4d2020-07-28 10:42:13 +0100807
Mike Kelly80512b02022-05-16 23:10:42 +0100808 networkOptions.push_back(shapeInferenceMethodOption);
809 }
810 if (m_Options.value().m_AllowExpandedDims)
811 {
812 BackendOptions shapeInferenceMethodOption("AllowExpandedDims",
813 {
814 { "AllowExpandedDims", true }
815 });
816
817 networkOptions.push_back(shapeInferenceMethodOption);
818 }
Sadik Armagand109a4d2020-07-28 10:42:13 +0100819 }
Sadik Armagand109a4d2020-07-28 10:42:13 +0100820 m_Network = INetwork::Create(networkOptions);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100821 ARMNN_ASSERT(m_Model.get() != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +0100822
telsoa01c577f2c2018-08-31 09:22:23 +0100823 if (m_Model->subgraphs.size() != 1)
824 {
825 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100826 fmt::format("Current TfLite parser only supports 1 subgraph. Current one has: {} {}",
827 m_Model->subgraphs.size(),
828 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +0100829 }
830
831 size_t subgraphIndex = 0;
Colm Donelan6350d272020-06-09 16:56:25 +0100832 size_t operatorIndex = 0;
833 try
telsoa01c577f2c2018-08-31 09:22:23 +0100834 {
Colm Donelan6350d272020-06-09 16:56:25 +0100835 for (SubgraphPtr const& subgraph : m_Model->subgraphs)
telsoa01c577f2c2018-08-31 09:22:23 +0100836 {
Colm Donelan6350d272020-06-09 16:56:25 +0100837 m_SubgraphConnections.emplace_back(subgraph->tensors.size());
838 for (OperatorPtr const& op : subgraph->operators)
telsoa01c577f2c2018-08-31 09:22:23 +0100839 {
Colm Donelan6350d272020-06-09 16:56:25 +0100840 auto const& opCodePtr = m_Model->operator_codes[op->opcode_index];
Jim Flynnfca233e2021-09-23 12:16:53 +0100841
842// work around the introduction of the deprecated_builtin_code introduced in 2.4 in a backwards compatible manner
Matthew Sloyan4d217c02021-10-07 11:48:58 +0100843#if defined(ARMNN_POST_TFLITE_2_3)
Jim Flynnfca233e2021-09-23 12:16:53 +0100844 auto builtinCode = std::max(opCodePtr->builtin_code,
845 static_cast<tflite::BuiltinOperator>(opCodePtr->deprecated_builtin_code));
846#else
telsoa01c577f2c2018-08-31 09:22:23 +0100847 auto builtinCode = opCodePtr->builtin_code;
Jim Flynnfca233e2021-09-23 12:16:53 +0100848#endif
telsoa01c577f2c2018-08-31 09:22:23 +0100849
850 if (builtinCode > tflite::BuiltinOperator_MAX)
851 {
James Ward58dec6b2020-09-11 17:32:44 +0100852 throw ParseException(fmt::format("Operator code {} is out of range 0-{}. "
853 "subgraph:{} operator idx:{}. {}",
854 builtinCode, tflite::BuiltinOperator_MAX, subgraphIndex,
855 operatorIndex, CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +0100856 }
857
858 // lookup and call the parser function
Colm Donelan6350d272020-06-09 16:56:25 +0100859 auto& parserFunction = m_ParserFunctions[builtinCode];
telsoa01c577f2c2018-08-31 09:22:23 +0100860 (this->*parserFunction)(subgraphIndex, operatorIndex);
Colm Donelan6350d272020-06-09 16:56:25 +0100861 ++operatorIndex;
telsoa01c577f2c2018-08-31 09:22:23 +0100862 }
telsoa01c577f2c2018-08-31 09:22:23 +0100863
Colm Donelan6350d272020-06-09 16:56:25 +0100864 SetupInputLayers(subgraphIndex);
865 SetupOutputLayers(subgraphIndex);
866 SetupConstantLayers(subgraphIndex);
telsoa01c577f2c2018-08-31 09:22:23 +0100867
Colm Donelan6350d272020-06-09 16:56:25 +0100868 ++subgraphIndex;
869 operatorIndex = 0;
telsoa01c577f2c2018-08-31 09:22:23 +0100870 }
telsoa01c577f2c2018-08-31 09:22:23 +0100871 }
Colm Donelan6350d272020-06-09 16:56:25 +0100872 catch (const ParseException& e)
telsoa01c577f2c2018-08-31 09:22:23 +0100873 {
Colm Donelan6350d272020-06-09 16:56:25 +0100874 std::stringstream errorString;
875 errorString << "Failed to parse operator #" << operatorIndex << " within subgraph #"
876 << subgraphIndex << " error: " << e.what();
877 ARMNN_LOG(error) << errorString.str();
878 std::stringstream errors;
879 errors << errorString.str() << "\n";
telsoa01c577f2c2018-08-31 09:22:23 +0100880 throw ParseException(errors.str());
881 }
882
883 // establish the connections from the layer outputs to the inputs of the subsequent layers
Colm Donelan6350d272020-06-09 16:56:25 +0100884 for (subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +0100885 {
886 for (size_t tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex)
887 {
888 if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot != nullptr)
889 {
890 for (size_t inputSlotIdx = 0;
891 inputSlotIdx < m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size();
892 ++inputSlotIdx)
893 {
894 m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot->Connect(
895 *(m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots[inputSlotIdx]));
896 }
897 }
898 }
899 }
telsoa01c577f2c2018-08-31 09:22:23 +0100900 return std::move(m_Network);
901}
902
Mike Kelly5880b912022-01-28 16:18:54 +0000903std::unique_ptr<float[]> AsFloatArray(TfLiteParserImpl::BufferRawPtr bufferPtr,
904 const TensorInfo& tensorInfo)
905{
906 if (tensorInfo.GetDataType() == DataType::QAsymmS8 || tensorInfo.GetDataType() == DataType::QSymmS8 ||
907 tensorInfo.GetDataType() == DataType::QAsymmU8)
908 {
909 std::unique_ptr<float[]> buffer(new float[tensorInfo.GetNumElements()]);
910
911 if (tensorInfo.HasPerAxisQuantization())
912 {
913 unsigned int axis = tensorInfo.GetQuantizationDim().value();
914 auto axisDimensionality = tensorInfo.GetShape()[axis];
915 auto axisFactor = armnnUtils::GetNumElementsAfter(tensorInfo.GetShape(), axis);
916
917 for (unsigned int i = 0; i < tensorInfo.GetNumDimensions(); ++i)
918 {
919 unsigned int axisIndex = (i / axisFactor) % axisDimensionality;
920 buffer[i] = Dequantize<int8_t>(bufferPtr->data[i], tensorInfo.GetQuantizationScales()[axisIndex],
921 tensorInfo.GetQuantizationOffset());
922 }
923 }
924 else
925 {
926 for (unsigned int i = 0; i < tensorInfo.GetNumElements(); ++i)
927 {
928 buffer[i] = Dequantize<int8_t>(bufferPtr->data[i], tensorInfo.GetQuantizationScale(),
929 tensorInfo.GetQuantizationOffset());
930 }
931 }
932 return buffer;
933 }
934 throw ParseException(
935 fmt::format("Unsupported input/weights combination: Input {} not supported with Weights {}",
936 GetDataTypeName(DataType::Float32),
937 GetDataTypeName(tensorInfo.GetDataType()),
938 CHECK_LOCATION().AsString()));
939}
940
Kevin May7d96b162021-02-03 17:38:41 +0000941void TfLiteParserImpl::RegisterProducerOfTensor(size_t subgraphIndex,
942 size_t tensorIndex,
943 armnn::IOutputSlot* slot)
telsoa01c577f2c2018-08-31 09:22:23 +0100944{
945 CHECK_TENSOR(m_Model, subgraphIndex, tensorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100946 ARMNN_ASSERT(m_SubgraphConnections.size() > subgraphIndex);
947 ARMNN_ASSERT(m_SubgraphConnections[subgraphIndex].size() > tensorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +0100948
949 TensorSlots & tensorSlots = m_SubgraphConnections[subgraphIndex][tensorIndex];
950
Nikhil Raj2803c8d2022-08-03 18:20:59 +0100951 if (slot->GetOwningIConnectableLayer().GetType() != LayerType::Constant)
telsoa01c577f2c2018-08-31 09:22:23 +0100952 {
telsoa01c577f2c2018-08-31 09:22:23 +0100953
Nikhil Raj2803c8d2022-08-03 18:20:59 +0100954 // assuming there is only one producer for that tensor
955 if (tensorSlots.outputSlot != nullptr)
956 {
957 throw ParseException(fmt::format("Another layer has already registered itself as the producer of "
958 "subgraph:{} tensor:{} {}",
959 subgraphIndex,
960 tensorIndex,
961 CHECK_LOCATION().AsString()));
962 }
963 }
telsoa01c577f2c2018-08-31 09:22:23 +0100964 tensorSlots.outputSlot = slot;
965}
966
Kevin May7d96b162021-02-03 17:38:41 +0000967void TfLiteParserImpl::RegisterConsumerOfTensor(size_t subgraphIndex,
968 size_t tensorIndex,
969 armnn::IInputSlot* slot)
telsoa01c577f2c2018-08-31 09:22:23 +0100970{
971 CHECK_TENSOR(m_Model, subgraphIndex, tensorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100972 ARMNN_ASSERT(m_SubgraphConnections.size() > subgraphIndex);
973 ARMNN_ASSERT(m_SubgraphConnections[subgraphIndex].size() > tensorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +0100974
Finn Williamsd4fa5452021-03-01 12:31:41 +0000975 TensorSlots& tensorSlots = m_SubgraphConnections[subgraphIndex][tensorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +0100976 tensorSlots.inputSlots.push_back(slot);
977}
978
Kevin May7d96b162021-02-03 17:38:41 +0000979void TfLiteParserImpl::ParseCustomOperator(size_t subgraphIndex, size_t operatorIndex)
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100980{
981 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
982
983 // NOTE: By default we presume the custom operator is not supported
Kevin May7d96b162021-02-03 17:38:41 +0000984 auto customParserFunction = &TfLiteParserImpl::ParseUnsupportedOperator;
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100985
986 // Identify custom code defined for custom operator
987 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
988 const auto& customCode = m_Model->operator_codes[operatorPtr->opcode_index]->custom_code;
989
990 // Find parser function that correspondes to custom code (if any)
991 auto iterator = m_CustomParserFunctions.find(customCode);
992 if (iterator != m_CustomParserFunctions.end())
993 {
994 customParserFunction = iterator->second;
995 }
996
997 // Run parser function
998 (this->*customParserFunction)(subgraphIndex, operatorIndex);
999}
1000
Kevin May7d96b162021-02-03 17:38:41 +00001001void TfLiteParserImpl::ParseUnsupportedOperator(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001002{
1003 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001004
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001005 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1006
1007 auto opcodeIndex = operatorPtr->opcode_index;
Jim Flynnfca233e2021-09-23 12:16:53 +01001008
1009// work around the introduction of the deprecated_builtin_code introduced in 2.4 in a backwards compatible manner
Matthew Sloyan4d217c02021-10-07 11:48:58 +01001010#if defined(ARMNN_POST_TFLITE_2_3)
Jim Flynnfca233e2021-09-23 12:16:53 +01001011 auto opcode = std::max(m_Model->operator_codes[opcodeIndex]->builtin_code,
1012 static_cast<tflite::BuiltinOperator>(m_Model->operator_codes[opcodeIndex]->deprecated_builtin_code));
1013#else
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001014 auto opcode = m_Model->operator_codes[opcodeIndex]->builtin_code;
Jim Flynnfca233e2021-09-23 12:16:53 +01001015#endif
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001016
1017 if (!m_Options || !m_Options.value().m_StandInLayerForUnsupported)
1018 {
1019 // Do not add StandInLayer, throw ParseException instead
1020 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01001021 fmt::format("Operator not supported. "
1022 "subgraph:{} operator:{} "
1023 "opcode_index:{} opcode:{} / {} {}",
1024 subgraphIndex,
1025 operatorIndex,
1026 opcodeIndex,
1027 opcode,
1028 tflite::EnumNameBuiltinOperator(opcode),
1029 CHECK_LOCATION().AsString()));
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001030 }
1031
1032 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1033 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1034
Matthew Sloyan589e3e82020-09-11 16:17:48 +01001035 const unsigned int numInputs = armnn::numeric_cast<unsigned int>(inputs.size());
1036 const unsigned int numOutputs = armnn::numeric_cast<unsigned int>(outputs.size());
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001037
1038 StandInDescriptor descriptor(numInputs, numOutputs);
James Ward58dec6b2020-09-11 17:32:44 +01001039 auto layerName = fmt::format("StandIn:{}:{}:{}", subgraphIndex, operatorIndex, opcode);
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001040
1041 // Add a non-executable StandInLayer as a placeholder for any unsupported operator
1042 IConnectableLayer* layer = m_Network->AddStandInLayer(descriptor, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01001043 ARMNN_ASSERT(layer != nullptr);
1044
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001045 for (unsigned int i = 0u; i < numOutputs; ++i)
1046 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01001047 layer->GetOutputSlot(i).SetTensorInfo(ToTensorInfo(outputs[i], true));
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001048 }
1049
1050 auto inputTensorIds = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1051 auto outputTensorIds = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1052
1053 RegisterInputSlots(subgraphIndex, operatorIndex, layer, inputTensorIds);
1054 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIds);
telsoa01c577f2c2018-08-31 09:22:23 +01001055}
1056
mathad01b392e982021-04-07 12:07:30 +01001057void TfLiteParserImpl::ParseCast(size_t subgraphIndex, size_t operatorIndex)
1058{
1059 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1060
1061 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1062 CHECK_VALID_SIZE(inputs.size(), 1);
1063 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1064 CHECK_VALID_SIZE(outputs.size(), 1);
1065
1066 auto layerName = fmt::format("Cast:{}:{}", subgraphIndex, operatorIndex);
1067
1068 IConnectableLayer* layer = m_Network->AddCastLayer(layerName.c_str());
1069 ARMNN_ASSERT(layer != nullptr);
1070
1071 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1072 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1073
1074 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1075 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1076
1077 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1078 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
1079}
1080
Kevin May7d96b162021-02-03 17:38:41 +00001081void TfLiteParserImpl::ParseConv2D(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001082{
1083 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1084
Mike Kelly0d77ae12022-01-07 17:42:27 +00001085 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1086 const auto* options = operatorPtr->builtin_options.AsConv2DOptions();
telsoa01c577f2c2018-08-31 09:22:23 +01001087
1088 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1089
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001090 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1091 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1092 CHECK_VALID_SIZE(outputs.size(), 1);
1093
telsoa01c577f2c2018-08-31 09:22:23 +01001094 Convolution2dDescriptor desc;
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001095 inputs.size() == 3 ?
1096 desc.m_BiasEnabled = true : desc.m_BiasEnabled = false;
telsoa01c577f2c2018-08-31 09:22:23 +01001097 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1098 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
jimfly01c25411c2018-11-14 17:47:22 +00001099 desc.m_DataLayout = armnn::DataLayout::NHWC;
Pablo Tellof0bd6832019-04-26 17:58:13 +01001100 desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
1101 desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
Kevin May83add212019-03-26 11:39:19 +00001102
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001103 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
telsoa01c577f2c2018-08-31 09:22:23 +01001104 armnn::TensorInfo filterTensorInfo = ToTensorInfo(inputs[1]);
1105
1106 // assuming input is NHWC
1107 unsigned int inputHeight = inputTensorInfo.GetShape()[1];
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001108 unsigned int inputWidth = inputTensorInfo.GetShape()[2];
telsoa01c577f2c2018-08-31 09:22:23 +01001109
1110 // assuming the filter is OHWI : Output, H, W, Input
1111 // which is essentially the same as NHWC
1112 unsigned int filterHeight = filterTensorInfo.GetShape()[1];
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001113 unsigned int filterWidth = filterTensorInfo.GetShape()[2];
telsoa01c577f2c2018-08-31 09:22:23 +01001114
Pablo Tellof0bd6832019-04-26 17:58:13 +01001115 CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
1116 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
1117 CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
1118 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
telsoa01c577f2c2018-08-31 09:22:23 +01001119
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001120 // Add the first input and weights tensor to the registration list.
1121 // The constant weights will be added by SetupConstantLayers.
1122 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1123 std::vector<unsigned int> tensorIndexesToRegister = { inputTensorIndexes[0], inputTensorIndexes[1] };
telsoa01c577f2c2018-08-31 09:22:23 +01001124
James Ward58dec6b2020-09-11 17:32:44 +01001125 auto layerName = fmt::format("Conv2D:{}:{}", subgraphIndex, operatorIndex);
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001126 armnn::IConnectableLayer* layer = m_Network->AddConvolution2dLayer(desc, layerName.c_str());
telsoa01c577f2c2018-08-31 09:22:23 +01001127
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001128 if (IsConstTensor(inputs[1]) && inputTensorInfo.GetDataType() == DataType::Float32 &&
1129 (filterTensorInfo.GetDataType() == DataType::QAsymmU8 ||
1130 filterTensorInfo.GetDataType() == DataType::QAsymmS8))
telsoa01c577f2c2018-08-31 09:22:23 +01001131 {
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001132 m_ConstantsToDequantize.emplace_back(inputs[1]->buffer);
telsoa01c577f2c2018-08-31 09:22:23 +01001133 }
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001134
1135 if (desc.m_BiasEnabled)
telsoa01c577f2c2018-08-31 09:22:23 +01001136 {
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001137 armnn::TensorInfo biasTensorInfo = ToTensorInfo(inputs[2]);
1138
1139 // Add the biases input to the registration list, a constant layer will be added by SetupConstantLayers.
1140 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
1141
1142 if (IsConstTensor(inputs[2]) && inputTensorInfo.GetDataType() == DataType::Float32 &&
1143 (filterTensorInfo.GetDataType() == DataType::QAsymmU8 ||
1144 filterTensorInfo.GetDataType() == DataType::QAsymmS8))
1145 {
1146 m_ConstantsToDequantize.emplace_back(inputs[2]->buffer);
1147 }
telsoa01c577f2c2018-08-31 09:22:23 +01001148 }
1149
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001150 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01001151
Sadik Armagand109a4d2020-07-28 10:42:13 +01001152 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
jimfly01c25411c2018-11-14 17:47:22 +00001153 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +01001154
1155 // register the input connection slots for the layer, connections are made after all layers have been created
1156 // only the tensors for the inputs are relevant, exclude the const tensors
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001157 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister);
telsoa01c577f2c2018-08-31 09:22:23 +01001158
jimfly01c25411c2018-11-14 17:47:22 +00001159 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
telsoa01c577f2c2018-08-31 09:22:23 +01001160 // register the output connection slots for the layer, connections are made after all layers have been created
1161 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001162 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, { outputTensorIndexes[0] });
telsoa01c577f2c2018-08-31 09:22:23 +01001163}
1164
Matthew Sloyan4d217c02021-10-07 11:48:58 +01001165// Conv3D support was added in TF 2.5, so for backwards compatibility a hash define is needed.
Cathal Corbette126be92022-05-25 11:21:11 +01001166#if defined(ARMNN_POST_TFLITE_2_4)
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001167void TfLiteParserImpl::ParseConv3D(size_t subgraphIndex, size_t operatorIndex)
1168{
1169 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1170
1171 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1172 const auto* options = operatorPtr->builtin_options.AsConv3DOptions();
1173
1174 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1175
1176 Convolution3dDescriptor desc;
1177 desc.m_BiasEnabled = false;
1178 desc.m_DataLayout = armnn::DataLayout::NDHWC;
1179 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1180 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1181 desc.m_StrideZ = CHECKED_NON_NEGATIVE(options->stride_d);
1182 desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
1183 desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
1184 desc.m_DilationZ = CHECKED_NON_NEGATIVE(options->dilation_d_factor);
1185
1186 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1187 CHECK_VALID_SIZE(inputs.size(), 2, 3);
1188
1189 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1190 CHECK_VALID_SIZE(outputs.size(), 1);
1191
1192 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
1193 armnn::TensorInfo filterTensorInfo = ToTensorInfo(inputs[1]);
1194
1195 // Assuming input is NDHWC
1196 unsigned int inputDepth = inputTensorInfo.GetShape()[1];
1197 unsigned int inputHeight = inputTensorInfo.GetShape()[2];
1198 unsigned int inputWidth = inputTensorInfo.GetShape()[3];
1199
1200 // Assuming the filter is DHWIO : Depth, Height, Width, OutputChannels, InputChannels
1201 unsigned int filterDepth = filterTensorInfo.GetShape()[0];
1202 unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1203 unsigned int filterWidth = filterTensorInfo.GetShape()[2];
1204
1205 CalcPadding(inputDepth, filterDepth, desc.m_StrideZ,
Teresa Charlin502ab942022-03-23 17:23:07 +00001206 desc.m_DilationZ, desc.m_PadFront, desc.m_PadBack, options->padding);
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001207 CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
1208 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
1209 CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
1210 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
1211
Mike Kelly5880b912022-01-28 16:18:54 +00001212 auto filterTensorAndData = CreateConstTensorNonPermuted(inputs[1], filterTensorInfo, inputTensorInfo.GetDataType());
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001213
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001214 auto layerName = fmt::format("Conv3D:{}:{}", subgraphIndex, operatorIndex);
1215
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001216 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1217 // Add the first input and weights tensor to the registration list.
1218 // The constant weights will be added by SetupConstantLayers.
1219 std::vector<unsigned int> tensorIndexesToRegister = {inputTensorIndexes[0], inputTensorIndexes[1]};
1220
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001221 if (inputs.size() == 3)
1222 {
1223 desc.m_BiasEnabled = true;
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001224
1225 // Add the biases input to the registration list, a constant layer will be added by SetupConstantLayers.
1226 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001227 }
1228
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001229 armnn::IConnectableLayer* layer = m_Network->AddConvolution3dLayer(desc, layerName.c_str());
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001230 ARMNN_ASSERT(layer != nullptr);
1231
1232 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1233 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1234
1235 // Register the input connection slots for the layer, connections are made after all layers have been created
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001236 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister);
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001237
1238 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
1239 // Register the output connection slots for the layer, connections are made after all layers have been created
1240 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1241 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1242}
Matthew Sloyan4d217c02021-10-07 11:48:58 +01001243#endif
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001244
Kevin May7d96b162021-02-03 17:38:41 +00001245void TfLiteParserImpl::ParseDepthwiseConv2D(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001246{
1247 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1248
Mike Kelly0d77ae12022-01-07 17:42:27 +00001249 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1250 const auto* options = operatorPtr->builtin_options.AsDepthwiseConv2DOptions();
telsoa01c577f2c2018-08-31 09:22:23 +01001251
1252 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1253
1254 DepthwiseConvolution2dDescriptor desc;
telsoa01c577f2c2018-08-31 09:22:23 +01001255 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1256 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
jimfly01c25411c2018-11-14 17:47:22 +00001257 desc.m_DataLayout = armnn::DataLayout::NHWC;
Matthew Jacksond6a9dee2019-07-22 13:53:24 +01001258 CHECKED_NON_NEGATIVE(options->depth_multiplier);
telsoa01c577f2c2018-08-31 09:22:23 +01001259
1260 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1261 CHECK_VALID_SIZE(inputs.size(), 2, 3);
Cathal Corbett06902652022-04-14 17:55:11 +01001262 if (inputs.size() == 3)
1263 {
1264 desc.m_BiasEnabled = true;
1265 }
1266
telsoa01c577f2c2018-08-31 09:22:23 +01001267 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1268 CHECK_VALID_SIZE(outputs.size(), 1);
Pablo Tellof0bd6832019-04-26 17:58:13 +01001269 desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
1270 desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
Kevin May83add212019-03-26 11:39:19 +00001271
telsoa01c577f2c2018-08-31 09:22:23 +01001272 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
Jan Eilers7612bd62021-04-06 17:29:03 +01001273 armnn::TensorInfo filterTensorInfo = ToTensorInfo(inputs[1]);
telsoa01c577f2c2018-08-31 09:22:23 +01001274
Matteo Martincigh747ef822018-12-18 09:26:39 +00001275 // Assuming input is NHWC
telsoa01c577f2c2018-08-31 09:22:23 +01001276 unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1277 unsigned int inputWidth = inputTensorInfo.GetShape()[2];
Matteo Martincigh747ef822018-12-18 09:26:39 +00001278
1279 // TensorflowLite weights come in the format [1, H, W, I * M]
telsoa01c577f2c2018-08-31 09:22:23 +01001280 unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1281 unsigned int filterWidth = filterTensorInfo.GetShape()[2];
1282
Pablo Tellof0bd6832019-04-26 17:58:13 +01001283 CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
1284 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
1285 CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
1286 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
telsoa01c577f2c2018-08-31 09:22:23 +01001287
Jan Eilers53ef7952021-06-02 12:01:25 +01001288 // ArmNN uses the same filter tensor layout at TfLite [1, H, W, O] no need for any permutation
James Ward58dec6b2020-09-11 17:32:44 +01001289 auto layerName = fmt::format("DepthwiseConv2D:{}:{}", subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001290
Cathal Corbett06902652022-04-14 17:55:11 +01001291 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1292 // Add the first input and weights tensor to the registration list.
1293 // The constant weights will be added by SetupConstantLayers.
1294 std::vector<unsigned int> tensorIndexesToRegister = {inputTensorIndexes[0], inputTensorIndexes[1]};
1295
1296 armnn::IConnectableLayer* layer = m_Network->AddDepthwiseConvolution2dLayer(desc, layerName.c_str());
1297
1298 if (desc.m_BiasEnabled)
telsoa01c577f2c2018-08-31 09:22:23 +01001299 {
1300 desc.m_BiasEnabled = true;
1301 TensorInfo biasTensorInfo = ToTensorInfo(inputs[2]);
Cathal Corbett06902652022-04-14 17:55:11 +01001302
1303 // Add the biases input to the registration list, a constant layer will be added by SetupConstantLayers.
1304 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
telsoa01c577f2c2018-08-31 09:22:23 +01001305 }
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001306 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01001307
Sadik Armagand109a4d2020-07-28 10:42:13 +01001308 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
jimfly01c25411c2018-11-14 17:47:22 +00001309 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +01001310
1311 // register the input connection slots for the layer, connections are made after all layers have been created
1312 // only the tensors for the inputs are relevant, exclude the const tensors
Cathal Corbett06902652022-04-14 17:55:11 +01001313 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister);
telsoa01c577f2c2018-08-31 09:22:23 +01001314
jimfly01c25411c2018-11-14 17:47:22 +00001315 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
telsoa01c577f2c2018-08-31 09:22:23 +01001316 // register the output connection slots for the layer, connections are made after all layers have been created
1317 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1318 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1319}
1320
Kevin May7d96b162021-02-03 17:38:41 +00001321void TfLiteParserImpl::ParseDequantize(size_t subgraphIndex, size_t operatorIndex)
Finn Williamsed66d142019-12-06 09:55:55 +00001322{
1323 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1324
1325 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1326 CHECK_VALID_SIZE(inputs.size(), 1);
1327
1328 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1329 CHECK_VALID_SIZE(outputs.size(), 1);
1330
James Ward58dec6b2020-09-11 17:32:44 +01001331 auto layerName = fmt::format("Dequantize:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsed66d142019-12-06 09:55:55 +00001332
1333 IConnectableLayer* layer = m_Network->AddDequantizeLayer(layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001334 ARMNN_ASSERT(layer != nullptr);
Finn Williamsed66d142019-12-06 09:55:55 +00001335
Sadik Armagand109a4d2020-07-28 10:42:13 +01001336 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Finn Williamsed66d142019-12-06 09:55:55 +00001337 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1338
1339 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1340 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1341
1342 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1343 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
1344}
1345
Teresa Charlin3ab85482021-06-08 16:59:29 +01001346void TfLiteParserImpl::ParseExpandDims(size_t subgraphIndex, size_t operatorIndex)
1347{
1348 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1349
1350 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1351 CHECK_VALID_SIZE(inputs.size(), 2);
1352
1353 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1354 CHECK_VALID_SIZE(outputs.size(), 1);
1355
1356 auto layerName = fmt::format("ExpandDims:{}:{}", subgraphIndex, operatorIndex);
1357
1358 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
1359 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1360
1361 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1362
1363 ReshapeDescriptor reshapeDesc;
Finn Williamsb49ed182021-06-29 15:50:08 +01001364
1365 if (outputTensorInfo.GetShape().AreAllDimensionsSpecified())
1366 {
1367 reshapeDesc.m_TargetShape = outputTensorInfo.GetShape();
1368 }
1369 else
1370 {
1371 int32_t axis = inputs[1]->shape[0];
1372
1373 int32_t inputDimSize = static_cast<int32_t>(inputTensorInfo.GetShape().GetNumDimensions());
1374
1375 if (axis > inputDimSize || axis < 0 - (inputDimSize + 1))
1376 {
1377 throw ParseException("axis must be in range [0 - (inputDimSize + 1), inputDimSize] inclusive");
1378 }
1379
1380 if(axis < 0)
1381 {
1382 axis = inputDimSize + axis + 1;
1383 }
1384
Rob Hughesd812a312021-08-06 13:10:53 +01001385 std::vector<unsigned int> shape(static_cast<unsigned int>(inputDimSize) + 1);
Finn Williamsb49ed182021-06-29 15:50:08 +01001386 unsigned int inputShapeIndex = 0;
1387 for (unsigned int i = 0; i < static_cast<unsigned int>(inputDimSize + 1); ++i)
1388 {
1389 if (i == static_cast<unsigned int>(axis))
1390 {
1391 shape[i] = 1;
1392 }
1393 else
1394 {
1395 shape[i] = inputTensorInfo.GetShape()[inputShapeIndex];
1396 ++inputShapeIndex;
1397 }
1398 }
1399
Rob Hughesd812a312021-08-06 13:10:53 +01001400 reshapeDesc.m_TargetShape = TensorShape(static_cast<unsigned int>(inputDimSize + 1), shape.data());
Finn Williamsb49ed182021-06-29 15:50:08 +01001401 }
Teresa Charlin3ab85482021-06-08 16:59:29 +01001402
1403 IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
1404 ARMNN_ASSERT(layer != nullptr);
1405 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1406
1407 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1408 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1409
1410 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1411 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1412}
1413
Kevin May7d96b162021-02-03 17:38:41 +00001414void TfLiteParserImpl::ParseTranspose(size_t subgraphIndex, size_t operatorIndex)
Keith Davis4cd29a02019-09-09 14:49:20 +01001415{
1416 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1417
1418 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Kevin May85d92602019-09-27 17:21:06 +01001419 CHECK_VALID_SIZE(inputs.size(), 1, 2);
Keith Davis4cd29a02019-09-09 14:49:20 +01001420
1421 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1422 CHECK_VALID_SIZE(outputs.size(), 1);
1423
James Ward58dec6b2020-09-11 17:32:44 +01001424 auto layerName = fmt::format("Transpose:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly08759e22020-03-02 11:41:31 +00001425 TransposeDescriptor desc;
Keith Davis4cd29a02019-09-09 14:49:20 +01001426
josh minorba424d22019-11-13 10:55:17 -06001427 if (inputs.size() == 2)
Kevin May85d92602019-09-27 17:21:06 +01001428 {
1429 armnn::TensorInfo permuteTensorInfo = ToTensorInfo(inputs[1]);
1430 BufferRawPtr permuteBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
josh minorba424d22019-11-13 10:55:17 -06001431 auto numPermVecElements = permuteTensorInfo.GetNumElements();
1432 std::vector<unsigned int> permuteShape(numPermVecElements);
Kevin May85d92602019-09-27 17:21:06 +01001433 ::memcpy(permuteShape.data(), permuteBufferPtr->data.data(), permuteTensorInfo.GetNumBytes());
Mike Kelly08759e22020-03-02 11:41:31 +00001434 PermutationVector permutationVector(permuteShape.data(), permuteTensorInfo.GetNumElements());
Kevin May85d92602019-09-27 17:21:06 +01001435
Mike Kelly08759e22020-03-02 11:41:31 +00001436 desc = TransposeDescriptor(permutationVector);
Kevin May85d92602019-09-27 17:21:06 +01001437 }
1438
James Conroy05102392020-06-24 15:39:55 +01001439 TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
Sadik Armagand109a4d2020-07-28 10:42:13 +01001440 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01001441 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Keith Davis4cd29a02019-09-09 14:49:20 +01001442
James Conroy05102392020-06-24 15:39:55 +01001443 IConnectableLayer* layer = m_Network->AddTransposeLayer(desc, layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001444 ARMNN_ASSERT(layer != nullptr);
Keith Davis4cd29a02019-09-09 14:49:20 +01001445 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1446
1447 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1448 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1449
1450 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1451 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1452}
1453
Kevin May7d96b162021-02-03 17:38:41 +00001454void TfLiteParserImpl::ParseTransposeConv(size_t subgraphIndex, size_t operatorIndex)
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001455{
1456 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1457
Mike Kelly0d77ae12022-01-07 17:42:27 +00001458 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1459 const auto* options = operatorPtr->builtin_options.AsTransposeConvOptions();
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001460
1461 TransposeConvolution2dDescriptor desc;
1462 desc.m_BiasEnabled = false;
1463 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1464 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1465 desc.m_DataLayout = armnn::DataLayout::NHWC;
1466
1467 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
David Monahan61683802021-01-12 09:11:07 +00001468 if (inputs.size() == 4)
1469 {
1470 desc.m_BiasEnabled = true;
1471 }
1472 else
1473 {
1474 CHECK_VALID_SIZE(inputs.size(), 3);
1475 }
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001476
1477 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1478 CHECK_VALID_SIZE(outputs.size(), 1);
1479
Colm Donelan0ad3ef12020-07-03 15:54:28 +01001480 if (inputs[0])
1481 {
1482 armnn::TensorInfo tensorInfo = ToTensorInfo(inputs[0]);
1483 std::vector<int> output_shape(tensorInfo.GetNumElements());
1484 if (tensorInfo.GetDataType() == DataType::Signed32)
1485 {
1486 ::memcpy(output_shape.data(), GetBuffer(m_Model, inputs[0]->buffer)->data.data(), tensorInfo.GetNumBytes());
1487 }
1488 if (tensorInfo.GetDataType() == DataType::QAsymmU8)
1489 {
1490 for(unsigned int i=0; i < tensorInfo.GetNumElements(); i++)
1491 {
1492 output_shape[i] = GetBuffer(m_Model, inputs[0]->buffer)->data.data()[i];
1493 }
1494 }
1495 // Change from signed to unsigned int to store in TransposeConvolution2dDescriptor.
1496 for (int dimension : output_shape)
1497 {
1498 desc.m_OutputShape.push_back(static_cast<unsigned int>(dimension));
1499 }
1500 desc.m_OutputShapeEnabled = true;
1501 }
Matthew Jacksonccb25ea2019-08-20 17:18:33 +01001502 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[2]);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001503 armnn::TensorInfo filterTensorInfo = ToTensorInfo(inputs[1]);
1504
1505 // TfLite uses NHWC tensors
1506 const unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1507 const unsigned int inputWidth = inputTensorInfo.GetShape()[2];
1508
1509 const unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1510 const unsigned int filterWidth = filterTensorInfo.GetShape()[2];
1511
1512 CalcPadding(inputHeight,
1513 filterHeight,
1514 desc.m_StrideY,
1515 1, // DilationY
1516 desc.m_PadTop,
1517 desc.m_PadBottom,
1518 options->padding);
1519
1520 CalcPadding(inputWidth,
1521 filterWidth,
1522 desc.m_StrideX,
1523 1, // DilationX
1524 desc.m_PadLeft,
1525 desc.m_PadRight,
1526 options->padding);
1527
Mike Kelly5880b912022-01-28 16:18:54 +00001528 auto filterTensorAndData = CreateConstTensorNonPermuted(inputs[1], filterTensorInfo, inputTensorInfo.GetDataType());
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001529
1530 armnn::IConnectableLayer* layer = nullptr;
James Ward58dec6b2020-09-11 17:32:44 +01001531 auto layerName = fmt::format("TransposeConv:{}:{}", subgraphIndex, operatorIndex);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001532
David Monahan61683802021-01-12 09:11:07 +00001533 if (desc.m_BiasEnabled)
1534 {
1535 auto biasTensorInfo = ToTensorInfo(inputs[3]);
Mike Kelly5880b912022-01-28 16:18:54 +00001536 auto biasConstTensor = CreateConstTensorNonPermuted(inputs[3], biasTensorInfo, inputTensorInfo.GetDataType());
David Monahan61683802021-01-12 09:11:07 +00001537 layer = m_Network->AddTransposeConvolution2dLayer(desc,
Mike Kelly5880b912022-01-28 16:18:54 +00001538 filterTensorAndData.first,
1539 biasConstTensor.first,
David Monahan61683802021-01-12 09:11:07 +00001540 layerName.c_str());
1541 }
1542 else
1543 {
1544 layer = m_Network->AddTransposeConvolution2dLayer(desc,
Mike Kelly5880b912022-01-28 16:18:54 +00001545 filterTensorAndData.first,
David Monahan61683802021-01-12 09:11:07 +00001546 EmptyOptional(),
1547 layerName.c_str());
1548 }
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001549
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001550 ARMNN_ASSERT(layer != nullptr);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001551
Sadik Armagand109a4d2020-07-28 10:42:13 +01001552 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001553 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1554
1555 // only the tensors for the inputs are relevant, exclude the const (filter) tensor
1556 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Matthew Jacksonccb25ea2019-08-20 17:18:33 +01001557 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[2]});
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001558
1559 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1560 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1561}
1562
Kevin May7d96b162021-02-03 17:38:41 +00001563void TfLiteParserImpl::ParseAveragePool2D(size_t subgraphIndex, size_t operatorIndex)
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001564{
1565 ParsePool(subgraphIndex, operatorIndex, PoolingAlgorithm::Average);
1566}
1567
Kevin May7d96b162021-02-03 17:38:41 +00001568void TfLiteParserImpl::ParseBatchToSpaceND(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001569{
1570 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1571
1572 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1573 CHECK_VALID_SIZE(inputs.size(), 3);
1574
1575 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1576 CHECK_VALID_SIZE(outputs.size(), 1);
1577
1578 armnn::TensorInfo blockShapeTensorInfo = ToTensorInfo(inputs[1]);
1579 BufferRawPtr blockShapeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1580
1581 armnn::TensorInfo cropsTensorInfo = ToTensorInfo(inputs[2]);
1582 BufferRawPtr cropsBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
1583
1584 std::vector<unsigned int> blockShape(blockShapeTensorInfo.GetNumElements());
1585 ::memcpy(blockShape.data(), blockShapeBufferPtr->data.data(), blockShapeTensorInfo.GetNumBytes());
1586
1587 std::vector<unsigned int> cropsVector(cropsTensorInfo.GetNumElements());
1588 ::memcpy(cropsVector.data(), cropsBufferPtr->data.data(), cropsTensorInfo.GetNumBytes());
1589
1590 size_t step = 2;
1591 std::vector<std::pair<unsigned int, unsigned int>> crops;
1592 for (unsigned int i = 0; i < cropsTensorInfo.GetNumElements() / step; ++i)
1593 {
1594 crops.emplace_back(cropsVector[i * step], cropsVector[i * step + 1]);
1595 }
1596
1597 armnn::BatchToSpaceNdDescriptor desc;
1598 desc.m_BlockShape = blockShape;
1599 desc.m_Crops = crops;
1600 desc.m_DataLayout = armnn::DataLayout::NHWC;
1601
James Ward58dec6b2020-09-11 17:32:44 +01001602 auto layerName = fmt::format("BatchToSpaceND:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001603
James Conroy05102392020-06-24 15:39:55 +01001604 TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
Sadik Armagand109a4d2020-07-28 10:42:13 +01001605 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01001606 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1607
1608 IConnectableLayer* layer = m_Network->AddBatchToSpaceNdLayer(desc, layerName.c_str());
1609 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001610 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1611
1612 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1613 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1614
1615 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1616 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1617}
1618
Kevin May7d96b162021-02-03 17:38:41 +00001619void TfLiteParserImpl::ParseL2Normalization(size_t subgraphIndex, size_t operatorIndex)
Matthew Jackson28c94572019-07-18 10:47:03 +01001620{
1621 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1622
1623 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1624 CHECK_VALID_SIZE(inputs.size(), 1);
1625
1626 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1627 CHECK_VALID_SIZE(outputs.size(), 1);
1628
1629 L2NormalizationDescriptor desc;
1630 desc.m_DataLayout = armnn::DataLayout::NHWC;
James Ward58dec6b2020-09-11 17:32:44 +01001631 auto layerName = fmt::format("L2Normalization:{}:{}", subgraphIndex, operatorIndex);
Matthew Jackson28c94572019-07-18 10:47:03 +01001632 IConnectableLayer* layer = m_Network->AddL2NormalizationLayer(desc, layerName.c_str());
1633
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001634 ARMNN_ASSERT(layer != nullptr);
Matthew Jackson28c94572019-07-18 10:47:03 +01001635
Sadik Armagand109a4d2020-07-28 10:42:13 +01001636 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Matthew Jackson28c94572019-07-18 10:47:03 +01001637 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1638
1639 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1640 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1641
1642 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1643 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1644}
1645
Kevin May7d96b162021-02-03 17:38:41 +00001646void TfLiteParserImpl::ParseMaxPool2D(size_t subgraphIndex, size_t operatorIndex)
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001647{
1648 ParsePool(subgraphIndex, operatorIndex, PoolingAlgorithm::Max);
1649}
1650
Kevin May7d96b162021-02-03 17:38:41 +00001651void TfLiteParserImpl::ParseMaximum(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001652{
1653 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1654
1655 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1656 CHECK_VALID_SIZE(inputs.size(), 2);
1657
1658 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1659 CHECK_VALID_SIZE(outputs.size(), 1);
1660
James Ward58dec6b2020-09-11 17:32:44 +01001661 auto layerName = fmt::format("Maximum:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01001662
1663 TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
1664 TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]);
1665 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001666
Sadik Armagand109a4d2020-07-28 10:42:13 +01001667 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01001668 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1669
1670 IConnectableLayer* layer = m_Network->AddMaximumLayer(layerName.c_str());
1671 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001672 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1673
1674 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01001675 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001676
1677 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1678 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1679}
1680
Kevin May7d96b162021-02-03 17:38:41 +00001681void TfLiteParserImpl::ParseMinimum(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001682{
1683 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1684
1685 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1686 CHECK_VALID_SIZE(inputs.size(), 2);
1687
1688 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1689 CHECK_VALID_SIZE(outputs.size(), 1);
1690
James Ward58dec6b2020-09-11 17:32:44 +01001691 auto layerName = fmt::format("Minimum:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01001692
1693 TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
1694 TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]);
1695 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001696
Sadik Armagand109a4d2020-07-28 10:42:13 +01001697 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01001698 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1699
1700 IConnectableLayer* layer = m_Network->AddMinimumLayer(layerName.c_str());
1701 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001702 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1703
1704 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01001705 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001706
1707 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1708 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1709}
1710
Kevin May7d96b162021-02-03 17:38:41 +00001711void TfLiteParserImpl::ParsePool(size_t subgraphIndex,
1712 size_t operatorIndex,
1713 PoolingAlgorithm algorithm)
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001714{
1715 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1716
Mike Kelly0d77ae12022-01-07 17:42:27 +00001717 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1718 const auto* options = operatorPtr->builtin_options.AsPool2DOptions();
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001719
1720 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1721
1722 std::string layerName;
1723
1724 switch (algorithm)
1725 {
1726 case PoolingAlgorithm::Average:
1727 layerName =
James Ward58dec6b2020-09-11 17:32:44 +01001728 fmt::format("AveragePool2D:{}:{}", subgraphIndex, operatorIndex);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001729 break;
1730 case PoolingAlgorithm::Max:
1731 layerName =
James Ward58dec6b2020-09-11 17:32:44 +01001732 fmt::format("MaxPool2D:{}:{}", subgraphIndex, operatorIndex);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001733 break;
1734 default:
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001735 ARMNN_ASSERT_MSG(false, "Unsupported Pooling Algorithm");
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001736 }
1737
1738 Pooling2dDescriptor desc;
1739
1740 desc.m_PoolType = algorithm;
1741 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1742 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1743 desc.m_PoolWidth = CHECKED_NON_NEGATIVE(options->filter_width);
1744 desc.m_PoolHeight = CHECKED_NON_NEGATIVE(options->filter_height);
1745 desc.m_PaddingMethod = PaddingMethod::Exclude;
1746 desc.m_OutputShapeRounding = OutputShapeRounding::Floor;
jimfly01c25411c2018-11-14 17:47:22 +00001747 desc.m_DataLayout = armnn::DataLayout::NHWC;
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001748
1749 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1750 CHECK_VALID_SIZE(inputs.size(), 1);
1751 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
1752
1753 // assuming input is NHWC
1754 unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1755 unsigned int inputWidth = inputTensorInfo.GetShape()[2];
1756
Pablo Tellof0bd6832019-04-26 17:58:13 +01001757 CalcPadding(inputHeight, desc.m_PoolHeight, desc.m_StrideY, 1u,
1758 desc.m_PadTop, desc.m_PadBottom, options->padding);
1759 CalcPadding(inputWidth, desc.m_PoolWidth, desc.m_StrideX, 1u,
1760 desc.m_PadLeft, desc.m_PadRight, options->padding);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001761
1762 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1763 CHECK_VALID_SIZE(outputs.size(), 1);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001764
Sadik Armagand109a4d2020-07-28 10:42:13 +01001765 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01001766 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1767
1768 IConnectableLayer* layer = m_Network->AddPooling2dLayer(desc, layerName.c_str());
1769 ARMNN_ASSERT(layer != nullptr);
jimfly01c25411c2018-11-14 17:47:22 +00001770 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001771
1772 // register the input connection slots for the layer, connections are made after all layers have been created
1773 // only the tensors for the inputs are relevant, exclude the const tensors
1774 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
jimfly01c25411c2018-11-14 17:47:22 +00001775 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001776
jimfly01c25411c2018-11-14 17:47:22 +00001777 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001778 // register the output connection slots for the layer, connections are made after all layers have been created
1779 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1780 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1781}
1782
Kevin May7d96b162021-02-03 17:38:41 +00001783void TfLiteParserImpl::ParseSlice(size_t subgraphIndex, size_t operatorIndex)
josh minorba424d22019-11-13 10:55:17 -06001784{
1785 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1786
1787 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1788 CHECK_VALID_SIZE(inputs.size(), 3);
1789 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1790 CHECK_VALID_SIZE(outputs.size(), 1);
1791
1792 SliceDescriptor desc;
1793
1794 // set begin tensor info for slice descriptor
1795 armnn::TensorInfo beginTensorInfo = ToTensorInfo(inputs[1]);
1796 BufferRawPtr beginBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1797
1798 std::vector<unsigned int> begin(beginTensorInfo.GetNumElements());
1799 ::memcpy(begin.data(), beginBufferPtr->data.data(), beginTensorInfo.GetNumBytes());
1800
1801 // set size tensor info for slice descriptor
1802 armnn::TensorInfo sizeTensorInfo = ToTensorInfo(inputs[2]);
1803 BufferRawPtr sizeBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
1804
Mike Kelly7ba84d62021-09-10 15:27:19 +01001805 std::vector<int> signedSize(sizeTensorInfo.GetNumElements());
1806 ::memcpy(signedSize.data(), sizeBufferPtr->data.data(), sizeTensorInfo.GetNumBytes());
josh minorba424d22019-11-13 10:55:17 -06001807 std::vector<unsigned int> size(sizeTensorInfo.GetNumElements());
Mike Kelly7ba84d62021-09-10 15:27:19 +01001808 TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
1809
1810 for (unsigned int i = 0; i < signedSize.size(); ++i)
1811 {
1812 int signedValue = signedSize[i];
Jim Flynnfca233e2021-09-23 12:16:53 +01001813
Mike Kelly7ba84d62021-09-10 15:27:19 +01001814 if (signedValue < -1 || signedValue > static_cast<int>(inputTensorInfo.GetShape()[i] - begin[i]))
1815 {
1816 throw ParseException(fmt::format("Invalid value for size {} size must be in range "
1817 "[-1, inputDimSize - begin] [-1, {}] inclusive {}",
1818 signedValue,
1819 inputTensorInfo.GetShape()[i] - begin[i],
1820 CHECK_LOCATION().AsString()));
1821 }
1822
1823 if (signedValue == -1)
1824 {
1825 size[i] = inputTensorInfo.GetShape()[i] - begin[i];
1826 }
1827 else
1828 {
1829 size[i] = static_cast<unsigned int>(signedValue);
1830 }
1831 }
1832
josh minorba424d22019-11-13 10:55:17 -06001833 desc = SliceDescriptor(begin, size);
1834
James Ward58dec6b2020-09-11 17:32:44 +01001835 auto layerName = fmt::format("Slice:{}:{}", subgraphIndex, operatorIndex);
josh minorba424d22019-11-13 10:55:17 -06001836
Sadik Armagand109a4d2020-07-28 10:42:13 +01001837 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01001838 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1839
1840 IConnectableLayer* const layer = m_Network->AddSliceLayer(desc, layerName.c_str());
josh minorba424d22019-11-13 10:55:17 -06001841 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1842
1843 // register the input connection slots for the layer, connections are made after all layers have been created
1844 // only the tensors for the inputs are relevant, exclude the const tensors
1845 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1846 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1847
1848 // register the output connection slots for the layer, connections are made after all layers have been created
1849 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1850 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1851}
1852
Kevin May7d96b162021-02-03 17:38:41 +00001853void TfLiteParserImpl::ParseSoftmax(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001854{
1855 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00001856 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1857 const auto* options = operatorPtr->builtin_options.AsSoftmaxOptions();
telsoa01c577f2c2018-08-31 09:22:23 +01001858
1859 SoftmaxDescriptor desc;
1860 desc.m_Beta = options->beta;
1861
1862 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1863 CHECK_VALID_SIZE(inputs.size(), 1);
1864 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1865 CHECK_VALID_SIZE(outputs.size(), 1);
1866
James Ward58dec6b2020-09-11 17:32:44 +01001867 auto layerName = fmt::format("Softmax:{}:{}", subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001868 IConnectableLayer* const layer = m_Network->AddSoftmaxLayer(desc, layerName.c_str());
1869
Sadik Armagand109a4d2020-07-28 10:42:13 +01001870 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
telsoa01c577f2c2018-08-31 09:22:23 +01001871 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1872
1873 // register the input connection slots for the layer, connections are made after all layers have been created
1874 // only the tensors for the inputs are relevant, exclude the const tensors
1875 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1876 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1877
1878 // register the output connection slots for the layer, connections are made after all layers have been created
1879 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1880 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1881}
1882
Teresa Charlin455172a2022-06-29 15:35:57 +01001883void TfLiteParserImpl::ParseLogSoftmax(size_t subgraphIndex, size_t operatorIndex)
1884{
1885 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1886
1887 LogSoftmaxDescriptor desc;
1888
1889 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1890 CHECK_VALID_SIZE(inputs.size(), 1);
1891 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1892 CHECK_VALID_SIZE(outputs.size(), 1);
1893
1894 auto layerName = fmt::format("LogSoftmax:{}:{}", subgraphIndex, operatorIndex);
1895 IConnectableLayer* const layer = m_Network->AddLogSoftmaxLayer(desc, layerName.c_str());
1896
1897 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1898 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1899
1900 // register the input connection slots for the layer, connections are made after all layers have been created
1901 // only the tensors for the inputs are relevant, exclude the const tensors
1902 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1903 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1904
1905 // register the output connection slots for the layer, connections are made after all layers have been created
1906 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1907 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1908}
1909
Kevin May7d96b162021-02-03 17:38:41 +00001910void TfLiteParserImpl::ParseSpaceToBatchND(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesbaded142019-02-08 19:02:48 -02001911{
1912 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1913
1914 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1915 CHECK_VALID_SIZE(inputs.size(), 3);
1916
1917 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1918 CHECK_VALID_SIZE(outputs.size(), 1);
1919
1920 armnn::TensorInfo blockShapeTensorInfo = ToTensorInfo(inputs[1]);
1921 BufferRawPtr blockShapeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1922
1923 armnn::TensorInfo padListTensorInfo = ToTensorInfo(inputs[2]);
1924 BufferRawPtr padListBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
1925
1926 std::vector<unsigned int> blockShape(blockShapeTensorInfo.GetNumElements());
1927 ::memcpy(blockShape.data(), blockShapeBufferPtr->data.data(), blockShapeTensorInfo.GetNumBytes());
1928
1929 std::vector<unsigned int> padListVector(padListTensorInfo.GetNumElements());
1930 ::memcpy(padListVector.data(), padListBufferPtr->data.data(), padListTensorInfo.GetNumBytes());
1931
1932 size_t step = 2;
1933 std::vector<std::pair<unsigned int, unsigned int>> padList;
1934 for (unsigned int i = 0; i < padListTensorInfo.GetNumElements() / step; ++i)
1935 {
1936 padList.emplace_back(padListVector[i * step], padListVector[i * step + 1]);
1937 }
1938
1939 armnn::SpaceToBatchNdDescriptor desc;
1940 desc.m_BlockShape = blockShape;
1941 desc.m_PadList = padList;
1942 desc.m_DataLayout = armnn::DataLayout::NHWC;
1943
James Ward58dec6b2020-09-11 17:32:44 +01001944 auto layerName = fmt::format("SpaceToBatchND:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesbaded142019-02-08 19:02:48 -02001945
James Conroy05102392020-06-24 15:39:55 +01001946 TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
Sadik Armagand109a4d2020-07-28 10:42:13 +01001947 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01001948 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1949
1950 IConnectableLayer* layer = m_Network->AddSpaceToBatchNdLayer(desc, layerName.c_str());
1951 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesbaded142019-02-08 19:02:48 -02001952 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1953
1954 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1955 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1956
1957 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1958 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1959}
1960
Teresa Charlin3ab85482021-06-08 16:59:29 +01001961armnn::TensorInfo TfLiteParserImpl::OutputShapeOfSqueeze(std::vector<uint32_t> squeezeDims,
Mike Kelly0d77ae12022-01-07 17:42:27 +00001962 const armnn::TensorInfo& inputTensorInfo)
telsoa01c577f2c2018-08-31 09:22:23 +01001963{
Teresa Charlin3ab85482021-06-08 16:59:29 +01001964 CHECK_VALID_SIZE(squeezeDims.size(), 0, 1, 2, 3, 4);
telsoa01c577f2c2018-08-31 09:22:23 +01001965 static const uint32_t dimensionSequence[] = { 0, 1, 2, 3 };
1966
1967 if (inputTensorInfo.GetNumDimensions() > 4)
1968 {
1969 std::stringstream ss;
1970 ss << "Input tensor has unexpected number of dimensions:" << inputTensorInfo.GetNumDimensions()
1971 << " shape:" << inputTensorInfo.GetShape() << " "
1972 << CHECK_LOCATION().AsString();
1973 throw ParseException(ss.str());
1974 }
1975
1976 if (squeezeDims.empty())
1977 {
1978 squeezeDims.assign(dimensionSequence,
1979 dimensionSequence+inputTensorInfo.GetNumDimensions());
1980 }
1981
1982 std::vector<uint32_t> outputDims;
1983 for(unsigned int i = 0; i < inputTensorInfo.GetNumDimensions(); i++)
1984 {
1985 bool skipSqueeze = (std::find(squeezeDims.begin(), squeezeDims.end(), i) == squeezeDims.end());
1986 auto currentDimension = inputTensorInfo.GetShape()[i];
1987 if (skipSqueeze || currentDimension != 1)
1988 {
1989 outputDims.push_back(currentDimension);
1990 }
1991 }
1992
1993 if (outputDims.size() > 4)
1994 {
1995 std::stringstream ss;
1996 ss << "Output tensor has unexpected number of dimensions:" << inputTensorInfo.GetNumDimensions()
1997 << " shape:" << inputTensorInfo.GetShape() << " "
1998 << CHECK_LOCATION().AsString();
1999 throw ParseException(ss.str());
2000 }
2001
2002 TensorShape outShape = TensorShape(static_cast<unsigned int>(outputDims.size()),
2003 outputDims.data());
2004
2005 // we need to preserve the tensor type and the quantization data as well
2006 TensorInfo outTensorInfo = inputTensorInfo;
2007 outTensorInfo.SetShape(outShape);
2008
2009 return outTensorInfo;
2010}
2011
Keith Davis0176fd82021-06-01 17:36:32 +01002012void TfLiteParserImpl::ParseShape(size_t subgraphIndex, size_t operatorIndex)
2013{
2014 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2015
2016 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2017 CHECK_VALID_SIZE(inputs.size(), 1);
2018 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2019 CHECK_VALID_SIZE(outputs.size(), 1);
2020
2021 auto layerName = fmt::format("Shape:{}:{}", subgraphIndex, operatorIndex);
2022
2023 IConnectableLayer* layer = m_Network->AddShapeLayer(layerName.c_str());
2024 ARMNN_ASSERT(layer != nullptr);
2025
2026
2027 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
2028 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2029
2030 // Check if output tensor type is Signed32 or Signed64
2031 if (outputTensorInfo.GetDataType() != armnn::DataType::Signed32 &&
2032 outputTensorInfo.GetDataType() != armnn::DataType::Signed64)
2033 {
2034 throw ParseException(
2035 fmt::format(
2036 "Output tensor data type is not supported. (Supported types: Signed32 & Signed64) {}",
2037 CHECK_LOCATION().AsString()));
2038 }
2039
2040 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2041 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2042
2043 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2044 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2045}
2046
Kevin May7d96b162021-02-03 17:38:41 +00002047void TfLiteParserImpl::ParseSqueeze(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01002048{
2049 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2050
2051 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2052 CHECK_VALID_SIZE(inputs.size(), 1);
2053
2054 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2055 CHECK_VALID_SIZE(outputs.size(), 1);
2056
2057 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2058 const auto * options = operatorPtr->builtin_options.AsSqueezeOptions();
James Ward58dec6b2020-09-11 17:32:44 +01002059 auto layerName = fmt::format("Squeeze:{}:{}", subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01002060
2061 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
Teresa Charlin3ab85482021-06-08 16:59:29 +01002062
2063 std::vector<uint32_t> squeezeDim;
2064 // A single negative dim index is interpreted as a negative index in python
2065 // Meaning the index will be the shape size plus the negative index value
2066 if (options->squeeze_dims.size() == 1 && options->squeeze_dims[0] < 0)
2067 {
2068 int32_t dim = static_cast<int32_t>(inputTensorInfo.GetShape().GetNumDimensions()) + options->squeeze_dims[0];
2069 squeezeDim.push_back(static_cast<uint32_t>(dim));
2070 }
2071 else
2072 {
2073 squeezeDim = AsUnsignedVector(options->squeeze_dims);
2074 }
2075
2076 armnn::TensorInfo outputTensorInfo = TfLiteParserImpl::OutputShapeOfSqueeze(squeezeDim, inputTensorInfo);
2077
James Conroy05102392020-06-24 15:39:55 +01002078 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
telsoa01c577f2c2018-08-31 09:22:23 +01002079
2080 ReshapeDescriptor reshapeDesc;
2081 reshapeDesc.m_TargetShape = outputTensorInfo.GetShape();
2082
telsoa01c577f2c2018-08-31 09:22:23 +01002083 IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002084 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01002085 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2086
2087 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2088 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2089
2090 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2091 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2092}
2093
Kevin May7d96b162021-02-03 17:38:41 +00002094void TfLiteParserImpl::ParseStridedSlice(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002095{
2096 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2097
2098 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2099 CHECK_VALID_SIZE(inputs.size(), 4);
2100
2101 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2102 CHECK_VALID_SIZE(outputs.size(), 1);
2103
Mike Kelly0d77ae12022-01-07 17:42:27 +00002104 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2105 const auto* options = operatorPtr->builtin_options.AsStridedSliceOptions();
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002106
2107 StridedSliceDescriptor desc;
2108 desc.m_BeginMask = options->begin_mask;
2109 desc.m_EllipsisMask = options->ellipsis_mask;
2110 desc.m_EndMask = options->end_mask;
2111 desc.m_NewAxisMask = options->new_axis_mask;
2112 desc.m_ShrinkAxisMask = options->shrink_axis_mask;
2113 desc.m_DataLayout = armnn::DataLayout::NHWC;
2114
2115 armnn::TensorInfo beginTensorInfo = ToTensorInfo(inputs[1]);
2116 BufferRawPtr beginBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2117
2118 std::vector<int> begin(beginTensorInfo.GetNumElements());
2119 ::memcpy(begin.data(), beginBufferPtr->data.data(), beginTensorInfo.GetNumBytes());
2120
2121 armnn::TensorInfo endTensorInfo = ToTensorInfo(inputs[2]);
2122 BufferRawPtr endBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
2123
2124 std::vector<int> end(endTensorInfo.GetNumElements());
2125 ::memcpy(end.data(), endBufferPtr->data.data(), endTensorInfo.GetNumBytes());
2126
2127 armnn::TensorInfo strideTensorInfo = ToTensorInfo(inputs[3]);
2128 BufferRawPtr strideBufferPtr = GetBuffer(m_Model, inputs[3]->buffer);
2129
2130 std::vector<int> stride(strideTensorInfo.GetNumElements());
2131 ::memcpy(stride.data(), strideBufferPtr->data.data(), strideTensorInfo.GetNumBytes());
2132
2133 desc.m_Begin = begin;
2134 desc.m_End = end;
2135 desc.m_Stride = stride;
2136
James Ward58dec6b2020-09-11 17:32:44 +01002137 auto layerName = fmt::format("StridedSlice:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002138 IConnectableLayer* layer = m_Network->AddStridedSliceLayer(desc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002139 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002140
Sadik Armagand109a4d2020-07-28 10:42:13 +01002141 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002142 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2143
2144 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2145 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2146
2147 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2148 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2149}
2150
Kevin May7d96b162021-02-03 17:38:41 +00002151void TfLiteParserImpl::ParseSub(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002152{
2153 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2154
Mike Kelly0d77ae12022-01-07 17:42:27 +00002155 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2156 const auto* options = operatorPtr->builtin_options.AsSubOptions();
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002157
2158 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2159 CHECK_VALID_SIZE(inputs.size(), 2);
2160
2161 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2162 CHECK_VALID_SIZE(outputs.size(), 1);
2163
2164 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
2165 armnn::TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]);
2166
James Ward58dec6b2020-09-11 17:32:44 +01002167 auto layerName = fmt::format("Sub:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002168 IConnectableLayer* layer = m_Network->AddSubtractionLayer(layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002169 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002170
Sadik Armagand109a4d2020-07-28 10:42:13 +01002171 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002172 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2173
2174 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002175 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002176
2177 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2178
2179 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2180 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2181}
2182
Kevin May7d96b162021-02-03 17:38:41 +00002183void TfLiteParserImpl::ParseDiv(size_t subgraphIndex, size_t operatorIndex)
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302184{
2185 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2186
Mike Kelly0d77ae12022-01-07 17:42:27 +00002187 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2188 const auto* options = operatorPtr->builtin_options.AsDivOptions();
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302189
2190 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2191 CHECK_VALID_SIZE(inputs.size(), 2);
2192
2193 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2194 CHECK_VALID_SIZE(outputs.size(), 1);
2195
2196 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
2197 armnn::TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]);
2198
James Ward58dec6b2020-09-11 17:32:44 +01002199 auto layerName = fmt::format("Div:{}:{}", subgraphIndex, operatorIndex);
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302200 IConnectableLayer* layer = m_Network->AddDivisionLayer(layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002201 ARMNN_ASSERT(layer != nullptr);
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302202
Sadik Armagand109a4d2020-07-28 10:42:13 +01002203 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302204 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2205
2206 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002207 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302208 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2209
2210 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2211 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2212}
2213
Teresa Charlincdbd40b2022-02-25 13:21:55 +00002214void TfLiteParserImpl::ParseFloorDiv(size_t subgraphIndex, size_t operatorIndex)
2215{
2216 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2217
2218 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2219 CHECK_VALID_SIZE(inputs.size(), 2);
2220
2221 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2222 CHECK_VALID_SIZE(outputs.size(), 1);
2223
2224 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
2225 armnn::TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]);
2226
2227 auto layerName = fmt::format("Div:{}:{}", subgraphIndex, operatorIndex);
2228 IConnectableLayer* layer = m_Network->AddDivisionLayer(layerName.c_str());
2229 ARMNN_ASSERT(layer != nullptr);
2230
2231 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
2232 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2233
2234 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2235 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
2236 layer = AddFusedFloorLayer(layer, 0);
2237
2238 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2239 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2240}
2241
Kevin May7d96b162021-02-03 17:38:41 +00002242void TfLiteParserImpl::ParseAdd(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002243{
2244 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2245
Mike Kelly0d77ae12022-01-07 17:42:27 +00002246 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2247 const auto* options = operatorPtr->builtin_options.AsAddOptions();
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002248
2249 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2250 CHECK_VALID_SIZE(inputs.size(), 2);
2251
2252 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2253 CHECK_VALID_SIZE(outputs.size(), 1);
2254
Bruno Goncalves9c761a62018-12-27 14:20:35 -02002255 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
2256 armnn::TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]);
2257
James Ward58dec6b2020-09-11 17:32:44 +01002258 auto layerName = fmt::format("Add:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002259 IConnectableLayer* layer = m_Network->AddAdditionLayer(layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002260 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002261
Sadik Armagand109a4d2020-07-28 10:42:13 +01002262 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002263 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2264
2265 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002266 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002267 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2268
2269 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2270 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2271}
2272
Kevin May7d96b162021-02-03 17:38:41 +00002273void TfLiteParserImpl::ParseMul(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002274{
2275 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2276
Mike Kelly0d77ae12022-01-07 17:42:27 +00002277 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2278 const auto* options = operatorPtr->builtin_options.AsMulOptions();
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002279
2280 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2281 CHECK_VALID_SIZE(inputs.size(), 2);
2282
2283 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2284 CHECK_VALID_SIZE(outputs.size(), 1);
2285
Bruno Goncalves9c761a62018-12-27 14:20:35 -02002286 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
2287 armnn::TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]);
2288
James Ward58dec6b2020-09-11 17:32:44 +01002289 auto layerName = fmt::format("Mul:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002290 IConnectableLayer* layer = m_Network->AddMultiplicationLayer(layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002291 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002292
Sadik Armagand109a4d2020-07-28 10:42:13 +01002293 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002294 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2295
2296 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002297 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002298 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2299
2300 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2301 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2302}
2303
Kevin May7d96b162021-02-03 17:38:41 +00002304void TfLiteParserImpl::ParseMean(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002305{
2306 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2307
2308 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2309
2310 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2311 CHECK_VALID_SIZE(outputs.size(), 1);
2312
2313 armnn::TensorInfo dimTensorInfo = ToTensorInfo(inputs[1]);
2314 BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2315
2316 armnn::MeanDescriptor desc;
2317 std::vector<unsigned int> axis(dimTensorInfo.GetNumElements());
2318 ::memcpy(axis.data(), bufferPtr->data.data(), dimTensorInfo.GetNumBytes());
2319 desc.m_Axis = axis;
2320
2321 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
Sadik Armagand109a4d2020-07-28 10:42:13 +01002322 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002323
2324 desc.m_KeepDims =
2325 inputTensorInfo.GetNumDimensions() == outputTensorInfo.GetNumDimensions() ?
2326 true : false;
2327
James Ward58dec6b2020-09-11 17:32:44 +01002328 auto layerName = fmt::format("Mean:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002329 IConnectableLayer* layer = m_Network->AddMeanLayer(desc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002330 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002331
2332 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2333
2334 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2335 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2336
2337 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2338 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2339}
2340
Kevin May7d96b162021-02-03 17:38:41 +00002341void TfLiteParserImpl::ParsePad(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002342{
2343 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2344
Kevin May7d96b162021-02-03 17:38:41 +00002345 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002346
Kevin May7d96b162021-02-03 17:38:41 +00002347 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002348 CHECK_VALID_SIZE(outputs.size(), 1);
2349
Narumol Prangnawarat8719d222020-11-27 16:57:56 +00002350 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002351 armnn::TensorInfo padTensorInfo = ToTensorInfo(inputs[1]);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002352
Mike Kelly0d77ae12022-01-07 17:42:27 +00002353 std::vector<unsigned int> padBuffer = GetUIntBuffer(padTensorInfo, m_Model, inputs[1]->buffer);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002354
2355 size_t step = 2;
2356 armnn::PadDescriptor desc;
Mike Kelly0d77ae12022-01-07 17:42:27 +00002357 auto opcode = GetOpCode(m_Model, subgraphIndex, operatorIndex);
2358
2359 if (opcode == tflite::BuiltinOperator_PAD)
Narumol Prangnawarat8719d222020-11-27 16:57:56 +00002360 {
Mike Kelly0d77ae12022-01-07 17:42:27 +00002361 CHECK_VALID_SIZE(inputs.size(), 2);
2362
2363 if (inputTensorInfo.IsQuantized())
2364 {
2365 desc.m_PadValue = static_cast<float>(inputTensorInfo.GetQuantizationOffset());
2366 }
Narumol Prangnawarat8719d222020-11-27 16:57:56 +00002367 }
Mike Kelly0d77ae12022-01-07 17:42:27 +00002368 else if (opcode == tflite::BuiltinOperator_PADV2)
2369 {
2370 CHECK_VALID_SIZE(inputs.size(), 3);
2371
2372 armnn::TensorInfo padValueTensorInfo = ToTensorInfo(inputs[2]);
2373
2374 if (padValueTensorInfo.GetNumElements() != 1)
2375 {
2376 ARMNN_THROW_PARSE_EXCEPTION("Multiple padding values are not supported in PADV2");
2377 }
2378 BufferRawPtr padValueBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
2379
2380 // Get the pad value from the input tensor
2381 if (padValueBufferPtr->data.size() > 0)
2382 {
2383 switch (padValueTensorInfo.GetDataType())
2384 {
2385 case armnn::DataType::Float32:
2386 {
2387 std::vector<float> padValueBuffer(padValueTensorInfo.GetNumElements());
2388 ::memcpy(padValueBuffer.data(), padValueBufferPtr->data.data(), padValueBufferPtr->data.size());
2389 desc.m_PadValue = padValueBuffer[0];
2390 break;
2391 }
2392 case armnn::DataType::QAsymmU8:
2393 {
2394 std::vector<uint8_t> padValueBuffer(padValueTensorInfo.GetNumElements());
2395 ::memcpy(padValueBuffer.data(), padValueBufferPtr->data.data(), padValueBufferPtr->data.size());
2396 desc.m_PadValue = armnn::Dequantize<uint8_t>(padValueBuffer[0],
2397 padValueTensorInfo.GetQuantizationScale(),
2398 padValueTensorInfo.GetQuantizationOffset());
2399 break;
2400 }
2401 case armnn::DataType::QAsymmS8:
2402 case armnn::DataType::QSymmS8:
2403 {
2404 std::vector<int8_t> padValueBuffer(padValueTensorInfo.GetNumElements());
2405 ::memcpy(padValueBuffer.data(), padValueBufferPtr->data.data(), padValueBufferPtr->data.size());
2406 desc.m_PadValue = armnn::Dequantize<int8_t>(padValueBuffer[0],
2407 padValueTensorInfo.GetQuantizationScale(),
2408 padValueTensorInfo.GetQuantizationOffset());
2409 break;
2410 }
2411 default: ARMNN_THROW_PARSE_EXCEPTION("Unsupported DataType");
2412 }
2413 }
2414 else if (inputTensorInfo.IsQuantized())
2415 {
2416 desc.m_PadValue = static_cast<float>(inputTensorInfo.GetQuantizationOffset());
2417 }
2418 }
2419
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002420 for (unsigned int i = 0; i < padTensorInfo.GetNumElements() / step; ++i)
2421 {
2422 desc.m_PadList.emplace_back(padBuffer[i * step], padBuffer[i * step + 1]);
2423 }
2424
Mike Kelly0d77ae12022-01-07 17:42:27 +00002425 auto layerName = (opcode == tflite::BuiltinOperator_PAD) ? fmt::format("Pad:{}:{}", subgraphIndex, operatorIndex)
2426 : fmt::format("PadV2:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagand109a4d2020-07-28 10:42:13 +01002427 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01002428
2429 IConnectableLayer* layer = m_Network->AddPadLayer(desc, layerName.c_str());
2430 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002431 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2432
2433 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2434 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2435
2436 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2437 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2438}
2439
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002440void TfLiteParserImpl::ParseMirrorPad(size_t subgraphIndex, size_t operatorIndex)
2441{
2442 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2443
2444 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2445 CHECK_VALID_SIZE(inputs.size(), 2);
2446
2447 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2448 CHECK_VALID_SIZE(outputs.size(), 1);
2449
2450 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
2451
2452 armnn::TensorInfo padTensorInfo = ToTensorInfo(inputs[1]);
2453 BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2454
2455 std::vector<unsigned int> padBuffer(padTensorInfo.GetNumElements());
2456 ::memcpy(padBuffer.data(), bufferPtr->data.data(), padTensorInfo.GetNumBytes());
2457
2458 size_t step = 2;
2459 armnn::PadDescriptor desc;
2460 for (unsigned int i = 0; i < padTensorInfo.GetNumElements() / step; ++i)
2461 {
2462 desc.m_PadList.emplace_back(padBuffer[i * step], padBuffer[i * step + 1]);
2463 }
2464
2465 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2466 const auto* options = operatorPtr->builtin_options.AsMirrorPadOptions();
2467
2468 if (options->mode == tflite::MirrorPadMode_REFLECT)
2469 {
2470 desc.m_PaddingMode = PaddingMode::Reflect;
2471 }
2472 else if (options->mode == tflite::MirrorPadMode_SYMMETRIC)
2473 {
2474 desc.m_PaddingMode = PaddingMode::Symmetric;
2475 }
2476 else
2477 {
2478 ARMNN_THROW_PARSE_EXCEPTION("PaddingMode must be either REFLECT or SYMMETRIC");
2479 }
2480
2481 // If padding mode is Reflect then both paddings must be no greater than inputShape(i) - 1.
2482 // If padding mode is Symmetric then both paddings must be no greater than inputShape(i).
2483 auto inputShape = inputTensorInfo.GetShape();
2484 auto padList = desc.m_PadList;
2485
2486 const unsigned int isReflect = static_cast<unsigned int>(desc.m_PaddingMode == PaddingMode::Reflect);
2487 for(unsigned int i = 0; i < padList.size(); ++i)
2488 {
2489 if(padList.at(i).first > (inputShape[i] - isReflect) ||
2490 padList.at(i).second > (inputShape[i] - isReflect))
2491 {
2492 ARMNN_THROW_PARSE_EXCEPTION("Padding values must be less (Reflect) or "
2493 "equal (Symmetric) to the dimension size.");
2494 }
2495 }
2496
2497 auto layerName = fmt::format("MirrorPad:{}:{}", subgraphIndex, operatorIndex);
2498 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
2499
2500 IConnectableLayer* layer = m_Network->AddPadLayer(desc, layerName.c_str());
2501 ARMNN_ASSERT(layer != nullptr);
2502 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2503
2504 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2505 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2506
2507 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2508 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2509}
2510
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002511void TfLiteParserImpl::ParsePrelu(size_t subgraphIndex, size_t operatorIndex)
2512{
2513 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2514
2515 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2516 CHECK_VALID_SIZE(inputs.size(), 2);
2517
2518 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2519 CHECK_VALID_SIZE(outputs.size(), 1);
2520
2521 auto layerName = fmt::format("Prelu:{}:{}", subgraphIndex, operatorIndex);
2522
2523 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
2524 armnn::TensorInfo alphaTensorInfo = ToTensorInfo(inputs[1]);
2525 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
2526 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
2527
2528 IConnectableLayer* layer = m_Network->AddPreluLayer(layerName.c_str());
2529 ARMNN_ASSERT(layer != nullptr);
2530 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2531
2532 if (IsConstTensor(inputs[1]))
2533 {
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002534 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawaratbf99b5f2021-05-27 09:55:43 +01002535 armnn::IInputSlot* slot = &(layer->GetInputSlot(0));
2536 RegisterConsumerOfTensor(subgraphIndex, inputTensorIndexes[0], slot);
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002537
Mike Kelly5880b912022-01-28 16:18:54 +00002538 auto alphaTensorAndData = CreateConstTensorNonPermuted(inputs[1], alphaTensorInfo,
2539 inputTensorInfo.GetDataType());
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002540 std::string constLayerName = fmt::format("Constant:{}", inputs[1]->name);
2541 IConnectableLayer* constLayer =
Mike Kelly5880b912022-01-28 16:18:54 +00002542 m_Network->AddConstantLayer(alphaTensorAndData.first, constLayerName.c_str());
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002543 ARMNN_ASSERT(constLayer != nullptr);
2544
2545 constLayer->GetOutputSlot(0).SetTensorInfo(alphaTensorInfo);
2546 constLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1));
2547 RegisterOutputSlots(subgraphIndex,
2548 VIRTUAL_OPERATOR_ID,
2549 constLayer,
2550 { inputTensorIndexes[1] });
2551 }
2552 else
2553 {
2554 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2555 RegisterInputSlots(subgraphIndex, operatorIndex, layer, inputTensorIndexes);
2556 }
2557
2558 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2559 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2560}
2561
Kevin May7d96b162021-02-03 17:38:41 +00002562void TfLiteParserImpl::ParseQuantize(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan66dedc72019-12-10 16:32:07 +00002563{
2564 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2565
2566 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2567 CHECK_VALID_SIZE(inputs.size(), 1);
2568
2569 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2570 CHECK_VALID_SIZE(outputs.size(), 1);
2571
James Ward58dec6b2020-09-11 17:32:44 +01002572 auto layerName = fmt::format("Quantize:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan66dedc72019-12-10 16:32:07 +00002573
2574 IConnectableLayer* layer = m_Network->AddQuantizeLayer(layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01002575 ARMNN_ASSERT(layer != nullptr);
Sadik Armagan66dedc72019-12-10 16:32:07 +00002576
Sadik Armagand109a4d2020-07-28 10:42:13 +01002577 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Sadik Armagan66dedc72019-12-10 16:32:07 +00002578 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2579
2580 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2581 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2582
2583 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2584 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2585}
Finn Williamsc42c3842019-01-22 14:18:11 +00002586
Kevin May7d96b162021-02-03 17:38:41 +00002587void TfLiteParserImpl::ParseRelu(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan58f39192018-09-17 14:14:39 +01002588{
Finn Williamsc42c3842019-01-22 14:18:11 +00002589 ParseActivation(subgraphIndex,operatorIndex, ActivationFunction::ReLu);
Sadik Armagan58f39192018-09-17 14:14:39 +01002590}
2591
Kevin May7d96b162021-02-03 17:38:41 +00002592void TfLiteParserImpl::ParseRelu6(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan58f39192018-09-17 14:14:39 +01002593{
Finn Williamsc42c3842019-01-22 14:18:11 +00002594 ParseActivation(subgraphIndex,operatorIndex, ActivationFunction::BoundedReLu);
2595}
Sadik Armagan58f39192018-09-17 14:14:39 +01002596
Kevin May7d96b162021-02-03 17:38:41 +00002597void TfLiteParserImpl::ParseLeakyRelu(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan12239e72020-05-27 11:06:17 +01002598{
Jan Eilers2f746b32020-07-28 14:00:06 +01002599 ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::LeakyReLu);
Sadik Armagan12239e72020-05-27 11:06:17 +01002600}
2601
Kevin May7d96b162021-02-03 17:38:41 +00002602void TfLiteParserImpl::ParseLogistic(size_t subgraphIndex, size_t operatorIndex)
Finn Williamsc42c3842019-01-22 14:18:11 +00002603{
2604 ParseActivation(subgraphIndex,operatorIndex,ActivationFunction::Sigmoid);
2605}
2606
Kevin May7d96b162021-02-03 17:38:41 +00002607void TfLiteParserImpl::ParseTanH(size_t subgraphIndex, size_t operatorIndex)
Nina Drozd99851762019-04-09 09:37:38 +01002608{
2609 ParseActivation(subgraphIndex,operatorIndex,ActivationFunction::TanH);
2610}
2611
Kevin May7d96b162021-02-03 17:38:41 +00002612void TfLiteParserImpl::ParseElu(size_t subgraphIndex, size_t operatorIndex)
Matthew Sloyan7515d072020-12-16 12:50:01 +00002613{
2614 ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::Elu);
2615}
2616
Kevin May7d96b162021-02-03 17:38:41 +00002617void TfLiteParserImpl::ParseHardSwish(size_t subgraphIndex, size_t operatorIndex)
Jan Eilers2f746b32020-07-28 14:00:06 +01002618{
2619 ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::HardSwish);
2620}
Finn Williamsc42c3842019-01-22 14:18:11 +00002621
Kevin May7d96b162021-02-03 17:38:41 +00002622void TfLiteParserImpl::ParseActivation(size_t subgraphIndex, size_t operatorIndex, ActivationFunction activationType)
Finn Williamsc42c3842019-01-22 14:18:11 +00002623{
2624 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00002625 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
Jan Eilers8eb25602020-03-09 12:13:48 +00002626 IgnoreUnused(operatorPtr);
Sadik Armagan58f39192018-09-17 14:14:39 +01002627
2628 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2629 CHECK_VALID_SIZE(inputs.size(), 1);
2630
2631 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2632 CHECK_VALID_SIZE(outputs.size(), 1);
2633
James Ward58dec6b2020-09-11 17:32:44 +01002634 auto layerName = fmt::format("Activation:");
Sadik Armagan58f39192018-09-17 14:14:39 +01002635 ActivationDescriptor activationDesc;
Finn Williamsc42c3842019-01-22 14:18:11 +00002636 activationDesc.m_Function = activationType;
2637
2638 switch (activationType)
2639 {
2640 case ActivationFunction::ReLu:
2641 {
James Ward58dec6b2020-09-11 17:32:44 +01002642 layerName += fmt::format("RELU:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsc42c3842019-01-22 14:18:11 +00002643 break;
2644 }
2645 case ActivationFunction::BoundedReLu:
2646 {
James Ward58dec6b2020-09-11 17:32:44 +01002647 layerName += fmt::format("RELU6:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsc42c3842019-01-22 14:18:11 +00002648 activationDesc.m_A = 6.0f;
2649 activationDesc.m_B = 0.0f;
2650 break;
2651 }
2652 case ActivationFunction::Sigmoid:
2653 {
James Ward58dec6b2020-09-11 17:32:44 +01002654 layerName += fmt::format("SIGMOID:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsc42c3842019-01-22 14:18:11 +00002655 break;
2656 }
Nina Drozd99851762019-04-09 09:37:38 +01002657 case ActivationFunction::TanH:
2658 {
James Ward58dec6b2020-09-11 17:32:44 +01002659 layerName += fmt::format("TANH:{}:{}", subgraphIndex, operatorIndex);
Nina Drozd99851762019-04-09 09:37:38 +01002660 activationDesc.m_A = 1.0f;
2661 activationDesc.m_B = 1.0f;
2662 break;
2663 }
Sadik Armagan12239e72020-05-27 11:06:17 +01002664 case ActivationFunction::LeakyReLu:
2665 {
James Ward58dec6b2020-09-11 17:32:44 +01002666 layerName += fmt::format("LEAKYRELU:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00002667 const auto* options = operatorPtr->builtin_options.AsLeakyReluOptions();
Sadik Armagan12239e72020-05-27 11:06:17 +01002668 activationDesc.m_A = options->alpha;
2669 break;
2670 }
Matthew Sloyan7515d072020-12-16 12:50:01 +00002671 case ActivationFunction::Elu:
2672 {
2673 layerName += fmt::format("ELU:{}:{}", subgraphIndex, operatorIndex);
2674 activationDesc.m_A = 1.0f;
2675 break;
2676 }
Jan Eilers2f746b32020-07-28 14:00:06 +01002677 case ActivationFunction::HardSwish:
Matthew Sloyan7515d072020-12-16 12:50:01 +00002678 {
James Ward58dec6b2020-09-11 17:32:44 +01002679 layerName += fmt::format("HARDSWISH:{}:{}", subgraphIndex, operatorIndex);
Jan Eilers2f746b32020-07-28 14:00:06 +01002680 break;
Matthew Sloyan7515d072020-12-16 12:50:01 +00002681 }
Finn Williamsc42c3842019-01-22 14:18:11 +00002682 default:
2683 {
2684 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01002685 fmt::format("Unexpected ActivationFunction[{}] when creating layerName {} ",
2686 static_cast<int>(activationType), CHECK_LOCATION().AsString()));
Finn Williamsc42c3842019-01-22 14:18:11 +00002687 }
2688 }
2689
2690 IConnectableLayer* const layer = m_Network->AddActivationLayer(activationDesc, layerName.c_str());
Sadik Armagan58f39192018-09-17 14:14:39 +01002691
Sadik Armagand109a4d2020-07-28 10:42:13 +01002692 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Sadik Armagan58f39192018-09-17 14:14:39 +01002693 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2694
2695 // register the input connection slots for the layer, connections are made after all layers have been created
2696 // only the tensors for the inputs are relevant, exclude the const tensors
2697 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2698 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2699
2700 // register the output connection slots for the layer, connections are made after all layers have been created
2701 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2702 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2703}
Mike Kelly0d77ae12022-01-07 17:42:27 +00002704armnn::TensorInfo TfLiteParserImpl::OutputShapeOfReshape(const armnn::TensorInfo& inputTensorInfo,
2705 const std::vector<int32_t>& targetDimsIn)
Sadikb94967b2018-09-19 15:30:00 +01002706{
2707 std::vector<unsigned int> outputDims(targetDimsIn.begin(), targetDimsIn.end());
2708 const auto stretchDim = std::find(targetDimsIn.begin(), targetDimsIn.end(), -1);
2709
2710 if (stretchDim != targetDimsIn.end())
2711 {
2712 if (std::find(std::next(stretchDim), targetDimsIn.end(), -1) != targetDimsIn.end())
2713 {
2714 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01002715 fmt::format("At most one component of shape can be -1 {}", CHECK_LOCATION().AsString()));
Sadikb94967b2018-09-19 15:30:00 +01002716 }
2717
2718 auto targetNumElements =
Matthew Sloyan589e3e82020-09-11 16:17:48 +01002719 armnn::numeric_cast<unsigned int>(
Sadikb94967b2018-09-19 15:30:00 +01002720 std::accumulate(targetDimsIn.begin(), targetDimsIn.end(), -1, std::multiplies<int32_t>()));
2721
2722 auto stretchIndex = static_cast<size_t>(std::distance(targetDimsIn.begin(), stretchDim));
2723 outputDims[stretchIndex] = inputTensorInfo.GetNumElements() / targetNumElements;
2724 }
2725
2726 TensorShape outputShape = TensorShape(static_cast<unsigned int>(outputDims.size()), outputDims.data());
2727
2728 TensorInfo reshapeInfo = inputTensorInfo;
2729 reshapeInfo.SetShape(outputShape);
2730
2731 return reshapeInfo;
2732}
2733
Kevin May7d96b162021-02-03 17:38:41 +00002734void TfLiteParserImpl::ParseReshape(size_t subgraphIndex, size_t operatorIndex)
Sadikb94967b2018-09-19 15:30:00 +01002735{
2736 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2737
2738 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Sadikb94967b2018-09-19 15:30:00 +01002739
2740 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2741 CHECK_VALID_SIZE(outputs.size(), 1);
2742
Mike Kelly0d77ae12022-01-07 17:42:27 +00002743 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2744 const auto* options = operatorPtr->builtin_options.AsReshapeOptions();
James Ward58dec6b2020-09-11 17:32:44 +01002745 auto layerName = fmt::format("Reshape:{}:{}", subgraphIndex, operatorIndex);
Sadikb94967b2018-09-19 15:30:00 +01002746
2747 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
kevmay0171972a82018-12-17 14:28:03 +00002748 armnn::TensorInfo actualOutputTensorInfo = ToTensorInfo(outputs[0]);
James Conroy05102392020-06-24 15:39:55 +01002749 CheckMatchingQuantization(inputTensorInfo, actualOutputTensorInfo, layerName, "Input 0", "Output 0");
Derek Lambertic9e52792020-03-11 11:42:26 +00002750
Jan Eilersbac9b352020-07-13 13:40:24 +01002751 // Extracting new shape for the output
2752 // There are two ways it can be passed
2753 // * First is to define the target shape in the operator built-in options
2754 // * Second is to pass it as a second input tensor
Derek Lambertic9e52792020-03-11 11:42:26 +00002755 std::vector<int32_t> targetShape;
Jan Eilersbac9b352020-07-13 13:40:24 +01002756 bool targetShapeFound = false;
2757 // Check if built-in options were given
2758 if (options != nullptr)
Derek Lambertic9e52792020-03-11 11:42:26 +00002759 {
Jan Eilersbac9b352020-07-13 13:40:24 +01002760 // make sure the parameter is given
2761 if (options->new_shape.empty() == false)
Derek Lambertic9e52792020-03-11 11:42:26 +00002762 {
Jan Eilersbac9b352020-07-13 13:40:24 +01002763 targetShape = options->new_shape;
2764 targetShapeFound = true;
Derek Lambertif4a953f2020-03-17 14:25:57 +00002765 }
Derek Lambertic9e52792020-03-11 11:42:26 +00002766 }
Jan Eilersbac9b352020-07-13 13:40:24 +01002767
2768 // If there is no built-in option given or if the built-in new_shape parameter was empty
2769 if (!targetShapeFound)
Derek Lambertic9e52792020-03-11 11:42:26 +00002770 {
Teresa Charlin6a056a42021-12-01 10:25:43 +00002771 // Check for a second input tensor
2772 if (inputs.size() > 1 && inputs[1] != nullptr)
Jan Eilersbac9b352020-07-13 13:40:24 +01002773 {
2774 if (inputs[1]->is_variable)
2775 {
2776 ARMNN_THROW_PARSE_EXCEPTION( "Target shapes defined in non-const input tensors is not supported");
2777 }
2778
2779 if (inputs[1]->shape.size() != 1)
2780 {
2781 ARMNN_THROW_PARSE_EXCEPTION("Target 'shape' input is not a 1D tensor");
2782 }
2783
2784 if (inputs[1]->type != tflite::TensorType_INT32)
2785 {
2786 ARMNN_THROW_PARSE_EXCEPTION("Target 'shape' input is not an int32 type");
2787 }
2788
Teresa Charlin6a056a42021-12-01 10:25:43 +00002789 // Extract target shape from input
2790 auto bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2791 auto values = reinterpret_cast<const int32_t*>(bufferPtr->data.data());
Cathal Corbettd2f73232021-12-10 13:38:52 +00002792 if (values)
Sadik Armagan19a1c032021-01-20 12:17:00 +00002793 {
Cathal Corbettd2f73232021-12-10 13:38:52 +00002794 for (int i = 0; i < inputs[1]->shape[0]; ++i)
2795 {
2796 targetShape.push_back(values[i]);
2797 }
Sadik Armagan19a1c032021-01-20 12:17:00 +00002798 }
Cathal Corbettd2f73232021-12-10 13:38:52 +00002799 else
Jan Eilersbac9b352020-07-13 13:40:24 +01002800 {
Cathal Corbettd2f73232021-12-10 13:38:52 +00002801 try
2802 {
2803 // We attempt to infer during Runtime.
2804 TensorShape reshapeShapes = ToTensorInfo(inputs[1]).GetShape();
2805 // The parser only supports shape (batch, -1) or (-1) for non-constant shape input.
2806 if (reshapeShapes[0] > 2)
2807 {
2808 throw ParseException(fmt::format("Invalid input shape '{}' in Reshape layer '{}' {}. "
2809 "When inferring during runtime, the parser only supports "
2810 "shape (batch, -1) or (-1) for target shape input.",
2811 reshapeShapes[0],
2812 layerName,
2813 CHECK_LOCATION().AsString()));
2814 }
2815
2816 const int32_t numInputElements = inputTensorInfo.GetNumElements();
2817 const int32_t inputTensorShape = inputTensorInfo.GetShape()[0];
2818 if (reshapeShapes[0] == 1)
2819 {
2820 targetShape = {numInputElements};
2821 }
2822 else if (reshapeShapes[0] == 2)
2823 {
2824 targetShape = {inputTensorShape, numInputElements / inputTensorShape};
2825 }
2826 }
2827 catch (const std::exception& exc)
2828 {
2829 ARMNN_THROW_PARSE_EXCEPTION("Failed attempt to infer during runtime the target shape input for "
2830 "Reshape operation. Reshape operator target shape input buffer data "
2831 "is null. " << exc.what());
2832 }
Jan Eilersbac9b352020-07-13 13:40:24 +01002833 }
2834 }
2835 else
Derek Lambertic9e52792020-03-11 11:42:26 +00002836 {
2837 ARMNN_THROW_PARSE_EXCEPTION("Target shape not defined in reshape parameters or input tensor. "
2838 "At least one method required");
2839 }
Derek Lambertic9e52792020-03-11 11:42:26 +00002840 }
2841
kevmay0171972a82018-12-17 14:28:03 +00002842 armnn::TensorInfo reshapeOutputTensorInfo =
Kevin May7d96b162021-02-03 17:38:41 +00002843 TfLiteParserImpl::OutputShapeOfReshape(inputTensorInfo, targetShape);
Sadikb94967b2018-09-19 15:30:00 +01002844
kevmay0171972a82018-12-17 14:28:03 +00002845 // Check for valid input size and that reshape parameters equal output shape
Aron Virginas-Tar70672f62019-01-23 14:00:00 +00002846 const armnn::TensorShape& reshapeOutputTensorShape = reshapeOutputTensorInfo.GetShape();
2847 if (inputs.size() > 1 && !CheckShape(reshapeOutputTensorShape, outputs[0]->shape))
kevmay0171972a82018-12-17 14:28:03 +00002848 {
2849 std::stringstream ss;
2850 ss << "New shape defined in reshape parameters "
Aron Virginas-Tar70672f62019-01-23 14:00:00 +00002851 << reshapeOutputTensorShape
kevmay0171972a82018-12-17 14:28:03 +00002852 << " does not equal output shape "
2853 << actualOutputTensorInfo.GetShape()
2854 << ": "
2855 << CHECK_LOCATION().AsString();
2856 throw ParseException(ss.str());
2857 }
2858
Sadikb94967b2018-09-19 15:30:00 +01002859 ReshapeDescriptor reshapeDesc;
kevmay0171972a82018-12-17 14:28:03 +00002860 reshapeDesc.m_TargetShape = reshapeOutputTensorInfo.GetShape();
Sadikb94967b2018-09-19 15:30:00 +01002861
Sadikb94967b2018-09-19 15:30:00 +01002862 IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002863 ARMNN_ASSERT(layer != nullptr);
kevmay0171972a82018-12-17 14:28:03 +00002864 layer->GetOutputSlot(0).SetTensorInfo(reshapeOutputTensorInfo);
Sadikb94967b2018-09-19 15:30:00 +01002865
2866 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2867 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2868
2869 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2870 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2871}
2872
Kevin May7d96b162021-02-03 17:38:41 +00002873void TfLiteParserImpl::ParseResizeBilinear(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02002874{
Sadik Armagana3b31f02019-12-05 09:08:53 +00002875 ParseResize(subgraphIndex, operatorIndex, ResizeMethod::Bilinear);
2876}
2877
Kevin May7d96b162021-02-03 17:38:41 +00002878void TfLiteParserImpl::ParseResizeNearestNeighbor(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagana3b31f02019-12-05 09:08:53 +00002879{
2880 ParseResize(subgraphIndex, operatorIndex, ResizeMethod::NearestNeighbor);
2881}
2882
Kevin May7d96b162021-02-03 17:38:41 +00002883void TfLiteParserImpl::ParseResize(size_t subgraphIndex, size_t operatorIndex, ResizeMethod resizeMethod)
Sadik Armagana3b31f02019-12-05 09:08:53 +00002884{
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02002885 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2886
2887 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2888 CHECK_VALID_SIZE(inputs.size(), 2);
2889
2890 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2891 CHECK_VALID_SIZE(outputs.size(), 1);
2892
2893 armnn::TensorInfo sizeTensorInfo = ToTensorInfo(inputs[1]);
2894
2895 // Data for the parsed tensor args (size) must be stored locally.
2896 std::vector<int32_t> sizeTensorData(sizeTensorInfo.GetNumElements());
2897
2898 BufferRawPtr sizeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2899 ::memcpy(sizeTensorData.data(), sizeBufferPtr->data.data(), sizeTensorInfo.GetNumBytes());
2900
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01002901 ResizeDescriptor desc;
Sadik Armagana3b31f02019-12-05 09:08:53 +00002902 desc.m_Method = resizeMethod;
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02002903 desc.m_TargetHeight = static_cast<uint32_t> (sizeTensorData[0]);
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01002904 desc.m_TargetWidth = static_cast<uint32_t> (sizeTensorData[1]);
2905 desc.m_DataLayout = armnn::DataLayout::NHWC;
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02002906
James Ward58dec6b2020-09-11 17:32:44 +01002907 auto layerName = fmt::format("Resize:");
Sadik Armagana3b31f02019-12-05 09:08:53 +00002908
2909 switch (resizeMethod)
2910 {
2911 case ResizeMethod::Bilinear:
2912 {
James Ward58dec6b2020-09-11 17:32:44 +01002913 layerName += fmt::format("BILINEAR:{}:{}", subgraphIndex, operatorIndex);
Sang-Hoon Park820eb142020-01-08 10:25:24 +00002914
2915 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2916 const auto * options = operatorPtr->builtin_options.AsResizeBilinearOptions();
2917
David Monahan4a0c9b92020-05-30 09:48:39 +01002918 desc.m_AlignCorners = options->align_corners;
Sadik Armagana3b31f02019-12-05 09:08:53 +00002919 break;
2920 }
2921 case ResizeMethod::NearestNeighbor:
2922 {
James Ward58dec6b2020-09-11 17:32:44 +01002923 layerName += fmt::format("NEARESTNEIGHBOR:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagana3b31f02019-12-05 09:08:53 +00002924 break;
2925 }
2926 default:
2927 {
2928 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01002929 fmt::format("Unexpected ResizeMethod[{}] when creating layerName {} ",
2930 static_cast<int>(resizeMethod), CHECK_LOCATION().AsString()));
Sadik Armagana3b31f02019-12-05 09:08:53 +00002931 }
2932 }
2933
James Conroy05102392020-06-24 15:39:55 +01002934 TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
Sadik Armagand109a4d2020-07-28 10:42:13 +01002935 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01002936 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
2937
2938 IConnectableLayer* layer = m_Network->AddResizeLayer(desc, layerName.c_str());
2939 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02002940 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2941
2942 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2943 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2944
2945 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2946 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2947}
2948
Kevin May7d96b162021-02-03 17:38:41 +00002949void TfLiteParserImpl::ParseConcatenation(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan479045b2018-10-01 11:51:37 +01002950{
2951 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2952
Mike Kelly0d77ae12022-01-07 17:42:27 +00002953 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2954 const auto* options = operatorPtr->builtin_options.AsConcatenationOptions();
Sadik Armagan479045b2018-10-01 11:51:37 +01002955
2956 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
2957
2958 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2959 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2960 CHECK_VALID_SIZE(outputs.size(), 1);
2961
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00002962 unsigned int numConcatView = static_cast<unsigned int>(inputs.size());
2963 uint32_t inputRank = ToTensorInfo(inputs[0]).GetNumDimensions();
Sadik Armagan479045b2018-10-01 11:51:37 +01002964
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00002965 const unsigned int concatDimInput = static_cast<unsigned int>(
2966 (static_cast<int>(inputRank) + options->axis) % static_cast<int>(inputRank));
Sadik Armagan479045b2018-10-01 11:51:37 +01002967
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00002968 OriginsDescriptor concatDescriptor(static_cast<uint32_t>(numConcatView), inputRank);
2969 concatDescriptor.SetConcatAxis(concatDimInput);
Sadik Armagan479045b2018-10-01 11:51:37 +01002970
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00002971 unsigned int mergeDimOrigin = 0;
Sadik Armagan479045b2018-10-01 11:51:37 +01002972
2973 for (unsigned int viewIndex = 0; viewIndex < numConcatView; ++viewIndex)
2974 {
2975 TensorInfo inputTensorInfo = ToTensorInfo(inputs[viewIndex]);
2976
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00002977 // This set up concatDescriptor view origin
2978 armnnUtils::ProcessConcatInputTensorInfo(
2979 inputTensorInfo, concatDescriptor, concatDimInput, viewIndex, mergeDimOrigin);
Sadik Armagan479045b2018-10-01 11:51:37 +01002980 }
2981
James Ward58dec6b2020-09-11 17:32:44 +01002982 auto layerName = fmt::format("Concatenation:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagand109a4d2020-07-28 10:42:13 +01002983 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01002984
Jim Flynn906f9462019-05-10 13:55:21 +01002985 IConnectableLayer* layer = m_Network->AddConcatLayer(concatDescriptor, layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01002986 ARMNN_ASSERT(layer != nullptr);
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00002987 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
Sadik Armagan479045b2018-10-01 11:51:37 +01002988
James Conroy05102392020-06-24 15:39:55 +01002989 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00002990 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes});
Sadik Armagan479045b2018-10-01 11:51:37 +01002991
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00002992 // add fused activation layer
2993 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
Sadik Armagan479045b2018-10-01 11:51:37 +01002994
Sadik Armagan479045b2018-10-01 11:51:37 +01002995 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2996 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2997}
2998
Kevin May7d96b162021-02-03 17:38:41 +00002999void TfLiteParserImpl::ParseFullyConnected(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003000{
3001 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3002
Mike Kelly0d77ae12022-01-07 17:42:27 +00003003 const auto& operatorRfr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003004 const auto options = operatorRfr->builtin_options.AsFullyConnectedOptions();
3005
3006 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
3007
3008 FullyConnectedDescriptor desc;
3009 desc.m_BiasEnabled = false;
Nattapat Chaimanowongd8eee592018-10-26 10:24:14 +01003010 desc.m_TransposeWeightMatrix = true;
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003011
3012 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3013 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3014 CHECK_VALID_SIZE(outputs.size(), 1);
3015
3016 armnn::TensorInfo filterTensorInfo = ToTensorInfo(inputs[1]);
3017
3018 // Fully Connected Layer accepts two dimensional weights input
3019 int32_t weightsDimension = static_cast<int32_t>(filterTensorInfo.GetNumDimensions());
3020 if (weightsDimension != 2)
3021 {
3022 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003023 fmt::format("Dimension {} for Fully Connected weights is not supported by Armnn. "
3024 "Node {}",
3025 weightsDimension,
3026 CHECK_LOCATION().AsString()));
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003027 }
3028
Matthew Jackson74bf7da2019-08-16 16:51:42 +01003029 armnn::IConnectableLayer* layer = nullptr;
James Ward58dec6b2020-09-11 17:32:44 +01003030 auto layerName = fmt::format("FullyConnected:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003031
Matthew Sloyan81beae32021-07-13 19:46:11 +01003032 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3033 // Add the first input tensor to the registration list
3034 std::vector<unsigned int> tensorIndexesToRegister = {inputTensorIndexes[0]};
3035 std::vector<unsigned int> ignoreInputWhenRegister = {};
Mike Kelly5880b912022-01-28 16:18:54 +00003036 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
Finn Williamsd4fa5452021-03-01 12:31:41 +00003037
3038 desc.m_ConstantWeights = IsConstTensor(inputs[1]);
3039
Matthew Sloyan81beae32021-07-13 19:46:11 +01003040 // Add the weights input to the registration list, constant layers will be added by SetupConstantLayers if constant.
3041 tensorIndexesToRegister.emplace_back(inputTensorIndexes[1]);
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003042
Mike Kelly5880b912022-01-28 16:18:54 +00003043 if (desc.m_ConstantWeights && inputTensorInfo.GetDataType() == DataType::Float32 &&
3044 (filterTensorInfo.GetDataType() == DataType::QAsymmU8 ||
3045 filterTensorInfo.GetDataType() == DataType::QAsymmS8))
3046 {
3047 m_ConstantsToDequantize.emplace_back(inputs[1]->buffer);
3048 }
3049
Finn Williamsd4fa5452021-03-01 12:31:41 +00003050 if (inputs.size() == 3)
3051 {
3052 desc.m_BiasEnabled = true;
Mike Kelly5880b912022-01-28 16:18:54 +00003053 armnn::TensorInfo biasTensorInfo = ToTensorInfo(inputs[2]);
Matthew Sloyan81beae32021-07-13 19:46:11 +01003054
3055 // Add the biases input to the registration list, constant layer will be added by SetupConstantLayers.
3056 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
Mike Kelly5880b912022-01-28 16:18:54 +00003057
3058 if (desc.m_ConstantWeights && inputTensorInfo.GetDataType() == DataType::Float32 &&
3059 (biasTensorInfo.GetDataType() == DataType::QAsymmU8 ||
3060 biasTensorInfo.GetDataType() == DataType::QAsymmS8))
3061 {
3062 m_ConstantsToDequantize.emplace_back(inputs[2]->buffer);
3063 }
Finn Williamsd4fa5452021-03-01 12:31:41 +00003064 }
3065
Matthew Sloyan81beae32021-07-13 19:46:11 +01003066 // Filters and biases are always passed to fully connected as inputs
3067 layer = m_Network->AddFullyConnectedLayer(desc, layerName.c_str());
Finn Williamsd4fa5452021-03-01 12:31:41 +00003068
3069 ARMNN_ASSERT(layer != nullptr);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003070
Finn Williamsd4fa5452021-03-01 12:31:41 +00003071 unsigned int startingSlotIndex = 0;
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003072 if (inputTensorInfo.GetNumDimensions() > 2)
3073 {
3074 // Add reshape to flatten to 2D [batch_size, input_size],
3075 // where "input_size" corresponds to the number of inputs to the layer,
3076 // matching the second dimension of weights,
3077 // and "batch_size" is calculated by dividing the number of elements by "input_size".
3078 std::vector<unsigned int> reshapedDimensions(2);
3079 reshapedDimensions[1] = filterTensorInfo.GetShape()[1];
3080 reshapedDimensions[0] = inputTensorInfo.GetNumElements() / reshapedDimensions[1];
3081
3082 if (inputTensorInfo.GetNumElements() % reshapedDimensions[1] != 0)
3083 {
3084 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003085 fmt::format("Failed to deduce input tensor shape from filter size {} {}",
3086 reshapedDimensions[1],
3087 CHECK_LOCATION().AsString()));
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003088 }
3089
3090 armnn::TensorInfo reshapedTensorInfo = ToTensorInfo(inputs[0]);
3091 reshapedTensorInfo.SetShape(armnn::TensorShape{ 2, reshapedDimensions.data() });
3092
James Ward58dec6b2020-09-11 17:32:44 +01003093 std::string reshapeLayerName = fmt::format("Reshape_for:{}", layer->GetName());
Finn Williamsd4fa5452021-03-01 12:31:41 +00003094 armnn::ReshapeDescriptor reshapeDescriptor;
3095 reshapeDescriptor.m_TargetShape = reshapedTensorInfo.GetShape();
3096 armnn::IConnectableLayer* reshapeLayer = m_Network->AddReshapeLayer(reshapeDescriptor, layerName.c_str());
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003097
3098 reshapeLayer->GetOutputSlot(0).SetTensorInfo(reshapedTensorInfo);
3099 reshapeLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
3100
3101 RegisterInputSlots(subgraphIndex, operatorIndex, reshapeLayer, {inputTensorIndexes[0]});
Finn Williamsd4fa5452021-03-01 12:31:41 +00003102 // Fc layer connects to the reshape layer, so we skip the first input slot when registering fc's input slots
3103 tensorIndexesToRegister.erase(tensorIndexesToRegister.begin());
3104 startingSlotIndex = 1;
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003105 }
Finn Williamsd4fa5452021-03-01 12:31:41 +00003106
3107 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister, startingSlotIndex);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003108
Sadik Armagand109a4d2020-07-28 10:42:13 +01003109 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003110 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3111
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003112 // we need to add the activation layer and fortunately we don't need to care about the data layout
3113 armnn::IConnectableLayer* fusedActivationLayer = AddFusedActivationLayer(layer, 0,
3114 options->fused_activation_function);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003115
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003116 // register the output connection slots for the layer, connections are made after all layers have been created
3117 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3118 RegisterOutputSlots(subgraphIndex, operatorIndex, fusedActivationLayer, {outputTensorIndexes[0]});
3119}
3120
Kevin May7d96b162021-02-03 17:38:41 +00003121void TfLiteParserImpl::ParseDetectionPostProcess(size_t subgraphIndex, size_t operatorIndex)
keidav011b3e2ea2019-02-21 10:07:37 +00003122{
3123 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3124
Mike Kelly0d77ae12022-01-07 17:42:27 +00003125 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
keidav011b3e2ea2019-02-21 10:07:37 +00003126
3127 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3128 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3129 CHECK_VALID_SIZE(outputs.size(), 4);
3130
3131 // Obtain custom options from flexbuffers
3132 auto custom_options = operatorPtr->custom_options;
3133 const flexbuffers::Map& m = flexbuffers::GetRoot(custom_options.data(), custom_options.size()).AsMap();
3134
3135 // Obtain descriptor information from tf lite
3136 DetectionPostProcessDescriptor desc;
3137 desc.m_MaxDetections = m["max_detections"].AsUInt32();
3138 desc.m_MaxClassesPerDetection = m["max_classes_per_detection"].AsUInt32();
3139 desc.m_NmsScoreThreshold = m["nms_score_threshold"].AsFloat();
3140 desc.m_NmsIouThreshold = m["nms_iou_threshold"].AsFloat();
3141 desc.m_NumClasses = m["num_classes"].AsUInt32();
3142 desc.m_ScaleH = m["h_scale"].AsFloat();
3143 desc.m_ScaleW = m["w_scale"].AsFloat();
3144 desc.m_ScaleX = m["x_scale"].AsFloat();
3145 desc.m_ScaleY = m["y_scale"].AsFloat();
3146
keidav0107d58c72019-02-26 11:57:39 +00003147 if (!(m["use_regular_nms"].IsNull()))
keidav011b3e2ea2019-02-21 10:07:37 +00003148 {
keidav0107d58c72019-02-26 11:57:39 +00003149 desc.m_UseRegularNms = m["use_regular_nms"].AsBool();
keidav011b3e2ea2019-02-21 10:07:37 +00003150 }
3151 if (!(m["detections_per_class"].IsNull()))
3152 {
3153 desc.m_DetectionsPerClass = m["detections_per_class"].AsUInt32();
3154 }
3155
3156 if (desc.m_NmsIouThreshold <= 0.0f || desc.m_NmsIouThreshold > 1.0f)
3157 {
3158 throw InvalidArgumentException("DetectionPostProcessTFLiteParser: Intersection over union threshold "
3159 "must be positive and less than or equal to 1.");
3160 }
3161
3162 armnn::TensorInfo anchorTensorInfo = ToTensorInfo(inputs[2]);
Finn Williamsd4fa5452021-03-01 12:31:41 +00003163 auto anchorTensorAndData = CreateConstTensorNonPermuted(inputs[2], anchorTensorInfo);
keidav011b3e2ea2019-02-21 10:07:37 +00003164
James Ward58dec6b2020-09-11 17:32:44 +01003165 auto layerName = fmt::format("DetectionPostProcess:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsd4fa5452021-03-01 12:31:41 +00003166 IConnectableLayer* layer = m_Network->AddDetectionPostProcessLayer(desc, anchorTensorAndData,
keidav011b3e2ea2019-02-21 10:07:37 +00003167 layerName.c_str());
3168
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01003169 ARMNN_ASSERT(layer != nullptr);
keidav011b3e2ea2019-02-21 10:07:37 +00003170
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00003171 // The model does not specify the output shapes.
3172 // The output shapes are calculated from the max_detection and max_classes_per_detection.
3173 unsigned int numDetectedBox = desc.m_MaxDetections * desc.m_MaxClassesPerDetection;
3174 m_OverridenOutputShapes.push_back({ 1, numDetectedBox, 4 });
3175 m_OverridenOutputShapes.push_back({ 1, numDetectedBox });
3176 m_OverridenOutputShapes.push_back({ 1, numDetectedBox });
3177 m_OverridenOutputShapes.push_back({ 1 });
3178
keidav011b3e2ea2019-02-21 10:07:37 +00003179 for (unsigned int i = 0 ; i < outputs.size() ; ++i)
3180 {
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00003181 armnn::TensorInfo detectionBoxOutputTensorInfo = ToTensorInfo(outputs[i], m_OverridenOutputShapes[i]);
keidav011b3e2ea2019-02-21 10:07:37 +00003182 layer->GetOutputSlot(i).SetTensorInfo(detectionBoxOutputTensorInfo);
3183 }
3184
3185 // Register the input connection slots for the layer, connections are made after all layers have been created
3186 // only the tensors for the inputs are relevant, exclude the const tensors
3187 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3188 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
3189
3190 // Register the output connection slots for the layer, connections are made after all layers have been created
3191 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3192 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0],
3193 outputTensorIndexes[1],
3194 outputTensorIndexes[2],
3195 outputTensorIndexes[3]});
3196}
3197
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003198/// The TfLite Pack operator is equivalent to the ArmNN Stack operator
Kevin May7d96b162021-02-03 17:38:41 +00003199void TfLiteParserImpl::ParsePack(size_t subgraphIndex, size_t operatorIndex)
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003200{
3201 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3202
3203 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3204 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3205 CHECK_VALID_SIZE(outputs.size(), 1);
3206
3207 if (inputs.size() < 1)
3208 {
3209 throw ParseException("Pack must have at least one input.");
3210 }
3211
3212 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3213 const auto* options = operatorPtr->builtin_options.AsPackOptions();
3214
3215 StackDescriptor desc;
3216 desc.m_Axis = static_cast<uint32_t>(options->axis);
3217 desc.m_NumInputs = static_cast<uint32_t>(inputs.size());
3218
3219 // Use the tensor shape of the first input as the "correct" input shape in the descriptor
3220 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
3221 desc.m_InputShape = inputTensorInfo.GetShape();
3222
James Ward58dec6b2020-09-11 17:32:44 +01003223 auto layerName = fmt::format("Pack:{}:{}", subgraphIndex, operatorIndex);
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003224 IConnectableLayer* layer = m_Network->AddStackLayer(desc, layerName.c_str());
3225
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01003226 ARMNN_ASSERT(layer != nullptr);
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003227
Sadik Armagand109a4d2020-07-28 10:42:13 +01003228 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003229 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3230
3231 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3232 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes});
3233
3234 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3235 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3236}
3237
Mike Kelly5880b912022-01-28 16:18:54 +00003238void TfLiteParserImpl::ParseUnidirectionalSequenceLSTM(size_t subgraphIndex, size_t operatorIndex)
3239{
3240 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3241
3242 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3243 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3244
3245 if (inputs.size() < 2)
3246 {
3247 throw ParseException("UnidirectionalSequenceLSTM must have at least 2 input.");
3248 }
3249
3250 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3251 const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex];
3252 const auto nodeParams = operatorPtr->builtin_options.AsUnidirectionalSequenceLSTMOptions();
3253 CHECK_SUPPORTED_FUSED_ACTIVATION(nodeParams, subgraphIndex, operatorIndex);
3254 auto inputTensorInfo = ToTensorInfo(inputs[0]);
3255 auto outputTensorInfo = ToTensorInfo(outputs[0]);
3256
3257 // Set the params structure for the AddUnidirectionalSequenceLstmLayer call
3258 // Please refer to each operand at
3259 // https://www.tensorflow.org/mlir/tfl_ops#tflunidirectional_sequence_lstm_tflunidirectionalsequencelstmop
3260 armnn::LstmInputParams params;
3261
3262 if (IsOptionalOperandPresent(operatorPtr->inputs[1]))
3263 {
3264 params.m_InputToInputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[1]].get(),
3265 inputTensorInfo).first;
3266 }
3267
3268 params.m_InputToForgetWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[2]].get(),
3269 inputTensorInfo).first;
3270 params.m_InputToCellWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[3]].get(),
3271 inputTensorInfo).first;
3272 params.m_InputToOutputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[4]].get(),
3273 inputTensorInfo).first;
3274
3275 // Recurrent weight tensors of size {n_cell, n_output}
3276 if (IsOptionalOperandPresent(operatorPtr->inputs[5]))
3277 {
3278 params.m_RecurrentToInputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[5]].get(),
3279 inputTensorInfo).first;
3280 }
3281
3282 params.m_RecurrentToForgetWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[6]].get(),
3283 inputTensorInfo).first;
3284 params.m_RecurrentToCellWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[7]].get(),
3285 inputTensorInfo).first;
3286 params.m_RecurrentToOutputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[8]].get(),
3287 inputTensorInfo).first;
3288
3289 // Peephole weights tensors of size {n_cell}, representing a diagonal matrix.
3290 if (IsOptionalOperandPresent(operatorPtr->inputs[9]))
3291 {
3292 params.m_CellToInputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[9]].get(),
3293 inputTensorInfo).first;
3294 }
3295
3296 if (IsOptionalOperandPresent(operatorPtr->inputs[10]))
3297 {
3298 params.m_CellToForgetWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[10]].get(),
3299 inputTensorInfo).first;
3300 }
3301
3302 if (IsOptionalOperandPresent(operatorPtr->inputs[11]))
3303 {
3304 params.m_CellToOutputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[11]].get(),
3305 inputTensorInfo).first;
3306 }
3307
3308 // Gates bias tensors of size {n_cell}
3309 if (IsOptionalOperandPresent(operatorPtr->inputs[12]))
3310 {
3311 params.m_InputGateBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[12]].get(),
3312 inputTensorInfo).first;
3313 }
3314
3315 params.m_ForgetGateBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[13]].get(),
3316 inputTensorInfo).first;
3317 params.m_CellBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[14]].get(),
3318 inputTensorInfo).first;
3319 params.m_OutputGateBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[15]].get(),
3320 inputTensorInfo).first;
3321
3322 // Projection weight tensor of size {n_output, n_cell}
3323 if (IsOptionalOperandPresent(operatorPtr->inputs[16]))
3324 {
3325 params.m_ProjectionWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[16]].get(),
3326 inputTensorInfo).first;
3327 }
3328 // Projection bias tensor of size {n_output}
3329 if (IsOptionalOperandPresent(operatorPtr->inputs[17]))
3330 {
3331 params.m_ProjectionBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[17]].get(),
3332 inputTensorInfo).first;
3333 }
3334
3335 // These state tensors are defined as variable tensors, and will be modified by this op.
3336 armnn::TensorInfo outputStateInInfo = ToTensorInfo(subgraphPtr->tensors[operatorPtr->inputs[18]].get());
3337 m_ConstantsToBeCreated.push_back(operatorPtr->inputs[18]);
3338 armnn::TensorInfo cellStateInInfo = ToTensorInfo(subgraphPtr->tensors[operatorPtr->inputs[19]].get());
3339 m_ConstantsToBeCreated.push_back(operatorPtr->inputs[19]);
3340
3341 // Layer norm coefficient tensors of size {n_cell}, representing a diagonal matrix.
3342 if (inputs.size() >= 21 && IsOptionalOperandPresent(operatorPtr->inputs[20]))
3343 {
3344 params.m_InputLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[20]].get(),
3345 inputTensorInfo).first;
3346 }
3347
3348 if (inputs.size() >= 22 && IsOptionalOperandPresent(operatorPtr->inputs[21]))
3349 {
3350 params.m_ForgetLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[21]].get(),
3351 inputTensorInfo).first;
3352 }
3353
3354 if (inputs.size() >= 23 && IsOptionalOperandPresent(operatorPtr->inputs[22]))
3355 {
3356 params.m_CellLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[22]].get(),
3357 inputTensorInfo).first;
3358 }
3359
3360 if (inputs.size() >= 24 && IsOptionalOperandPresent(operatorPtr->inputs[23]))
3361 {
3362 params.m_OutputLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[23]].get(),
3363 inputTensorInfo).first;
3364 }
3365
3366 // set the layer descriptor
3367 armnn::UnidirectionalSequenceLstmDescriptor desc;
3368 desc.m_ActivationFunc = nodeParams->fused_activation_function;
3369 desc.m_ClippingThresCell = nodeParams->cell_clip;
3370 desc.m_ClippingThresProj = nodeParams->proj_clip;
3371 desc.m_CifgEnabled = (params.m_InputToInputWeights == nullptr
3372 || params.m_RecurrentToInputWeights == nullptr
3373 || params.m_InputGateBias == nullptr);
3374 desc.m_PeepholeEnabled = (params.m_CellToForgetWeights != nullptr || params.m_CellToOutputWeights != nullptr);
3375 desc.m_ProjectionEnabled = (params.m_ProjectionWeights != nullptr);
3376 desc.m_LayerNormEnabled = (params.m_InputLayerNormWeights != nullptr
3377 || params.m_ForgetLayerNormWeights != nullptr
3378 || params.m_CellLayerNormWeights != nullptr
3379 || params.m_OutputLayerNormWeights != nullptr);
3380 desc.m_TimeMajor = nodeParams->time_major;
3381
Mike Kellyc0800a32022-06-15 10:57:52 +01003382 if (operatorPtr->intermediates.size() > 3 && desc.m_LayerNormEnabled)
Mike Kelly5880b912022-01-28 16:18:54 +00003383 {
3384 auto inputIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[0]].get(),
3385 inputTensorInfo).first;
3386 auto inputIntermediateTensorInfo = inputIntermediate->GetInfo();
3387 desc.m_InputIntermediateScale = inputIntermediateTensorInfo.GetQuantizationScale();
3388
3389 auto forgetIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[1]].get(),
3390 inputTensorInfo).first;
3391 auto forgetIntermediateTensorInfo = forgetIntermediate->GetInfo();
3392 desc.m_ForgetIntermediateScale = forgetIntermediateTensorInfo.GetQuantizationScale();
3393
3394 auto cellIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[2]].get(),
3395 inputTensorInfo).first;
3396 auto cellIntermediateTensorInfo = cellIntermediate->GetInfo();
3397 desc.m_CellIntermediateScale = cellIntermediateTensorInfo.GetQuantizationScale();
3398
3399 auto outputIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[3]].get(),
3400 inputTensorInfo).first;
3401 auto outputIntermediateTensorInfo = outputIntermediate->GetInfo();
3402 desc.m_OutputIntermediateScale = outputIntermediateTensorInfo.GetQuantizationScale();
3403 }
3404 else
3405 {
3406 float defaultIntermediate = std::pow(2, -12);
3407 desc.m_InputIntermediateScale = defaultIntermediate;
3408 desc.m_ForgetIntermediateScale = defaultIntermediate;
3409 desc.m_CellIntermediateScale = defaultIntermediate;
3410 desc.m_OutputIntermediateScale = defaultIntermediate;
3411 }
3412
Mike Kellyc0800a32022-06-15 10:57:52 +01003413 if (operatorPtr->intermediates.size() > 4)
3414 {
3415 auto hiddentensor = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[4]].get(),
3416 inputTensorInfo).first;
Mike Kelly5880b912022-01-28 16:18:54 +00003417
Mike Kellyc0800a32022-06-15 10:57:52 +01003418 desc.m_HiddenStateScale = hiddentensor->GetInfo().GetQuantizationScale();
3419 desc.m_HiddenStateZeroPoint = hiddentensor->GetInfo().GetQuantizationOffset();
3420 }
Mike Kelly5880b912022-01-28 16:18:54 +00003421 unsigned int batchSize = inputTensorInfo.GetShape()[0];
3422 unsigned int outputSize = outputTensorInfo.GetShape()[2];
3423 unsigned int numUnits = cellStateInInfo.GetShape()[1];
3424
3425 armnn::DataType dataType = inputTensorInfo.GetDataType();
3426 float qScale = inputTensorInfo.GetQuantizationScale();
3427 float qOffset = inputTensorInfo.GetQuantizationOffset();
3428
3429 armnn::TensorInfo scratchBufferTensorInfo({batchSize, numUnits * 3}, dataType, qScale, qOffset);
3430 if (!desc.m_CifgEnabled)
3431 {
3432 scratchBufferTensorInfo = armnn::TensorInfo({batchSize, numUnits * 4}, dataType, qScale, qOffset);
3433 }
3434 armnn::TensorInfo cellStateOutTensorInfo({batchSize, numUnits},
3435 cellStateInInfo.GetDataType(),
3436 cellStateInInfo.GetQuantizationScale(),
3437 cellStateInInfo.GetQuantizationOffset());
3438 armnn::TensorInfo outputStateOutTensorInfo({batchSize, outputSize}, dataType, qScale, qOffset);
3439
3440 armnn::LstmInputParamsInfo paramsInfo;
3441 paramsInfo.m_InputToForgetWeights = &(params.m_InputToForgetWeights->GetInfo());
3442 paramsInfo.m_InputToCellWeights = &(params.m_InputToCellWeights->GetInfo());
3443 paramsInfo.m_InputToOutputWeights = &(params.m_InputToOutputWeights->GetInfo());
3444 paramsInfo.m_RecurrentToForgetWeights = &(params.m_RecurrentToForgetWeights->GetInfo());
3445 paramsInfo.m_RecurrentToCellWeights = &(params.m_RecurrentToCellWeights->GetInfo());
3446 paramsInfo.m_RecurrentToOutputWeights = &(params.m_RecurrentToOutputWeights->GetInfo());
3447 paramsInfo.m_ForgetGateBias = &(params.m_ForgetGateBias->GetInfo());
3448 paramsInfo.m_CellBias = &(params.m_CellBias->GetInfo());
3449 paramsInfo.m_OutputGateBias = &(params.m_OutputGateBias->GetInfo());
3450
3451 if (!desc.m_CifgEnabled)
3452 {
3453 paramsInfo.m_InputToInputWeights = &(params.m_InputToInputWeights->GetInfo());
3454 paramsInfo.m_RecurrentToInputWeights = &(params.m_RecurrentToInputWeights->GetInfo());
3455 if (params.m_CellToInputWeights != nullptr)
3456 {
3457 paramsInfo.m_CellToInputWeights = &(params.m_CellToInputWeights->GetInfo());
3458 }
3459 paramsInfo.m_InputGateBias = &(params.m_InputGateBias->GetInfo());
3460 }
3461
3462 if (desc.m_ProjectionEnabled)
3463 {
3464 paramsInfo.m_ProjectionWeights = &(params.m_ProjectionWeights->GetInfo());
3465 if (params.m_ProjectionBias != nullptr)
3466 {
3467 paramsInfo.m_ProjectionBias = &(params.m_ProjectionBias->GetInfo());
3468 }
3469 }
3470
3471 if (desc.m_PeepholeEnabled)
3472 {
3473 paramsInfo.m_CellToForgetWeights = &(params.m_CellToForgetWeights->GetInfo());
3474 paramsInfo.m_CellToOutputWeights = &(params.m_CellToOutputWeights->GetInfo());
3475 }
3476
3477 if (desc.m_LayerNormEnabled)
3478 {
3479 if(!desc.m_CifgEnabled)
3480 {
3481 paramsInfo.m_InputLayerNormWeights = &(params.m_InputLayerNormWeights->GetInfo());
3482 }
3483 paramsInfo.m_ForgetLayerNormWeights = &(params.m_ForgetLayerNormWeights->GetInfo());
3484 paramsInfo.m_CellLayerNormWeights = &(params.m_CellLayerNormWeights->GetInfo());
3485 paramsInfo.m_OutputLayerNormWeights = &(params.m_OutputLayerNormWeights->GetInfo());
3486 }
3487
3488 auto layerName = fmt::format("UnidirectionalSequenceLSTM:{}:{}", subgraphIndex, operatorIndex);
3489 armnn::IConnectableLayer* layer = m_Network->AddUnidirectionalSequenceLstmLayer(desc, params);
3490 ARMNN_ASSERT(layer != nullptr);
3491
3492 // register the input connection slots for the layer, connections are made after all layers have been created
3493 // only the tensors for the inputs are relevant, exclude the const tensors
3494 auto inputTensorIndexes = AsUnsignedVector({operatorPtr->inputs[0],
3495 operatorPtr->inputs[18],
3496 operatorPtr->inputs[19]});
3497 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0],
3498 inputTensorIndexes[1],
3499 inputTensorIndexes[2]});
3500
3501 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3502
3503 layer->GetOutputSlot(0).SetTensorInfo(outputStateOutTensorInfo);
3504 layer->GetOutputSlot(1).SetTensorInfo(cellStateOutTensorInfo);
3505 layer->GetOutputSlot(2).SetTensorInfo(outputTensorInfo);
3506
3507 unsigned int tensorIndex = outputTensorIndexes[0];
3508 armnn::IOutputSlot* slot = &(layer->GetOutputSlot(2));
3509 RegisterProducerOfTensor(subgraphIndex, tensorIndex, slot);
3510}
3511
Kevin May7d96b162021-02-03 17:38:41 +00003512void TfLiteParserImpl::ParseUnpack(size_t subgraphIndex, size_t operatorIndex)
Nina Drozd200e3802019-04-15 09:47:39 +01003513{
3514 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3515
Mike Kelly0d77ae12022-01-07 17:42:27 +00003516 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3517 const auto* options = operatorPtr->builtin_options.AsUnpackOptions();
Nina Drozd200e3802019-04-15 09:47:39 +01003518
3519 // This unpackAxis indicates the axis to unpack
3520 const unsigned int unpackAxis = CHECKED_NON_NEGATIVE(options->axis);
3521
3522 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3523 CHECK_VALID_SIZE(inputs.size(), 1);
3524
3525 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003526
3527 if (unpackAxis >= inputTensorInfo.GetNumDimensions())
3528 {
3529 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003530 fmt::format("The unpack axis: {} cannot be greater than or equal to "
3531 "the number of input dimension {} {}",
3532 unpackAxis,
3533 inputTensorInfo.GetNumDimensions(),
3534 CHECK_LOCATION().AsString()));
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003535 }
3536
Nina Drozd200e3802019-04-15 09:47:39 +01003537 unsigned int unpackNum = CHECKED_NON_NEGATIVE(options->num);
3538 // If num is not defined, automatically infer from the length of the dimension axis.
3539 if(unpackNum == 0)
3540 {
3541 unpackNum = inputTensorInfo.GetShape()[unpackAxis];
3542 }
3543
3544 // If unpack number cannot be inferred and is still zero, throw ParseException.
3545 if(unpackNum == 0)
3546 {
3547 throw ParseException("Number to unpack must greater than zero.");
3548 }
3549
3550 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3551 CHECK_VALID_SIZE(outputs.size(), unpackNum);
3552
3553 auto inputDimSize = inputTensorInfo.GetNumDimensions();
3554 std::vector<unsigned int> unpackDimSizes(inputDimSize);
3555
3556 // Add current input shape to unpackDimSizes
3557 for (unsigned int i = 0; i < inputDimSize; ++i)
3558 {
3559 unpackDimSizes[i] = inputTensorInfo.GetShape()[i];
3560 }
3561
3562 if (unpackDimSizes[unpackAxis] != unpackNum)
3563 {
3564 throw ParseException("Number to unpack must be the same as length of the dimension to "
3565 "unpack along.");
3566 }
3567
3568 unpackDimSizes[unpackAxis] /= unpackNum;
3569
3570 SplitterDescriptor splitDesc(unpackNum, static_cast<unsigned int>(unpackDimSizes.size()));
3571 for (unsigned int j = 0; j < unpackNum; ++j)
3572 {
3573 // Set the size of the views.
3574 for (unsigned int dimIdx = 0; dimIdx < unpackDimSizes.size(); ++dimIdx)
3575 {
3576 splitDesc.SetViewSize(j, dimIdx, unpackDimSizes[dimIdx]);
3577 }
3578 splitDesc.SetViewOriginCoord(j, unpackAxis, unpackDimSizes[unpackAxis] * j);
3579 }
3580
James Ward58dec6b2020-09-11 17:32:44 +01003581 auto layerName = fmt::format("Unpack:{}:{}", subgraphIndex, operatorIndex);
Nina Drozd200e3802019-04-15 09:47:39 +01003582 IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01003583 ARMNN_ASSERT(layer != nullptr);
Nina Drozd200e3802019-04-15 09:47:39 +01003584
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003585 TensorShape splitOutShape = TensorShape(static_cast<unsigned int>(unpackDimSizes.size()),
3586 unpackDimSizes.data());
3587
Nina Drozd200e3802019-04-15 09:47:39 +01003588 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3589 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3590
Finn Williamsb49ed182021-06-29 15:50:08 +01003591 std::vector<unsigned int> reshapeDims;
3592 for (unsigned int axis = 0; axis < splitOutShape.GetNumDimensions(); ++axis)
3593 {
3594 if (axis != unpackAxis)
3595 {
3596 reshapeDims.push_back(splitOutShape[axis]);
3597 }
3598 }
3599
3600 TensorShape reshapeOutputShape(splitOutShape.GetNumDimensions() -1, reshapeDims.data());
3601
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003602 // Create reshape to remove the unpacked dimension for unpack operator of each output from Splitter.
3603 for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
3604 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01003605 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[k], true);
James Ward58dec6b2020-09-11 17:32:44 +01003606 std::string reshapeLayerName = fmt::format("Reshape_for:{}", layer->GetName());
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003607 armnn::ReshapeDescriptor desc;
Finn Williamsb49ed182021-06-29 15:50:08 +01003608 desc.m_TargetShape = reshapeOutputShape;
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003609 armnn::IConnectableLayer* reshapeLayer = m_Network->AddReshapeLayer(desc, layerName.c_str());
3610
Narumol Prangnawarat2c526462019-10-21 14:58:26 +01003611 layer->GetOutputSlot(k).SetTensorInfo(armnn::TensorInfo(splitOutShape,
3612 outputTensorInfo.GetDataType(),
3613 outputTensorInfo.GetQuantizationScale(),
3614 outputTensorInfo.GetQuantizationOffset()));
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003615 layer->GetOutputSlot(k).Connect(reshapeLayer->GetInputSlot(0));
3616
Narumol Prangnawarat2c526462019-10-21 14:58:26 +01003617 reshapeLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003618
3619 uint32_t reshapedOutputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[k]);
3620 armnn::IOutputSlot* slot = &(reshapeLayer->GetOutputSlot(0));
3621 RegisterProducerOfTensor(subgraphIndex, reshapedOutputId, slot);
3622 }
Nina Drozd200e3802019-04-15 09:47:39 +01003623}
3624
Kevin May7d96b162021-02-03 17:38:41 +00003625void TfLiteParserImpl::ParseSplit(size_t subgraphIndex, size_t operatorIndex)
Nina Drozd0324f482019-04-08 10:52:10 +01003626{
3627 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3628
Mike Kelly0d77ae12022-01-07 17:42:27 +00003629 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3630 const auto* options = operatorPtr->builtin_options.AsSplitOptions();
Nina Drozd0324f482019-04-08 10:52:10 +01003631
3632 const unsigned int numSplits = CHECKED_NON_NEGATIVE(options->num_splits);
3633
Nina Drozd200e3802019-04-15 09:47:39 +01003634 // If number of splits cannot be inferred and is zero, throw ParseException.
3635 if(numSplits == 0)
3636 {
3637 throw ParseException("Number to splits must greater than zero.");
3638 }
3639
Nina Drozd0324f482019-04-08 10:52:10 +01003640 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3641 CHECK_VALID_SIZE(inputs.size(), 2);
3642 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3643 CHECK_VALID_SIZE(outputs.size(), numSplits);
3644
Matthew Sloyaned7fce42021-04-15 20:46:24 +01003645 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[1]);
3646 armnn::TensorInfo axisTensorInfo = ToTensorInfo(inputs[0]);
3647 ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
Nina Drozd0324f482019-04-08 10:52:10 +01003648
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01003649 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[0]->buffer);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01003650 if (axisBufferPtr == nullptr)
3651 {
3652 throw ParseException(
3653 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
3654 CHECK_LOCATION().AsString()));
3655 }
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01003656
Matthew Sloyaned7fce42021-04-15 20:46:24 +01003657 std::vector<int32_t> axisData(axisTensorInfo.GetNumElements());
3658 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
3659 int32_t axis = axisData[0];
3660
3661 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
3662 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
3663 {
3664 // Square bracket denotes inclusive n while parenthesis denotes exclusive n
3665 // E.g. Rank 4 tensor can have axis in range [-4, 3)
3666 // -1 == 3, -2 == 2, -3 == 1, -4 == 0
3667 throw ParseException(
3668 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
3669 axis,
3670 CHECK_LOCATION().AsString()));
3671 }
3672
3673 const unsigned int splitDim = armnnUtils::GetUnsignedAxis(inputTensorInfo.GetNumDimensions(), axis);
Nina Drozd0324f482019-04-08 10:52:10 +01003674
Nina Drozd0324f482019-04-08 10:52:10 +01003675 auto inputDimSize = inputTensorInfo.GetNumDimensions();
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01003676 if (inputDimSize > MaxNumOfTensorDimensions)
Nina Drozd0324f482019-04-08 10:52:10 +01003677 {
3678 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003679 fmt::format("The number of dimensions: {} for input tensors of the split op cannot be greater than {} {}",
3680 inputTensorInfo.GetNumDimensions(),
3681 MaxNumOfTensorDimensions,
3682 CHECK_LOCATION().AsString()));
Nina Drozd0324f482019-04-08 10:52:10 +01003683 }
3684
3685 std::vector<unsigned int> splitterDimSizes(inputDimSize);
3686
3687 // Add current input shape to splitterDimSizes
3688 for (unsigned int i = 0; i < inputDimSize; ++i)
3689 {
3690 splitterDimSizes[i] = inputTensorInfo.GetShape()[i];
3691 }
3692
3693 if (splitterDimSizes[splitDim] % numSplits != 0)
3694 {
3695 throw ParseException("Number of splits must evenly divide the dimension");
3696 }
3697 splitterDimSizes[splitDim] /= numSplits;
3698
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01003699 SplitterDescriptor splitDesc(numSplits, inputDimSize);
Nina Drozd0324f482019-04-08 10:52:10 +01003700 for (unsigned int j = 0; j < numSplits; ++j)
3701 {
3702 // Set the size of the views.
3703 for (unsigned int dimIdx = 0; dimIdx < splitterDimSizes.size(); ++dimIdx)
3704 {
3705 splitDesc.SetViewSize(j, dimIdx, splitterDimSizes[dimIdx]);
3706 }
3707 splitDesc.SetViewOriginCoord(j, splitDim, splitterDimSizes[splitDim] * j);
3708 }
3709
James Ward58dec6b2020-09-11 17:32:44 +01003710 auto layerName = fmt::format("Split:{}:{}", subgraphIndex, operatorIndex);
Nina Drozd0324f482019-04-08 10:52:10 +01003711 IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01003712 ARMNN_ASSERT(layer != nullptr);
Nina Drozd0324f482019-04-08 10:52:10 +01003713
3714 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01003715 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[1]});
Nina Drozd0324f482019-04-08 10:52:10 +01003716
Nina Drozd0324f482019-04-08 10:52:10 +01003717 for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
3718 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01003719 armnn::TensorInfo tensorInfo = ToTensorInfo(outputs[k], true);
Francis Murtagh98d6b3d2019-10-21 10:52:54 +01003720 layer->GetOutputSlot(k).SetTensorInfo(tensorInfo);
Nina Drozd0324f482019-04-08 10:52:10 +01003721 }
3722
3723 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3724 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
3725}
3726
Derek Lambertif0176992020-04-28 13:37:49 +01003727unsigned int ComputeWrappedIndex(int idx, unsigned int numDimsIn)
3728{
3729 int numDims = armnn::numeric_cast<int>(numDimsIn);
3730 int v = idx < 0 ? numDims + idx : idx;
3731 ARMNN_ASSERT(v >= 0);
3732 ARMNN_ASSERT(v < numDims);
3733
3734 return static_cast<unsigned int>(v);
3735}
3736
Kevin May7d96b162021-02-03 17:38:41 +00003737void TfLiteParserImpl::ParseSplitV(size_t subgraphIndex, size_t operatorIndex)
Derek Lambertif0176992020-04-28 13:37:49 +01003738{
3739 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3740
Mike Kelly0d77ae12022-01-07 17:42:27 +00003741 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3742 const auto* options = operatorPtr->builtin_options.AsSplitVOptions();
Derek Lambertif0176992020-04-28 13:37:49 +01003743
3744 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3745 CHECK_VALID_SIZE(inputs.size(), 3);
3746
3747 auto& inputTensor = inputs[0];
3748 auto& splitsTensor = inputs[1];
3749 auto& axisTensor = inputs[2];
3750
3751 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputTensor);
3752 armnn::TensorInfo splitsInfo = ToTensorInfo(splitsTensor);
3753 armnn::TensorInfo axisTensorInfo = ToTensorInfo(axisTensor);
3754 ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
3755
3756 // Inputs
3757 auto inputDimSize = inputTensorInfo.GetNumDimensions();
3758 if (inputDimSize > MaxNumOfTensorDimensions)
3759 {
3760 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003761 fmt::format("The number of dimensions: {} for input tensors of the "
3762 "SplitV op cannot be greater than {} {}",
3763 inputTensorInfo.GetNumDimensions(),
3764 MaxNumOfTensorDimensions,
3765 CHECK_LOCATION().AsString()));
Derek Lambertif0176992020-04-28 13:37:49 +01003766 }
3767
3768 // Get split axis
3769 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, axisTensor->buffer);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01003770 if (axisBufferPtr == nullptr)
3771 {
3772 throw ParseException(
3773 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
3774 CHECK_LOCATION().AsString()));
3775 }
3776
Derek Lambertif0176992020-04-28 13:37:49 +01003777 std::vector<int> axisData(axisTensorInfo.GetNumElements());
3778 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
Matthew Sloyaned7fce42021-04-15 20:46:24 +01003779 int32_t axis = axisData[0];
3780
3781 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
3782 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
3783 {
3784 // Square bracket denotes inclusive n while parenthesis denotes exclusive n
3785 // E.g. Rank 4 tensor can have axis in range [-4, 3)
3786 // -1 == 3, -2 == 2, -3 == 1, -4 == 0
3787 throw ParseException(
3788 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
3789 axis,
3790 CHECK_LOCATION().AsString()));
3791 }
3792 const unsigned int splitDim = ComputeWrappedIndex(axis, inputTensorInfo.GetNumDimensions());
Derek Lambertif0176992020-04-28 13:37:49 +01003793
Derek Lambertif0176992020-04-28 13:37:49 +01003794 // Set split sizes
Derek Lambertif0176992020-04-28 13:37:49 +01003795 CHECK_VALID_SIZE(splitsInfo.GetNumDimensions(), 1);
Ryan OShea86704732020-05-26 11:41:04 +01003796 unsigned int numSplits{0};
3797
3798 if(options)
Derek Lambertif0176992020-04-28 13:37:49 +01003799 {
3800 numSplits = CHECKED_NON_NEGATIVE(options->num_splits);
Derek Lambertif0176992020-04-28 13:37:49 +01003801 }
3802 else
3803 {
Ryan OShea86704732020-05-26 11:41:04 +01003804 numSplits = splitsInfo.GetNumElements();
Derek Lambertif0176992020-04-28 13:37:49 +01003805 }
3806
3807 if (numSplits <=0)
3808 {
3809 throw ParseException("SplitV has invalid number of splits");
3810 }
3811
Jan Eilersc0761e92020-06-29 16:48:44 +01003812 std::vector<int> splitsData(numSplits);
Ryan OShea86704732020-05-26 11:41:04 +01003813 BufferRawPtr splitsBufferPtr = GetBuffer(m_Model, splitsTensor->buffer);
Jan Eilersc0761e92020-06-29 16:48:44 +01003814 ::memcpy(splitsData.data(), splitsBufferPtr->data.data(), splitsInfo.GetNumBytes());
Ryan OShea86704732020-05-26 11:41:04 +01003815
Jan Eilersc0761e92020-06-29 16:48:44 +01003816 unsigned int idx = 0;
Ryan OShea86704732020-05-26 11:41:04 +01003817 int numInferred{0};
3818 unsigned int inferIdx{0};
3819 int splitSum{0};
3820 for (auto split : splitsData)
3821 {
3822 if (split < 0)
3823 {
3824 numInferred++;
3825 inferIdx = idx;
3826 }
3827 else
3828 {
3829 splitSum += split;
3830 }
3831 idx++;
3832 }
3833 // Check for inferred Axis
3834 if (numInferred == 0)
3835 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +01003836 if (splitSum != armnn::numeric_cast<int>(inputTensorInfo.GetShape()[splitDim]))
Ryan OShea86704732020-05-26 11:41:04 +01003837 {
3838 throw ParseException("SplitV split_sizes does not sum to the dimension of value along split_dim.");
3839 }
3840 }
3841 else if (numInferred == 1)
3842 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +01003843 splitsData[inferIdx] = armnn::numeric_cast<int>(inputTensorInfo.GetShape()[splitDim]) - splitSum;
Ryan OShea86704732020-05-26 11:41:04 +01003844 }
3845 else
3846 {
3847 throw ParseException("Cannot infer split size for more than one split");
3848 }
3849
Derek Lambertif0176992020-04-28 13:37:49 +01003850 //Ouput size validation
3851 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3852 CHECK_VALID_SIZE(outputs.size(), numSplits);
3853
3854 // Setup Armnn descriptor
3855 SplitterDescriptor splitDesc(numSplits, inputDimSize);
3856 unsigned int accumSplit = 0;
3857 for (unsigned int j = 0; j < numSplits; ++j)
3858 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +01003859 unsigned int splitSize = armnn::numeric_cast<unsigned int>(splitsData[j]);
Derek Lambertif0176992020-04-28 13:37:49 +01003860
3861 // Set the size of the views.
3862 for (unsigned int dimIdx = 0; dimIdx < inputTensorInfo.GetNumDimensions(); ++dimIdx)
3863 {
3864 unsigned int dimSize = inputTensorInfo.GetShape()[dimIdx];
3865 if (dimIdx == splitDim)
3866 {
3867 dimSize = splitSize;
3868 }
3869 splitDesc.SetViewSize(j, dimIdx, dimSize);
3870 }
3871
3872 splitDesc.SetViewOriginCoord(j, splitDim, accumSplit);
3873 accumSplit += splitSize;
3874 }
3875
James Ward58dec6b2020-09-11 17:32:44 +01003876 auto layerName = fmt::format("SplitV:{}:{}", subgraphIndex, operatorIndex);
Derek Lambertif0176992020-04-28 13:37:49 +01003877 IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01003878 ARMNN_ASSERT(layer != nullptr);
Derek Lambertif0176992020-04-28 13:37:49 +01003879
3880 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3881 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3882
3883 for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
3884 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01003885 armnn::TensorInfo tensorInfo = ToTensorInfo(outputs[k], true);
Derek Lambertif0176992020-04-28 13:37:49 +01003886 layer->GetOutputSlot(k).SetTensorInfo(tensorInfo);
3887 }
3888
3889 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3890 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
3891}
3892
Matthew Sloyan28f177c2021-04-09 14:38:52 +01003893void TfLiteParserImpl::ParseArgMin(size_t subgraphIndex, size_t operatorIndex)
3894{
3895 ParseArgMinMax(subgraphIndex, operatorIndex, armnn::ArgMinMaxFunction::Min);
3896}
3897
Kevin May7d96b162021-02-03 17:38:41 +00003898void TfLiteParserImpl::ParseArgMax(size_t subgraphIndex, size_t operatorIndex)
Inki Daed4619e22020-09-10 15:33:54 +09003899{
Matthew Sloyan28f177c2021-04-09 14:38:52 +01003900 ParseArgMinMax(subgraphIndex, operatorIndex, armnn::ArgMinMaxFunction::Max);
3901}
3902
3903void TfLiteParserImpl::ParseArgMinMax(size_t subgraphIndex, size_t operatorIndex, ArgMinMaxFunction argMinMaxFunction)
3904{
Inki Daed4619e22020-09-10 15:33:54 +09003905 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3906 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3907 CHECK_VALID_SIZE(inputs.size(), 2);
3908
3909 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3910 CHECK_VALID_SIZE(outputs.size(), 1);
3911
Matthew Sloyan28f177c2021-04-09 14:38:52 +01003912 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
3913 armnn::TensorInfo axisTensorInfo = ToTensorInfo(inputs[1]);
Inki Daed4619e22020-09-10 15:33:54 +09003914 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01003915 ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
Matthew Sloyan28f177c2021-04-09 14:38:52 +01003916
3917 // Check if output tensor type is Signed32 or Signed64
Mike Kelly1f140f72021-04-06 12:25:55 +01003918 if (outputTensorInfo.GetDataType() != armnn::DataType::Signed32 &&
3919 outputTensorInfo.GetDataType() != armnn::DataType::Signed64)
3920 {
3921 throw ParseException(
3922 fmt::format(
3923 "Output tensor data type is not supported. (Supported types: Signed32 & Signed64) {}",
3924 CHECK_LOCATION().AsString()));
3925 }
Matthew Sloyan28f177c2021-04-09 14:38:52 +01003926
3927 // Get const axis value from model and set it to descriptor.
3928 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
3929 if (axisBufferPtr == nullptr)
3930 {
3931 throw ParseException(
3932 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
3933 CHECK_LOCATION().AsString()));
3934 }
3935
3936 std::vector<int32_t> axisData(axisTensorInfo.GetNumElements());
3937 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
3938 int32_t axis = axisData.front();
3939
3940 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
3941 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
3942 {
3943 // Square bracket denotes inclusive n while parenthesis denotes exclusive n
3944 // E.g. Rank 4 tensor can have axis in range [-4, 3)
3945 // -1 == 3, -2 == 2, -3 == 1, -4 == 0
3946 throw ParseException(
3947 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
3948 axis,
3949 CHECK_LOCATION().AsString()));
3950 }
3951
3952 ArgMinMaxDescriptor desc;
3953 desc.m_Axis = axis;
3954 desc.m_Function = argMinMaxFunction;
3955
3956 // Register a ArgMin/ArgMax layer.
3957 auto layerName = argMinMaxFunction == ArgMinMaxFunction::Max ? "ArgMax:{}:{}" : "ArgMin:{}:{}";
3958 auto layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
3959 IConnectableLayer *layer = m_Network->AddArgMinMaxLayer(desc, layerNameFormatted.c_str());
3960 ARMNN_ASSERT(layer != nullptr);
Inki Daed4619e22020-09-10 15:33:54 +09003961 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3962
3963 // Register input tensor to the layer.
3964 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3965 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3966
3967 // Register output tensor to the layer.
3968 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3969 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
3970}
3971
Kevin May7d96b162021-02-03 17:38:41 +00003972void TfLiteParserImpl::ParseGather(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan26868492021-01-22 14:25:31 +00003973{
3974 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3975
Kevin May7d96b162021-02-03 17:38:41 +00003976 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00003977 CHECK_VALID_SIZE(inputs.size(), 2);
Kevin May7d96b162021-02-03 17:38:41 +00003978 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00003979 CHECK_VALID_SIZE(outputs.size(), 1);
3980
3981 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
3982 armnn::TensorInfo indicesTensorInfo = ToTensorInfo(inputs[1]);
3983 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
3984
3985 armnn::GatherDescriptor gatherDescriptor;
3986
Mike Kelly0d77ae12022-01-07 17:42:27 +00003987 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3988 const auto* options = operatorPtr->builtin_options.AsGatherOptions();
Sadik Armagan26868492021-01-22 14:25:31 +00003989 auto axis = options->axis;
3990
3991 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
3992 auto indicesDimensions = indicesTensorInfo.GetNumDimensions();
3993 auto outputDimensions = outputTensorInfo.GetNumDimensions();
3994 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
3995 {
3996 throw ParseException(
3997 fmt::format("Operation has invalid axis: {} It is out of bounds [ -{}, {} ) {}",
3998 axis,
3999 inputDimensions, inputDimensions,
4000 CHECK_LOCATION().AsString()));
4001 }
4002 if (outputDimensions != static_cast<unsigned int>(inputDimensions) + indicesDimensions - 1)
4003 {
4004 throw ParseException(
4005 fmt::format("Operation has invalid output dimensions: {} Output must be an ({} + {} - 1) -D tensor {}",
4006 outputDimensions,
4007 inputDimensions, indicesDimensions,
4008 CHECK_LOCATION().AsString()));
4009 }
4010
4011 gatherDescriptor.m_Axis = axis;
4012
4013 auto layerName = fmt::format("Gather:{}:{}", subgraphIndex, operatorIndex);
4014 IConnectableLayer* layer = m_Network->AddGatherLayer(gatherDescriptor, layerName.c_str());
4015 ARMNN_ASSERT(layer != nullptr);
4016 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4017
4018 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4019 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4020
4021 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4022 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4023}
4024
Teresa Charlin91a53ea2022-04-25 15:47:29 +01004025void TfLiteParserImpl::ParseGatherNd(size_t subgraphIndex, size_t operatorIndex)
4026{
4027 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4028
4029 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4030 CHECK_VALID_SIZE(inputs.size(), 2);
4031 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4032 CHECK_VALID_SIZE(outputs.size(), 1);
4033
4034 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
4035 armnn::TensorInfo indicesTensorInfo = ToTensorInfo(inputs[1]);
4036 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
4037
4038 auto layerName = fmt::format("GatherNd:{}:{}", subgraphIndex, operatorIndex);
4039 IConnectableLayer* layer = m_Network->AddGatherNdLayer(layerName.c_str());
4040 ARMNN_ASSERT(layer != nullptr);
4041 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4042
4043 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4044 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4045
4046 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4047 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4048}
4049
Kevin May7d96b162021-02-03 17:38:41 +00004050void TfLiteParserImpl::ParseDepthToSpace(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan26868492021-01-22 14:25:31 +00004051{
4052 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4053
Kevin May7d96b162021-02-03 17:38:41 +00004054 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00004055 CHECK_VALID_SIZE(inputs.size(), 1);
Kevin May7d96b162021-02-03 17:38:41 +00004056 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00004057 CHECK_VALID_SIZE(outputs.size(), 1);
4058
4059 armnn::DepthToSpaceDescriptor descriptor;
4060
Mike Kelly0d77ae12022-01-07 17:42:27 +00004061 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4062 const auto* options = operatorPtr->builtin_options.AsDepthToSpaceOptions();
Sadik Armagan26868492021-01-22 14:25:31 +00004063 auto blockSize = options->block_size;
4064 if (blockSize < 2)
4065 {
4066 throw ParseException(
4067 fmt::format("Operation has invalid block size: {} Block size should be >= 2 {}",
4068 blockSize,
4069 CHECK_LOCATION().AsString()));
4070 }
4071 descriptor.m_BlockSize = armnn::numeric_cast<uint32_t>(blockSize);
4072
4073 auto layerName = fmt::format("DepthToSpace:{}:{}", subgraphIndex, operatorIndex);
4074 IConnectableLayer* layer = m_Network->AddDepthToSpaceLayer(descriptor, layerName.c_str());
4075 ARMNN_ASSERT(layer != nullptr);
4076 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
4077 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4078
4079 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4080 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4081
4082 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4083 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4084}
4085
Kevin May7d96b162021-02-03 17:38:41 +00004086void TfLiteParserImpl::ParseSum(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004087{
Sadik Armagana2747482021-02-09 10:28:54 +00004088 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Sum);
4089}
4090
Teresa Charlin4e3e8312021-08-05 12:34:37 +01004091void TfLiteParserImpl::ParseReduceProd(size_t subgraphIndex, size_t operatorIndex)
4092{
4093 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Prod);
4094}
4095
Sadik Armagana2747482021-02-09 10:28:54 +00004096void TfLiteParserImpl::ParseReduceMax(size_t subgraphIndex, size_t operatorIndex)
4097{
4098 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Max);
4099}
4100
4101void TfLiteParserImpl::ParseReduceMin(size_t subgraphIndex, size_t operatorIndex)
4102{
4103 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Min);
4104}
4105
4106void TfLiteParserImpl::ParseReduce(size_t subgraphIndex, size_t operatorIndex, ReduceOperation reduceOperation)
4107{
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004108 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4109
Mike Kelly0d77ae12022-01-07 17:42:27 +00004110 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4111 const auto* options = operatorPtr->builtin_options.AsReducerOptions();
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004112
4113 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4114 CHECK_VALID_SIZE(inputs.size(), 2);
4115
4116 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4117 CHECK_VALID_SIZE(outputs.size(), 1);
4118
Sadik Armagana2747482021-02-09 10:28:54 +00004119 auto layerName = fmt::format("Reduce:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004120
4121 armnn::TensorInfo inputTensorInfo0 = ToTensorInfo(inputs[0]);
4122 armnn::TensorInfo inputTensorInfo1 = ToTensorInfo(inputs[1]);
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004123
4124 ReduceDescriptor desc;
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004125 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
4126 // Get const axis value from model and set it to descriptor.
4127 if (axisBufferPtr != nullptr)
4128 {
Sadik Armagan49bdb792021-02-11 13:57:07 +00004129 std::vector<int32_t> axisData(inputTensorInfo1.GetNumElements());
4130 ::memcpy(axisData.data(), axisBufferPtr->data.data(), inputTensorInfo1.GetNumBytes());
4131
4132 // Convert the axis to unsigned int and remove duplicates.
4133 auto rank = static_cast<int32_t>(inputTensorInfo0.GetNumDimensions());
4134 std::set<unsigned int> uniqueAxis;
4135 std::transform(axisData.begin(),
4136 axisData.end(),
4137 std::inserter(uniqueAxis, uniqueAxis.begin()),
4138 [rank](int i)->unsigned int{
4139 return static_cast<uint32_t>(((i + rank) % rank)); });
4140 desc.m_vAxis.assign(uniqueAxis.begin(), uniqueAxis.end());
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004141 }
Sadik Armagana2747482021-02-09 10:28:54 +00004142 else
4143 {
4144 for (uint32_t i = 0; i < inputTensorInfo0.GetNumDimensions(); ++i)
4145 {
4146 desc.m_vAxis.push_back(i);
4147 }
4148 }
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004149
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004150 desc.m_KeepDims = options->keep_dims;
Sadik Armagana2747482021-02-09 10:28:54 +00004151 desc.m_ReduceOperation = reduceOperation;
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004152
4153 // Register a new layer object, Sum.
Mike Kelly0d77ae12022-01-07 17:42:27 +00004154 IConnectableLayer* layer = m_Network->AddReduceLayer(desc, layerName.c_str());
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004155
4156 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
4157 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4158
4159 // Register input tensor to the layer.
4160 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4161 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4162
4163 // Register output tensor to the layer.
4164 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4165 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4166}
4167
Mike Kelly31dce2b2021-09-01 21:22:37 +01004168void TfLiteParserImpl::ParseLocalResponseNormalization(size_t subgraphIndex, size_t operatorIndex)
4169{
4170 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4171
4172 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4173 CHECK_VALID_SIZE(inputs.size(), 1);
4174
4175 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4176 CHECK_VALID_SIZE(outputs.size(), 1);
4177
4178 auto layerName = fmt::format("LRN:{}:{}", subgraphIndex, operatorIndex);
4179 std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4180
4181 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
4182
4183 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4184 const auto* options = operatorPtr->builtin_options.AsLocalResponseNormalizationOptions();
4185
4186 armnn::NormalizationDescriptor descriptor;
4187 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
4188 descriptor.m_NormChannelType = armnn::NormalizationAlgorithmChannel::Across;
4189 descriptor.m_NormMethodType = armnn::NormalizationAlgorithmMethod::LocalBrightness;
4190 descriptor.m_NormSize = static_cast<uint32_t>(options->radius);
4191 descriptor.m_K = options->bias;
4192 descriptor.m_Alpha = options->alpha;
4193 descriptor.m_Beta = options->beta;
4194
4195 // ArmNN expects normSize to be the full size of the normalization
4196 // window rather than the radius as in TfLite.
4197 descriptor.m_NormSize = 1 + (2 * descriptor.m_NormSize);
4198
4199 IConnectableLayer* layer = m_Network->AddNormalizationLayer(descriptor, layerNameFormatted.c_str());
4200 ARMNN_ASSERT(layer != nullptr);
4201
4202 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
4203 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4204
4205 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4206 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4207
4208 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4209 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4210}
4211
Teresa Charlin8b0bee12022-07-12 11:18:44 +01004212void TfLiteParserImpl::ParseAbs(size_t subgraphIndex, size_t operatorIndex)
4213{
4214 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Abs);
4215}
4216
4217void TfLiteParserImpl::ParseExp(size_t subgraphIndex, size_t operatorIndex)
4218{
4219 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Exp);
4220}
4221
4222void TfLiteParserImpl::ParseLog(size_t subgraphIndex, size_t operatorIndex)
4223{
4224 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Log);
4225}
4226
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004227void TfLiteParserImpl::ParseLogicalNot(size_t subgraphIndex, size_t operatorIndex)
4228{
4229 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::LogicalNot);
4230}
4231
4232void TfLiteParserImpl::ParseNeg(size_t subgraphIndex, size_t operatorIndex)
4233{
4234 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Neg);
4235}
4236
4237void TfLiteParserImpl::ParseRsqrt(size_t subgraphIndex, size_t operatorIndex)
4238{
4239 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Rsqrt);
4240}
4241
Teresa Charlin8b0bee12022-07-12 11:18:44 +01004242void TfLiteParserImpl::ParseSin(size_t subgraphIndex, size_t operatorIndex)
4243{
4244 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Sin);
4245}
4246
Teresa Charlinf0fce5b2022-05-04 17:24:43 +01004247void TfLiteParserImpl::ParseSqrt(size_t subgraphIndex, size_t operatorIndex)
4248{
4249 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Sqrt);
4250}
4251
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004252void TfLiteParserImpl::ParseElementwiseUnary(size_t subgraphIndex, size_t operatorIndex, UnaryOperation unaryOperation)
4253{
4254 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4255
4256 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4257 CHECK_VALID_SIZE(inputs.size(), 1);
4258
4259 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4260 CHECK_VALID_SIZE(outputs.size(), 1);
4261
4262 std::string layerName = std::string(GetUnaryOperationAsCString(unaryOperation)) + ":{}:{}";
4263 std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4264
4265 ElementwiseUnaryDescriptor desc;
4266 desc.m_Operation = unaryOperation;
4267 IConnectableLayer* layer = m_Network->AddElementwiseUnaryLayer(desc, layerNameFormatted.c_str());
4268 ARMNN_ASSERT(layer != nullptr);
4269
4270 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
4271 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4272
4273 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4274 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4275
4276 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4277 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4278}
4279
Bruno Goncalves2d0eb862021-07-11 14:10:15 -03004280void TfLiteParserImpl::ParseEqual(size_t subgraphIndex, size_t operatorIndex)
4281{
4282 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::Equal);
4283}
4284
4285void TfLiteParserImpl::ParseNotEqual(size_t subgraphIndex, size_t operatorIndex)
4286{
4287 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::NotEqual);
4288}
4289
4290void TfLiteParserImpl::ParseGreater(size_t subgraphIndex, size_t operatorIndex)
4291{
4292 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::Greater);
4293}
4294
4295void TfLiteParserImpl::ParseGreaterOrEqual(size_t subgraphIndex, size_t operatorIndex)
4296{
4297 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::GreaterOrEqual);
4298}
4299
4300void TfLiteParserImpl::ParseLess(size_t subgraphIndex, size_t operatorIndex)
4301{
4302 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::Less);
4303}
4304
4305void TfLiteParserImpl::ParseLessOrEqual(size_t subgraphIndex, size_t operatorIndex)
4306{
4307 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::LessOrEqual);
4308}
4309
4310void TfLiteParserImpl::ParseComparison(size_t subgraphIndex, size_t operatorIndex,
4311 ComparisonOperation comparisonOperation)
4312{
4313 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4314
4315 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4316 CHECK_VALID_SIZE(inputs.size(), 2);
4317
4318 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4319 CHECK_VALID_SIZE(outputs.size(), 1);
4320
4321 auto layerName = std::string(GetComparisonOperationAsCString(comparisonOperation)) + ":{}:{}";
4322 std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4323
4324 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
4325 armnn::TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]);
4326 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerNameFormatted, "Input 0", "Input 1");
4327
4328 ComparisonDescriptor desc;
4329 desc.m_Operation = comparisonOperation;
4330 IConnectableLayer* layer = m_Network->AddComparisonLayer(desc, layerNameFormatted.c_str());
4331 ARMNN_ASSERT(layer != nullptr);
4332
4333 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
4334 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4335
4336 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4337 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4338
4339 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4340 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4341}
4342
Kevin May7d96b162021-02-03 17:38:41 +00004343armnn::IConnectableLayer* TfLiteParserImpl::AddFusedActivationLayer(armnn::IConnectableLayer* prevLayer,
4344 unsigned int outputSlot,
4345 tflite::ActivationFunctionType activationType)
telsoa01c577f2c2018-08-31 09:22:23 +01004346{
4347 ActivationDescriptor activationDesc;
4348 std::string layerName = prevLayer->GetName();
4349
4350 switch(activationType)
4351 {
4352 case tflite::ActivationFunctionType_NONE:
4353 {
4354 // this is a no-op: return previous layer
4355 return prevLayer;
4356 }
4357 case tflite::ActivationFunctionType_RELU:
4358 {
4359 activationDesc.m_Function = ActivationFunction::ReLu;
4360 layerName += ":RELU";
4361 break;
4362 }
4363 case tflite::ActivationFunctionType_RELU6:
4364 {
4365 activationDesc.m_Function = ActivationFunction::BoundedReLu;
4366 activationDesc.m_A = 6.0f;
4367 activationDesc.m_B = 0.0f;
4368 layerName += ":RELU6";
4369 break;
4370 }
4371 case tflite::ActivationFunctionType_TANH:
4372 {
4373 activationDesc.m_Function = ActivationFunction::TanH;
4374 activationDesc.m_A = 1.0f;
4375 activationDesc.m_B = 1.0f;
4376 layerName += ":TANH";
4377 break;
4378 }
4379
4380 // I only put these here as a reminder what others we could support
4381 case tflite::ActivationFunctionType_RELU_N1_TO_1:
4382 case tflite::ActivationFunctionType_SIGN_BIT:
4383 default:
4384 {
4385 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01004386 fmt::format("TfLite parser doesn't suppport fused activation: "
4387 "{}/{} {} ",
4388 activationType,
4389 tflite::EnumNameActivationFunctionType(activationType),
4390 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01004391
4392 }
4393 }
4394
4395 IConnectableLayer* activationLayer =
4396 m_Network->AddActivationLayer(activationDesc, layerName.c_str());
4397
4398 auto & prevOutputSlot = prevLayer->GetOutputSlot(outputSlot);
4399 prevOutputSlot.Connect(activationLayer->GetInputSlot(0));
4400 activationLayer->GetOutputSlot(0).SetTensorInfo(prevOutputSlot.GetTensorInfo());
4401 return activationLayer;
4402}
4403
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004404armnn::IConnectableLayer* TfLiteParserImpl::AddFusedFloorLayer(armnn::IConnectableLayer* prevLayer,
4405 unsigned int outputSlot)
4406{
Teresa Charlin725728e2022-05-05 13:33:33 +01004407
4408 auto& prevOutputSlot = prevLayer->GetOutputSlot(outputSlot);
4409 DataType dataType = prevOutputSlot.GetTensorInfo().GetDataType();
4410
4411 if (dataType == DataType::Signed32)
4412 {
4413 return prevLayer;
4414 }
4415
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004416 std::string layerName = prevLayer->GetName();
4417 IConnectableLayer* floorLayer = m_Network->AddFloorLayer(layerName.c_str());
4418
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004419 prevOutputSlot.Connect(floorLayer->GetInputSlot(0));
4420 floorLayer->GetOutputSlot(0).SetTensorInfo(prevOutputSlot.GetTensorInfo());
Teresa Charlin725728e2022-05-05 13:33:33 +01004421
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004422 return floorLayer;
4423}
4424
Mike Kelly0d77ae12022-01-07 17:42:27 +00004425TfLiteParserImpl::ModelPtr TfLiteParserImpl::LoadModelFromFile(const char* fileName)
telsoa01c577f2c2018-08-31 09:22:23 +01004426{
4427 if (fileName == nullptr)
4428 {
James Ward58dec6b2020-09-11 17:32:44 +01004429 throw InvalidArgumentException(fmt::format("Invalid (null) file name {}",
telsoa01c577f2c2018-08-31 09:22:23 +01004430 CHECK_LOCATION().AsString()));
4431 }
Francis Murtagh532a29d2020-06-29 11:50:01 +01004432 std::error_code errorCode;
4433 fs::path pathToFile(fileName);
4434 if (!fs::exists(pathToFile, errorCode))
telsoa01c577f2c2018-08-31 09:22:23 +01004435 {
James Ward58dec6b2020-09-11 17:32:44 +01004436 //fmt::format() could not be used here (format error)
4437 std::stringstream msg;
4438 msg << "Cannot find the file (" << fileName << ") errorCode: " << errorCode
4439 << " " << CHECK_LOCATION().AsString();
4440
4441 throw FileNotFoundException(msg.str());
telsoa01c577f2c2018-08-31 09:22:23 +01004442 }
4443 std::ifstream file(fileName, std::ios::binary);
4444 std::string fileContent((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
4445 return LoadModelFromBinary(reinterpret_cast<const uint8_t *>(fileContent.c_str()),
4446 fileContent.size());
4447}
4448
Mike Kelly0d77ae12022-01-07 17:42:27 +00004449TfLiteParserImpl::ModelPtr TfLiteParserImpl::LoadModelFromBinary(const uint8_t* binaryContent, size_t len)
telsoa01c577f2c2018-08-31 09:22:23 +01004450{
4451 if (binaryContent == nullptr)
4452 {
James Ward58dec6b2020-09-11 17:32:44 +01004453 throw InvalidArgumentException(fmt::format("Invalid (null) binary content {}",
telsoa01c577f2c2018-08-31 09:22:23 +01004454 CHECK_LOCATION().AsString()));
4455 }
4456 flatbuffers::Verifier verifier(binaryContent, len);
4457 if (verifier.VerifyBuffer<tflite::Model>() == false)
4458 {
4459 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01004460 fmt::format("Buffer doesn't conform to the expected Tensorflow Lite "
4461 "flatbuffers format. size:{} {}",
4462 len,
4463 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01004464 }
4465 return tflite::UnPackModel(binaryContent);
4466}
4467
Mike Kelly0d77ae12022-01-07 17:42:27 +00004468TfLiteParserImpl::TensorRawPtrVector TfLiteParserImpl::GetInputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00004469 size_t subgraphIndex,
4470 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004471{
4472 CHECK_MODEL(model, subgraphIndex, operatorIndex);
4473
Mike Kelly0d77ae12022-01-07 17:42:27 +00004474 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
4475 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01004476
4477 size_t inputCount = operatorPtr->inputs.size();
mathad01c21025d2021-04-26 10:09:37 +01004478 TensorRawPtrVector result;
Mike Kelly0d77ae12022-01-07 17:42:27 +00004479 for (size_t i = 0; i < inputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01004480 {
mathad01c21025d2021-04-26 10:09:37 +01004481 // If the input location is -1 then assume input is turned off.
4482 if (operatorPtr->inputs[i] == -1)
4483 {
4484 continue;
4485 }
4486 else
4487 {
4488 uint32_t inputId = CHECKED_NON_NEGATIVE(operatorPtr->inputs[i]);
4489 result.push_back(subgraphPtr->tensors[inputId].get());
4490 }
telsoa01c577f2c2018-08-31 09:22:23 +01004491 }
4492 return result;
4493}
4494
Mike Kelly0d77ae12022-01-07 17:42:27 +00004495TfLiteParserImpl::TensorRawPtrVector TfLiteParserImpl::GetOutputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00004496 size_t subgraphIndex,
4497 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004498{
4499 CHECK_MODEL(model, subgraphIndex, operatorIndex);
4500
Mike Kelly0d77ae12022-01-07 17:42:27 +00004501 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
4502 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01004503
4504 size_t outputCount = operatorPtr->outputs.size();
4505 TensorRawPtrVector result(outputCount);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004506 for (size_t i = 0; i < outputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01004507 {
4508 uint32_t outputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[i]);
4509 CHECK_TENSOR(model, subgraphIndex, outputId);
Derek Lambertiff05cc52019-04-26 13:05:17 +01004510 result[i] = subgraphPtr->tensors[outputId].get();
telsoa01c577f2c2018-08-31 09:22:23 +01004511 }
4512 return result;
4513}
4514
Mike Kelly0d77ae12022-01-07 17:42:27 +00004515TfLiteParserImpl::TensorIdRawPtrVector TfLiteParserImpl::GetSubgraphInputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00004516 size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004517{
4518 CHECK_SUBGRAPH(model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004519 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01004520
Derek Lambertiff05cc52019-04-26 13:05:17 +01004521 size_t inputCount = subgraphPtr->inputs.size();
telsoa01c577f2c2018-08-31 09:22:23 +01004522 TensorIdRawPtrVector result(inputCount);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004523 for (size_t i = 0; i < inputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01004524 {
Derek Lambertiff05cc52019-04-26 13:05:17 +01004525 uint32_t inputId = CHECKED_NON_NEGATIVE(subgraphPtr->inputs[i]);
telsoa01c577f2c2018-08-31 09:22:23 +01004526 CHECK_TENSOR(model, subgraphIndex, inputId);
Derek Lambertiff05cc52019-04-26 13:05:17 +01004527 result[i] = std::make_pair(inputId, subgraphPtr->tensors[inputId].get());
telsoa01c577f2c2018-08-31 09:22:23 +01004528 }
4529 return result;
4530}
4531
Mike Kelly0d77ae12022-01-07 17:42:27 +00004532TfLiteParserImpl::TensorIdRawPtrVector TfLiteParserImpl::GetSubgraphOutputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00004533 size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004534{
4535 CHECK_SUBGRAPH(model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004536 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01004537
Derek Lambertiff05cc52019-04-26 13:05:17 +01004538 size_t outputCount = subgraphPtr->outputs.size();
telsoa01c577f2c2018-08-31 09:22:23 +01004539 TensorIdRawPtrVector result(outputCount);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004540 for (size_t i = 0; i < outputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01004541 {
Derek Lambertiff05cc52019-04-26 13:05:17 +01004542 uint32_t outputId = CHECKED_NON_NEGATIVE(subgraphPtr->outputs[i]);
4543 result[i] = std::make_pair(outputId, subgraphPtr->tensors[outputId].get());
telsoa01c577f2c2018-08-31 09:22:23 +01004544 }
4545 return result;
4546}
4547
Kevin May7d96b162021-02-03 17:38:41 +00004548std::vector<int32_t>& TfLiteParserImpl::GetInputTensorIds(const ModelPtr& model,
4549 size_t subgraphIndex,
4550 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004551{
4552 CHECK_MODEL(model, subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004553 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
4554 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01004555 return operatorPtr->inputs;
4556}
4557
Kevin May7d96b162021-02-03 17:38:41 +00004558std::vector<int32_t>& TfLiteParserImpl::GetOutputTensorIds(const ModelPtr& model,
4559 size_t subgraphIndex,
4560 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004561{
4562 CHECK_MODEL(model, subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004563 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
4564 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01004565 return operatorPtr->outputs;
4566}
4567
Kevin May7d96b162021-02-03 17:38:41 +00004568void TfLiteParserImpl::RegisterInputSlots(size_t subgraphIndex,
4569 size_t operatorIndex,
4570 IConnectableLayer* layer,
Finn Williamsd4fa5452021-03-01 12:31:41 +00004571 const std::vector<unsigned int>& tensorIndexes,
4572 unsigned int startingSlotIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004573{
4574 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01004575 ARMNN_ASSERT(layer != nullptr);
Matthew Sloyan81beae32021-07-13 19:46:11 +01004576
Finn Williamsd4fa5452021-03-01 12:31:41 +00004577 if (tensorIndexes.size() + startingSlotIndex != layer->GetNumInputSlots())
telsoa01c577f2c2018-08-31 09:22:23 +01004578 {
4579 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01004580 fmt::format("The number of tensor inputs ({}) does not match the number expected ({})"
4581 " for subgraph:{} operator index:{} {}",
4582 tensorIndexes.size(),
4583 layer->GetNumInputSlots(),
4584 subgraphIndex,
4585 operatorIndex,
4586 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01004587 }
4588
Finn Williamsd4fa5452021-03-01 12:31:41 +00004589 for (unsigned int index = 0; index < tensorIndexes.size() ; ++index)
telsoa01c577f2c2018-08-31 09:22:23 +01004590 {
Finn Williamsd4fa5452021-03-01 12:31:41 +00004591 unsigned int tensorIndex = tensorIndexes[index];
4592 armnn::IInputSlot* slot = &(layer->GetInputSlot(startingSlotIndex + index));
telsoa01c577f2c2018-08-31 09:22:23 +01004593 RegisterConsumerOfTensor(subgraphIndex, tensorIndex, slot);
4594 }
4595}
4596
Kevin May7d96b162021-02-03 17:38:41 +00004597void TfLiteParserImpl::RegisterOutputSlots(size_t subgraphIndex,
4598 size_t operatorIndex,
4599 IConnectableLayer* layer,
4600 const std::vector<unsigned int>& tensorIndexes)
telsoa01c577f2c2018-08-31 09:22:23 +01004601{
4602 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01004603 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01004604 if (tensorIndexes.size() != layer->GetNumOutputSlots())
4605 {
4606 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01004607 fmt::format("The number of tensor outputs ({}) does not match the number expected ({})"
4608 " for subgraph:{} operator index:{} {}",
4609 tensorIndexes.size(),
4610 layer->GetNumOutputSlots(),
4611 subgraphIndex,
4612 operatorIndex,
4613 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01004614 }
4615
4616 for (unsigned int slotIndex = 0; slotIndex < layer->GetNumOutputSlots(); ++slotIndex)
4617 {
4618 unsigned int tensorIndex = tensorIndexes[slotIndex];
4619 armnn::IOutputSlot* slot = &(layer->GetOutputSlot(slotIndex));
4620 RegisterProducerOfTensor(subgraphIndex, tensorIndex, slot);
4621 }
4622}
4623
Kevin May7d96b162021-02-03 17:38:41 +00004624void TfLiteParserImpl::SetupInputLayers(size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004625{
4626 CHECK_SUBGRAPH(m_Model, subgraphIndex);
4627
4628 auto inputs = GetSubgraphInputs(m_Model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004629 for (auto const& tensorIdAndPtr : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01004630 {
4631 auto bindingId = GenerateLayerBindingId(subgraphIndex, tensorIdAndPtr.first);
4632 IConnectableLayer* layer =
4633 m_Network->AddInputLayer(bindingId, tensorIdAndPtr.second->name.c_str());
4634
4635 auto tensorInfo = ToTensorInfo(tensorIdAndPtr.second);
4636 layer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
4637
4638 RegisterOutputSlots(subgraphIndex,
4639 VIRTUAL_OPERATOR_ID,
4640 layer,
4641 { static_cast<uint32_t>(tensorIdAndPtr.first) });
4642 }
4643}
4644
Kevin May7d96b162021-02-03 17:38:41 +00004645void TfLiteParserImpl::SetupOutputLayers(size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004646{
4647 CHECK_SUBGRAPH(m_Model, subgraphIndex);
4648
4649 auto outputs = GetSubgraphOutputs(m_Model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004650 for (auto const& tensorIdAndPtr : outputs)
telsoa01c577f2c2018-08-31 09:22:23 +01004651 {
4652 auto bindingId = GenerateLayerBindingId(subgraphIndex, tensorIdAndPtr.first);
4653 IConnectableLayer* layer =
4654 m_Network->AddOutputLayer(bindingId, tensorIdAndPtr.second->name.c_str());
4655
4656 RegisterInputSlots(subgraphIndex,
4657 VIRTUAL_OPERATOR_ID,
4658 layer,
4659 { static_cast<uint32_t>(tensorIdAndPtr.first) });
4660 }
4661}
4662
Mike Kelly5880b912022-01-28 16:18:54 +00004663void TfLiteParserImpl::SetupConstantLayers(size_t subgraph)
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02004664{
Mike Kelly5880b912022-01-28 16:18:54 +00004665 CHECK_SUBGRAPH(m_Model, subgraph);
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02004666
Mike Kelly5880b912022-01-28 16:18:54 +00004667 const auto & subgraphPtr = m_Model->subgraphs[subgraph];
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02004668 for (unsigned int subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex)
4669 {
4670 for (unsigned int tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex)
4671 {
4672 if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot == nullptr &&
4673 m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size() > 0)
4674 {
Derek Lambertiff05cc52019-04-26 13:05:17 +01004675 TensorRawPtr tensorPtr = subgraphPtr->tensors[tensorIndex].get();
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02004676
Mike Kelly5880b912022-01-28 16:18:54 +00004677 if (IsConstTensor(tensorPtr))
Matthew Sloyan81beae32021-07-13 19:46:11 +01004678 {
4679 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
Mike Kelly5880b912022-01-28 16:18:54 +00004680 armnn::DataType dataType = tensorInfo.GetDataType();
4681
4682 if (std::find(m_ConstantsToDequantize.begin(), m_ConstantsToDequantize.end(), tensorPtr->buffer)
4683 != m_ConstantsToDequantize.end())
4684 {
4685 dataType = DataType::Float32;
4686 }
4687 auto tensorAndData = CreateConstTensorNonPermuted(tensorPtr, tensorInfo, dataType);
4688
4689 std::string layerName = fmt::format("Constant:{}", tensorPtr->name);
4690 IConnectableLayer *layer = m_Network->AddConstantLayer(tensorAndData.first, layerName.c_str());
4691
4692 layer->GetOutputSlot(0).SetTensorInfo(tensorAndData.first.GetInfo());
4693 RegisterOutputSlots(subgraphIndex,
4694 VIRTUAL_OPERATOR_ID,
4695 layer,
4696 { tensorIndex });
4697 }
4698 else if (ShouldConstantTensorBeCreated(tensorIndex))
4699 {
4700 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
4701 armnn::DataType dataType = tensorInfo.GetDataType();
4702
4703 if (std::find(m_ConstantsToDequantize.begin(), m_ConstantsToDequantize.end(), tensorPtr->buffer)
4704 != m_ConstantsToDequantize.end())
4705 {
4706 dataType = DataType::Float32;
4707 }
4708 // Make sure isConstant flag is set.
4709 tensorInfo.SetConstant();
4710 tensorInfo.SetDataType(dataType);
4711
4712 auto tensorAndData = ConstTensor(tensorInfo, std::vector<uint8_t>(tensorInfo.GetNumBytes()));
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02004713
Matthew Sloyan81beae32021-07-13 19:46:11 +01004714 std::string layerName = fmt::format("Constant:{}", tensorPtr->name);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004715 IConnectableLayer* layer = m_Network->AddConstantLayer(tensorAndData, layerName.c_str());
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02004716
Matthew Sloyan81beae32021-07-13 19:46:11 +01004717 layer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
4718 RegisterOutputSlots(subgraphIndex,
4719 VIRTUAL_OPERATOR_ID,
4720 layer,
Mike Kelly5880b912022-01-28 16:18:54 +00004721 {tensorIndex});
Matthew Sloyan81beae32021-07-13 19:46:11 +01004722 }
4723 else
4724 {
4725 throw ParseException(
4726 fmt::format("Invalid Tensor: Tensor should be constant. {}",
4727 CHECK_LOCATION().AsString()));
4728 }
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02004729 }
4730 }
4731 }
4732}
4733
telsoa01c577f2c2018-08-31 09:22:23 +01004734// example usage: BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[0]->buffer);
Kevin May7d96b162021-02-03 17:38:41 +00004735TfLiteParserImpl::BufferRawPtr TfLiteParserImpl::GetBuffer(const ModelPtr& model, size_t bufferIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004736{
4737 CHECK_BUFFER(model, bufferIndex);
4738 return model->buffers[bufferIndex].get();
4739}
4740
Matteo Martincigh747ef822018-12-18 09:26:39 +00004741template<typename T>
Kevin May7d96b162021-02-03 17:38:41 +00004742std::pair<armnn::ConstTensor, TfLiteParserImpl::SupportedDataStorage>
4743TfLiteParserImpl::CreateConstTensorAndStoreData(TfLiteParserImpl::BufferRawPtr bufferPtr,
4744 TfLiteParserImpl::TensorRawPtr tensorPtr,
Matteo Martincigh747ef822018-12-18 09:26:39 +00004745 armnn::TensorInfo& tensorInfo,
4746 armnn::Optional<armnn::PermutationVector&> permutationVector)
4747{
Matthew Sloyan81beae32021-07-13 19:46:11 +01004748 // Make sure isConstant flag is set.
4749 tensorInfo.SetConstant();
4750
Matteo Martincigh747ef822018-12-18 09:26:39 +00004751 auto constData = CreateConstTensorImpl<T>(bufferPtr,
4752 tensorPtr,
4753 tensorInfo,
4754 permutationVector);
Kevin May7d96b162021-02-03 17:38:41 +00004755 TfLiteParserImpl::SupportedDataStorage storage(std::move(constData.second));
Matteo Martincigh747ef822018-12-18 09:26:39 +00004756 return std::make_pair(constData.first, std::move(storage));
4757}
4758
Mike Kelly5880b912022-01-28 16:18:54 +00004759bool TfLiteParserImpl::ShouldConstantTensorBeCreated(unsigned int tensorIndex)
4760{
4761 // If the TensorIndex appears in the list of ConstantsToBeCreated then return true
4762 return (std::find(m_ConstantsToBeCreated.begin(), m_ConstantsToBeCreated.end(), tensorIndex)
4763 != m_ConstantsToBeCreated.end());
4764}
4765
Finn Williamsd4fa5452021-03-01 12:31:41 +00004766bool TfLiteParserImpl::IsConstTensor(TensorRawPtr tensorPtr)
4767{
4768 CHECK_TENSOR_PTR(tensorPtr);
mathad01bf7edb62021-04-20 16:12:45 +01004769 bool isConst = true;
4770
4771 auto buffer = GetBuffer(m_Model, tensorPtr->buffer);
4772 if (buffer->data.size() == 0)
4773 {
4774 isConst = false;
4775 }
4776
4777 return isConst;
Finn Williamsd4fa5452021-03-01 12:31:41 +00004778}
4779
Kevin May7d96b162021-02-03 17:38:41 +00004780std::pair<armnn::ConstTensor, TfLiteParserImpl::SupportedDataStorage>
Finn Williamsd4fa5452021-03-01 12:31:41 +00004781TfLiteParserImpl::CreateConstTensorPermuted(TensorRawPtr tensorPtr,
4782 armnn::TensorInfo& tensorInfo,
4783 armnn::Optional<armnn::PermutationVector&> permutationVector)
telsoa01c577f2c2018-08-31 09:22:23 +01004784{
4785 CHECK_TENSOR_PTR(tensorPtr);
4786 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
4787 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
4788
Matthew Sloyan81beae32021-07-13 19:46:11 +01004789 // Make sure isConstant flag is set.
4790 tensorInfo.SetConstant();
4791
telsoa01c577f2c2018-08-31 09:22:23 +01004792 switch (tensorInfo.GetDataType())
4793 {
4794 case armnn::DataType::Float32:
Matteo Martincigh747ef822018-12-18 09:26:39 +00004795 return CreateConstTensorAndStoreData<float>(bufferPtr,
4796 tensorPtr,
4797 tensorInfo,
4798 permutationVector);
Derek Lambertif90c56d2020-01-10 17:14:08 +00004799 case armnn::DataType::QAsymmU8:
Matteo Martincigh747ef822018-12-18 09:26:39 +00004800 return CreateConstTensorAndStoreData<uint8_t>(bufferPtr,
4801 tensorPtr,
4802 tensorInfo,
4803 permutationVector);
Keith Davisd305e1a2020-01-22 11:57:54 +00004804 case armnn::DataType::QSymmS8:
4805 return CreateConstTensorAndStoreData<int8_t>(bufferPtr,
4806 tensorPtr,
4807 tensorInfo,
4808 permutationVector);
Keith Davis67e6c542020-02-19 10:08:33 +00004809 case armnn::DataType::QAsymmS8:
4810 return CreateConstTensorAndStoreData<int8_t>(bufferPtr,
4811 tensorPtr,
4812 tensorInfo,
4813 permutationVector);
telsoa01c577f2c2018-08-31 09:22:23 +01004814 case armnn::DataType::Signed32:
Matteo Martincigh747ef822018-12-18 09:26:39 +00004815 return CreateConstTensorAndStoreData<int32_t>(bufferPtr,
4816 tensorPtr,
4817 tensorInfo,
4818 permutationVector);
telsoa01c577f2c2018-08-31 09:22:23 +01004819 default:
4820 {
4821 std::stringstream errString;
4822 errString << "Unexpected datatype when creating const tensor: "
4823 << armnn::GetDataTypeName(tensorInfo.GetDataType())
4824 << " shape:" << tensorInfo.GetShape()
4825 << CHECK_LOCATION().AsString();
4826 throw ParseException(errString.str());
4827 }
4828 }
4829}
4830
Finn Williamsd4fa5452021-03-01 12:31:41 +00004831armnn::ConstTensor TfLiteParserImpl::CreateConstTensorNonPermuted(TensorRawPtr tensorPtr,
4832 armnn::TensorInfo& tensorInfo)
4833{
4834 CHECK_TENSOR_PTR(tensorPtr);
4835 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
4836 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
4837
Matthew Sloyan81beae32021-07-13 19:46:11 +01004838 // Make sure isConstant flag is set.
4839 tensorInfo.SetConstant();
4840
Finn Williamsd4fa5452021-03-01 12:31:41 +00004841 return ConstTensor(tensorInfo, bufferPtr->data.data());
4842}
4843
Mike Kelly5880b912022-01-28 16:18:54 +00004844std::pair<armnn::ConstTensor, std::unique_ptr<float[]>>
4845TfLiteParserImpl::CreateConstTensorNonPermuted(TensorRawPtr tensorPtr,
4846 armnn::TensorInfo& tensorInfo,
4847 armnn::DataType inputDataType)
4848{
4849 CHECK_TENSOR_PTR(tensorPtr);
4850 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
4851 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
4852
4853 // Make sure isConstant flag is set.
4854 tensorInfo.SetConstant();
4855
4856 if (inputDataType == DataType::Float32 && tensorInfo.GetDataType() != DataType::Float32)
4857 {
4858 TensorInfo constTensorInfo(tensorInfo.GetShape(), DataType::Float32, 0.0f, 0, true);
4859 std::unique_ptr<float[]> data = AsFloatArray(bufferPtr, tensorInfo);
4860 return std::make_pair(ConstTensor(constTensorInfo, data.get()), std::move(data));
4861 }
4862 else
4863 {
4864 return std::make_pair(ConstTensor(tensorInfo, bufferPtr->data.data()), std::unique_ptr<float[]>());
4865 }
4866}
4867
4868std::pair<armnn::ConstTensor*, std::unique_ptr<float[]>>
4869TfLiteParserImpl::CreateConstTensorPtr(TensorRawPtr tensorPtr, armnn::TensorInfo& inputTensorInfo)
4870{
4871 CHECK_TENSOR_PTR(tensorPtr);
4872 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
4873 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
4874 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
4875
4876 // Make sure isConstant flag is set.
4877 tensorInfo.SetConstant();
4878
4879 if (inputTensorInfo.GetDataType() == DataType::Float32 && tensorInfo.GetDataType() != DataType::Float32)
4880 {
4881 TensorInfo constTensorInfo(tensorInfo.GetShape(), DataType::Float32, 0.0f, 0, true);
4882 std::unique_ptr<float[]> data = AsFloatArray(bufferPtr, tensorInfo);
4883 return std::make_pair(new ConstTensor(constTensorInfo, data.get()), std::move(data));
4884 }
4885 else
4886 {
4887 return std::make_pair(new ConstTensor(tensorInfo, bufferPtr->data.data()), std::unique_ptr<float[]>());
4888 }
4889}
4890
Kevin May7d96b162021-02-03 17:38:41 +00004891BindingPointInfo TfLiteParserImpl::GetNetworkInputBindingInfo(size_t subgraphId,
4892 const std::string& name) const
telsoa01c577f2c2018-08-31 09:22:23 +01004893{
4894 CHECK_SUBGRAPH(m_Model, subgraphId);
4895 auto inputs = GetSubgraphInputs(m_Model, subgraphId);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004896 for (auto const& input : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01004897 {
4898 if (input.second->name == name)
4899 {
4900 auto bindingId = GenerateLayerBindingId(subgraphId, input.first);
Colm Donelan4bc993b2021-11-09 20:39:10 +00004901 auto inputTensorInfo = ToTensorInfo(input.second);
4902 // Input tensors are always treated as constant tensors during network execution.
4903 inputTensorInfo.SetConstant(true);
4904 return std::make_pair(bindingId, inputTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +01004905 }
4906 }
4907
4908 std::stringstream bindings;
Mike Kelly0d77ae12022-01-07 17:42:27 +00004909 for (auto const& input : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01004910 {
4911 bindings << "'" << input.second->name << "' ";
4912 }
4913
4914 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01004915 fmt::format("No input binding found for subgraph:{} and name:{}. "
4916 "Possible inputs are: [{}] {}",
4917 subgraphId,
4918 name,
4919 bindings.str(),
4920 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01004921}
4922
Kevin May7d96b162021-02-03 17:38:41 +00004923BindingPointInfo TfLiteParserImpl::GetNetworkOutputBindingInfo(size_t subgraphId,
4924 const std::string& name) const
telsoa01c577f2c2018-08-31 09:22:23 +01004925{
4926 CHECK_SUBGRAPH(m_Model, subgraphId);
4927 auto outputs = GetSubgraphOutputs(m_Model, subgraphId);
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00004928 for (unsigned int i = 0; i < outputs.size(); ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01004929 {
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00004930 auto const output = outputs[i];
telsoa01c577f2c2018-08-31 09:22:23 +01004931 if (output.second->name == name)
4932 {
4933 auto bindingId = GenerateLayerBindingId(subgraphId, output.first);
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00004934 std::vector<unsigned int> shape = m_OverridenOutputShapes.size() > 0 ?
4935 m_OverridenOutputShapes[i] : AsUnsignedVector(output.second->shape);
4936 return std::make_pair(bindingId, ToTensorInfo(output.second, shape));
telsoa01c577f2c2018-08-31 09:22:23 +01004937 }
4938 }
4939
4940 std::stringstream bindings;
Mike Kelly0d77ae12022-01-07 17:42:27 +00004941 for (auto const& output : outputs)
telsoa01c577f2c2018-08-31 09:22:23 +01004942 {
4943 bindings << "'" << output.second->name << "' ";
4944 }
4945
4946 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01004947 fmt::format("No output binding found for subgraph:{} and name:{}. "
4948 "Possible outputs are: [{}] {}",
4949 subgraphId,
4950 name,
4951 bindings.str(),
4952 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01004953}
4954
Kevin May7d96b162021-02-03 17:38:41 +00004955size_t TfLiteParserImpl::GetSubgraphCount() const
telsoa01c577f2c2018-08-31 09:22:23 +01004956{
4957 return m_Model->subgraphs.size();
4958}
4959
Kevin May7d96b162021-02-03 17:38:41 +00004960std::vector<std::string> TfLiteParserImpl::GetSubgraphInputTensorNames(size_t subgraphId) const
telsoa01c577f2c2018-08-31 09:22:23 +01004961{
4962 CHECK_SUBGRAPH(m_Model, subgraphId);
4963 auto inputs = GetSubgraphInputs(m_Model, subgraphId);
4964 std::vector<std::string> result;
4965 result.reserve(inputs.size());
Mike Kelly0d77ae12022-01-07 17:42:27 +00004966 for (auto const& input : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01004967 {
4968 result.push_back(input.second->name);
4969 }
4970 return result;
4971}
4972
Kevin May7d96b162021-02-03 17:38:41 +00004973std::vector<std::string> TfLiteParserImpl::GetSubgraphOutputTensorNames(size_t subgraphId) const
telsoa01c577f2c2018-08-31 09:22:23 +01004974{
4975 CHECK_SUBGRAPH(m_Model, subgraphId);
4976 auto outputs = GetSubgraphOutputs(m_Model, subgraphId);
4977 std::vector<std::string> result;
4978 result.reserve(outputs.size());
Mike Kelly0d77ae12022-01-07 17:42:27 +00004979 for (auto const& output : outputs)
telsoa01c577f2c2018-08-31 09:22:23 +01004980 {
4981 result.push_back(output.second->name);
4982 }
4983 return result;
4984}
4985
Matthew Sloyanac001ee2021-02-03 10:43:04 +00004986const std::string TfLiteParserImpl::GetVersion()
4987{
4988 return TFLITE_PARSER_VERSION;
4989}
4990
Mike Kelly0d77ae12022-01-07 17:42:27 +00004991TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<float[]>&& data)
telsoa01c577f2c2018-08-31 09:22:23 +01004992: m_FloatData(std::move(data))
4993, m_Uint8Data(nullptr)
Keith Davisd305e1a2020-01-22 11:57:54 +00004994, m_Int8Data(nullptr)
telsoa01c577f2c2018-08-31 09:22:23 +01004995, m_Int32Data(nullptr)
4996{
4997}
4998
Mike Kelly0d77ae12022-01-07 17:42:27 +00004999TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<uint8_t[]>&& data)
telsoa01c577f2c2018-08-31 09:22:23 +01005000: m_FloatData(nullptr)
5001, m_Uint8Data(std::move(data))
Keith Davisd305e1a2020-01-22 11:57:54 +00005002, m_Int8Data(nullptr)
5003, m_Int32Data(nullptr)
5004{
5005}
5006
Mike Kelly0d77ae12022-01-07 17:42:27 +00005007TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<int8_t[]>&& data)
Keith Davisd305e1a2020-01-22 11:57:54 +00005008: m_FloatData(nullptr)
5009, m_Uint8Data(nullptr)
5010, m_Int8Data(std::move(data))
telsoa01c577f2c2018-08-31 09:22:23 +01005011, m_Int32Data(nullptr)
5012{
5013}
5014
Mike Kelly0d77ae12022-01-07 17:42:27 +00005015TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<int32_t[]>&& data)
telsoa01c577f2c2018-08-31 09:22:23 +01005016: m_FloatData(nullptr)
5017, m_Uint8Data(nullptr)
Keith Davisd305e1a2020-01-22 11:57:54 +00005018, m_Int8Data(nullptr)
telsoa01c577f2c2018-08-31 09:22:23 +01005019, m_Int32Data(std::move(data))
5020{
5021}
5022
5023} // armnnTfLiteParser