blob: a6d651f5ab85479bbea6f155d414530009c64e89 [file] [log] [blame]
telsoa01c577f2c2018-08-31 09:22:23 +01001//
Mike Kelly04d82292023-01-19 18:29:40 +00002// Copyright © 2017-2023 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>
Mike Kelly377fb212023-01-10 15:55:28 +000021#include <armnn/LayerSupport.hpp>
telsoa01c577f2c2018-08-31 09:22:23 +010022
23// armnnUtils:
Matteo Martincighe011d202019-11-28 11:35:47 +000024#include <armnnUtils/Permute.hpp>
Rob Hughes9542f902021-07-14 09:48:54 +010025#include <armnnUtils/Filesystem.hpp>
Matteo Martincighe011d202019-11-28 11:35:47 +000026
Sadik Armagan479045b2018-10-01 11:51:37 +010027#include <ParserHelper.hpp>
telsoa01c577f2c2018-08-31 09:22:23 +010028#include <VerificationHelpers.hpp>
29
30// The generated code based on the Tf Lite schema:
31#include <schema_generated.h>
32
Matteo Martincighe011d202019-11-28 11:35:47 +000033#include <flatbuffers/flexbuffers.h>
34
James Ward58dec6b2020-09-11 17:32:44 +010035#include <fmt/format.h>
telsoa01c577f2c2018-08-31 09:22:23 +010036
telsoa01c577f2c2018-08-31 09:22:23 +010037#include <algorithm>
Matthew Sloyanac001ee2021-02-03 10:43:04 +000038#include <iostream>
telsoa01c577f2c2018-08-31 09:22:23 +010039#include <limits>
Sadikb94967b2018-09-19 15:30:00 +010040#include <numeric>
Derek Lambertic9e52792020-03-11 11:42:26 +000041
42#define ARMNN_THROW_PARSE_EXCEPTION(msg) \
43 { \
44 throw armnn::ParseException( static_cast<const std::stringstream&>( std::stringstream() << msg \
45 << ": " \
46 << CHECK_LOCATION().AsString()).str()); \
47 }
telsoa01c577f2c2018-08-31 09:22:23 +010048
49using namespace armnn;
50using armnn::CheckLocation;
51namespace armnnTfLiteParser
52{
Kevin May7d96b162021-02-03 17:38:41 +000053
54ITfLiteParser::ITfLiteParser(const armnn::Optional<TfLiteParserOptions>& options) :
55 pTfLiteParserImpl(new TfLiteParserImpl(options)) {}
56
57ITfLiteParser::~ITfLiteParser() = default;
58
59ITfLiteParser* ITfLiteParser::CreateRaw(const armnn::Optional<TfLiteParserOptions>& options)
60{
61 return new ITfLiteParser(options);
62}
63
64ITfLiteParserPtr ITfLiteParser::Create(const armnn::Optional<TfLiteParserOptions>& options)
65{
66 return ITfLiteParserPtr(CreateRaw(options), &ITfLiteParser::Destroy);
67}
68
69void ITfLiteParser::Destroy(ITfLiteParser* parser)
70{
71 delete parser;
72}
73
74armnn::INetworkPtr ITfLiteParser::CreateNetworkFromBinaryFile(const char* graphFile)
75{
76 return pTfLiteParserImpl->CreateNetworkFromBinaryFile(graphFile);
77}
78
Mike Kelly0d77ae12022-01-07 17:42:27 +000079armnn::INetworkPtr ITfLiteParser::CreateNetworkFromBinary(const std::vector<uint8_t>& binaryContent)
Kevin May7d96b162021-02-03 17:38:41 +000080{
81 return pTfLiteParserImpl->CreateNetworkFromBinary(binaryContent);
82}
83
84BindingPointInfo ITfLiteParser::GetNetworkInputBindingInfo(size_t subgraphId,
85 const std::string& name) const
86{
87 return pTfLiteParserImpl->GetNetworkInputBindingInfo(subgraphId, name);
88}
89
90BindingPointInfo ITfLiteParser::GetNetworkOutputBindingInfo(size_t subgraphId,
91 const std::string& name) const
92{
93 return pTfLiteParserImpl->GetNetworkOutputBindingInfo(subgraphId, name);
94}
95
96size_t ITfLiteParser::GetSubgraphCount() const
97{
98 return pTfLiteParserImpl->GetSubgraphCount();
99}
100
101std::vector<std::string> ITfLiteParser::GetSubgraphInputTensorNames(size_t subgraphId) const
102{
103 return pTfLiteParserImpl->GetSubgraphInputTensorNames(subgraphId);
104}
105
106std::vector<std::string> ITfLiteParser::GetSubgraphOutputTensorNames(size_t subgraphId) const
107{
108 return pTfLiteParserImpl->GetSubgraphOutputTensorNames(subgraphId);
109}
110
telsoa01c577f2c2018-08-31 09:22:23 +0100111namespace
112{
jimfly01c25411c2018-11-14 17:47:22 +0000113
telsoa01c577f2c2018-08-31 09:22:23 +0100114const uint32_t VIRTUAL_OPERATOR_ID = std::numeric_limits<uint32_t>::max();
115
Mike Kelly0d77ae12022-01-07 17:42:27 +0000116void CheckSubgraph(const TfLiteParserImpl::ModelPtr& model,
telsoa01c577f2c2018-08-31 09:22:23 +0100117 size_t subgraphIndex,
Mike Kelly0d77ae12022-01-07 17:42:27 +0000118 const CheckLocation& location)
telsoa01c577f2c2018-08-31 09:22:23 +0100119{
120 if (model.get() == nullptr)
121 {
122 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100123 fmt::format("{} was called with invalid (null) model. "
124 "Possible reason is that the model is not yet loaded and Unpack(ed). "
125 "subgraph:{} at {}",
126 location.m_Function,
127 subgraphIndex,
128 location.FileLine()));
telsoa01c577f2c2018-08-31 09:22:23 +0100129 }
130 else if (subgraphIndex >= model->subgraphs.size())
131 {
132 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100133 fmt::format("{} was called with an invalid subgraph index. "
134 "subgraph:{} at {}",
135 location.m_Function,
136 subgraphIndex,
137 location.FileLine()));
telsoa01c577f2c2018-08-31 09:22:23 +0100138 }
139}
140
141#define CHECK_SUBGRAPH(MODEL, SUBGRAPH_INDEX) \
142 CheckSubgraph(MODEL, SUBGRAPH_INDEX, CHECK_LOCATION())
143
Mike Kelly0d77ae12022-01-07 17:42:27 +0000144void CheckModel(const TfLiteParserImpl::ModelPtr& model,
telsoa01c577f2c2018-08-31 09:22:23 +0100145 size_t subgraphIndex,
146 size_t operatorIndex,
Mike Kelly0d77ae12022-01-07 17:42:27 +0000147 const CheckLocation& location)
telsoa01c577f2c2018-08-31 09:22:23 +0100148{
149 if (model.get() == nullptr)
150 {
151 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100152 fmt::format("{} was called with invalid (null) model. "
153 "Possible reason is that the model is not yet loaded and Unpack(ed). "
154 "subgraph:{} operator:{} at {}",
155 location.m_Function,
156 subgraphIndex,
157 operatorIndex,
158 location.FileLine()));
telsoa01c577f2c2018-08-31 09:22:23 +0100159 }
160 else if (subgraphIndex >= model->subgraphs.size())
161 {
162 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100163 fmt::format("{} was called with an invalid subgraph index. "
164 "subgraph:{} operator:{} at {}",
165 location.m_Function,
166 subgraphIndex,
167 operatorIndex,
168 location.FileLine()));
telsoa01c577f2c2018-08-31 09:22:23 +0100169 }
170 else if (operatorIndex >= model->subgraphs[subgraphIndex]->operators.size() &&
171 operatorIndex != VIRTUAL_OPERATOR_ID)
172 {
173 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100174 fmt::format("{} was called with an invalid operator index. "
175 "subgraph:{} operator:{} at {}",
176 location.m_Function,
177 subgraphIndex,
178 operatorIndex,
179 location.FileLine()));
telsoa01c577f2c2018-08-31 09:22:23 +0100180 }
181}
182
183#define CHECK_MODEL(MODEL, SUBGRAPH_INDEX, OPERATOR_INDEX) \
184 CheckModel(MODEL, SUBGRAPH_INDEX, OPERATOR_INDEX, CHECK_LOCATION())
185
Mike Kelly0d77ae12022-01-07 17:42:27 +0000186void CheckTensor(const TfLiteParserImpl::ModelPtr& model,
telsoa01c577f2c2018-08-31 09:22:23 +0100187 size_t subgraphIndex,
188 size_t tensorIndex,
Mike Kelly0d77ae12022-01-07 17:42:27 +0000189 const CheckLocation& location)
telsoa01c577f2c2018-08-31 09:22:23 +0100190{
191 // not checking model, because I assume CHECK_MODEL already run
192 // and checked that. An assert would do.
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100193 ARMNN_ASSERT_MSG(model.get() != nullptr, "Expecting a valid model in this function");
telsoa01c577f2c2018-08-31 09:22:23 +0100194
195 // also subgraph index should be checked by CHECK_MODEL so
196 // I only add an assert here
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100197 ARMNN_ASSERT_MSG(subgraphIndex < model->subgraphs.size(), "Expecting a valid subgraph index");
telsoa01c577f2c2018-08-31 09:22:23 +0100198
199 // the tensor index is the only one to check here
200 if (tensorIndex >= model->subgraphs[subgraphIndex]->tensors.size())
201 {
202 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100203 fmt::format("{} was called with an invalid tensor index. "
204 "subgraph:{} tensor:{} at {}",
205 location.m_Function,
206 subgraphIndex,
207 tensorIndex,
208 location.FileLine()));
telsoa01c577f2c2018-08-31 09:22:23 +0100209 }
210}
211
212#define CHECK_TENSOR(MODEL, SUBGRAPH_INDEX, TENSOR_INDEX) \
213 CheckTensor(MODEL, SUBGRAPH_INDEX, TENSOR_INDEX, CHECK_LOCATION())
214
Kevin May7d96b162021-02-03 17:38:41 +0000215void CheckTensorPtr(TfLiteParserImpl::TensorRawPtr rawPtr,
Mike Kelly0d77ae12022-01-07 17:42:27 +0000216 const CheckLocation& location)
telsoa01c577f2c2018-08-31 09:22:23 +0100217{
218 if (rawPtr == nullptr)
219 {
220 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100221 fmt::format("{} was called with a null tensor pointer at {}", location.m_Function, location.FileLine()));
telsoa01c577f2c2018-08-31 09:22:23 +0100222 }
223}
224
225#define CHECK_TENSOR_PTR(TENSOR_PTR) \
226 CheckTensorPtr(TENSOR_PTR, CHECK_LOCATION())
227
Mike Kelly0d77ae12022-01-07 17:42:27 +0000228void CheckBuffer(const TfLiteParserImpl::ModelPtr& model,
telsoa01c577f2c2018-08-31 09:22:23 +0100229 size_t bufferIndex,
Mike Kelly0d77ae12022-01-07 17:42:27 +0000230 const CheckLocation& location)
telsoa01c577f2c2018-08-31 09:22:23 +0100231{
232 if (model.get() == nullptr)
233 {
234 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100235 fmt::format("{} was called with invalid (null) model. "
236 "Possible reason is that the model is not yet loaded and Unpack(ed). "
237 "buffer:{} at {}",
238 location.m_Function,
239 bufferIndex,
240 location.FileLine()));
telsoa01c577f2c2018-08-31 09:22:23 +0100241 }
242 else if (bufferIndex >= model->buffers.size())
243 {
244 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100245 fmt::format("{} was called with an invalid buffer index. "
246 "buffer index:{} at {}",
247 location.m_Function,
248 bufferIndex,
249 location.FileLine()));
telsoa01c577f2c2018-08-31 09:22:23 +0100250 }
251 else if (model->buffers[bufferIndex].get() == nullptr)
252 {
253 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100254 fmt::format("The buffer #{} is null. {}",
255 bufferIndex,
256 location.AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +0100257 }
258}
259
260#define CHECK_BUFFER(MODEL, BUFFER_INDEX) \
261 CheckBuffer(MODEL, BUFFER_INDEX, CHECK_LOCATION())
262
Kevin May7d96b162021-02-03 17:38:41 +0000263void CheckBufferSize(TfLiteParserImpl::BufferRawPtr bufferPtr,
Mike Kelly0d77ae12022-01-07 17:42:27 +0000264 const armnn::TensorInfo& tensorInfo,
telsoa01c577f2c2018-08-31 09:22:23 +0100265 uint32_t bufferId,
Mike Kelly0d77ae12022-01-07 17:42:27 +0000266 const CheckLocation& location)
telsoa01c577f2c2018-08-31 09:22:23 +0100267{
268 if (bufferPtr == nullptr)
269 {
270 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100271 fmt::format("BufferPtr is null for buffer:{}. {}",
272 bufferId,
273 location.AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +0100274 }
275 else if(tensorInfo.GetNumElements() > bufferPtr->data.size() ||
276 tensorInfo.GetNumBytes() > bufferPtr->data.size())
277 {
278 std::stringstream ss;
279 ss << "Buffer #" << bufferId << " has " << bufferPtr->data.size() << " bytes. "
280 << "For tensor: " << tensorInfo.GetShape()
281 << " expecting: " << tensorInfo.GetNumBytes() << " bytes and "
282 << tensorInfo.GetNumElements() << " elements. " << location.AsString();
283 throw ParseException(ss.str());
284 }
285}
286
Mike Kelly0d77ae12022-01-07 17:42:27 +0000287
288tflite::BuiltinOperator GetOpCode(const TfLiteParserImpl::ModelPtr& model, size_t subgraphIndex, size_t operatorIndex)
289{
290 const auto& operatorPtr = model->subgraphs[subgraphIndex]->operators[operatorIndex];
291 auto opcodeIndex = operatorPtr->opcode_index;
292
293// work around the introduction of the deprecated_builtin_code introduced in 2.4 in a backwards compatible manner
294#if defined(ARMNN_POST_TFLITE_2_3)
295 auto opcode = std::max(model->operator_codes[opcodeIndex]->builtin_code,
296 static_cast<tflite::BuiltinOperator>(model->operator_codes[opcodeIndex]->deprecated_builtin_code));
297#else
298 auto opcode = model->operator_codes[opcodeIndex]->builtin_code;
299#endif
300 return opcode;
301}
302
303std::vector<unsigned int> GetUIntBuffer(armnn::TensorInfo info,
304 const TfLiteParserImpl::ModelPtr& model,
305 size_t bufferIndex)
306{
307 TfLiteParserImpl::BufferRawPtr bufferPtr = TfLiteParserImpl::GetBuffer(model, bufferIndex);
308 std::vector<unsigned int> buffer(info.GetNumElements());
309
310 if (info.GetDataType() == DataType::Signed32)
311 {
312 ::memcpy(buffer.data(), bufferPtr->data.data(), bufferPtr->data.size());
313 }
314 else if (info.GetDataType() == DataType::Signed64)
315 {
316 std::vector<uint64_t> uint64Buffer(info.GetNumElements());
317 ::memcpy(uint64Buffer.data(), bufferPtr->data.data(), bufferPtr->data.size());
318 buffer.assign(std::begin(uint64Buffer), std::end(uint64Buffer));
319 }
Mike Kelly0506ef02023-01-03 16:29:44 +0000320 else
321 {
322 CheckLocation location = CHECK_LOCATION();
323 throw ParseException(
324 fmt::format("Unsupported data type for uint buffer {}, only Signed 32 or Signed 64 are supported. {}",
325 GetDataTypeName(info.GetDataType()),
326 location.AsString()));
327 }
Mike Kelly0d77ae12022-01-07 17:42:27 +0000328 return buffer;
329}
330
telsoa01c577f2c2018-08-31 09:22:23 +0100331#define CHECK_BUFFER_SIZE(BUFFER_PTR, TENSOR_INFO, BUFFER_ID) \
332 CheckBufferSize(BUFFER_PTR, TENSOR_INFO, BUFFER_ID, CHECK_LOCATION())
333
334bool IsActivationSupported(tflite::ActivationFunctionType activationType)
335{
336 switch(activationType)
337 {
338 case tflite::ActivationFunctionType_NONE:
339 case tflite::ActivationFunctionType_RELU:
340 case tflite::ActivationFunctionType_RELU6:
341 case tflite::ActivationFunctionType_TANH:
342 {
343 return true;
344 }
345 default:
346 {
347 return false;
348 }
349 }
350}
351
352#define CHECK_SUPPORTED_FUSED_ACTIVATION(OPTION, SUBGRAPH_INDEX, OPERATOR_INDEX) \
353 do { \
354 if (IsActivationSupported(OPTION->fused_activation_function) == false) \
355 { \
356 throw ParseException( \
Mike Kelly377fb212023-01-10 15:55:28 +0000357 fmt::format("TfLite parser doesn't support fused activation: " \
James Ward58dec6b2020-09-11 17:32:44 +0100358 "{}/{} in {} subgraph:{} operator:{} at {}", \
359 OPTION->fused_activation_function, \
360 tflite::EnumNameActivationFunctionType(\
361 OPTION->fused_activation_function), \
362 __func__, \
363 SUBGRAPH_INDEX, \
364 OPERATOR_INDEX, \
365 CHECK_LOCATION().FileLine())); \
telsoa01c577f2c2018-08-31 09:22:23 +0100366 } \
367 } while(false)
368
369
Mike Kelly0d77ae12022-01-07 17:42:27 +0000370std::vector<unsigned int> AsUnsignedVector(const std::vector<int32_t>& in)
telsoa01c577f2c2018-08-31 09:22:23 +0100371{
372 std::vector<unsigned int> result;
373 result.reserve(in.size());
Mike Kelly0d77ae12022-01-07 17:42:27 +0000374 for (auto& i : in)
telsoa01c577f2c2018-08-31 09:22:23 +0100375 {
mathad01c21025d2021-04-26 10:09:37 +0100376 // If the location of the input data is -1 then the input should be ignored.
377 if (i == -1)
378 {
379 continue;
380 }
telsoa01c577f2c2018-08-31 09:22:23 +0100381 result.push_back(CHECKED_NON_NEGATIVE(i));
382 }
383 return result;
384}
385
Mike Kelly5880b912022-01-28 16:18:54 +0000386bool IsOptionalOperandPresent(int input)
387{
388 return (input >= 0);
389}
390
telsoa01c577f2c2018-08-31 09:22:23 +0100391void CalcPadding(uint32_t inputSize,
392 uint32_t filterSize,
393 uint32_t stride,
Pablo Tellof0bd6832019-04-26 17:58:13 +0100394 uint32_t dilation,
telsoa01c577f2c2018-08-31 09:22:23 +0100395 uint32_t& paddingFront,
396 uint32_t& paddingBack,
397 tflite::Padding padding)
398{
399 paddingFront = 0;
400 paddingBack = 0;
401 if (padding == tflite::Padding_SAME)
402 {
403 uint32_t outputSize = (inputSize + stride - 1) / stride;
Pablo Tellof0bd6832019-04-26 17:58:13 +0100404 uint32_t dilatedSize = filterSize + (dilation - 1) * (filterSize - 1);
405 uint32_t temp = (outputSize - 1) * stride + dilatedSize;
telsoa01c577f2c2018-08-31 09:22:23 +0100406 if (temp > inputSize)
407 {
408 paddingFront = (temp - inputSize) / 2;
409 paddingBack = (temp - inputSize) - paddingFront;
410 }
411 }
412}
413
Teresa Charlin024ef0b2023-04-26 11:19:03 +0100414// Function that calculates explicit padding when the output shape is known.
415// At the moment the output is only given as an input parameter in Transpose Convolution,
416// not in Convolution and Depthwise Convolution
417void CalcPadding(uint32_t inputSize,
418 uint32_t filterSize,
419 uint32_t stride,
420 uint32_t dilation,
421 uint32_t& paddingFront,
422 uint32_t& paddingBack,
423 tflite::Padding padding,
424 uint32_t outputSize)
425{
426 IgnoreUnused(dilation);
427 paddingFront = 0;
428 paddingBack = 0;
429 if (padding == tflite::Padding_SAME)
430 {
431 uint32_t totalPadding = (inputSize - 1) * stride + filterSize - outputSize;
432 paddingFront = totalPadding / 2;
433 paddingBack = totalPadding - paddingFront;
434 }
435}
436
Kevin May7d96b162021-02-03 17:38:41 +0000437armnn::TensorInfo ToTensorInfo(TfLiteParserImpl::TensorRawPtr tensorPtr,
Finn Williamsb49ed182021-06-29 15:50:08 +0100438 const std::vector<unsigned int>& shape,
Sadik Armagand109a4d2020-07-28 10:42:13 +0100439 const bool outputTensor = false)
telsoa01c577f2c2018-08-31 09:22:23 +0100440{
441 armnn::DataType type;
442 CHECK_TENSOR_PTR(tensorPtr);
443
444 switch (tensorPtr->type)
445 {
446 case tflite::TensorType_UINT8:
Derek Lambertif90c56d2020-01-10 17:14:08 +0000447 type = armnn::DataType::QAsymmU8;
telsoa01c577f2c2018-08-31 09:22:23 +0100448 break;
449 case tflite::TensorType_FLOAT32:
450 type = armnn::DataType::Float32;
451 break;
Keith Davisb4dd5cc2022-04-07 11:32:00 +0100452 case tflite::TensorType_FLOAT16:
453 type = armnn::DataType::Float16;
454 break;
Finn Williamsed66d142019-12-06 09:55:55 +0000455 case tflite::TensorType_INT8:
Keith Davis67e6c542020-02-19 10:08:33 +0000456 if (tensorPtr->quantization->zero_point.size() == 1)
Ryan OShea03181ff2020-02-07 17:22:22 +0000457 {
Keith Davis0c2eeac2020-02-11 16:51:50 +0000458 // Per-tensor
Ryan OShea03181ff2020-02-07 17:22:22 +0000459 type = armnn::DataType::QAsymmS8;
460 }
461 else
462 {
Keith Davis0c2eeac2020-02-11 16:51:50 +0000463 // Per-channel
Ryan OShea03181ff2020-02-07 17:22:22 +0000464 type = armnn::DataType::QSymmS8;
465 }
Finn Williamsed66d142019-12-06 09:55:55 +0000466 break;
467 case tflite::TensorType_INT16:
Derek Lambertif90c56d2020-01-10 17:14:08 +0000468 type = armnn::DataType::QSymmS16;
Finn Williamsed66d142019-12-06 09:55:55 +0000469 break;
telsoa01c577f2c2018-08-31 09:22:23 +0100470 case tflite::TensorType_INT32:
471 type = armnn::DataType::Signed32;
472 break;
Inki Daed4619e22020-09-10 15:33:54 +0900473 case tflite::TensorType_INT64:
474 type = armnn::DataType::Signed64;
475 break;
Matthew Sloyaned7fce42021-04-15 20:46:24 +0100476 case tflite::TensorType_BOOL:
477 type = armnn::DataType::Boolean;
478 break;
telsoa01c577f2c2018-08-31 09:22:23 +0100479 default:
480 {
481 CheckLocation location = CHECK_LOCATION();
482 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100483 fmt::format("Unsupported data type {} = {} for tensor: {}. {}",
484 tensorPtr->type,
485 tflite::EnumNameTensorType(tensorPtr->type),
486 tensorPtr->name,
487 location.AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +0100488 }
489 }
Finn Williamsb49ed182021-06-29 15:50:08 +0100490 TensorShape tensorShape;
491
492 std::vector<unsigned int> safeShape = shape;
493 if (shape.size() == 0)
Narumol Prangnawarat4818d462019-04-17 11:22:38 +0100494 {
495 safeShape.push_back(1);
Finn Williamsb49ed182021-06-29 15:50:08 +0100496 }
497
498 if (!outputTensor)
499 {
500 tensorShape = TensorShape(armnn::numeric_cast<unsigned int>(safeShape.size()), safeShape.data());
501 }
502 else
503 {
Rob Hughesd812a312021-08-06 13:10:53 +0100504 size_t shapeSignatureSize = tensorPtr->shape_signature.size();
Finn Williamsb49ed182021-06-29 15:50:08 +0100505
506 // If a shape signature exists we will use that to infer dynamic tensors
507 if (shapeSignatureSize != 0)
Sadik Armagand109a4d2020-07-28 10:42:13 +0100508 {
Finn Williamsb49ed182021-06-29 15:50:08 +0100509 // If the shape is incompatible with the shape signature override the shape
510 if (shapeSignatureSize != shape.size())
511 {
512 safeShape = {};
513
514 for (unsigned int i = 0; i < shapeSignatureSize; ++i)
515 {
516 unsigned int dim = tensorPtr->shape_signature[i] > -1 ?
517 static_cast<unsigned int>(tensorPtr->shape_signature[i]) : 0;
518 safeShape.push_back(dim);
519 }
520 }
521
Rob Hughesd812a312021-08-06 13:10:53 +0100522 std::unique_ptr<bool[]> dimMask = std::make_unique<bool[]>(tensorPtr->shape_signature.size());
Mike Kelly04d82292023-01-19 18:29:40 +0000523 bool batchOnly = true;
Finn Williamsb49ed182021-06-29 15:50:08 +0100524 for (unsigned int i = 0; i < tensorPtr->shape_signature.size(); ++i)
525 {
Mike Kelly04d82292023-01-19 18:29:40 +0000526 dimMask[i] = tensorPtr->shape_signature[i] != -1;
527
528 if (i > 0 && !dimMask[i])
529 {
530 batchOnly = false;
531 }
532 }
533 if (batchOnly)
534 {
535 dimMask[0] = true;
Finn Williamsb49ed182021-06-29 15:50:08 +0100536 }
Rob Hughesd812a312021-08-06 13:10:53 +0100537 tensorShape = TensorShape(static_cast<unsigned int>(safeShape.size()), safeShape.data(), dimMask.get());
Finn Williamsb49ed182021-06-29 15:50:08 +0100538 }
539 // If there is no shape signature treat the tensor as dynamic if the shape has a size of zero
540 else if (shape.size() == 0)
541 {
542 tensorShape = TensorShape(1, false);
543 }
544 else
545 {
546 tensorShape = TensorShape(armnn::numeric_cast<unsigned int>(shape.size()), shape.data());
Sadik Armagand109a4d2020-07-28 10:42:13 +0100547 }
Narumol Prangnawarat4818d462019-04-17 11:22:38 +0100548 }
549
Teresa Charlinacb3ec52023-04-03 19:57:00 +0100550 float quantizationScale = 1.0f;
Keith Davisd305e1a2020-01-22 11:57:54 +0000551 int32_t quantizationOffset = 0;
552
553 if (tensorPtr->quantization.get())
554 {
555 if (tensorPtr->quantization->scale.size() <= 1)
556 {
557 CHECK_VALID_SIZE(tensorPtr->quantization->zero_point.size(), 0, 1);
558 CHECK_VALID_SIZE(tensorPtr->quantization->zero_point.size(), 0, 1);
559
560 if (tensorPtr->quantization->scale.size() == 1)
561 {
562 quantizationScale = tensorPtr->quantization->scale[0];
563 }
564 if (tensorPtr->quantization->zero_point.size() == 1)
565 {
566 // NOTE: we lose precision here when converting from 64 bit to 32
Ryan OShea03181ff2020-02-07 17:22:22 +0000567 // but this is what we support at the moment in ArmNN
Matthew Sloyan589e3e82020-09-11 16:17:48 +0100568 quantizationOffset = armnn::numeric_cast<int32_t>(tensorPtr->quantization->zero_point[0]);
Keith Davisd305e1a2020-01-22 11:57:54 +0000569 }
570
Sadik Armagand109a4d2020-07-28 10:42:13 +0100571 armnn::TensorInfo result(tensorShape,
572 type,
573 quantizationScale,
574 quantizationOffset);
Keith Davisd305e1a2020-01-22 11:57:54 +0000575 return result;
576 }
577 else
578 {
579 std::vector<float> quantizationScales;
580 std::vector<int32_t> quantizationOffsets;
581
582 // Scale
583 std::copy(tensorPtr->quantization->scale.begin(),
584 tensorPtr->quantization->scale.end(),
585 std::back_inserter(quantizationScales));
586
Keith Davis0c2eeac2020-02-11 16:51:50 +0000587 // QSymmS8 Per-axis
Sadik Armagand109a4d2020-07-28 10:42:13 +0100588 armnn::TensorInfo result(tensorShape,
589 type,
590 quantizationScales,
Jan Eilers7612bd62021-04-06 17:29:03 +0100591 armnn::numeric_cast<unsigned int>(tensorPtr->quantization->quantized_dimension));
Keith Davisd305e1a2020-01-22 11:57:54 +0000592 return result;
593 }
594 }
595 else
596 {
Sadik Armagand109a4d2020-07-28 10:42:13 +0100597 armnn::TensorInfo result(tensorShape,
Keith Davisd305e1a2020-01-22 11:57:54 +0000598 type,
599 quantizationScale,
600 quantizationOffset);
601 return result;
602 }
telsoa01c577f2c2018-08-31 09:22:23 +0100603}
604
Kevin May7d96b162021-02-03 17:38:41 +0000605armnn::TensorInfo ToTensorInfo(TfLiteParserImpl::TensorRawPtr tensorPtr,
Mike Kelly377fb212023-01-10 15:55:28 +0000606 const bool outputTensor = false)
Sadik Armagand109a4d2020-07-28 10:42:13 +0100607{
Mike Kelly0d77ae12022-01-07 17:42:27 +0000608 auto const& dimensions = AsUnsignedVector(tensorPtr->shape);
Jan Eilers7612bd62021-04-06 17:29:03 +0100609 return ToTensorInfo(tensorPtr, dimensions, outputTensor);
Sadik Armagand109a4d2020-07-28 10:42:13 +0100610}
611
telsoa01c577f2c2018-08-31 09:22:23 +0100612template<typename T>
613std::pair<armnn::ConstTensor, std::unique_ptr<T[]>>
Kevin May7d96b162021-02-03 17:38:41 +0000614CreateConstTensorImpl(TfLiteParserImpl::BufferRawPtr bufferPtr,
615 TfLiteParserImpl::TensorRawPtr tensorPtr,
Matteo Martincigh747ef822018-12-18 09:26:39 +0000616 armnn::TensorInfo& tensorInfo,
617 armnn::Optional<armnn::PermutationVector&> permutationVector)
telsoa01c577f2c2018-08-31 09:22:23 +0100618{
Jan Eilers8eb25602020-03-09 12:13:48 +0000619 IgnoreUnused(tensorPtr);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100620 ARMNN_ASSERT_MSG(tensorPtr != nullptr, "tensorPtr is null");
621 ARMNN_ASSERT_MSG(bufferPtr != nullptr,
James Ward58dec6b2020-09-11 17:32:44 +0100622 fmt::format("Buffer for buffer:{} is null", tensorPtr->buffer).c_str());
telsoa01c577f2c2018-08-31 09:22:23 +0100623
624 std::unique_ptr<T[]> data(new T[tensorInfo.GetNumElements()]);
Matteo Martincigh747ef822018-12-18 09:26:39 +0000625
626 if (permutationVector.has_value() && permutationVector.value().GetSize() > 0)
627 {
628 tensorInfo = armnnUtils::Permuted(tensorInfo, permutationVector.value());
Matteo Martincighd5b9e642019-01-04 18:01:21 +0000629 armnnUtils::Permute(tensorInfo.GetShape(), permutationVector.value(),
630 reinterpret_cast<const T*>(bufferPtr->data.data()), data.get(), sizeof(T));
Matteo Martincigh747ef822018-12-18 09:26:39 +0000631 }
632 else
633 {
634 ::memcpy(data.get(), bufferPtr->data.data(), tensorInfo.GetNumBytes());
635 }
636
Matthew Sloyan81beae32021-07-13 19:46:11 +0100637 // Make sure isConstant flag is set.
638 tensorInfo.SetConstant();
639
telsoa01c577f2c2018-08-31 09:22:23 +0100640 return std::make_pair(ConstTensor(tensorInfo, data.get()), std::move(data));
641}
642
telsoa01c577f2c2018-08-31 09:22:23 +0100643armnn::LayerBindingId GenerateLayerBindingId(size_t subgraphIndex, size_t tensorIndex)
644{
645 // generate the binding id by shifting the tensor id by 8 bit
646 // and add the subgraph id, which allows 256 subgraphs
647 return static_cast<armnn::LayerBindingId>((tensorIndex<<8)+subgraphIndex);
648}
649
Aron Virginas-Tar70672f62019-01-23 14:00:00 +0000650bool CheckShape(const armnn::TensorShape& actual, const std::vector<int32_t>& expected)
651{
652 const unsigned int actualSize = actual.GetNumDimensions();
653 if (actualSize != expected.size())
654 {
655 return false;
656 }
657
658 for (unsigned int i = 0u; i < actualSize; i++)
659 {
660 if (expected[i] < 0 ||
661 actual[i] != static_cast<unsigned int>(expected[i]))
662 {
663 return false;
664 }
665 }
666
667 return true;
668}
669
Cathal Corbett2b922e22022-09-23 15:49:24 +0100670bool CheckShape(const armnn::TensorShape& actual, const armnn::TensorShape& expected)
671{
672 std::vector<int32_t> expectedVec;
673 for (uint32_t i = 0; i < expected.GetNumDimensions(); i++)
674 {
675 expectedVec.push_back(expected[i]);
676 }
677 return CheckShape(actual, expectedVec);
678}
679
James Conroy05102392020-06-24 15:39:55 +0100680void CheckMatchingQuantization(const TensorInfo& first,
681 const TensorInfo& second,
682 const std::string& descName,
683 std::string const& firstName,
684 std::string const& secondName)
685{
686 if (!first.IsQuantized() ||
687 !second.IsQuantized())
688 {
689 // Not a quantized type, ignore the validation
690 return;
691 }
692
693 DataType firstDataType = first.GetDataType();
694 DataType secondDataType = second.GetDataType();
695
696 if (firstDataType != secondDataType)
697 {
698 throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
699 " must be of the same quantized type, " +
700 firstName + " is " + GetDataTypeName(firstDataType) + ", " +
701 secondName + " is " + GetDataTypeName(secondDataType));
702 }
703
704 if (!first.IsTypeSpaceMatch(second))
705 {
706 throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
707 " must have the same quantization space, " +
708 firstName + " has offset " + std::to_string(first.GetQuantizationOffset()) +
709 " and scale " + std::to_string(first.GetQuantizationScale()) + ", " +
710 secondName + " has offset " + std::to_string(second.GetQuantizationOffset()) +
711 " and scale " + std::to_string(second.GetQuantizationScale()));
712 }
713}
714
Mike Kelly377fb212023-01-10 15:55:28 +0000715bool IsDynamic(TfLiteParserImpl::TensorRawPtr tensorPtr)
716{
717 auto shape = tensorPtr->shape;
718
719 if (shape.empty())
720 {
721 return true;
722 }
723 auto shapeSig = tensorPtr->shape_signature;
724
725 if (shapeSig.empty())
726 {
727 return false;
728 }
729
730 for (unsigned int i = 0; i < shapeSig.size() ; ++i)
731 {
732 if (shapeSig[i] == -1)
733 {
734 return true;
735 }
736 }
737 return false;
738}
739
telsoa01c577f2c2018-08-31 09:22:23 +0100740} // <anonymous>
741
Kevin May7d96b162021-02-03 17:38:41 +0000742TfLiteParserImpl::TfLiteParserImpl(const Optional<ITfLiteParser::TfLiteParserOptions>& options)
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100743: m_Options(options)
744, m_Network(nullptr, nullptr)
Kevin May7d96b162021-02-03 17:38:41 +0000745, m_ParserFunctions(tflite::BuiltinOperator_MAX+1, &TfLiteParserImpl::ParseUnsupportedOperator)
telsoa01c577f2c2018-08-31 09:22:23 +0100746{
747 // register supported operators
Matthew Sloyaned7fce42021-04-15 20:46:24 +0100748 m_ParserFunctions[tflite::BuiltinOperator_ABS] = &TfLiteParserImpl::ParseAbs;
Kevin May7d96b162021-02-03 17:38:41 +0000749 m_ParserFunctions[tflite::BuiltinOperator_ADD] = &TfLiteParserImpl::ParseAdd;
Matthew Sloyan28f177c2021-04-09 14:38:52 +0100750 m_ParserFunctions[tflite::BuiltinOperator_ARG_MIN] = &TfLiteParserImpl::ParseArgMin;
751 m_ParserFunctions[tflite::BuiltinOperator_ARG_MAX] = &TfLiteParserImpl::ParseArgMax;
Kevin May7d96b162021-02-03 17:38:41 +0000752 m_ParserFunctions[tflite::BuiltinOperator_AVERAGE_POOL_2D] = &TfLiteParserImpl::ParseAveragePool2D;
753 m_ParserFunctions[tflite::BuiltinOperator_BATCH_TO_SPACE_ND] = &TfLiteParserImpl::ParseBatchToSpaceND;
Samuel Yapfd3ba5a2022-08-24 17:04:34 +0100754 m_ParserFunctions[tflite::BuiltinOperator_BATCH_MATMUL] = &TfLiteParserImpl::ParseBatchMatMul;
Teresa Charlin93f0ad02023-03-23 15:28:02 +0000755 m_ParserFunctions[tflite::BuiltinOperator_CEIL] = &TfLiteParserImpl::ParseCeil;
mathad01b392e982021-04-07 12:07:30 +0100756 m_ParserFunctions[tflite::BuiltinOperator_CAST] = &TfLiteParserImpl::ParseCast;
Kevin May7d96b162021-02-03 17:38:41 +0000757 m_ParserFunctions[tflite::BuiltinOperator_CONCATENATION] = &TfLiteParserImpl::ParseConcatenation;
758 m_ParserFunctions[tflite::BuiltinOperator_CONV_2D] = &TfLiteParserImpl::ParseConv2D;
Matthew Sloyan4d217c02021-10-07 11:48:58 +0100759 // Conv3D support was added in TF 2.5, so for backwards compatibility a hash define is needed.
Cathal Corbett80b4ef02022-05-25 11:21:11 +0100760 #if defined(ARMNN_POST_TFLITE_2_4)
Matthew Sloyaneb5f8102021-10-05 17:31:42 +0100761 m_ParserFunctions[tflite::BuiltinOperator_CONV_3D] = &TfLiteParserImpl::ParseConv3D;
Matthew Sloyan4d217c02021-10-07 11:48:58 +0100762 #endif
Kevin May7d96b162021-02-03 17:38:41 +0000763 m_ParserFunctions[tflite::BuiltinOperator_CUSTOM] = &TfLiteParserImpl::ParseCustomOperator;
764 m_ParserFunctions[tflite::BuiltinOperator_DEPTH_TO_SPACE] = &TfLiteParserImpl::ParseDepthToSpace;
765 m_ParserFunctions[tflite::BuiltinOperator_DEPTHWISE_CONV_2D] = &TfLiteParserImpl::ParseDepthwiseConv2D;
766 m_ParserFunctions[tflite::BuiltinOperator_DEQUANTIZE] = &TfLiteParserImpl::ParseDequantize;
Matthew Sloyan28f177c2021-04-09 14:38:52 +0100767 m_ParserFunctions[tflite::BuiltinOperator_DIV] = &TfLiteParserImpl::ParseDiv;
Kevin May7d96b162021-02-03 17:38:41 +0000768 m_ParserFunctions[tflite::BuiltinOperator_ELU] = &TfLiteParserImpl::ParseElu;
Bruno Goncalves2d0eb862021-07-11 14:10:15 -0300769 m_ParserFunctions[tflite::BuiltinOperator_EQUAL] = &TfLiteParserImpl::ParseEqual;
Kevin May7d96b162021-02-03 17:38:41 +0000770 m_ParserFunctions[tflite::BuiltinOperator_EXP] = &TfLiteParserImpl::ParseExp;
Teresa Charlin3ab85482021-06-08 16:59:29 +0100771 m_ParserFunctions[tflite::BuiltinOperator_EXPAND_DIMS] = &TfLiteParserImpl::ParseExpandDims;
Teresa Charlincdbd40b2022-02-25 13:21:55 +0000772 m_ParserFunctions[tflite::BuiltinOperator_FLOOR_DIV] = &TfLiteParserImpl::ParseFloorDiv;
Kevin May7d96b162021-02-03 17:38:41 +0000773 m_ParserFunctions[tflite::BuiltinOperator_FULLY_CONNECTED] = &TfLiteParserImpl::ParseFullyConnected;
774 m_ParserFunctions[tflite::BuiltinOperator_GATHER] = &TfLiteParserImpl::ParseGather;
Teresa Charlin91a53ea2022-04-25 15:47:29 +0100775 m_ParserFunctions[tflite::BuiltinOperator_GATHER_ND] = &TfLiteParserImpl::ParseGatherNd;
Bruno Goncalves2d0eb862021-07-11 14:10:15 -0300776 m_ParserFunctions[tflite::BuiltinOperator_GREATER] = &TfLiteParserImpl::ParseGreater;
777 m_ParserFunctions[tflite::BuiltinOperator_GREATER_EQUAL] = &TfLiteParserImpl::ParseGreaterOrEqual;
Kevin May7d96b162021-02-03 17:38:41 +0000778 m_ParserFunctions[tflite::BuiltinOperator_HARD_SWISH] = &TfLiteParserImpl::ParseHardSwish;
779 m_ParserFunctions[tflite::BuiltinOperator_LEAKY_RELU] = &TfLiteParserImpl::ParseLeakyRelu;
Bruno Goncalves2d0eb862021-07-11 14:10:15 -0300780 m_ParserFunctions[tflite::BuiltinOperator_LESS] = &TfLiteParserImpl::ParseLess;
781 m_ParserFunctions[tflite::BuiltinOperator_LESS_EQUAL] = &TfLiteParserImpl::ParseLessOrEqual;
Mike Kelly31dce2b2021-09-01 21:22:37 +0100782 m_ParserFunctions[tflite::BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION]
783 = &TfLiteParserImpl::ParseLocalResponseNormalization;
Teresa Charlin28aa6692022-07-12 11:18:44 +0100784 m_ParserFunctions[tflite::BuiltinOperator_LOG] = &TfLiteParserImpl::ParseLog;
Matthew Sloyaned7fce42021-04-15 20:46:24 +0100785 m_ParserFunctions[tflite::BuiltinOperator_LOGICAL_NOT] = &TfLiteParserImpl::ParseLogicalNot;
Kevin May7d96b162021-02-03 17:38:41 +0000786 m_ParserFunctions[tflite::BuiltinOperator_LOGISTIC] = &TfLiteParserImpl::ParseLogistic;
Teresa Charlinfd33a692022-06-29 15:35:57 +0100787 m_ParserFunctions[tflite::BuiltinOperator_LOG_SOFTMAX] = &TfLiteParserImpl::ParseLogSoftmax;
Kevin May7d96b162021-02-03 17:38:41 +0000788 m_ParserFunctions[tflite::BuiltinOperator_L2_NORMALIZATION] = &TfLiteParserImpl::ParseL2Normalization;
789 m_ParserFunctions[tflite::BuiltinOperator_MAX_POOL_2D] = &TfLiteParserImpl::ParseMaxPool2D;
790 m_ParserFunctions[tflite::BuiltinOperator_MAXIMUM] = &TfLiteParserImpl::ParseMaximum;
791 m_ParserFunctions[tflite::BuiltinOperator_MEAN] = &TfLiteParserImpl::ParseMean;
792 m_ParserFunctions[tflite::BuiltinOperator_MINIMUM] = &TfLiteParserImpl::ParseMinimum;
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +0100793 m_ParserFunctions[tflite::BuiltinOperator_MIRROR_PAD] = &TfLiteParserImpl::ParseMirrorPad;
Kevin May7d96b162021-02-03 17:38:41 +0000794 m_ParserFunctions[tflite::BuiltinOperator_MUL] = &TfLiteParserImpl::ParseMul;
795 m_ParserFunctions[tflite::BuiltinOperator_NEG] = &TfLiteParserImpl::ParseNeg;
Bruno Goncalves2d0eb862021-07-11 14:10:15 -0300796 m_ParserFunctions[tflite::BuiltinOperator_NOT_EQUAL] = &TfLiteParserImpl::ParseNotEqual;
Kevin May7d96b162021-02-03 17:38:41 +0000797 m_ParserFunctions[tflite::BuiltinOperator_PACK] = &TfLiteParserImpl::ParsePack;
798 m_ParserFunctions[tflite::BuiltinOperator_PAD] = &TfLiteParserImpl::ParsePad;
Mike Kelly0d77ae12022-01-07 17:42:27 +0000799 m_ParserFunctions[tflite::BuiltinOperator_PADV2] = &TfLiteParserImpl::ParsePad;
John Mcloughlin0ec00872023-05-15 17:03:49 +0100800 m_ParserFunctions[tflite::BuiltinOperator_POW] = &TfLiteParserImpl::ParsePower;
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +0100801 m_ParserFunctions[tflite::BuiltinOperator_PRELU] = &TfLiteParserImpl::ParsePrelu;
Kevin May7d96b162021-02-03 17:38:41 +0000802 m_ParserFunctions[tflite::BuiltinOperator_QUANTIZE] = &TfLiteParserImpl::ParseQuantize;
803 m_ParserFunctions[tflite::BuiltinOperator_RELU] = &TfLiteParserImpl::ParseRelu;
804 m_ParserFunctions[tflite::BuiltinOperator_RELU6] = &TfLiteParserImpl::ParseRelu6;
Sadik Armagana2747482021-02-09 10:28:54 +0000805 m_ParserFunctions[tflite::BuiltinOperator_REDUCE_MAX] = &TfLiteParserImpl::ParseReduceMax;
806 m_ParserFunctions[tflite::BuiltinOperator_REDUCE_MIN] = &TfLiteParserImpl::ParseReduceMin;
Teresa Charlin4e3e8312021-08-05 12:34:37 +0100807 m_ParserFunctions[tflite::BuiltinOperator_REDUCE_PROD] = &TfLiteParserImpl::ParseReduceProd;
Kevin May7d96b162021-02-03 17:38:41 +0000808 m_ParserFunctions[tflite::BuiltinOperator_RESHAPE] = &TfLiteParserImpl::ParseReshape;
809 m_ParserFunctions[tflite::BuiltinOperator_RESIZE_BILINEAR] = &TfLiteParserImpl::ParseResizeBilinear;
810 m_ParserFunctions[tflite::BuiltinOperator_RESIZE_NEAREST_NEIGHBOR] = &TfLiteParserImpl::ParseResizeNearestNeighbor;
Tianle Chenge5a30ff2023-07-03 11:24:12 +0100811 m_ParserFunctions[tflite::BuiltinOperator_REVERSE_V2] = &TfLiteParserImpl::ParseReverseV2;
Matthew Sloyaned7fce42021-04-15 20:46:24 +0100812 m_ParserFunctions[tflite::BuiltinOperator_RSQRT] = &TfLiteParserImpl::ParseRsqrt;
Teresa Charlinf0fce5b2022-05-04 17:24:43 +0100813 m_ParserFunctions[tflite::BuiltinOperator_SQRT] = &TfLiteParserImpl::ParseSqrt;
Keith Davis0176fd82021-06-01 17:36:32 +0100814 m_ParserFunctions[tflite::BuiltinOperator_SHAPE] = &TfLiteParserImpl::ParseShape;
Teresa Charlin28aa6692022-07-12 11:18:44 +0100815 m_ParserFunctions[tflite::BuiltinOperator_SIN] = &TfLiteParserImpl::ParseSin;
Kevin May7d96b162021-02-03 17:38:41 +0000816 m_ParserFunctions[tflite::BuiltinOperator_SLICE] = &TfLiteParserImpl::ParseSlice;
817 m_ParserFunctions[tflite::BuiltinOperator_SOFTMAX] = &TfLiteParserImpl::ParseSoftmax;
818 m_ParserFunctions[tflite::BuiltinOperator_SPACE_TO_BATCH_ND] = &TfLiteParserImpl::ParseSpaceToBatchND;
Teresa Charlin2a764ad2023-02-24 18:17:31 +0000819 m_ParserFunctions[tflite::BuiltinOperator_SPACE_TO_DEPTH] = &TfLiteParserImpl::ParseSpaceToDepth;
Kevin May7d96b162021-02-03 17:38:41 +0000820 m_ParserFunctions[tflite::BuiltinOperator_SPLIT] = &TfLiteParserImpl::ParseSplit;
821 m_ParserFunctions[tflite::BuiltinOperator_SPLIT_V] = &TfLiteParserImpl::ParseSplitV;
822 m_ParserFunctions[tflite::BuiltinOperator_SQUEEZE] = &TfLiteParserImpl::ParseSqueeze;
Teresa Charlin6963b332023-07-11 11:35:41 +0100823 m_ParserFunctions[tflite::BuiltinOperator_SQUARE] = &TfLiteParserImpl::ParseSquare;
John Mcloughlin0ec00872023-05-15 17:03:49 +0100824 m_ParserFunctions[tflite::BuiltinOperator_SQUARED_DIFFERENCE] = &TfLiteParserImpl::ParseSquaredDifference;
Kevin May7d96b162021-02-03 17:38:41 +0000825 m_ParserFunctions[tflite::BuiltinOperator_STRIDED_SLICE] = &TfLiteParserImpl::ParseStridedSlice;
826 m_ParserFunctions[tflite::BuiltinOperator_SUB] = &TfLiteParserImpl::ParseSub;
827 m_ParserFunctions[tflite::BuiltinOperator_SUM] = &TfLiteParserImpl::ParseSum;
828 m_ParserFunctions[tflite::BuiltinOperator_TANH] = &TfLiteParserImpl::ParseTanH;
Teresa Charlin777008b2023-07-26 10:07:55 +0100829 m_ParserFunctions[tflite::BuiltinOperator_TILE] = &TfLiteParserImpl::ParseTile;
Kevin May7d96b162021-02-03 17:38:41 +0000830 m_ParserFunctions[tflite::BuiltinOperator_TRANSPOSE] = &TfLiteParserImpl::ParseTranspose;
831 m_ParserFunctions[tflite::BuiltinOperator_TRANSPOSE_CONV] = &TfLiteParserImpl::ParseTransposeConv;
Mike Kelly5880b912022-01-28 16:18:54 +0000832 m_ParserFunctions[tflite::BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM]
833 = &TfLiteParserImpl::ParseUnidirectionalSequenceLSTM;
Kevin May7d96b162021-02-03 17:38:41 +0000834 m_ParserFunctions[tflite::BuiltinOperator_UNPACK] = &TfLiteParserImpl::ParseUnpack;
Matthew Sloyan28f177c2021-04-09 14:38:52 +0100835
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100836 // register supported custom operators
Kevin May7d96b162021-02-03 17:38:41 +0000837 m_CustomParserFunctions["TFLite_Detection_PostProcess"] = &TfLiteParserImpl::ParseDetectionPostProcess;
telsoa01c577f2c2018-08-31 09:22:23 +0100838}
839
Mike Kelly377fb212023-01-10 15:55:28 +0000840armnn::TensorInfo TfLiteParserImpl::InputTensorInfo(size_t subgraphIndex,
841 size_t operatorIndex,
842 int input)
843{
844 const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex];
845 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
846
847 uint32_t inputId = CHECKED_NON_NEGATIVE(operatorPtr->inputs[input]);
848 auto search = armnnTfLiteParser::TfLiteParserImpl::m_TensorInfos.find(inputId);
849
850 if (search != m_TensorInfos.end())
851 {
852 return m_TensorInfos[inputId];
853 }
854 else
855 {
856 auto tensorInfo = ::armnnTfLiteParser::ToTensorInfo(subgraphPtr->tensors[inputId].get());
857 m_TensorInfos.insert({ inputId, tensorInfo });
858 return tensorInfo;
859 }
860}
861
862armnn::TensorInfo TfLiteParserImpl::OutputTensorInfoFromInputs(size_t subgraphIndex,
863 size_t operatorIndex,
864 armnn::IConnectableLayer* layer,
865 int output,
866 std::vector<int> inputs)
867{
868 const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex];
869 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
870
871 uint32_t outputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[output]);
872
873 auto outputSearch = armnnTfLiteParser::TfLiteParserImpl::m_TensorInfos.find(outputId);
874
875 if (outputSearch != m_TensorInfos.end())
876 {
877 return m_TensorInfos[outputId];
878 }
879
880 const auto& outputTensorPtr = subgraphPtr->tensors[outputId].get();
881 TensorInfo tensor = ::armnnTfLiteParser::ToTensorInfo(outputTensorPtr, true);
882
883 if (IsDynamic(outputTensorPtr))
884 {
885 if (inputs.empty())
886 {
887 for (unsigned int i = 0; i < layer->GetNumInputSlots(); ++i)
888 {
889 inputs.emplace_back(i);
890 }
891 }
892 auto inputTensorIds = GetInputTensorIds(m_Model, subgraphIndex, operatorIndex);
893 std::vector<armnn::TensorShape> inputShapes;
894
895 for (unsigned int i = 0; i < inputs.size(); ++i)
896 {
897 uint32_t inputId = CHECKED_NON_NEGATIVE(operatorPtr->inputs[inputs[i]]);
898 auto search = armnnTfLiteParser::TfLiteParserImpl::m_TensorInfos.find(inputId);
899
900 if (search != m_TensorInfos.end())
901 {
902 auto &inputTensorInfo = m_TensorInfos[inputId];
903 inputShapes.push_back(inputTensorInfo.GetShape());
904 }
905 else
906 {
Mike Kelly377fb212023-01-10 15:55:28 +0000907 auto inputTensorInfo = ::armnnTfLiteParser::ToTensorInfo(subgraphPtr->tensors[inputId].get());
908 m_TensorInfos.insert({ inputId, inputTensorInfo});
909 inputShapes.push_back(inputTensorInfo.GetShape());
910 }
911 }
912 const auto outputShape = layer->InferOutputShapes(inputShapes)[output];
913 tensor.SetShape(outputShape);
914 }
915 m_TensorInfos.insert({ outputId, tensor});
916 return tensor;
917}
918
919armnn::TensorInfo TfLiteParserImpl::OutputTensorInfoFromShapes(size_t subgraphIndex,
920 size_t operatorIndex,
921 armnn::IConnectableLayer* layer,
922 int output,
923 std::vector<armnn::TensorShape> inputShapes)
924{
925 const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex];
926 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
927
928 uint32_t outputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[output]);
929 const auto& outputTensorPtr = subgraphPtr->tensors[outputId].get();
930 TensorInfo tensor = ::armnnTfLiteParser::ToTensorInfo(outputTensorPtr, true);
931
932 if (IsDynamic(outputTensorPtr))
933 {
934 const auto outputShape = layer->InferOutputShapes(inputShapes)[output];
935 tensor.SetShape(outputShape);
936 }
937 m_TensorInfos.insert({ outputId, tensor});
938 return tensor;
939}
940
Kevin May7d96b162021-02-03 17:38:41 +0000941void TfLiteParserImpl::ResetParser()
telsoa01c577f2c2018-08-31 09:22:23 +0100942{
943 m_Network = armnn::INetworkPtr(nullptr, nullptr);
944 m_Model = nullptr;
945 m_SubgraphConnections.clear();
Mike Kelly377fb212023-01-10 15:55:28 +0000946 m_OverriddenOutputShapes.clear();
Mike Kelly5880b912022-01-28 16:18:54 +0000947 m_ConstantsToDequantize.clear();
948 m_ConstantsToBeCreated.clear();
Mike Kelly377fb212023-01-10 15:55:28 +0000949 m_TensorInfos.clear();
telsoa01c577f2c2018-08-31 09:22:23 +0100950}
951
Kevin May7d96b162021-02-03 17:38:41 +0000952INetworkPtr TfLiteParserImpl::CreateNetworkFromBinaryFile(const char* graphFile)
telsoa01c577f2c2018-08-31 09:22:23 +0100953{
954 ResetParser();
955 m_Model = LoadModelFromFile(graphFile);
956 return CreateNetworkFromModel();
957}
958
Mike Kelly0d77ae12022-01-07 17:42:27 +0000959INetworkPtr TfLiteParserImpl::CreateNetworkFromBinary(const std::vector<uint8_t>& binaryContent)
telsoa01c577f2c2018-08-31 09:22:23 +0100960{
961 ResetParser();
962 m_Model = LoadModelFromBinary(binaryContent.data(), binaryContent.size());
963 return CreateNetworkFromModel();
964}
965
Finn Williamsb49ed182021-06-29 15:50:08 +0100966
967armnn::INetworkPtr TfLiteParserImpl::LoadModel(std::unique_ptr<tflite::ModelT> model)
968{
969 ResetParser();
970 m_Model = std::move(model);
971
972 return CreateNetworkFromModel();
973}
974
Kevin May7d96b162021-02-03 17:38:41 +0000975INetworkPtr TfLiteParserImpl::CreateNetworkFromModel()
telsoa01c577f2c2018-08-31 09:22:23 +0100976{
Sadik Armagand109a4d2020-07-28 10:42:13 +0100977
978 using NetworkOptions = std::vector<BackendOptions>;
979 NetworkOptions networkOptions = {};
Mike Kelly80512b02022-05-16 23:10:42 +0100980 if (m_Options)
Sadik Armagand109a4d2020-07-28 10:42:13 +0100981 {
Mike Kelly80512b02022-05-16 23:10:42 +0100982 if (m_Options.value().m_InferAndValidate)
983 {
984 BackendOptions shapeInferenceMethodOption("ShapeInferenceMethod",
985 {
986 { "InferAndValidate", true }
987 });
Sadik Armagand109a4d2020-07-28 10:42:13 +0100988
Mike Kelly80512b02022-05-16 23:10:42 +0100989 networkOptions.push_back(shapeInferenceMethodOption);
990 }
991 if (m_Options.value().m_AllowExpandedDims)
992 {
993 BackendOptions shapeInferenceMethodOption("AllowExpandedDims",
994 {
995 { "AllowExpandedDims", true }
996 });
997
998 networkOptions.push_back(shapeInferenceMethodOption);
999 }
Sadik Armagand109a4d2020-07-28 10:42:13 +01001000 }
Sadik Armagand109a4d2020-07-28 10:42:13 +01001001 m_Network = INetwork::Create(networkOptions);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001002 ARMNN_ASSERT(m_Model.get() != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01001003
telsoa01c577f2c2018-08-31 09:22:23 +01001004 if (m_Model->subgraphs.size() != 1)
1005 {
1006 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01001007 fmt::format("Current TfLite parser only supports 1 subgraph. Current one has: {} {}",
1008 m_Model->subgraphs.size(),
1009 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01001010 }
1011
1012 size_t subgraphIndex = 0;
Colm Donelan6350d272020-06-09 16:56:25 +01001013 size_t operatorIndex = 0;
1014 try
telsoa01c577f2c2018-08-31 09:22:23 +01001015 {
Colm Donelan6350d272020-06-09 16:56:25 +01001016 for (SubgraphPtr const& subgraph : m_Model->subgraphs)
telsoa01c577f2c2018-08-31 09:22:23 +01001017 {
Mike Kelly377fb212023-01-10 15:55:28 +00001018 SetupInputLayerTensorInfos(subgraphIndex);
1019 SetupConstantLayerTensorInfos(subgraphIndex);
1020
Colm Donelan6350d272020-06-09 16:56:25 +01001021 m_SubgraphConnections.emplace_back(subgraph->tensors.size());
1022 for (OperatorPtr const& op : subgraph->operators)
telsoa01c577f2c2018-08-31 09:22:23 +01001023 {
Colm Donelan6350d272020-06-09 16:56:25 +01001024 auto const& opCodePtr = m_Model->operator_codes[op->opcode_index];
Jim Flynnfca233e2021-09-23 12:16:53 +01001025
1026// 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 +01001027#if defined(ARMNN_POST_TFLITE_2_3)
Jim Flynnfca233e2021-09-23 12:16:53 +01001028 auto builtinCode = std::max(opCodePtr->builtin_code,
1029 static_cast<tflite::BuiltinOperator>(opCodePtr->deprecated_builtin_code));
1030#else
telsoa01c577f2c2018-08-31 09:22:23 +01001031 auto builtinCode = opCodePtr->builtin_code;
Jim Flynnfca233e2021-09-23 12:16:53 +01001032#endif
telsoa01c577f2c2018-08-31 09:22:23 +01001033
1034 if (builtinCode > tflite::BuiltinOperator_MAX)
1035 {
James Ward58dec6b2020-09-11 17:32:44 +01001036 throw ParseException(fmt::format("Operator code {} is out of range 0-{}. "
1037 "subgraph:{} operator idx:{}. {}",
1038 builtinCode, tflite::BuiltinOperator_MAX, subgraphIndex,
1039 operatorIndex, CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01001040 }
1041
1042 // lookup and call the parser function
Colm Donelan6350d272020-06-09 16:56:25 +01001043 auto& parserFunction = m_ParserFunctions[builtinCode];
telsoa01c577f2c2018-08-31 09:22:23 +01001044 (this->*parserFunction)(subgraphIndex, operatorIndex);
Colm Donelan6350d272020-06-09 16:56:25 +01001045 ++operatorIndex;
telsoa01c577f2c2018-08-31 09:22:23 +01001046 }
telsoa01c577f2c2018-08-31 09:22:23 +01001047
Colm Donelan6350d272020-06-09 16:56:25 +01001048 SetupInputLayers(subgraphIndex);
1049 SetupOutputLayers(subgraphIndex);
1050 SetupConstantLayers(subgraphIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001051
Colm Donelan6350d272020-06-09 16:56:25 +01001052 ++subgraphIndex;
1053 operatorIndex = 0;
telsoa01c577f2c2018-08-31 09:22:23 +01001054 }
telsoa01c577f2c2018-08-31 09:22:23 +01001055 }
Colm Donelan6350d272020-06-09 16:56:25 +01001056 catch (const ParseException& e)
telsoa01c577f2c2018-08-31 09:22:23 +01001057 {
Colm Donelan6350d272020-06-09 16:56:25 +01001058 std::stringstream errorString;
1059 errorString << "Failed to parse operator #" << operatorIndex << " within subgraph #"
1060 << subgraphIndex << " error: " << e.what();
1061 ARMNN_LOG(error) << errorString.str();
1062 std::stringstream errors;
1063 errors << errorString.str() << "\n";
telsoa01c577f2c2018-08-31 09:22:23 +01001064 throw ParseException(errors.str());
1065 }
1066
1067 // establish the connections from the layer outputs to the inputs of the subsequent layers
Colm Donelan6350d272020-06-09 16:56:25 +01001068 for (subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001069 {
1070 for (size_t tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex)
1071 {
1072 if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot != nullptr)
1073 {
1074 for (size_t inputSlotIdx = 0;
1075 inputSlotIdx < m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size();
1076 ++inputSlotIdx)
1077 {
1078 m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot->Connect(
1079 *(m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots[inputSlotIdx]));
1080 }
1081 }
1082 }
1083 }
telsoa01c577f2c2018-08-31 09:22:23 +01001084 return std::move(m_Network);
1085}
1086
Mike Kelly0506ef02023-01-03 16:29:44 +00001087bool TfLiteParserImpl::ShouldConstantTensorBeConverted(TfLiteParserImpl::TensorRawPtr tensorPtr,
1088 armnn::DataType inputDataType,
1089 armnn::DataType tensorDataType)
Mike Kelly5880b912022-01-28 16:18:54 +00001090{
Mike Kelly0506ef02023-01-03 16:29:44 +00001091 return (TfLiteParserImpl::IsConstTensor(tensorPtr) && inputDataType == DataType::Float32 &&
1092 (tensorDataType == DataType::QAsymmU8 ||
1093 tensorDataType == DataType::QAsymmS8 ||
1094 tensorDataType == DataType::QSymmS8 ||
1095 tensorDataType == DataType::Signed32 ||
1096 tensorDataType == DataType::Signed64));
Mike Kelly5880b912022-01-28 16:18:54 +00001097}
1098
Kevin May7d96b162021-02-03 17:38:41 +00001099void TfLiteParserImpl::RegisterProducerOfTensor(size_t subgraphIndex,
1100 size_t tensorIndex,
1101 armnn::IOutputSlot* slot)
telsoa01c577f2c2018-08-31 09:22:23 +01001102{
1103 CHECK_TENSOR(m_Model, subgraphIndex, tensorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001104 ARMNN_ASSERT(m_SubgraphConnections.size() > subgraphIndex);
1105 ARMNN_ASSERT(m_SubgraphConnections[subgraphIndex].size() > tensorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001106
1107 TensorSlots & tensorSlots = m_SubgraphConnections[subgraphIndex][tensorIndex];
1108
Nikhil Rajd4d1c312022-08-03 18:20:59 +01001109 if (slot->GetOwningIConnectableLayer().GetType() != LayerType::Constant)
telsoa01c577f2c2018-08-31 09:22:23 +01001110 {
telsoa01c577f2c2018-08-31 09:22:23 +01001111
Nikhil Rajd4d1c312022-08-03 18:20:59 +01001112 // assuming there is only one producer for that tensor
1113 if (tensorSlots.outputSlot != nullptr)
1114 {
1115 throw ParseException(fmt::format("Another layer has already registered itself as the producer of "
1116 "subgraph:{} tensor:{} {}",
1117 subgraphIndex,
1118 tensorIndex,
1119 CHECK_LOCATION().AsString()));
1120 }
1121 }
telsoa01c577f2c2018-08-31 09:22:23 +01001122 tensorSlots.outputSlot = slot;
1123}
1124
Kevin May7d96b162021-02-03 17:38:41 +00001125void TfLiteParserImpl::RegisterConsumerOfTensor(size_t subgraphIndex,
1126 size_t tensorIndex,
1127 armnn::IInputSlot* slot)
telsoa01c577f2c2018-08-31 09:22:23 +01001128{
1129 CHECK_TENSOR(m_Model, subgraphIndex, tensorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001130 ARMNN_ASSERT(m_SubgraphConnections.size() > subgraphIndex);
1131 ARMNN_ASSERT(m_SubgraphConnections[subgraphIndex].size() > tensorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001132
Finn Williamsd4fa5452021-03-01 12:31:41 +00001133 TensorSlots& tensorSlots = m_SubgraphConnections[subgraphIndex][tensorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01001134 tensorSlots.inputSlots.push_back(slot);
1135}
1136
Kevin May7d96b162021-02-03 17:38:41 +00001137void TfLiteParserImpl::ParseCustomOperator(size_t subgraphIndex, size_t operatorIndex)
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001138{
1139 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1140
1141 // NOTE: By default we presume the custom operator is not supported
Kevin May7d96b162021-02-03 17:38:41 +00001142 auto customParserFunction = &TfLiteParserImpl::ParseUnsupportedOperator;
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001143
1144 // Identify custom code defined for custom operator
1145 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1146 const auto& customCode = m_Model->operator_codes[operatorPtr->opcode_index]->custom_code;
1147
Mike Kelly377fb212023-01-10 15:55:28 +00001148 // Find parser function that corresponds to custom code (if any)
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001149 auto iterator = m_CustomParserFunctions.find(customCode);
1150 if (iterator != m_CustomParserFunctions.end())
1151 {
1152 customParserFunction = iterator->second;
1153 }
1154
1155 // Run parser function
1156 (this->*customParserFunction)(subgraphIndex, operatorIndex);
1157}
1158
Kevin May7d96b162021-02-03 17:38:41 +00001159void TfLiteParserImpl::ParseUnsupportedOperator(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001160{
1161 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001162
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001163 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1164
1165 auto opcodeIndex = operatorPtr->opcode_index;
Jim Flynnfca233e2021-09-23 12:16:53 +01001166
1167// 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 +01001168#if defined(ARMNN_POST_TFLITE_2_3)
Jim Flynnfca233e2021-09-23 12:16:53 +01001169 auto opcode = std::max(m_Model->operator_codes[opcodeIndex]->builtin_code,
1170 static_cast<tflite::BuiltinOperator>(m_Model->operator_codes[opcodeIndex]->deprecated_builtin_code));
1171#else
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001172 auto opcode = m_Model->operator_codes[opcodeIndex]->builtin_code;
Jim Flynnfca233e2021-09-23 12:16:53 +01001173#endif
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001174
1175 if (!m_Options || !m_Options.value().m_StandInLayerForUnsupported)
1176 {
1177 // Do not add StandInLayer, throw ParseException instead
1178 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01001179 fmt::format("Operator not supported. "
1180 "subgraph:{} operator:{} "
1181 "opcode_index:{} opcode:{} / {} {}",
1182 subgraphIndex,
1183 operatorIndex,
1184 opcodeIndex,
1185 opcode,
1186 tflite::EnumNameBuiltinOperator(opcode),
1187 CHECK_LOCATION().AsString()));
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001188 }
1189
1190 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1191 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1192
Matthew Sloyan589e3e82020-09-11 16:17:48 +01001193 const unsigned int numInputs = armnn::numeric_cast<unsigned int>(inputs.size());
1194 const unsigned int numOutputs = armnn::numeric_cast<unsigned int>(outputs.size());
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001195
1196 StandInDescriptor descriptor(numInputs, numOutputs);
James Ward58dec6b2020-09-11 17:32:44 +01001197 auto layerName = fmt::format("StandIn:{}:{}:{}", subgraphIndex, operatorIndex, opcode);
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001198
1199 // Add a non-executable StandInLayer as a placeholder for any unsupported operator
1200 IConnectableLayer* layer = m_Network->AddStandInLayer(descriptor, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01001201 ARMNN_ASSERT(layer != nullptr);
1202
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001203 for (unsigned int i = 0u; i < numOutputs; ++i)
1204 {
Mike Kelly04d82292023-01-19 18:29:40 +00001205 layer->GetOutputSlot(i).SetTensorInfo(ToTensorInfo(outputs[0], true));
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001206 }
1207
1208 auto inputTensorIds = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1209 auto outputTensorIds = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1210
1211 RegisterInputSlots(subgraphIndex, operatorIndex, layer, inputTensorIds);
1212 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIds);
telsoa01c577f2c2018-08-31 09:22:23 +01001213}
1214
mathad01b392e982021-04-07 12:07:30 +01001215void TfLiteParserImpl::ParseCast(size_t subgraphIndex, size_t operatorIndex)
1216{
1217 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1218
1219 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1220 CHECK_VALID_SIZE(inputs.size(), 1);
1221 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1222 CHECK_VALID_SIZE(outputs.size(), 1);
1223
1224 auto layerName = fmt::format("Cast:{}:{}", subgraphIndex, operatorIndex);
1225
1226 IConnectableLayer* layer = m_Network->AddCastLayer(layerName.c_str());
1227 ARMNN_ASSERT(layer != nullptr);
1228
Mike Kelly377fb212023-01-10 15:55:28 +00001229 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
mathad01b392e982021-04-07 12:07:30 +01001230 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1231
1232 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1233 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1234
1235 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1236 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
1237}
1238
Kevin May7d96b162021-02-03 17:38:41 +00001239void TfLiteParserImpl::ParseConv2D(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001240{
1241 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1242
Mike Kelly0d77ae12022-01-07 17:42:27 +00001243 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1244 const auto* options = operatorPtr->builtin_options.AsConv2DOptions();
telsoa01c577f2c2018-08-31 09:22:23 +01001245
1246 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1247
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001248 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1249 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1250 CHECK_VALID_SIZE(outputs.size(), 1);
1251
telsoa01c577f2c2018-08-31 09:22:23 +01001252 Convolution2dDescriptor desc;
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001253 inputs.size() == 3 ?
1254 desc.m_BiasEnabled = true : desc.m_BiasEnabled = false;
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;
Pablo Tellof0bd6832019-04-26 17:58:13 +01001258 desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
1259 desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
Kevin May83add212019-03-26 11:39:19 +00001260
Mike Kelly377fb212023-01-10 15:55:28 +00001261 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1262 armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
telsoa01c577f2c2018-08-31 09:22:23 +01001263
1264 // assuming input is NHWC
1265 unsigned int inputHeight = inputTensorInfo.GetShape()[1];
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001266 unsigned int inputWidth = inputTensorInfo.GetShape()[2];
telsoa01c577f2c2018-08-31 09:22:23 +01001267
1268 // assuming the filter is OHWI : Output, H, W, Input
1269 // which is essentially the same as NHWC
1270 unsigned int filterHeight = filterTensorInfo.GetShape()[1];
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001271 unsigned int filterWidth = filterTensorInfo.GetShape()[2];
telsoa01c577f2c2018-08-31 09:22:23 +01001272
Pablo Tellof0bd6832019-04-26 17:58:13 +01001273 CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
1274 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
1275 CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
1276 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
telsoa01c577f2c2018-08-31 09:22:23 +01001277
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001278 // Add the first input and weights tensor to the registration list.
1279 // The constant weights will be added by SetupConstantLayers.
1280 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1281 std::vector<unsigned int> tensorIndexesToRegister = { inputTensorIndexes[0], inputTensorIndexes[1] };
telsoa01c577f2c2018-08-31 09:22:23 +01001282
James Ward58dec6b2020-09-11 17:32:44 +01001283 auto layerName = fmt::format("Conv2D:{}:{}", subgraphIndex, operatorIndex);
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001284 armnn::IConnectableLayer* layer = m_Network->AddConvolution2dLayer(desc, layerName.c_str());
telsoa01c577f2c2018-08-31 09:22:23 +01001285
Mike Kelly0506ef02023-01-03 16:29:44 +00001286 if (ShouldConstantTensorBeConverted(inputs[1], inputTensorInfo.GetDataType(), filterTensorInfo.GetDataType()))
telsoa01c577f2c2018-08-31 09:22:23 +01001287 {
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001288 m_ConstantsToDequantize.emplace_back(inputs[1]->buffer);
telsoa01c577f2c2018-08-31 09:22:23 +01001289 }
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001290
1291 if (desc.m_BiasEnabled)
telsoa01c577f2c2018-08-31 09:22:23 +01001292 {
Mike Kelly377fb212023-01-10 15:55:28 +00001293 armnn::TensorInfo biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001294
1295 // Add the biases input to the registration list, a constant layer will be added by SetupConstantLayers.
1296 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
1297
Mike Kelly0506ef02023-01-03 16:29:44 +00001298 if (ShouldConstantTensorBeConverted(inputs[2], inputTensorInfo.GetDataType(), biasTensorInfo.GetDataType()))
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001299 {
1300 m_ConstantsToDequantize.emplace_back(inputs[2]->buffer);
1301 }
telsoa01c577f2c2018-08-31 09:22:23 +01001302 }
1303
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001304 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01001305
Mike Kelly377fb212023-01-10 15:55:28 +00001306 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
jimfly01c25411c2018-11-14 17:47:22 +00001307 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +01001308
1309 // register the input connection slots for the layer, connections are made after all layers have been created
1310 // only the tensors for the inputs are relevant, exclude the const tensors
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001311 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister);
telsoa01c577f2c2018-08-31 09:22:23 +01001312
jimfly01c25411c2018-11-14 17:47:22 +00001313 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
telsoa01c577f2c2018-08-31 09:22:23 +01001314 // register the output connection slots for the layer, connections are made after all layers have been created
1315 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001316 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, { outputTensorIndexes[0] });
telsoa01c577f2c2018-08-31 09:22:23 +01001317}
1318
Matthew Sloyan4d217c02021-10-07 11:48:58 +01001319// Conv3D support was added in TF 2.5, so for backwards compatibility a hash define is needed.
Cathal Corbett80b4ef02022-05-25 11:21:11 +01001320#if defined(ARMNN_POST_TFLITE_2_4)
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001321void TfLiteParserImpl::ParseConv3D(size_t subgraphIndex, size_t operatorIndex)
1322{
1323 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1324
1325 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1326 const auto* options = operatorPtr->builtin_options.AsConv3DOptions();
1327
1328 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1329
1330 Convolution3dDescriptor desc;
1331 desc.m_BiasEnabled = false;
1332 desc.m_DataLayout = armnn::DataLayout::NDHWC;
1333 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1334 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1335 desc.m_StrideZ = CHECKED_NON_NEGATIVE(options->stride_d);
1336 desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
1337 desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
1338 desc.m_DilationZ = CHECKED_NON_NEGATIVE(options->dilation_d_factor);
1339
1340 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1341 CHECK_VALID_SIZE(inputs.size(), 2, 3);
1342
1343 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1344 CHECK_VALID_SIZE(outputs.size(), 1);
1345
Mike Kelly377fb212023-01-10 15:55:28 +00001346 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1347 armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001348
1349 // Assuming input is NDHWC
1350 unsigned int inputDepth = inputTensorInfo.GetShape()[1];
1351 unsigned int inputHeight = inputTensorInfo.GetShape()[2];
1352 unsigned int inputWidth = inputTensorInfo.GetShape()[3];
1353
1354 // Assuming the filter is DHWIO : Depth, Height, Width, OutputChannels, InputChannels
1355 unsigned int filterDepth = filterTensorInfo.GetShape()[0];
1356 unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1357 unsigned int filterWidth = filterTensorInfo.GetShape()[2];
1358
1359 CalcPadding(inputDepth, filterDepth, desc.m_StrideZ,
Teresa Charlin502ab942022-03-23 17:23:07 +00001360 desc.m_DilationZ, desc.m_PadFront, desc.m_PadBack, options->padding);
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001361 CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
1362 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
1363 CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
1364 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
1365
Mike Kelly5880b912022-01-28 16:18:54 +00001366 auto filterTensorAndData = CreateConstTensorNonPermuted(inputs[1], filterTensorInfo, inputTensorInfo.GetDataType());
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001367
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001368 auto layerName = fmt::format("Conv3D:{}:{}", subgraphIndex, operatorIndex);
1369
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001370 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1371 // Add the first input and weights tensor to the registration list.
1372 // The constant weights will be added by SetupConstantLayers.
1373 std::vector<unsigned int> tensorIndexesToRegister = {inputTensorIndexes[0], inputTensorIndexes[1]};
1374
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001375 if (inputs.size() == 3)
1376 {
1377 desc.m_BiasEnabled = true;
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001378
1379 // Add the biases input to the registration list, a constant layer will be added by SetupConstantLayers.
1380 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001381 }
1382
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001383 armnn::IConnectableLayer* layer = m_Network->AddConvolution3dLayer(desc, layerName.c_str());
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001384 ARMNN_ASSERT(layer != nullptr);
1385
Mike Kelly377fb212023-01-10 15:55:28 +00001386 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001387 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1388
1389 // Register the input connection slots for the layer, connections are made after all layers have been created
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001390 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister);
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001391
1392 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
1393 // Register the output connection slots for the layer, connections are made after all layers have been created
1394 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1395 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1396}
Matthew Sloyan4d217c02021-10-07 11:48:58 +01001397#endif
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001398
Kevin May7d96b162021-02-03 17:38:41 +00001399void TfLiteParserImpl::ParseDepthwiseConv2D(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001400{
1401 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1402
Mike Kelly0d77ae12022-01-07 17:42:27 +00001403 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1404 const auto* options = operatorPtr->builtin_options.AsDepthwiseConv2DOptions();
telsoa01c577f2c2018-08-31 09:22:23 +01001405
1406 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1407
1408 DepthwiseConvolution2dDescriptor desc;
telsoa01c577f2c2018-08-31 09:22:23 +01001409 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1410 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
jimfly01c25411c2018-11-14 17:47:22 +00001411 desc.m_DataLayout = armnn::DataLayout::NHWC;
Matthew Jacksond6a9dee2019-07-22 13:53:24 +01001412 CHECKED_NON_NEGATIVE(options->depth_multiplier);
telsoa01c577f2c2018-08-31 09:22:23 +01001413
1414 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1415 CHECK_VALID_SIZE(inputs.size(), 2, 3);
Cathal Corbett06902652022-04-14 17:55:11 +01001416 if (inputs.size() == 3)
1417 {
1418 desc.m_BiasEnabled = true;
1419 }
1420
telsoa01c577f2c2018-08-31 09:22:23 +01001421 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1422 CHECK_VALID_SIZE(outputs.size(), 1);
Pablo Tellof0bd6832019-04-26 17:58:13 +01001423 desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
1424 desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
Kevin May83add212019-03-26 11:39:19 +00001425
Mike Kelly377fb212023-01-10 15:55:28 +00001426 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1427 armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
telsoa01c577f2c2018-08-31 09:22:23 +01001428
Matteo Martincigh747ef822018-12-18 09:26:39 +00001429 // Assuming input is NHWC
telsoa01c577f2c2018-08-31 09:22:23 +01001430 unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1431 unsigned int inputWidth = inputTensorInfo.GetShape()[2];
Matteo Martincigh747ef822018-12-18 09:26:39 +00001432
1433 // TensorflowLite weights come in the format [1, H, W, I * M]
telsoa01c577f2c2018-08-31 09:22:23 +01001434 unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1435 unsigned int filterWidth = filterTensorInfo.GetShape()[2];
1436
Pablo Tellof0bd6832019-04-26 17:58:13 +01001437 CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
1438 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
1439 CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
1440 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
telsoa01c577f2c2018-08-31 09:22:23 +01001441
Jan Eilers53ef7952021-06-02 12:01:25 +01001442 // 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 +01001443 auto layerName = fmt::format("DepthwiseConv2D:{}:{}", subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001444
Cathal Corbett06902652022-04-14 17:55:11 +01001445 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1446 // Add the first input and weights tensor to the registration list.
1447 // The constant weights will be added by SetupConstantLayers.
1448 std::vector<unsigned int> tensorIndexesToRegister = {inputTensorIndexes[0], inputTensorIndexes[1]};
1449
1450 armnn::IConnectableLayer* layer = m_Network->AddDepthwiseConvolution2dLayer(desc, layerName.c_str());
1451
1452 if (desc.m_BiasEnabled)
telsoa01c577f2c2018-08-31 09:22:23 +01001453 {
1454 desc.m_BiasEnabled = true;
Mike Kelly377fb212023-01-10 15:55:28 +00001455 TensorInfo biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Cathal Corbett06902652022-04-14 17:55:11 +01001456
1457 // Add the biases input to the registration list, a constant layer will be added by SetupConstantLayers.
1458 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
telsoa01c577f2c2018-08-31 09:22:23 +01001459 }
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001460 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01001461
Mike Kelly377fb212023-01-10 15:55:28 +00001462 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
jimfly01c25411c2018-11-14 17:47:22 +00001463 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +01001464
1465 // register the input connection slots for the layer, connections are made after all layers have been created
1466 // only the tensors for the inputs are relevant, exclude the const tensors
Cathal Corbett06902652022-04-14 17:55:11 +01001467 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister);
telsoa01c577f2c2018-08-31 09:22:23 +01001468
jimfly01c25411c2018-11-14 17:47:22 +00001469 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
telsoa01c577f2c2018-08-31 09:22:23 +01001470 // register the output connection slots for the layer, connections are made after all layers have been created
1471 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1472 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1473}
1474
Kevin May7d96b162021-02-03 17:38:41 +00001475void TfLiteParserImpl::ParseDequantize(size_t subgraphIndex, size_t operatorIndex)
Finn Williamsed66d142019-12-06 09:55:55 +00001476{
1477 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1478
1479 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1480 CHECK_VALID_SIZE(inputs.size(), 1);
1481
1482 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1483 CHECK_VALID_SIZE(outputs.size(), 1);
1484
James Ward58dec6b2020-09-11 17:32:44 +01001485 auto layerName = fmt::format("Dequantize:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsed66d142019-12-06 09:55:55 +00001486
1487 IConnectableLayer* layer = m_Network->AddDequantizeLayer(layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001488 ARMNN_ASSERT(layer != nullptr);
Finn Williamsed66d142019-12-06 09:55:55 +00001489
Mike Kelly377fb212023-01-10 15:55:28 +00001490 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Finn Williamsed66d142019-12-06 09:55:55 +00001491 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1492
1493 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1494 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1495
1496 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1497 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
1498}
1499
Teresa Charlin3ab85482021-06-08 16:59:29 +01001500void TfLiteParserImpl::ParseExpandDims(size_t subgraphIndex, size_t operatorIndex)
1501{
1502 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1503
1504 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1505 CHECK_VALID_SIZE(inputs.size(), 2);
1506
1507 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1508 CHECK_VALID_SIZE(outputs.size(), 1);
1509
1510 auto layerName = fmt::format("ExpandDims:{}:{}", subgraphIndex, operatorIndex);
1511
Mike Kelly377fb212023-01-10 15:55:28 +00001512 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Teresa Charlin3ab85482021-06-08 16:59:29 +01001513 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Teresa Charlin3ab85482021-06-08 16:59:29 +01001514 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1515
Teresa Charlina7a605a2023-06-14 14:51:17 +01001516 armnn::TensorInfo axisTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
1517
1518 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1519 if (axisBufferPtr == nullptr)
1520 {
1521 throw ParseException(fmt::format("{}: Operation has invalid inputs. Failed to read axis.",
1522 CHECK_LOCATION().AsString()));
1523 }
1524
1525 std::vector<int32_t> axisData(axisTensorInfo.GetNumElements());
1526 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
1527 int32_t axis = axisData[0];
1528
1529 auto inputRank = static_cast<int32_t>(inputTensorInfo.GetShape().GetNumDimensions());
1530 auto outputRank = inputRank + 1;
1531 if((axis < -1 * outputRank) || (outputRank <= axis))
1532 {
1533 throw ParseException(fmt::format("{}: Axis {} is not within [-{}, {}) range.",
1534 CHECK_LOCATION().AsString(), axis, outputRank, outputRank));
1535 }
1536
1537 axis = axis < 0 ? (axis + outputRank) : axis;
1538
1539 std::vector<unsigned int> shape(static_cast<unsigned int>(outputRank));
1540 unsigned int inputShapeIndex = 0;
1541 for (unsigned int i = 0; i < static_cast<unsigned int>(outputRank); ++i)
1542 {
1543 if (i == static_cast<unsigned int>(axis))
1544 {
1545 shape[i] = 1;
1546 }
1547 else
1548 {
1549 shape[i] = inputTensorInfo.GetShape()[inputShapeIndex];
1550 ++inputShapeIndex;
1551 }
1552 }
1553
Teresa Charlin3ab85482021-06-08 16:59:29 +01001554 ReshapeDescriptor reshapeDesc;
Teresa Charlina7a605a2023-06-14 14:51:17 +01001555 reshapeDesc.m_TargetShape = TensorShape(static_cast<unsigned int>(outputRank), shape.data());
1556 outputTensorInfo.SetShape(reshapeDesc.m_TargetShape);
Teresa Charlin3ab85482021-06-08 16:59:29 +01001557
1558 IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
1559 ARMNN_ASSERT(layer != nullptr);
1560 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1561
Teresa Charlina7a605a2023-06-14 14:51:17 +01001562 auto outputTensorIds = GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex);
1563 m_TensorInfos[outputTensorIds[0]] = outputTensorInfo;
1564
Teresa Charlin3ab85482021-06-08 16:59:29 +01001565 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1566 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1567
1568 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1569 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1570}
1571
Kevin May7d96b162021-02-03 17:38:41 +00001572void TfLiteParserImpl::ParseTranspose(size_t subgraphIndex, size_t operatorIndex)
Keith Davis4cd29a02019-09-09 14:49:20 +01001573{
1574 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1575
1576 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Kevin May85d92602019-09-27 17:21:06 +01001577 CHECK_VALID_SIZE(inputs.size(), 1, 2);
Keith Davis4cd29a02019-09-09 14:49:20 +01001578
1579 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1580 CHECK_VALID_SIZE(outputs.size(), 1);
1581
James Ward58dec6b2020-09-11 17:32:44 +01001582 auto layerName = fmt::format("Transpose:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly08759e22020-03-02 11:41:31 +00001583 TransposeDescriptor desc;
Keith Davis4cd29a02019-09-09 14:49:20 +01001584
josh minorba424d22019-11-13 10:55:17 -06001585 if (inputs.size() == 2)
Kevin May85d92602019-09-27 17:21:06 +01001586 {
Mike Kelly377fb212023-01-10 15:55:28 +00001587 armnn::TensorInfo permuteTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Kevin May85d92602019-09-27 17:21:06 +01001588 BufferRawPtr permuteBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
josh minorba424d22019-11-13 10:55:17 -06001589 auto numPermVecElements = permuteTensorInfo.GetNumElements();
1590 std::vector<unsigned int> permuteShape(numPermVecElements);
Kevin May85d92602019-09-27 17:21:06 +01001591 ::memcpy(permuteShape.data(), permuteBufferPtr->data.data(), permuteTensorInfo.GetNumBytes());
Mike Kelly08759e22020-03-02 11:41:31 +00001592 PermutationVector permutationVector(permuteShape.data(), permuteTensorInfo.GetNumElements());
Kevin May85d92602019-09-27 17:21:06 +01001593
Mike Kelly08759e22020-03-02 11:41:31 +00001594 desc = TransposeDescriptor(permutationVector);
Kevin May85d92602019-09-27 17:21:06 +01001595 }
Mike Kelly377fb212023-01-10 15:55:28 +00001596 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Keith Davis4cd29a02019-09-09 14:49:20 +01001597
James Conroy05102392020-06-24 15:39:55 +01001598 IConnectableLayer* layer = m_Network->AddTransposeLayer(desc, layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001599 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00001600
1601 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
1602 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Keith Davis4cd29a02019-09-09 14:49:20 +01001603 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1604
1605 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1606 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1607
1608 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1609 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1610}
1611
Kevin May7d96b162021-02-03 17:38:41 +00001612void TfLiteParserImpl::ParseTransposeConv(size_t subgraphIndex, size_t operatorIndex)
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001613{
1614 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1615
Mike Kelly0d77ae12022-01-07 17:42:27 +00001616 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1617 const auto* options = operatorPtr->builtin_options.AsTransposeConvOptions();
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001618
1619 TransposeConvolution2dDescriptor desc;
1620 desc.m_BiasEnabled = false;
1621 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1622 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1623 desc.m_DataLayout = armnn::DataLayout::NHWC;
1624
1625 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
David Monahan61683802021-01-12 09:11:07 +00001626 if (inputs.size() == 4)
1627 {
1628 desc.m_BiasEnabled = true;
1629 }
1630 else
1631 {
1632 CHECK_VALID_SIZE(inputs.size(), 3);
1633 }
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001634
1635 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1636 CHECK_VALID_SIZE(outputs.size(), 1);
1637
Teresa Charlin024ef0b2023-04-26 11:19:03 +01001638
1639 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
1640 armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
1641
1642 // TfLite uses NHWC tensors
1643 const unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1644 const unsigned int inputWidth = inputTensorInfo.GetShape()[2];
1645
1646 const unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1647 const unsigned int filterWidth = filterTensorInfo.GetShape()[2];
1648
Ryan OSheaf0a35b82023-02-21 18:32:30 +00001649 // This block determines the output shape of the transpose convolution. If the output shape tensor ptr is not null
1650 // And the tensor is a constant, we can access the data at load time and set the output shape of the
1651 // layer. If this is not constant, We do not have access to the shape data, so we have to use
1652 // infer output shape and skip this code block.
1653 if (inputs[0] && IsConstTensor(inputs[0]))
Colm Donelan0ad3ef12020-07-03 15:54:28 +01001654 {
Mike Kelly377fb212023-01-10 15:55:28 +00001655 armnn::TensorInfo tensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Colm Donelan0ad3ef12020-07-03 15:54:28 +01001656 std::vector<int> output_shape(tensorInfo.GetNumElements());
Mike Kelly377fb212023-01-10 15:55:28 +00001657
Colm Donelan0ad3ef12020-07-03 15:54:28 +01001658 if (tensorInfo.GetDataType() == DataType::Signed32)
1659 {
1660 ::memcpy(output_shape.data(), GetBuffer(m_Model, inputs[0]->buffer)->data.data(), tensorInfo.GetNumBytes());
1661 }
1662 if (tensorInfo.GetDataType() == DataType::QAsymmU8)
1663 {
1664 for(unsigned int i=0; i < tensorInfo.GetNumElements(); i++)
1665 {
1666 output_shape[i] = GetBuffer(m_Model, inputs[0]->buffer)->data.data()[i];
1667 }
1668 }
1669 // Change from signed to unsigned int to store in TransposeConvolution2dDescriptor.
1670 for (int dimension : output_shape)
1671 {
1672 desc.m_OutputShape.push_back(static_cast<unsigned int>(dimension));
1673 }
1674 desc.m_OutputShapeEnabled = true;
Teresa Charlin024ef0b2023-04-26 11:19:03 +01001675
1676 // TfLite uses NHWC tensors
1677 const unsigned int outputHeight = desc.m_OutputShape[1];
1678 const unsigned int outputWidth = desc.m_OutputShape[2];
1679
1680 CalcPadding(inputHeight,
1681 filterHeight,
1682 desc.m_StrideY,
1683 1, // DilationY
1684 desc.m_PadTop,
1685 desc.m_PadBottom,
1686 options->padding,
1687 outputHeight);
1688
1689 CalcPadding(inputWidth,
1690 filterWidth,
1691 desc.m_StrideX,
1692 1, // DilationX
1693 desc.m_PadLeft,
1694 desc.m_PadRight,
1695 options->padding,
1696 outputWidth);
Colm Donelan0ad3ef12020-07-03 15:54:28 +01001697 }
Teresa Charlin024ef0b2023-04-26 11:19:03 +01001698 else
1699 {
1700 CalcPadding(inputHeight,
1701 filterHeight,
1702 desc.m_StrideY,
1703 1, // DilationY
1704 desc.m_PadTop,
1705 desc.m_PadBottom,
1706 options->padding);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001707
Teresa Charlin024ef0b2023-04-26 11:19:03 +01001708 CalcPadding(inputWidth,
1709 filterWidth,
1710 desc.m_StrideX,
1711 1, // DilationX
1712 desc.m_PadLeft,
1713 desc.m_PadRight,
1714 options->padding);
1715 }
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001716
Mike Kelly5880b912022-01-28 16:18:54 +00001717 auto filterTensorAndData = CreateConstTensorNonPermuted(inputs[1], filterTensorInfo, inputTensorInfo.GetDataType());
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001718
1719 armnn::IConnectableLayer* layer = nullptr;
James Ward58dec6b2020-09-11 17:32:44 +01001720 auto layerName = fmt::format("TransposeConv:{}:{}", subgraphIndex, operatorIndex);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001721
David Monahan61683802021-01-12 09:11:07 +00001722 if (desc.m_BiasEnabled)
1723 {
Mike Kelly377fb212023-01-10 15:55:28 +00001724 auto biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 3);
Mike Kelly5880b912022-01-28 16:18:54 +00001725 auto biasConstTensor = CreateConstTensorNonPermuted(inputs[3], biasTensorInfo, inputTensorInfo.GetDataType());
David Monahan61683802021-01-12 09:11:07 +00001726 layer = m_Network->AddTransposeConvolution2dLayer(desc,
Mike Kelly5880b912022-01-28 16:18:54 +00001727 filterTensorAndData.first,
1728 biasConstTensor.first,
David Monahan61683802021-01-12 09:11:07 +00001729 layerName.c_str());
1730 }
1731 else
1732 {
1733 layer = m_Network->AddTransposeConvolution2dLayer(desc,
Mike Kelly5880b912022-01-28 16:18:54 +00001734 filterTensorAndData.first,
David Monahan61683802021-01-12 09:11:07 +00001735 EmptyOptional(),
1736 layerName.c_str());
1737 }
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001738
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001739 ARMNN_ASSERT(layer != nullptr);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001740
Mike Kelly377fb212023-01-10 15:55:28 +00001741 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0 , { 2, 1 });
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001742 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1743
1744 // only the tensors for the inputs are relevant, exclude the const (filter) tensor
1745 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Matthew Jacksonccb25ea2019-08-20 17:18:33 +01001746 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[2]});
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001747
1748 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1749 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1750}
1751
Kevin May7d96b162021-02-03 17:38:41 +00001752void TfLiteParserImpl::ParseAveragePool2D(size_t subgraphIndex, size_t operatorIndex)
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001753{
1754 ParsePool(subgraphIndex, operatorIndex, PoolingAlgorithm::Average);
1755}
1756
Samuel Yapfd3ba5a2022-08-24 17:04:34 +01001757void TfLiteParserImpl::ParseBatchMatMul(size_t subgraphIndex, size_t operatorIndex)
1758{
1759 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1760
1761 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1762 CHECK_VALID_SIZE(inputs.size(), 2);
1763
1764 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1765 CHECK_VALID_SIZE(outputs.size(), 1);
1766
1767 auto layerName = fmt::format("BatchMatMul:{}:{}", subgraphIndex, operatorIndex);
1768
Mike Kelly377fb212023-01-10 15:55:28 +00001769 TensorInfo inputXTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1770 TensorInfo inputYTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Samuel Yapfd3ba5a2022-08-24 17:04:34 +01001771
1772 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1773 const auto* options = operatorPtr->builtin_options.AsBatchMatMulOptions();
1774
Teresa Charlinbc37a6b2022-09-22 10:12:58 +01001775 // Adjoint in tensorflow lite performs transpose operation
1776 BatchMatMulDescriptor descriptor(options->adj_x,
1777 options->adj_y,
Samuel Yapfd3ba5a2022-08-24 17:04:34 +01001778 false,
Teresa Charlinbc37a6b2022-09-22 10:12:58 +01001779 false);
Samuel Yapfd3ba5a2022-08-24 17:04:34 +01001780 // Arbitrary DataLayout
1781
1782 IConnectableLayer* layer = m_Network->AddBatchMatMulLayer(descriptor, layerName.c_str());
1783 ARMNN_ASSERT(layer != nullptr);
1784
Mike Kelly377fb212023-01-10 15:55:28 +00001785 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Samuel Yapfd3ba5a2022-08-24 17:04:34 +01001786 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1787
1788 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1789 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
1790
1791 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1792 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1793}
1794
Kevin May7d96b162021-02-03 17:38:41 +00001795void TfLiteParserImpl::ParseBatchToSpaceND(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001796{
1797 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1798
1799 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1800 CHECK_VALID_SIZE(inputs.size(), 3);
1801
1802 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1803 CHECK_VALID_SIZE(outputs.size(), 1);
1804
Mike Kelly377fb212023-01-10 15:55:28 +00001805 armnn::TensorInfo blockShapeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001806 BufferRawPtr blockShapeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1807
Mike Kelly377fb212023-01-10 15:55:28 +00001808 armnn::TensorInfo cropsTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001809 BufferRawPtr cropsBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
1810
1811 std::vector<unsigned int> blockShape(blockShapeTensorInfo.GetNumElements());
1812 ::memcpy(blockShape.data(), blockShapeBufferPtr->data.data(), blockShapeTensorInfo.GetNumBytes());
1813
1814 std::vector<unsigned int> cropsVector(cropsTensorInfo.GetNumElements());
1815 ::memcpy(cropsVector.data(), cropsBufferPtr->data.data(), cropsTensorInfo.GetNumBytes());
1816
1817 size_t step = 2;
1818 std::vector<std::pair<unsigned int, unsigned int>> crops;
1819 for (unsigned int i = 0; i < cropsTensorInfo.GetNumElements() / step; ++i)
1820 {
1821 crops.emplace_back(cropsVector[i * step], cropsVector[i * step + 1]);
1822 }
1823
1824 armnn::BatchToSpaceNdDescriptor desc;
1825 desc.m_BlockShape = blockShape;
1826 desc.m_Crops = crops;
1827 desc.m_DataLayout = armnn::DataLayout::NHWC;
1828
James Ward58dec6b2020-09-11 17:32:44 +01001829 auto layerName = fmt::format("BatchToSpaceND:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001830
Mike Kelly377fb212023-01-10 15:55:28 +00001831 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
James Conroy05102392020-06-24 15:39:55 +01001832
1833 IConnectableLayer* layer = m_Network->AddBatchToSpaceNdLayer(desc, layerName.c_str());
1834 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00001835
1836 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
1837 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001838 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1839
1840 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1841 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1842
1843 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1844 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1845}
1846
Kevin May7d96b162021-02-03 17:38:41 +00001847void TfLiteParserImpl::ParseL2Normalization(size_t subgraphIndex, size_t operatorIndex)
Matthew Jackson28c94572019-07-18 10:47:03 +01001848{
1849 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1850
1851 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1852 CHECK_VALID_SIZE(inputs.size(), 1);
1853
1854 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1855 CHECK_VALID_SIZE(outputs.size(), 1);
1856
1857 L2NormalizationDescriptor desc;
1858 desc.m_DataLayout = armnn::DataLayout::NHWC;
James Ward58dec6b2020-09-11 17:32:44 +01001859 auto layerName = fmt::format("L2Normalization:{}:{}", subgraphIndex, operatorIndex);
Matthew Jackson28c94572019-07-18 10:47:03 +01001860 IConnectableLayer* layer = m_Network->AddL2NormalizationLayer(desc, layerName.c_str());
1861
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001862 ARMNN_ASSERT(layer != nullptr);
Matthew Jackson28c94572019-07-18 10:47:03 +01001863
Mike Kelly377fb212023-01-10 15:55:28 +00001864 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Matthew Jackson28c94572019-07-18 10:47:03 +01001865 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1866
1867 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1868 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1869
1870 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1871 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1872}
1873
Kevin May7d96b162021-02-03 17:38:41 +00001874void TfLiteParserImpl::ParseMaxPool2D(size_t subgraphIndex, size_t operatorIndex)
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001875{
1876 ParsePool(subgraphIndex, operatorIndex, PoolingAlgorithm::Max);
1877}
1878
Kevin May7d96b162021-02-03 17:38:41 +00001879void TfLiteParserImpl::ParseMaximum(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001880{
1881 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1882
1883 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1884 CHECK_VALID_SIZE(inputs.size(), 2);
1885
1886 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1887 CHECK_VALID_SIZE(outputs.size(), 1);
1888
James Ward58dec6b2020-09-11 17:32:44 +01001889 auto layerName = fmt::format("Maximum:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01001890
Mike Kelly377fb212023-01-10 15:55:28 +00001891 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1892 TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
James Conroy05102392020-06-24 15:39:55 +01001893 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001894
Mike Kelly3ec30772023-03-08 13:47:17 +00001895 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Maximum, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01001896 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00001897
1898 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
1899 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001900 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1901
1902 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01001903 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001904
1905 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1906 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1907}
1908
Kevin May7d96b162021-02-03 17:38:41 +00001909void TfLiteParserImpl::ParseMinimum(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001910{
1911 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1912
1913 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1914 CHECK_VALID_SIZE(inputs.size(), 2);
1915
1916 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1917 CHECK_VALID_SIZE(outputs.size(), 1);
1918
James Ward58dec6b2020-09-11 17:32:44 +01001919 auto layerName = fmt::format("Minimum:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01001920
Mike Kelly377fb212023-01-10 15:55:28 +00001921 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1922 TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
James Conroy05102392020-06-24 15:39:55 +01001923 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001924
Mike Kelly3ec30772023-03-08 13:47:17 +00001925 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Minimum, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01001926 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00001927
1928 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
1929 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001930 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1931
1932 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01001933 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001934
1935 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1936 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1937}
1938
Kevin May7d96b162021-02-03 17:38:41 +00001939void TfLiteParserImpl::ParsePool(size_t subgraphIndex,
1940 size_t operatorIndex,
1941 PoolingAlgorithm algorithm)
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001942{
1943 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1944
Mike Kelly0d77ae12022-01-07 17:42:27 +00001945 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1946 const auto* options = operatorPtr->builtin_options.AsPool2DOptions();
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001947
1948 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1949
1950 std::string layerName;
1951
1952 switch (algorithm)
1953 {
1954 case PoolingAlgorithm::Average:
1955 layerName =
James Ward58dec6b2020-09-11 17:32:44 +01001956 fmt::format("AveragePool2D:{}:{}", subgraphIndex, operatorIndex);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001957 break;
1958 case PoolingAlgorithm::Max:
1959 layerName =
James Ward58dec6b2020-09-11 17:32:44 +01001960 fmt::format("MaxPool2D:{}:{}", subgraphIndex, operatorIndex);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001961 break;
1962 default:
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001963 ARMNN_ASSERT_MSG(false, "Unsupported Pooling Algorithm");
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001964 }
1965
1966 Pooling2dDescriptor desc;
1967
1968 desc.m_PoolType = algorithm;
1969 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1970 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1971 desc.m_PoolWidth = CHECKED_NON_NEGATIVE(options->filter_width);
1972 desc.m_PoolHeight = CHECKED_NON_NEGATIVE(options->filter_height);
1973 desc.m_PaddingMethod = PaddingMethod::Exclude;
1974 desc.m_OutputShapeRounding = OutputShapeRounding::Floor;
jimfly01c25411c2018-11-14 17:47:22 +00001975 desc.m_DataLayout = armnn::DataLayout::NHWC;
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001976
1977 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1978 CHECK_VALID_SIZE(inputs.size(), 1);
Mike Kelly377fb212023-01-10 15:55:28 +00001979 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001980
1981 // assuming input is NHWC
1982 unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1983 unsigned int inputWidth = inputTensorInfo.GetShape()[2];
1984
Pablo Tellof0bd6832019-04-26 17:58:13 +01001985 CalcPadding(inputHeight, desc.m_PoolHeight, desc.m_StrideY, 1u,
1986 desc.m_PadTop, desc.m_PadBottom, options->padding);
1987 CalcPadding(inputWidth, desc.m_PoolWidth, desc.m_StrideX, 1u,
1988 desc.m_PadLeft, desc.m_PadRight, options->padding);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001989
1990 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1991 CHECK_VALID_SIZE(outputs.size(), 1);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001992
James Conroy05102392020-06-24 15:39:55 +01001993 IConnectableLayer* layer = m_Network->AddPooling2dLayer(desc, layerName.c_str());
1994 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00001995
1996 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
1997 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
jimfly01c25411c2018-11-14 17:47:22 +00001998 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001999
2000 // register the input connection slots for the layer, connections are made after all layers have been created
2001 // only the tensors for the inputs are relevant, exclude the const tensors
2002 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
jimfly01c25411c2018-11-14 17:47:22 +00002003 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01002004
jimfly01c25411c2018-11-14 17:47:22 +00002005 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01002006 // register the output connection slots for the layer, connections are made after all layers have been created
2007 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2008 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2009}
2010
Kevin May7d96b162021-02-03 17:38:41 +00002011void TfLiteParserImpl::ParseSlice(size_t subgraphIndex, size_t operatorIndex)
josh minorba424d22019-11-13 10:55:17 -06002012{
2013 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2014
2015 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2016 CHECK_VALID_SIZE(inputs.size(), 3);
2017 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2018 CHECK_VALID_SIZE(outputs.size(), 1);
2019
2020 SliceDescriptor desc;
2021
2022 // set begin tensor info for slice descriptor
Mike Kelly377fb212023-01-10 15:55:28 +00002023 armnn::TensorInfo beginTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
josh minorba424d22019-11-13 10:55:17 -06002024 BufferRawPtr beginBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2025
2026 std::vector<unsigned int> begin(beginTensorInfo.GetNumElements());
2027 ::memcpy(begin.data(), beginBufferPtr->data.data(), beginTensorInfo.GetNumBytes());
2028
2029 // set size tensor info for slice descriptor
Mike Kelly377fb212023-01-10 15:55:28 +00002030 armnn::TensorInfo sizeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
josh minorba424d22019-11-13 10:55:17 -06002031 BufferRawPtr sizeBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
2032
Cathal Corbettde33dda2022-09-20 16:40:09 +01002033 std::vector<int> signedSize(sizeTensorInfo.GetNumElements(), 1);
2034
2035 // if size buffer data is not specified, all contents of size vector remain as values of 1
2036 if (sizeBufferPtr->data.data())
2037 {
2038 ::memcpy(signedSize.data(), sizeBufferPtr->data.data(), sizeTensorInfo.GetNumBytes());
2039 }
2040
josh minorba424d22019-11-13 10:55:17 -06002041 std::vector<unsigned int> size(sizeTensorInfo.GetNumElements());
Mike Kelly377fb212023-01-10 15:55:28 +00002042 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Mike Kelly7ba84d62021-09-10 15:27:19 +01002043
2044 for (unsigned int i = 0; i < signedSize.size(); ++i)
2045 {
2046 int signedValue = signedSize[i];
Jim Flynnfca233e2021-09-23 12:16:53 +01002047
Mike Kelly7ba84d62021-09-10 15:27:19 +01002048 if (signedValue < -1 || signedValue > static_cast<int>(inputTensorInfo.GetShape()[i] - begin[i]))
2049 {
2050 throw ParseException(fmt::format("Invalid value for size {} size must be in range "
2051 "[-1, inputDimSize - begin] [-1, {}] inclusive {}",
2052 signedValue,
2053 inputTensorInfo.GetShape()[i] - begin[i],
2054 CHECK_LOCATION().AsString()));
2055 }
2056
2057 if (signedValue == -1)
2058 {
2059 size[i] = inputTensorInfo.GetShape()[i] - begin[i];
2060 }
2061 else
2062 {
2063 size[i] = static_cast<unsigned int>(signedValue);
2064 }
2065 }
2066
josh minorba424d22019-11-13 10:55:17 -06002067 desc = SliceDescriptor(begin, size);
2068
James Ward58dec6b2020-09-11 17:32:44 +01002069 auto layerName = fmt::format("Slice:{}:{}", subgraphIndex, operatorIndex);
josh minorba424d22019-11-13 10:55:17 -06002070
James Conroy05102392020-06-24 15:39:55 +01002071 IConnectableLayer* const layer = m_Network->AddSliceLayer(desc, layerName.c_str());
Mike Kelly377fb212023-01-10 15:55:28 +00002072
2073 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
2074 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
josh minorba424d22019-11-13 10:55:17 -06002075 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2076
2077 // register the input connection slots for the layer, connections are made after all layers have been created
2078 // only the tensors for the inputs are relevant, exclude the const tensors
2079 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2080 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2081
2082 // register the output connection slots for the layer, connections are made after all layers have been created
2083 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2084 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2085}
2086
Kevin May7d96b162021-02-03 17:38:41 +00002087void TfLiteParserImpl::ParseSoftmax(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01002088{
2089 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00002090 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2091 const auto* options = operatorPtr->builtin_options.AsSoftmaxOptions();
telsoa01c577f2c2018-08-31 09:22:23 +01002092
2093 SoftmaxDescriptor desc;
2094 desc.m_Beta = options->beta;
2095
2096 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2097 CHECK_VALID_SIZE(inputs.size(), 1);
2098 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2099 CHECK_VALID_SIZE(outputs.size(), 1);
2100
James Ward58dec6b2020-09-11 17:32:44 +01002101 auto layerName = fmt::format("Softmax:{}:{}", subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01002102 IConnectableLayer* const layer = m_Network->AddSoftmaxLayer(desc, layerName.c_str());
2103
Mike Kelly377fb212023-01-10 15:55:28 +00002104 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
telsoa01c577f2c2018-08-31 09:22:23 +01002105 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2106
2107 // register the input connection slots for the layer, connections are made after all layers have been created
2108 // only the tensors for the inputs are relevant, exclude the const tensors
2109 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2110 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2111
2112 // register the output connection slots for the layer, connections are made after all layers have been created
2113 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2114 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2115}
2116
Teresa Charlinfd33a692022-06-29 15:35:57 +01002117void TfLiteParserImpl::ParseLogSoftmax(size_t subgraphIndex, size_t operatorIndex)
2118{
2119 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2120
2121 LogSoftmaxDescriptor desc;
2122
2123 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2124 CHECK_VALID_SIZE(inputs.size(), 1);
2125 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2126 CHECK_VALID_SIZE(outputs.size(), 1);
2127
2128 auto layerName = fmt::format("LogSoftmax:{}:{}", subgraphIndex, operatorIndex);
2129 IConnectableLayer* const layer = m_Network->AddLogSoftmaxLayer(desc, layerName.c_str());
2130
Mike Kelly377fb212023-01-10 15:55:28 +00002131 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Teresa Charlinfd33a692022-06-29 15:35:57 +01002132 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2133
2134 // register the input connection slots for the layer, connections are made after all layers have been created
2135 // only the tensors for the inputs are relevant, exclude the const tensors
2136 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2137 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2138
2139 // register the output connection slots for the layer, connections are made after all layers have been created
2140 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2141 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2142}
2143
Kevin May7d96b162021-02-03 17:38:41 +00002144void TfLiteParserImpl::ParseSpaceToBatchND(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesbaded142019-02-08 19:02:48 -02002145{
2146 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2147
2148 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2149 CHECK_VALID_SIZE(inputs.size(), 3);
2150
2151 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2152 CHECK_VALID_SIZE(outputs.size(), 1);
2153
Mike Kelly377fb212023-01-10 15:55:28 +00002154 armnn::TensorInfo blockShapeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalvesbaded142019-02-08 19:02:48 -02002155 BufferRawPtr blockShapeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2156
Mike Kelly377fb212023-01-10 15:55:28 +00002157 armnn::TensorInfo padListTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Bruno Goncalvesbaded142019-02-08 19:02:48 -02002158 BufferRawPtr padListBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
2159
2160 std::vector<unsigned int> blockShape(blockShapeTensorInfo.GetNumElements());
2161 ::memcpy(blockShape.data(), blockShapeBufferPtr->data.data(), blockShapeTensorInfo.GetNumBytes());
2162
2163 std::vector<unsigned int> padListVector(padListTensorInfo.GetNumElements());
2164 ::memcpy(padListVector.data(), padListBufferPtr->data.data(), padListTensorInfo.GetNumBytes());
2165
2166 size_t step = 2;
2167 std::vector<std::pair<unsigned int, unsigned int>> padList;
2168 for (unsigned int i = 0; i < padListTensorInfo.GetNumElements() / step; ++i)
2169 {
2170 padList.emplace_back(padListVector[i * step], padListVector[i * step + 1]);
2171 }
2172
2173 armnn::SpaceToBatchNdDescriptor desc;
2174 desc.m_BlockShape = blockShape;
2175 desc.m_PadList = padList;
2176 desc.m_DataLayout = armnn::DataLayout::NHWC;
2177
James Ward58dec6b2020-09-11 17:32:44 +01002178 auto layerName = fmt::format("SpaceToBatchND:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesbaded142019-02-08 19:02:48 -02002179
Mike Kelly377fb212023-01-10 15:55:28 +00002180 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
James Conroy05102392020-06-24 15:39:55 +01002181
2182 IConnectableLayer* layer = m_Network->AddSpaceToBatchNdLayer(desc, layerName.c_str());
2183 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00002184
2185 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
2186 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Bruno Goncalvesbaded142019-02-08 19:02:48 -02002187 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2188
2189 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2190 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2191
2192 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2193 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2194}
2195
Teresa Charlin2a764ad2023-02-24 18:17:31 +00002196void TfLiteParserImpl::ParseSpaceToDepth(size_t subgraphIndex, size_t operatorIndex)
2197{
2198 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2199
2200 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2201 CHECK_VALID_SIZE(inputs.size(), 1);
2202 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2203 CHECK_VALID_SIZE(outputs.size(), 1);
2204
2205 armnn::SpaceToDepthDescriptor descriptor;
2206
2207 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2208 const auto* options = operatorPtr->builtin_options.AsSpaceToDepthOptions();
2209 auto blockSize = options->block_size;
2210 if (blockSize < 2)
2211 {
2212 throw ParseException(
2213 fmt::format("Operation has invalid block size: {} Block size should be >= 2 {}",
2214 blockSize,
2215 CHECK_LOCATION().AsString()));
2216 }
2217 descriptor.m_BlockSize = armnn::numeric_cast<uint32_t>(blockSize);
2218
2219 auto layerName = fmt::format("SpaceToDepth:{}:{}", subgraphIndex, operatorIndex);
2220 IConnectableLayer* layer = m_Network->AddSpaceToDepthLayer(descriptor, layerName.c_str());
2221 ARMNN_ASSERT(layer != nullptr);
2222 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
2223 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2224
2225 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2226 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2227
2228 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2229 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2230}
2231
Teresa Charlin3ab85482021-06-08 16:59:29 +01002232armnn::TensorInfo TfLiteParserImpl::OutputShapeOfSqueeze(std::vector<uint32_t> squeezeDims,
Mike Kelly0d77ae12022-01-07 17:42:27 +00002233 const armnn::TensorInfo& inputTensorInfo)
telsoa01c577f2c2018-08-31 09:22:23 +01002234{
Teresa Charlin3ab85482021-06-08 16:59:29 +01002235 CHECK_VALID_SIZE(squeezeDims.size(), 0, 1, 2, 3, 4);
telsoa01c577f2c2018-08-31 09:22:23 +01002236 static const uint32_t dimensionSequence[] = { 0, 1, 2, 3 };
2237
2238 if (inputTensorInfo.GetNumDimensions() > 4)
2239 {
2240 std::stringstream ss;
2241 ss << "Input tensor has unexpected number of dimensions:" << inputTensorInfo.GetNumDimensions()
2242 << " shape:" << inputTensorInfo.GetShape() << " "
2243 << CHECK_LOCATION().AsString();
2244 throw ParseException(ss.str());
2245 }
2246
2247 if (squeezeDims.empty())
2248 {
2249 squeezeDims.assign(dimensionSequence,
2250 dimensionSequence+inputTensorInfo.GetNumDimensions());
2251 }
2252
2253 std::vector<uint32_t> outputDims;
2254 for(unsigned int i = 0; i < inputTensorInfo.GetNumDimensions(); i++)
2255 {
2256 bool skipSqueeze = (std::find(squeezeDims.begin(), squeezeDims.end(), i) == squeezeDims.end());
2257 auto currentDimension = inputTensorInfo.GetShape()[i];
2258 if (skipSqueeze || currentDimension != 1)
2259 {
2260 outputDims.push_back(currentDimension);
2261 }
2262 }
2263
2264 if (outputDims.size() > 4)
2265 {
2266 std::stringstream ss;
2267 ss << "Output tensor has unexpected number of dimensions:" << inputTensorInfo.GetNumDimensions()
2268 << " shape:" << inputTensorInfo.GetShape() << " "
2269 << CHECK_LOCATION().AsString();
2270 throw ParseException(ss.str());
2271 }
2272
2273 TensorShape outShape = TensorShape(static_cast<unsigned int>(outputDims.size()),
2274 outputDims.data());
2275
2276 // we need to preserve the tensor type and the quantization data as well
2277 TensorInfo outTensorInfo = inputTensorInfo;
2278 outTensorInfo.SetShape(outShape);
2279
2280 return outTensorInfo;
2281}
2282
Keith Davis0176fd82021-06-01 17:36:32 +01002283void TfLiteParserImpl::ParseShape(size_t subgraphIndex, size_t operatorIndex)
2284{
2285 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2286
2287 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2288 CHECK_VALID_SIZE(inputs.size(), 1);
2289 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2290 CHECK_VALID_SIZE(outputs.size(), 1);
2291
2292 auto layerName = fmt::format("Shape:{}:{}", subgraphIndex, operatorIndex);
2293
2294 IConnectableLayer* layer = m_Network->AddShapeLayer(layerName.c_str());
2295 ARMNN_ASSERT(layer != nullptr);
2296
Mike Kelly377fb212023-01-10 15:55:28 +00002297 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Keith Davis0176fd82021-06-01 17:36:32 +01002298 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2299
2300 // Check if output tensor type is Signed32 or Signed64
2301 if (outputTensorInfo.GetDataType() != armnn::DataType::Signed32 &&
2302 outputTensorInfo.GetDataType() != armnn::DataType::Signed64)
2303 {
2304 throw ParseException(
2305 fmt::format(
2306 "Output tensor data type is not supported. (Supported types: Signed32 & Signed64) {}",
2307 CHECK_LOCATION().AsString()));
2308 }
2309
2310 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2311 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2312
2313 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2314 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2315}
2316
Kevin May7d96b162021-02-03 17:38:41 +00002317void TfLiteParserImpl::ParseSqueeze(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01002318{
2319 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2320
2321 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2322 CHECK_VALID_SIZE(inputs.size(), 1);
2323
2324 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2325 CHECK_VALID_SIZE(outputs.size(), 1);
2326
2327 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2328 const auto * options = operatorPtr->builtin_options.AsSqueezeOptions();
James Ward58dec6b2020-09-11 17:32:44 +01002329 auto layerName = fmt::format("Squeeze:{}:{}", subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01002330
Mike Kelly377fb212023-01-10 15:55:28 +00002331 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Teresa Charlin3ab85482021-06-08 16:59:29 +01002332
2333 std::vector<uint32_t> squeezeDim;
2334 // A single negative dim index is interpreted as a negative index in python
2335 // Meaning the index will be the shape size plus the negative index value
2336 if (options->squeeze_dims.size() == 1 && options->squeeze_dims[0] < 0)
2337 {
2338 int32_t dim = static_cast<int32_t>(inputTensorInfo.GetShape().GetNumDimensions()) + options->squeeze_dims[0];
2339 squeezeDim.push_back(static_cast<uint32_t>(dim));
2340 }
2341 else
2342 {
2343 squeezeDim = AsUnsignedVector(options->squeeze_dims);
2344 }
2345
2346 armnn::TensorInfo outputTensorInfo = TfLiteParserImpl::OutputShapeOfSqueeze(squeezeDim, inputTensorInfo);
2347
James Conroy05102392020-06-24 15:39:55 +01002348 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
telsoa01c577f2c2018-08-31 09:22:23 +01002349
2350 ReshapeDescriptor reshapeDesc;
2351 reshapeDesc.m_TargetShape = outputTensorInfo.GetShape();
2352
Mike Kellyb2293702023-02-14 17:16:12 +00002353 auto outputTensorIds = GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex);
2354 m_TensorInfos[outputTensorIds[0]] = outputTensorInfo;
2355
telsoa01c577f2c2018-08-31 09:22:23 +01002356 IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002357 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01002358 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2359
2360 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2361 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2362
2363 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2364 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2365}
2366
Kevin May7d96b162021-02-03 17:38:41 +00002367void TfLiteParserImpl::ParseStridedSlice(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002368{
2369 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2370
2371 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2372 CHECK_VALID_SIZE(inputs.size(), 4);
2373
2374 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2375 CHECK_VALID_SIZE(outputs.size(), 1);
2376
Mike Kelly0d77ae12022-01-07 17:42:27 +00002377 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2378 const auto* options = operatorPtr->builtin_options.AsStridedSliceOptions();
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002379
2380 StridedSliceDescriptor desc;
2381 desc.m_BeginMask = options->begin_mask;
2382 desc.m_EllipsisMask = options->ellipsis_mask;
2383 desc.m_EndMask = options->end_mask;
2384 desc.m_NewAxisMask = options->new_axis_mask;
2385 desc.m_ShrinkAxisMask = options->shrink_axis_mask;
2386 desc.m_DataLayout = armnn::DataLayout::NHWC;
2387
Mike Kelly377fb212023-01-10 15:55:28 +00002388 armnn::TensorInfo beginTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002389 BufferRawPtr beginBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2390
2391 std::vector<int> begin(beginTensorInfo.GetNumElements());
2392 ::memcpy(begin.data(), beginBufferPtr->data.data(), beginTensorInfo.GetNumBytes());
2393
Mike Kelly377fb212023-01-10 15:55:28 +00002394 armnn::TensorInfo endTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002395 BufferRawPtr endBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
2396
2397 std::vector<int> end(endTensorInfo.GetNumElements());
2398 ::memcpy(end.data(), endBufferPtr->data.data(), endTensorInfo.GetNumBytes());
2399
Mike Kelly377fb212023-01-10 15:55:28 +00002400 armnn::TensorInfo strideTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 3);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002401 BufferRawPtr strideBufferPtr = GetBuffer(m_Model, inputs[3]->buffer);
2402
2403 std::vector<int> stride(strideTensorInfo.GetNumElements());
2404 ::memcpy(stride.data(), strideBufferPtr->data.data(), strideTensorInfo.GetNumBytes());
2405
2406 desc.m_Begin = begin;
2407 desc.m_End = end;
2408 desc.m_Stride = stride;
2409
James Ward58dec6b2020-09-11 17:32:44 +01002410 auto layerName = fmt::format("StridedSlice:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002411 IConnectableLayer* layer = m_Network->AddStridedSliceLayer(desc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002412 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002413
Mike Kelly377fb212023-01-10 15:55:28 +00002414 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002415 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2416
2417 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2418 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2419
2420 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2421 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2422}
2423
Kevin May7d96b162021-02-03 17:38:41 +00002424void TfLiteParserImpl::ParseSub(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002425{
2426 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2427
Mike Kelly0d77ae12022-01-07 17:42:27 +00002428 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2429 const auto* options = operatorPtr->builtin_options.AsSubOptions();
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002430
2431 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2432 CHECK_VALID_SIZE(inputs.size(), 2);
2433
2434 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2435 CHECK_VALID_SIZE(outputs.size(), 1);
2436
Mike Kelly377fb212023-01-10 15:55:28 +00002437 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2438 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002439
James Ward58dec6b2020-09-11 17:32:44 +01002440 auto layerName = fmt::format("Sub:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +00002441 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Sub, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002442 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002443
Mike Kelly377fb212023-01-10 15:55:28 +00002444 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002445 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2446
2447 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002448 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Teresa Charlind04873f2023-05-23 14:16:28 +01002449 if (options)
2450 {
2451 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2452 }
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002453
2454 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2455 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2456}
2457
Kevin May7d96b162021-02-03 17:38:41 +00002458void TfLiteParserImpl::ParseDiv(size_t subgraphIndex, size_t operatorIndex)
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302459{
2460 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2461
Mike Kelly0d77ae12022-01-07 17:42:27 +00002462 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2463 const auto* options = operatorPtr->builtin_options.AsDivOptions();
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302464
2465 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2466 CHECK_VALID_SIZE(inputs.size(), 2);
2467
2468 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2469 CHECK_VALID_SIZE(outputs.size(), 1);
2470
Mike Kelly377fb212023-01-10 15:55:28 +00002471 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2472 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302473
James Ward58dec6b2020-09-11 17:32:44 +01002474 auto layerName = fmt::format("Div:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +00002475 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Div, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002476 ARMNN_ASSERT(layer != nullptr);
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302477
Mike Kelly377fb212023-01-10 15:55:28 +00002478 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302479 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2480
2481 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002482 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Teresa Charlind04873f2023-05-23 14:16:28 +01002483 if (options)
2484 {
2485 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2486 }
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302487
2488 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2489 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2490}
2491
Teresa Charlincdbd40b2022-02-25 13:21:55 +00002492void TfLiteParserImpl::ParseFloorDiv(size_t subgraphIndex, size_t operatorIndex)
2493{
2494 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2495
2496 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2497 CHECK_VALID_SIZE(inputs.size(), 2);
2498
2499 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2500 CHECK_VALID_SIZE(outputs.size(), 1);
2501
Mike Kelly377fb212023-01-10 15:55:28 +00002502 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2503 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Teresa Charlincdbd40b2022-02-25 13:21:55 +00002504
2505 auto layerName = fmt::format("Div:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +00002506 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Div, layerName.c_str());
Teresa Charlincdbd40b2022-02-25 13:21:55 +00002507 ARMNN_ASSERT(layer != nullptr);
2508
Mike Kelly377fb212023-01-10 15:55:28 +00002509 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Teresa Charlincdbd40b2022-02-25 13:21:55 +00002510 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2511
2512 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2513 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
2514 layer = AddFusedFloorLayer(layer, 0);
2515
2516 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2517 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2518}
2519
Kevin May7d96b162021-02-03 17:38:41 +00002520void TfLiteParserImpl::ParseAdd(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002521{
2522 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2523
Mike Kelly0d77ae12022-01-07 17:42:27 +00002524 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2525 const auto* options = operatorPtr->builtin_options.AsAddOptions();
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002526
2527 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2528 CHECK_VALID_SIZE(inputs.size(), 2);
2529
2530 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2531 CHECK_VALID_SIZE(outputs.size(), 1);
2532
Mike Kelly377fb212023-01-10 15:55:28 +00002533 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2534 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves9c761a62018-12-27 14:20:35 -02002535
James Ward58dec6b2020-09-11 17:32:44 +01002536 auto layerName = fmt::format("Add:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +00002537 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Add, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002538 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002539
Mike Kelly377fb212023-01-10 15:55:28 +00002540 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002541 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2542
2543 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002544 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Teresa Charlind04873f2023-05-23 14:16:28 +01002545 if (options)
2546 {
2547 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2548 }
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002549
2550 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2551 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2552}
2553
Kevin May7d96b162021-02-03 17:38:41 +00002554void TfLiteParserImpl::ParseMul(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002555{
2556 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2557
Mike Kelly0d77ae12022-01-07 17:42:27 +00002558 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2559 const auto* options = operatorPtr->builtin_options.AsMulOptions();
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002560
2561 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2562 CHECK_VALID_SIZE(inputs.size(), 2);
2563
2564 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2565 CHECK_VALID_SIZE(outputs.size(), 1);
2566
Mike Kelly377fb212023-01-10 15:55:28 +00002567 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2568 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves9c761a62018-12-27 14:20:35 -02002569
James Ward58dec6b2020-09-11 17:32:44 +01002570 auto layerName = fmt::format("Mul:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +00002571 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Mul, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002572 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002573
Mike Kelly377fb212023-01-10 15:55:28 +00002574 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002575 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2576
2577 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002578 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Teresa Charlind04873f2023-05-23 14:16:28 +01002579 if (options)
2580 {
2581 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2582 }
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002583
2584 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2585 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2586}
2587
Kevin May7d96b162021-02-03 17:38:41 +00002588void TfLiteParserImpl::ParseMean(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002589{
2590 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2591
2592 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2593
2594 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2595 CHECK_VALID_SIZE(outputs.size(), 1);
2596
Teresa Charlin046e2cb2023-03-28 17:20:19 +01002597 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2598 TensorInfo dimTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002599
2600 armnn::MeanDescriptor desc;
Teresa Charlin046e2cb2023-03-28 17:20:19 +01002601 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2602 // Get const axis value from model and set it to descriptor.
2603 if (axisBufferPtr != nullptr)
2604 {
2605 std::vector<int32_t> axisData(dimTensorInfo.GetNumElements());
2606 ::memcpy(axisData.data(), axisBufferPtr->data.data(), dimTensorInfo.GetNumBytes());
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002607
Teresa Charlin046e2cb2023-03-28 17:20:19 +01002608 // Convert the axis to unsigned int and remove duplicates.
2609 auto rank = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
2610 std::set<unsigned int> uniqueAxis;
2611 std::transform(axisData.begin(),
2612 axisData.end(),
2613 std::inserter(uniqueAxis, uniqueAxis.begin()),
2614 [rank](int i)->unsigned int{
2615 return static_cast<uint32_t>(((i + rank) % rank)); });
2616 desc.m_Axis.assign(uniqueAxis.begin(), uniqueAxis.end());
2617 }
2618 else
2619 {
2620 for (uint32_t i = 0; i < inputTensorInfo.GetNumDimensions(); ++i)
2621 {
2622 desc.m_Axis.push_back(i);
2623 }
2624 }
2625
Sadik Armagand109a4d2020-07-28 10:42:13 +01002626 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002627
Teresa Charlin046e2cb2023-03-28 17:20:19 +01002628 desc.m_KeepDims = inputTensorInfo.GetNumDimensions() == outputTensorInfo.GetNumDimensions() ? true : false;
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002629
James Ward58dec6b2020-09-11 17:32:44 +01002630 auto layerName = fmt::format("Mean:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002631 IConnectableLayer* layer = m_Network->AddMeanLayer(desc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002632 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002633
Mike Kelly377fb212023-01-10 15:55:28 +00002634 outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002635 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2636
2637 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2638 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2639
2640 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2641 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2642}
2643
Kevin May7d96b162021-02-03 17:38:41 +00002644void TfLiteParserImpl::ParsePad(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002645{
2646 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2647
Kevin May7d96b162021-02-03 17:38:41 +00002648 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002649
Kevin May7d96b162021-02-03 17:38:41 +00002650 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002651 CHECK_VALID_SIZE(outputs.size(), 1);
2652
Mike Kelly377fb212023-01-10 15:55:28 +00002653 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2654 armnn::TensorInfo padTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002655
Mike Kelly0d77ae12022-01-07 17:42:27 +00002656 std::vector<unsigned int> padBuffer = GetUIntBuffer(padTensorInfo, m_Model, inputs[1]->buffer);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002657
2658 size_t step = 2;
2659 armnn::PadDescriptor desc;
Mike Kelly0d77ae12022-01-07 17:42:27 +00002660 auto opcode = GetOpCode(m_Model, subgraphIndex, operatorIndex);
2661
2662 if (opcode == tflite::BuiltinOperator_PAD)
Narumol Prangnawarat8719d222020-11-27 16:57:56 +00002663 {
Mike Kelly0d77ae12022-01-07 17:42:27 +00002664 CHECK_VALID_SIZE(inputs.size(), 2);
2665
2666 if (inputTensorInfo.IsQuantized())
2667 {
2668 desc.m_PadValue = static_cast<float>(inputTensorInfo.GetQuantizationOffset());
2669 }
Narumol Prangnawarat8719d222020-11-27 16:57:56 +00002670 }
Mike Kelly0d77ae12022-01-07 17:42:27 +00002671 else if (opcode == tflite::BuiltinOperator_PADV2)
2672 {
2673 CHECK_VALID_SIZE(inputs.size(), 3);
2674
Mike Kelly377fb212023-01-10 15:55:28 +00002675 armnn::TensorInfo padValueTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Mike Kelly0d77ae12022-01-07 17:42:27 +00002676
2677 if (padValueTensorInfo.GetNumElements() != 1)
2678 {
2679 ARMNN_THROW_PARSE_EXCEPTION("Multiple padding values are not supported in PADV2");
2680 }
2681 BufferRawPtr padValueBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
2682
2683 // Get the pad value from the input tensor
2684 if (padValueBufferPtr->data.size() > 0)
2685 {
2686 switch (padValueTensorInfo.GetDataType())
2687 {
2688 case armnn::DataType::Float32:
2689 {
2690 std::vector<float> padValueBuffer(padValueTensorInfo.GetNumElements());
2691 ::memcpy(padValueBuffer.data(), padValueBufferPtr->data.data(), padValueBufferPtr->data.size());
2692 desc.m_PadValue = padValueBuffer[0];
2693 break;
2694 }
2695 case armnn::DataType::QAsymmU8:
2696 {
2697 std::vector<uint8_t> padValueBuffer(padValueTensorInfo.GetNumElements());
2698 ::memcpy(padValueBuffer.data(), padValueBufferPtr->data.data(), padValueBufferPtr->data.size());
2699 desc.m_PadValue = armnn::Dequantize<uint8_t>(padValueBuffer[0],
2700 padValueTensorInfo.GetQuantizationScale(),
2701 padValueTensorInfo.GetQuantizationOffset());
2702 break;
2703 }
2704 case armnn::DataType::QAsymmS8:
2705 case armnn::DataType::QSymmS8:
2706 {
2707 std::vector<int8_t> padValueBuffer(padValueTensorInfo.GetNumElements());
2708 ::memcpy(padValueBuffer.data(), padValueBufferPtr->data.data(), padValueBufferPtr->data.size());
2709 desc.m_PadValue = armnn::Dequantize<int8_t>(padValueBuffer[0],
2710 padValueTensorInfo.GetQuantizationScale(),
2711 padValueTensorInfo.GetQuantizationOffset());
2712 break;
2713 }
2714 default: ARMNN_THROW_PARSE_EXCEPTION("Unsupported DataType");
2715 }
2716 }
2717 else if (inputTensorInfo.IsQuantized())
2718 {
2719 desc.m_PadValue = static_cast<float>(inputTensorInfo.GetQuantizationOffset());
2720 }
2721 }
2722
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002723 for (unsigned int i = 0; i < padTensorInfo.GetNumElements() / step; ++i)
2724 {
2725 desc.m_PadList.emplace_back(padBuffer[i * step], padBuffer[i * step + 1]);
2726 }
2727
Mike Kelly0d77ae12022-01-07 17:42:27 +00002728 auto layerName = (opcode == tflite::BuiltinOperator_PAD) ? fmt::format("Pad:{}:{}", subgraphIndex, operatorIndex)
2729 : fmt::format("PadV2:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01002730
2731 IConnectableLayer* layer = m_Network->AddPadLayer(desc, layerName.c_str());
2732 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00002733 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002734 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2735
2736 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2737 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2738
2739 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2740 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2741}
2742
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002743void TfLiteParserImpl::ParseMirrorPad(size_t subgraphIndex, size_t operatorIndex)
2744{
2745 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2746
2747 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2748 CHECK_VALID_SIZE(inputs.size(), 2);
2749
2750 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2751 CHECK_VALID_SIZE(outputs.size(), 1);
2752
Mike Kelly377fb212023-01-10 15:55:28 +00002753 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002754
Mike Kelly377fb212023-01-10 15:55:28 +00002755 armnn::TensorInfo padTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002756 BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2757
2758 std::vector<unsigned int> padBuffer(padTensorInfo.GetNumElements());
2759 ::memcpy(padBuffer.data(), bufferPtr->data.data(), padTensorInfo.GetNumBytes());
2760
2761 size_t step = 2;
2762 armnn::PadDescriptor desc;
2763 for (unsigned int i = 0; i < padTensorInfo.GetNumElements() / step; ++i)
2764 {
2765 desc.m_PadList.emplace_back(padBuffer[i * step], padBuffer[i * step + 1]);
2766 }
2767
2768 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2769 const auto* options = operatorPtr->builtin_options.AsMirrorPadOptions();
2770
2771 if (options->mode == tflite::MirrorPadMode_REFLECT)
2772 {
2773 desc.m_PaddingMode = PaddingMode::Reflect;
2774 }
2775 else if (options->mode == tflite::MirrorPadMode_SYMMETRIC)
2776 {
2777 desc.m_PaddingMode = PaddingMode::Symmetric;
2778 }
2779 else
2780 {
2781 ARMNN_THROW_PARSE_EXCEPTION("PaddingMode must be either REFLECT or SYMMETRIC");
2782 }
2783
2784 // If padding mode is Reflect then both paddings must be no greater than inputShape(i) - 1.
2785 // If padding mode is Symmetric then both paddings must be no greater than inputShape(i).
2786 auto inputShape = inputTensorInfo.GetShape();
2787 auto padList = desc.m_PadList;
2788
2789 const unsigned int isReflect = static_cast<unsigned int>(desc.m_PaddingMode == PaddingMode::Reflect);
2790 for(unsigned int i = 0; i < padList.size(); ++i)
2791 {
2792 if(padList.at(i).first > (inputShape[i] - isReflect) ||
2793 padList.at(i).second > (inputShape[i] - isReflect))
2794 {
2795 ARMNN_THROW_PARSE_EXCEPTION("Padding values must be less (Reflect) or "
2796 "equal (Symmetric) to the dimension size.");
2797 }
2798 }
2799
2800 auto layerName = fmt::format("MirrorPad:{}:{}", subgraphIndex, operatorIndex);
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002801
2802 IConnectableLayer* layer = m_Network->AddPadLayer(desc, layerName.c_str());
2803 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00002804 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002805 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2806
2807 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2808 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2809
2810 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2811 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2812}
2813
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002814void TfLiteParserImpl::ParsePrelu(size_t subgraphIndex, size_t operatorIndex)
2815{
2816 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2817
2818 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2819 CHECK_VALID_SIZE(inputs.size(), 2);
2820
2821 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2822 CHECK_VALID_SIZE(outputs.size(), 1);
2823
2824 auto layerName = fmt::format("Prelu:{}:{}", subgraphIndex, operatorIndex);
2825
Mike Kelly377fb212023-01-10 15:55:28 +00002826 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2827 armnn::TensorInfo alphaTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002828
2829 IConnectableLayer* layer = m_Network->AddPreluLayer(layerName.c_str());
2830 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00002831
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002832
2833 if (IsConstTensor(inputs[1]))
2834 {
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002835 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawaratbf99b5f2021-05-27 09:55:43 +01002836 armnn::IInputSlot* slot = &(layer->GetInputSlot(0));
2837 RegisterConsumerOfTensor(subgraphIndex, inputTensorIndexes[0], slot);
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002838
Mike Kelly5880b912022-01-28 16:18:54 +00002839 auto alphaTensorAndData = CreateConstTensorNonPermuted(inputs[1], alphaTensorInfo,
2840 inputTensorInfo.GetDataType());
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002841 std::string constLayerName = fmt::format("Constant:{}", inputs[1]->name);
2842 IConnectableLayer* constLayer =
Mike Kelly5880b912022-01-28 16:18:54 +00002843 m_Network->AddConstantLayer(alphaTensorAndData.first, constLayerName.c_str());
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002844 ARMNN_ASSERT(constLayer != nullptr);
2845
2846 constLayer->GetOutputSlot(0).SetTensorInfo(alphaTensorInfo);
2847 constLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1));
2848 RegisterOutputSlots(subgraphIndex,
2849 VIRTUAL_OPERATOR_ID,
2850 constLayer,
2851 { inputTensorIndexes[1] });
2852 }
2853 else
2854 {
2855 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2856 RegisterInputSlots(subgraphIndex, operatorIndex, layer, inputTensorIndexes);
2857 }
2858
Mike Kelly377fb212023-01-10 15:55:28 +00002859 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
2860 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
2861 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2862
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002863 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2864 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2865}
2866
Kevin May7d96b162021-02-03 17:38:41 +00002867void TfLiteParserImpl::ParseQuantize(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan66dedc72019-12-10 16:32:07 +00002868{
2869 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2870
2871 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2872 CHECK_VALID_SIZE(inputs.size(), 1);
2873
2874 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2875 CHECK_VALID_SIZE(outputs.size(), 1);
2876
James Ward58dec6b2020-09-11 17:32:44 +01002877 auto layerName = fmt::format("Quantize:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan66dedc72019-12-10 16:32:07 +00002878
2879 IConnectableLayer* layer = m_Network->AddQuantizeLayer(layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01002880 ARMNN_ASSERT(layer != nullptr);
Sadik Armagan66dedc72019-12-10 16:32:07 +00002881
Mike Kelly377fb212023-01-10 15:55:28 +00002882 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Sadik Armagan66dedc72019-12-10 16:32:07 +00002883 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2884
2885 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2886 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2887
2888 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2889 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2890}
Finn Williamsc42c3842019-01-22 14:18:11 +00002891
Kevin May7d96b162021-02-03 17:38:41 +00002892void TfLiteParserImpl::ParseRelu(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan58f39192018-09-17 14:14:39 +01002893{
Finn Williamsc42c3842019-01-22 14:18:11 +00002894 ParseActivation(subgraphIndex,operatorIndex, ActivationFunction::ReLu);
Sadik Armagan58f39192018-09-17 14:14:39 +01002895}
2896
Kevin May7d96b162021-02-03 17:38:41 +00002897void TfLiteParserImpl::ParseRelu6(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan58f39192018-09-17 14:14:39 +01002898{
Finn Williamsc42c3842019-01-22 14:18:11 +00002899 ParseActivation(subgraphIndex,operatorIndex, ActivationFunction::BoundedReLu);
2900}
Sadik Armagan58f39192018-09-17 14:14:39 +01002901
Kevin May7d96b162021-02-03 17:38:41 +00002902void TfLiteParserImpl::ParseLeakyRelu(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan12239e72020-05-27 11:06:17 +01002903{
Jan Eilers2f746b32020-07-28 14:00:06 +01002904 ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::LeakyReLu);
Sadik Armagan12239e72020-05-27 11:06:17 +01002905}
2906
Kevin May7d96b162021-02-03 17:38:41 +00002907void TfLiteParserImpl::ParseLogistic(size_t subgraphIndex, size_t operatorIndex)
Finn Williamsc42c3842019-01-22 14:18:11 +00002908{
2909 ParseActivation(subgraphIndex,operatorIndex,ActivationFunction::Sigmoid);
2910}
2911
Kevin May7d96b162021-02-03 17:38:41 +00002912void TfLiteParserImpl::ParseTanH(size_t subgraphIndex, size_t operatorIndex)
Nina Drozd99851762019-04-09 09:37:38 +01002913{
2914 ParseActivation(subgraphIndex,operatorIndex,ActivationFunction::TanH);
2915}
2916
Kevin May7d96b162021-02-03 17:38:41 +00002917void TfLiteParserImpl::ParseElu(size_t subgraphIndex, size_t operatorIndex)
Matthew Sloyan7515d072020-12-16 12:50:01 +00002918{
2919 ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::Elu);
2920}
2921
Kevin May7d96b162021-02-03 17:38:41 +00002922void TfLiteParserImpl::ParseHardSwish(size_t subgraphIndex, size_t operatorIndex)
Jan Eilers2f746b32020-07-28 14:00:06 +01002923{
2924 ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::HardSwish);
2925}
Finn Williamsc42c3842019-01-22 14:18:11 +00002926
Kevin May7d96b162021-02-03 17:38:41 +00002927void TfLiteParserImpl::ParseActivation(size_t subgraphIndex, size_t operatorIndex, ActivationFunction activationType)
Finn Williamsc42c3842019-01-22 14:18:11 +00002928{
2929 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00002930 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
Jan Eilers8eb25602020-03-09 12:13:48 +00002931 IgnoreUnused(operatorPtr);
Sadik Armagan58f39192018-09-17 14:14:39 +01002932
2933 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2934 CHECK_VALID_SIZE(inputs.size(), 1);
2935
2936 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2937 CHECK_VALID_SIZE(outputs.size(), 1);
2938
James Ward58dec6b2020-09-11 17:32:44 +01002939 auto layerName = fmt::format("Activation:");
Sadik Armagan58f39192018-09-17 14:14:39 +01002940 ActivationDescriptor activationDesc;
Finn Williamsc42c3842019-01-22 14:18:11 +00002941 activationDesc.m_Function = activationType;
2942
2943 switch (activationType)
2944 {
2945 case ActivationFunction::ReLu:
2946 {
James Ward58dec6b2020-09-11 17:32:44 +01002947 layerName += fmt::format("RELU:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsc42c3842019-01-22 14:18:11 +00002948 break;
2949 }
2950 case ActivationFunction::BoundedReLu:
2951 {
James Ward58dec6b2020-09-11 17:32:44 +01002952 layerName += fmt::format("RELU6:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsc42c3842019-01-22 14:18:11 +00002953 activationDesc.m_A = 6.0f;
2954 activationDesc.m_B = 0.0f;
2955 break;
2956 }
2957 case ActivationFunction::Sigmoid:
2958 {
James Ward58dec6b2020-09-11 17:32:44 +01002959 layerName += fmt::format("SIGMOID:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsc42c3842019-01-22 14:18:11 +00002960 break;
2961 }
Nina Drozd99851762019-04-09 09:37:38 +01002962 case ActivationFunction::TanH:
2963 {
James Ward58dec6b2020-09-11 17:32:44 +01002964 layerName += fmt::format("TANH:{}:{}", subgraphIndex, operatorIndex);
Nina Drozd99851762019-04-09 09:37:38 +01002965 activationDesc.m_A = 1.0f;
2966 activationDesc.m_B = 1.0f;
2967 break;
2968 }
Sadik Armagan12239e72020-05-27 11:06:17 +01002969 case ActivationFunction::LeakyReLu:
2970 {
James Ward58dec6b2020-09-11 17:32:44 +01002971 layerName += fmt::format("LEAKYRELU:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00002972 const auto* options = operatorPtr->builtin_options.AsLeakyReluOptions();
Sadik Armagan12239e72020-05-27 11:06:17 +01002973 activationDesc.m_A = options->alpha;
2974 break;
2975 }
Matthew Sloyan7515d072020-12-16 12:50:01 +00002976 case ActivationFunction::Elu:
2977 {
2978 layerName += fmt::format("ELU:{}:{}", subgraphIndex, operatorIndex);
2979 activationDesc.m_A = 1.0f;
2980 break;
2981 }
Jan Eilers2f746b32020-07-28 14:00:06 +01002982 case ActivationFunction::HardSwish:
Matthew Sloyan7515d072020-12-16 12:50:01 +00002983 {
James Ward58dec6b2020-09-11 17:32:44 +01002984 layerName += fmt::format("HARDSWISH:{}:{}", subgraphIndex, operatorIndex);
Jan Eilers2f746b32020-07-28 14:00:06 +01002985 break;
Matthew Sloyan7515d072020-12-16 12:50:01 +00002986 }
Finn Williamsc42c3842019-01-22 14:18:11 +00002987 default:
2988 {
2989 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01002990 fmt::format("Unexpected ActivationFunction[{}] when creating layerName {} ",
2991 static_cast<int>(activationType), CHECK_LOCATION().AsString()));
Finn Williamsc42c3842019-01-22 14:18:11 +00002992 }
2993 }
2994
2995 IConnectableLayer* const layer = m_Network->AddActivationLayer(activationDesc, layerName.c_str());
Sadik Armagan58f39192018-09-17 14:14:39 +01002996
Mike Kelly377fb212023-01-10 15:55:28 +00002997 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Sadik Armagan58f39192018-09-17 14:14:39 +01002998 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2999
3000 // register the input connection slots for the layer, connections are made after all layers have been created
3001 // only the tensors for the inputs are relevant, exclude the const tensors
3002 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3003 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3004
3005 // register the output connection slots for the layer, connections are made after all layers have been created
3006 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3007 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3008}
Mike Kelly0d77ae12022-01-07 17:42:27 +00003009armnn::TensorInfo TfLiteParserImpl::OutputShapeOfReshape(const armnn::TensorInfo& inputTensorInfo,
3010 const std::vector<int32_t>& targetDimsIn)
Sadikb94967b2018-09-19 15:30:00 +01003011{
3012 std::vector<unsigned int> outputDims(targetDimsIn.begin(), targetDimsIn.end());
3013 const auto stretchDim = std::find(targetDimsIn.begin(), targetDimsIn.end(), -1);
3014
3015 if (stretchDim != targetDimsIn.end())
3016 {
3017 if (std::find(std::next(stretchDim), targetDimsIn.end(), -1) != targetDimsIn.end())
3018 {
3019 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003020 fmt::format("At most one component of shape can be -1 {}", CHECK_LOCATION().AsString()));
Sadikb94967b2018-09-19 15:30:00 +01003021 }
3022
3023 auto targetNumElements =
Matthew Sloyan589e3e82020-09-11 16:17:48 +01003024 armnn::numeric_cast<unsigned int>(
Sadikb94967b2018-09-19 15:30:00 +01003025 std::accumulate(targetDimsIn.begin(), targetDimsIn.end(), -1, std::multiplies<int32_t>()));
3026
3027 auto stretchIndex = static_cast<size_t>(std::distance(targetDimsIn.begin(), stretchDim));
3028 outputDims[stretchIndex] = inputTensorInfo.GetNumElements() / targetNumElements;
3029 }
3030
3031 TensorShape outputShape = TensorShape(static_cast<unsigned int>(outputDims.size()), outputDims.data());
3032
3033 TensorInfo reshapeInfo = inputTensorInfo;
3034 reshapeInfo.SetShape(outputShape);
3035
3036 return reshapeInfo;
3037}
3038
Kevin May7d96b162021-02-03 17:38:41 +00003039void TfLiteParserImpl::ParseReshape(size_t subgraphIndex, size_t operatorIndex)
Sadikb94967b2018-09-19 15:30:00 +01003040{
3041 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3042
3043 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Sadikb94967b2018-09-19 15:30:00 +01003044
3045 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3046 CHECK_VALID_SIZE(outputs.size(), 1);
3047
Mike Kelly0d77ae12022-01-07 17:42:27 +00003048 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3049 const auto* options = operatorPtr->builtin_options.AsReshapeOptions();
James Ward58dec6b2020-09-11 17:32:44 +01003050 auto layerName = fmt::format("Reshape:{}:{}", subgraphIndex, operatorIndex);
Sadikb94967b2018-09-19 15:30:00 +01003051
Mike Kelly377fb212023-01-10 15:55:28 +00003052 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
kevmay0171972a82018-12-17 14:28:03 +00003053 armnn::TensorInfo actualOutputTensorInfo = ToTensorInfo(outputs[0]);
James Conroy05102392020-06-24 15:39:55 +01003054 CheckMatchingQuantization(inputTensorInfo, actualOutputTensorInfo, layerName, "Input 0", "Output 0");
Derek Lambertic9e52792020-03-11 11:42:26 +00003055
Jan Eilersbac9b352020-07-13 13:40:24 +01003056 // Extracting new shape for the output
3057 // There are two ways it can be passed
3058 // * First is to define the target shape in the operator built-in options
3059 // * Second is to pass it as a second input tensor
Derek Lambertic9e52792020-03-11 11:42:26 +00003060 std::vector<int32_t> targetShape;
Jan Eilersbac9b352020-07-13 13:40:24 +01003061 bool targetShapeFound = false;
3062 // Check if built-in options were given
3063 if (options != nullptr)
Derek Lambertic9e52792020-03-11 11:42:26 +00003064 {
Jan Eilersbac9b352020-07-13 13:40:24 +01003065 // make sure the parameter is given
3066 if (options->new_shape.empty() == false)
Derek Lambertic9e52792020-03-11 11:42:26 +00003067 {
Jan Eilersbac9b352020-07-13 13:40:24 +01003068 targetShape = options->new_shape;
3069 targetShapeFound = true;
Derek Lambertif4a953f2020-03-17 14:25:57 +00003070 }
Derek Lambertic9e52792020-03-11 11:42:26 +00003071 }
Jan Eilersbac9b352020-07-13 13:40:24 +01003072
3073 // If there is no built-in option given or if the built-in new_shape parameter was empty
3074 if (!targetShapeFound)
Derek Lambertic9e52792020-03-11 11:42:26 +00003075 {
Teresa Charlin6a056a42021-12-01 10:25:43 +00003076 // Check for a second input tensor
3077 if (inputs.size() > 1 && inputs[1] != nullptr)
Jan Eilersbac9b352020-07-13 13:40:24 +01003078 {
3079 if (inputs[1]->is_variable)
3080 {
3081 ARMNN_THROW_PARSE_EXCEPTION( "Target shapes defined in non-const input tensors is not supported");
3082 }
3083
3084 if (inputs[1]->shape.size() != 1)
3085 {
3086 ARMNN_THROW_PARSE_EXCEPTION("Target 'shape' input is not a 1D tensor");
3087 }
3088
3089 if (inputs[1]->type != tflite::TensorType_INT32)
3090 {
3091 ARMNN_THROW_PARSE_EXCEPTION("Target 'shape' input is not an int32 type");
3092 }
3093
Teresa Charlin6a056a42021-12-01 10:25:43 +00003094 // Extract target shape from input
3095 auto bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
3096 auto values = reinterpret_cast<const int32_t*>(bufferPtr->data.data());
Cathal Corbettd2f73232021-12-10 13:38:52 +00003097 if (values)
Sadik Armagan19a1c032021-01-20 12:17:00 +00003098 {
Cathal Corbettd2f73232021-12-10 13:38:52 +00003099 for (int i = 0; i < inputs[1]->shape[0]; ++i)
3100 {
3101 targetShape.push_back(values[i]);
3102 }
Sadik Armagan19a1c032021-01-20 12:17:00 +00003103 }
Cathal Corbettd2f73232021-12-10 13:38:52 +00003104 else
Jan Eilersbac9b352020-07-13 13:40:24 +01003105 {
Cathal Corbettd2f73232021-12-10 13:38:52 +00003106 try
3107 {
3108 // We attempt to infer during Runtime.
Mike Kelly04d82292023-01-19 18:29:40 +00003109 TensorShape reshapeShapes = ToTensorInfo(inputs[1]).GetShape();
3110
3111 if (reshapeShapes[0] == actualOutputTensorInfo.GetNumDimensions())
3112 {
3113 for (unsigned int i = 0; i < actualOutputTensorInfo.GetShape().GetNumDimensions(); ++i)
3114 {
3115 targetShape.push_back(actualOutputTensorInfo.GetShape()[i]);
3116 }
3117 }
Cathal Corbettd2f73232021-12-10 13:38:52 +00003118 // The parser only supports shape (batch, -1) or (-1) for non-constant shape input.
Mike Kelly04d82292023-01-19 18:29:40 +00003119 else if (reshapeShapes[0] > 2)
Cathal Corbettd2f73232021-12-10 13:38:52 +00003120 {
3121 throw ParseException(fmt::format("Invalid input shape '{}' in Reshape layer '{}' {}. "
3122 "When inferring during runtime, the parser only supports "
3123 "shape (batch, -1) or (-1) for target shape input.",
3124 reshapeShapes[0],
3125 layerName,
3126 CHECK_LOCATION().AsString()));
3127 }
Mike Kelly04d82292023-01-19 18:29:40 +00003128 else
Cathal Corbettd2f73232021-12-10 13:38:52 +00003129 {
Mike Kelly04d82292023-01-19 18:29:40 +00003130 const int32_t numInputElements = inputTensorInfo.GetNumElements();
3131 const int32_t inputTensorShape = inputTensorInfo.GetShape()[0];
3132 if (reshapeShapes[0] == 1)
3133 {
3134 targetShape = {numInputElements};
3135 }
3136 else if (reshapeShapes[0] == 2)
3137 {
3138 targetShape = {inputTensorShape, numInputElements / inputTensorShape};
3139 }
Cathal Corbettd2f73232021-12-10 13:38:52 +00003140 }
3141 }
3142 catch (const std::exception& exc)
3143 {
3144 ARMNN_THROW_PARSE_EXCEPTION("Failed attempt to infer during runtime the target shape input for "
3145 "Reshape operation. Reshape operator target shape input buffer data "
3146 "is null. " << exc.what());
3147 }
Jan Eilersbac9b352020-07-13 13:40:24 +01003148 }
3149 }
3150 else
Derek Lambertic9e52792020-03-11 11:42:26 +00003151 {
3152 ARMNN_THROW_PARSE_EXCEPTION("Target shape not defined in reshape parameters or input tensor. "
3153 "At least one method required");
3154 }
Derek Lambertic9e52792020-03-11 11:42:26 +00003155 }
3156
kevmay0171972a82018-12-17 14:28:03 +00003157 armnn::TensorInfo reshapeOutputTensorInfo =
Kevin May7d96b162021-02-03 17:38:41 +00003158 TfLiteParserImpl::OutputShapeOfReshape(inputTensorInfo, targetShape);
Sadikb94967b2018-09-19 15:30:00 +01003159
kevmay0171972a82018-12-17 14:28:03 +00003160 // Check for valid input size and that reshape parameters equal output shape
Cathal Corbett2b922e22022-09-23 15:49:24 +01003161 // The output shape can be provided to us in 2 ways:
3162 // 1. through the normal 'shape' parameter given by outputs[indx]->shape
3163 // 2. through additional parameter 'shape_signature' given by outputs[indx]->buffer.
3164 // This parameter can sometimes contain -1 value not visible in the 'shape' parameter.
Aron Virginas-Tar70672f62019-01-23 14:00:00 +00003165 const armnn::TensorShape& reshapeOutputTensorShape = reshapeOutputTensorInfo.GetShape();
3166 if (inputs.size() > 1 && !CheckShape(reshapeOutputTensorShape, outputs[0]->shape))
kevmay0171972a82018-12-17 14:28:03 +00003167 {
Cathal Corbett2b922e22022-09-23 15:49:24 +01003168 // Attempt to extract output shape from secondary 'shape_signature'
3169 // parameter and try to CheckShape() with this param.
3170 std::vector<int32_t> secondaryOutputTargetShape = outputs[0]->shape_signature;
3171
3172 // if outputs[0]->shape_signature contain a -1 value, we need to compute its actual value
3173 // from reshape input in order to correctly verify reshape parameters equal output shape
3174 armnn::TensorInfo secondaryReshapeOutputTensorInfo =
3175 TfLiteParserImpl::OutputShapeOfReshape(inputTensorInfo, secondaryOutputTargetShape);
3176
3177 if (!CheckShape(reshapeOutputTensorShape, secondaryReshapeOutputTensorInfo.GetShape()))
3178 {
3179 std::stringstream ss;
3180 ss << "New shape defined in reshape parameters "
3181 << reshapeOutputTensorShape
3182 << " does not equal output shape "
3183 << actualOutputTensorInfo.GetShape()
3184 << ": "
3185 << CHECK_LOCATION().AsString();
3186 throw ParseException(ss.str());
3187 }
kevmay0171972a82018-12-17 14:28:03 +00003188 }
Mike Kelly377fb212023-01-10 15:55:28 +00003189 auto outputTensorIds = GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex);
kevmay0171972a82018-12-17 14:28:03 +00003190
Sadikb94967b2018-09-19 15:30:00 +01003191 ReshapeDescriptor reshapeDesc;
kevmay0171972a82018-12-17 14:28:03 +00003192 reshapeDesc.m_TargetShape = reshapeOutputTensorInfo.GetShape();
Mike Kelly377fb212023-01-10 15:55:28 +00003193 m_TensorInfos[outputTensorIds[0]] = reshapeOutputTensorInfo;
Sadikb94967b2018-09-19 15:30:00 +01003194
Sadikb94967b2018-09-19 15:30:00 +01003195 IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01003196 ARMNN_ASSERT(layer != nullptr);
kevmay0171972a82018-12-17 14:28:03 +00003197 layer->GetOutputSlot(0).SetTensorInfo(reshapeOutputTensorInfo);
Sadikb94967b2018-09-19 15:30:00 +01003198
3199 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3200 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3201
3202 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3203 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3204}
3205
Kevin May7d96b162021-02-03 17:38:41 +00003206void TfLiteParserImpl::ParseResizeBilinear(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003207{
Sadik Armagana3b31f02019-12-05 09:08:53 +00003208 ParseResize(subgraphIndex, operatorIndex, ResizeMethod::Bilinear);
3209}
3210
Kevin May7d96b162021-02-03 17:38:41 +00003211void TfLiteParserImpl::ParseResizeNearestNeighbor(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagana3b31f02019-12-05 09:08:53 +00003212{
3213 ParseResize(subgraphIndex, operatorIndex, ResizeMethod::NearestNeighbor);
3214}
3215
Kevin May7d96b162021-02-03 17:38:41 +00003216void TfLiteParserImpl::ParseResize(size_t subgraphIndex, size_t operatorIndex, ResizeMethod resizeMethod)
Sadik Armagana3b31f02019-12-05 09:08:53 +00003217{
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003218 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3219
3220 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3221 CHECK_VALID_SIZE(inputs.size(), 2);
3222
3223 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3224 CHECK_VALID_SIZE(outputs.size(), 1);
3225
Mike Kelly377fb212023-01-10 15:55:28 +00003226 armnn::TensorInfo sizeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003227
3228 // Data for the parsed tensor args (size) must be stored locally.
3229 std::vector<int32_t> sizeTensorData(sizeTensorInfo.GetNumElements());
3230
3231 BufferRawPtr sizeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
3232 ::memcpy(sizeTensorData.data(), sizeBufferPtr->data.data(), sizeTensorInfo.GetNumBytes());
3233
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01003234 ResizeDescriptor desc;
Sadik Armagana3b31f02019-12-05 09:08:53 +00003235 desc.m_Method = resizeMethod;
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003236 desc.m_TargetHeight = static_cast<uint32_t> (sizeTensorData[0]);
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01003237 desc.m_TargetWidth = static_cast<uint32_t> (sizeTensorData[1]);
3238 desc.m_DataLayout = armnn::DataLayout::NHWC;
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003239
James Ward58dec6b2020-09-11 17:32:44 +01003240 auto layerName = fmt::format("Resize:");
Sadik Armagana3b31f02019-12-05 09:08:53 +00003241
3242 switch (resizeMethod)
3243 {
3244 case ResizeMethod::Bilinear:
3245 {
James Ward58dec6b2020-09-11 17:32:44 +01003246 layerName += fmt::format("BILINEAR:{}:{}", subgraphIndex, operatorIndex);
Sang-Hoon Park820eb142020-01-08 10:25:24 +00003247
3248 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3249 const auto * options = operatorPtr->builtin_options.AsResizeBilinearOptions();
3250
David Monahan4a0c9b92020-05-30 09:48:39 +01003251 desc.m_AlignCorners = options->align_corners;
Sadik Armagana3b31f02019-12-05 09:08:53 +00003252 break;
3253 }
3254 case ResizeMethod::NearestNeighbor:
3255 {
James Ward58dec6b2020-09-11 17:32:44 +01003256 layerName += fmt::format("NEARESTNEIGHBOR:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagana3b31f02019-12-05 09:08:53 +00003257 break;
3258 }
3259 default:
3260 {
3261 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003262 fmt::format("Unexpected ResizeMethod[{}] when creating layerName {} ",
3263 static_cast<int>(resizeMethod), CHECK_LOCATION().AsString()));
Sadik Armagana3b31f02019-12-05 09:08:53 +00003264 }
3265 }
3266
Mike Kelly377fb212023-01-10 15:55:28 +00003267 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
James Conroy05102392020-06-24 15:39:55 +01003268
3269 IConnectableLayer* layer = m_Network->AddResizeLayer(desc, layerName.c_str());
3270 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00003271 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
3272 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003273 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3274
3275 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3276 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3277
3278 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3279 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
3280}
3281
Tianle Chenge5a30ff2023-07-03 11:24:12 +01003282void TfLiteParserImpl::ParseReverseV2(size_t subgraphIndex, size_t operatorIndex)
3283{
3284 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3285
3286 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3287 CHECK_VALID_SIZE(inputs.size(), 2);
3288
3289 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3290 CHECK_VALID_SIZE(outputs.size(), 1);
3291
3292 auto layerName = fmt::format("ReverseV2:{}:{}", subgraphIndex, operatorIndex);
3293
3294 TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
3295 TensorInfo axisTensorInfo = ToTensorInfo(inputs[1]);
3296 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
3297
Tracy Narinebb8d7592023-07-13 16:50:54 +01003298 IConnectableLayer* layer = m_Network->AddReverseV2Layer(layerName.c_str());
Tianle Chenge5a30ff2023-07-03 11:24:12 +01003299 ARMNN_ASSERT(layer != nullptr);
3300
3301 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3302
3303 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Tracy Narinebb8d7592023-07-13 16:50:54 +01003304 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Tianle Chenge5a30ff2023-07-03 11:24:12 +01003305
3306 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3307 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3308}
3309
Teresa Charlin777008b2023-07-26 10:07:55 +01003310void TfLiteParserImpl::ParseTile(size_t subgraphIndex, size_t operatorIndex)
3311{
3312 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3313
3314 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3315 CHECK_VALID_SIZE(inputs.size(), 2);
3316
3317 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3318 CHECK_VALID_SIZE(outputs.size(), 1);
3319
3320 TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
3321 TensorInfo multiplesTensorInfo = ToTensorInfo(inputs[1]);
3322 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
3323
3324 auto layerName = fmt::format("Tile:{}:{}", subgraphIndex, operatorIndex);
3325
3326 TileDescriptor descriptor;
3327
3328 BufferRawPtr multiplesBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
3329 if (multiplesBufferPtr != nullptr)
3330 {
3331 std::vector<int32_t> multiplesData(multiplesTensorInfo.GetNumElements());
3332 ::memcpy(multiplesData.data(), multiplesBufferPtr->data.data(), multiplesTensorInfo.GetNumBytes());
3333 descriptor.m_Multiples.assign(multiplesData.begin(), multiplesData.end());
3334 }
3335 else
3336 {
3337 ARMNN_THROW_PARSE_EXCEPTION("For Tile layer, Multiples data was not found in the buffer.");
3338 }
3339
3340 IConnectableLayer* layer = m_Network->AddTileLayer(descriptor, layerName.c_str());
3341 ARMNN_ASSERT(layer != nullptr);
3342
3343 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3344
3345 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3346 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3347
3348 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3349 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3350}
3351
Kevin May7d96b162021-02-03 17:38:41 +00003352void TfLiteParserImpl::ParseConcatenation(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan479045b2018-10-01 11:51:37 +01003353{
3354 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3355
Mike Kelly0d77ae12022-01-07 17:42:27 +00003356 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3357 const auto* options = operatorPtr->builtin_options.AsConcatenationOptions();
Sadik Armagan479045b2018-10-01 11:51:37 +01003358
3359 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
3360
3361 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3362 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Mike Kelly377fb212023-01-10 15:55:28 +00003363 auto inputTensorIds = GetInputTensorIds(m_Model, subgraphIndex, operatorIndex);
3364
Sadik Armagan479045b2018-10-01 11:51:37 +01003365 CHECK_VALID_SIZE(outputs.size(), 1);
3366
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003367 unsigned int numConcatView = static_cast<unsigned int>(inputs.size());
Mike Kelly377fb212023-01-10 15:55:28 +00003368 uint32_t inputRank = InputTensorInfo(subgraphIndex, operatorIndex, 0).GetNumDimensions();
Sadik Armagan479045b2018-10-01 11:51:37 +01003369
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003370 const unsigned int concatDimInput = static_cast<unsigned int>(
Mike Kelly377fb212023-01-10 15:55:28 +00003371 (static_cast<int>(inputRank) + options->axis) % static_cast<int>(inputRank));
Sadik Armagan479045b2018-10-01 11:51:37 +01003372
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003373 OriginsDescriptor concatDescriptor(static_cast<uint32_t>(numConcatView), inputRank);
3374 concatDescriptor.SetConcatAxis(concatDimInput);
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003375 unsigned int mergeDimOrigin = 0;
Sadik Armagan479045b2018-10-01 11:51:37 +01003376
3377 for (unsigned int viewIndex = 0; viewIndex < numConcatView; ++viewIndex)
3378 {
Mike Kelly377fb212023-01-10 15:55:28 +00003379 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, viewIndex);
Sadik Armagan479045b2018-10-01 11:51:37 +01003380
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003381 // This set up concatDescriptor view origin
3382 armnnUtils::ProcessConcatInputTensorInfo(
Mike Kelly377fb212023-01-10 15:55:28 +00003383 inputTensorInfo, concatDescriptor, concatDimInput, viewIndex, mergeDimOrigin);
Sadik Armagan479045b2018-10-01 11:51:37 +01003384 }
3385
James Ward58dec6b2020-09-11 17:32:44 +01003386 auto layerName = fmt::format("Concatenation:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01003387
Jim Flynn906f9462019-05-10 13:55:21 +01003388 IConnectableLayer* layer = m_Network->AddConcatLayer(concatDescriptor, layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01003389 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00003390 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {});
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003391 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
Sadik Armagan479045b2018-10-01 11:51:37 +01003392
James Conroy05102392020-06-24 15:39:55 +01003393 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003394 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes});
Sadik Armagan479045b2018-10-01 11:51:37 +01003395
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003396 // add fused activation layer
3397 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
Sadik Armagan479045b2018-10-01 11:51:37 +01003398
Sadik Armagan479045b2018-10-01 11:51:37 +01003399 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3400 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3401}
3402
Kevin May7d96b162021-02-03 17:38:41 +00003403void TfLiteParserImpl::ParseFullyConnected(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003404{
3405 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3406
Mike Kelly0d77ae12022-01-07 17:42:27 +00003407 const auto& operatorRfr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003408 const auto options = operatorRfr->builtin_options.AsFullyConnectedOptions();
3409
3410 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
3411
3412 FullyConnectedDescriptor desc;
3413 desc.m_BiasEnabled = false;
Nattapat Chaimanowongd8eee592018-10-26 10:24:14 +01003414 desc.m_TransposeWeightMatrix = true;
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003415
3416 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3417 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3418 CHECK_VALID_SIZE(outputs.size(), 1);
3419
Mike Kelly377fb212023-01-10 15:55:28 +00003420 armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003421
3422 // Fully Connected Layer accepts two dimensional weights input
3423 int32_t weightsDimension = static_cast<int32_t>(filterTensorInfo.GetNumDimensions());
3424 if (weightsDimension != 2)
3425 {
3426 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003427 fmt::format("Dimension {} for Fully Connected weights is not supported by Armnn. "
3428 "Node {}",
3429 weightsDimension,
3430 CHECK_LOCATION().AsString()));
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003431 }
3432
Matthew Jackson74bf7da2019-08-16 16:51:42 +01003433 armnn::IConnectableLayer* layer = nullptr;
James Ward58dec6b2020-09-11 17:32:44 +01003434 auto layerName = fmt::format("FullyConnected:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003435
Matthew Sloyan81beae32021-07-13 19:46:11 +01003436 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3437 // Add the first input tensor to the registration list
3438 std::vector<unsigned int> tensorIndexesToRegister = {inputTensorIndexes[0]};
Mike Kelly377fb212023-01-10 15:55:28 +00003439 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Finn Williamsd4fa5452021-03-01 12:31:41 +00003440
3441 desc.m_ConstantWeights = IsConstTensor(inputs[1]);
3442
Matthew Sloyan81beae32021-07-13 19:46:11 +01003443 // Add the weights input to the registration list, constant layers will be added by SetupConstantLayers if constant.
3444 tensorIndexesToRegister.emplace_back(inputTensorIndexes[1]);
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003445
Mike Kelly0506ef02023-01-03 16:29:44 +00003446 if (ShouldConstantTensorBeConverted(inputs[1], inputTensorInfo.GetDataType(), filterTensorInfo.GetDataType()))
Mike Kelly5880b912022-01-28 16:18:54 +00003447 {
3448 m_ConstantsToDequantize.emplace_back(inputs[1]->buffer);
3449 }
3450
Finn Williamsd4fa5452021-03-01 12:31:41 +00003451 if (inputs.size() == 3)
3452 {
3453 desc.m_BiasEnabled = true;
Mike Kelly377fb212023-01-10 15:55:28 +00003454 armnn::TensorInfo biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Matthew Sloyan81beae32021-07-13 19:46:11 +01003455
3456 // Add the biases input to the registration list, constant layer will be added by SetupConstantLayers.
3457 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
Mike Kelly5880b912022-01-28 16:18:54 +00003458
Mike Kelly0506ef02023-01-03 16:29:44 +00003459 if (ShouldConstantTensorBeConverted(inputs[2], inputTensorInfo.GetDataType(), biasTensorInfo.GetDataType()))
Mike Kelly5880b912022-01-28 16:18:54 +00003460 {
3461 m_ConstantsToDequantize.emplace_back(inputs[2]->buffer);
3462 }
Finn Williamsd4fa5452021-03-01 12:31:41 +00003463 }
3464
Matthew Sloyan81beae32021-07-13 19:46:11 +01003465 // Filters and biases are always passed to fully connected as inputs
3466 layer = m_Network->AddFullyConnectedLayer(desc, layerName.c_str());
Finn Williamsd4fa5452021-03-01 12:31:41 +00003467
3468 ARMNN_ASSERT(layer != nullptr);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003469
Finn Williamsd4fa5452021-03-01 12:31:41 +00003470 unsigned int startingSlotIndex = 0;
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003471 if (inputTensorInfo.GetNumDimensions() > 2)
3472 {
3473 // Add reshape to flatten to 2D [batch_size, input_size],
3474 // where "input_size" corresponds to the number of inputs to the layer,
3475 // matching the second dimension of weights,
3476 // and "batch_size" is calculated by dividing the number of elements by "input_size".
3477 std::vector<unsigned int> reshapedDimensions(2);
3478 reshapedDimensions[1] = filterTensorInfo.GetShape()[1];
3479 reshapedDimensions[0] = inputTensorInfo.GetNumElements() / reshapedDimensions[1];
3480
3481 if (inputTensorInfo.GetNumElements() % reshapedDimensions[1] != 0)
3482 {
3483 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003484 fmt::format("Failed to deduce input tensor shape from filter size {} {}",
3485 reshapedDimensions[1],
3486 CHECK_LOCATION().AsString()));
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003487 }
3488
Mike Kelly377fb212023-01-10 15:55:28 +00003489 armnn::TensorInfo reshapedTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003490 reshapedTensorInfo.SetShape(armnn::TensorShape{ 2, reshapedDimensions.data() });
Mike Kelly377fb212023-01-10 15:55:28 +00003491 inputTensorInfo = reshapedTensorInfo;
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003492
James Ward58dec6b2020-09-11 17:32:44 +01003493 std::string reshapeLayerName = fmt::format("Reshape_for:{}", layer->GetName());
Finn Williamsd4fa5452021-03-01 12:31:41 +00003494 armnn::ReshapeDescriptor reshapeDescriptor;
3495 reshapeDescriptor.m_TargetShape = reshapedTensorInfo.GetShape();
Mike Kelly04d82292023-01-19 18:29:40 +00003496 armnn::IConnectableLayer* reshapeLayer = m_Network->AddReshapeLayer(reshapeDescriptor,
3497 reshapeLayerName.c_str());
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003498
3499 reshapeLayer->GetOutputSlot(0).SetTensorInfo(reshapedTensorInfo);
3500 reshapeLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
3501
3502 RegisterInputSlots(subgraphIndex, operatorIndex, reshapeLayer, {inputTensorIndexes[0]});
Finn Williamsd4fa5452021-03-01 12:31:41 +00003503 // Fc layer connects to the reshape layer, so we skip the first input slot when registering fc's input slots
3504 tensorIndexesToRegister.erase(tensorIndexesToRegister.begin());
3505 startingSlotIndex = 1;
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003506 }
Finn Williamsd4fa5452021-03-01 12:31:41 +00003507
3508 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister, startingSlotIndex);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003509
Mike Kelly377fb212023-01-10 15:55:28 +00003510 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromShapes(subgraphIndex, operatorIndex, layer, 0,
3511 { inputTensorInfo.GetShape(),
3512 filterTensorInfo.GetShape() });
Mike Kelly04d82292023-01-19 18:29:40 +00003513
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003514 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3515
Mike Kelly04d82292023-01-19 18:29:40 +00003516 if (outputTensorInfo.GetNumDimensions() > 2)
3517 {
3518 // Calculate reshape to flatten to 2D [batch_size, input_size]
3519 std::vector<unsigned int> reshapedDimensions(2);
3520 reshapedDimensions[1] = filterTensorInfo.GetShape()[0];
3521 reshapedDimensions[0] = outputTensorInfo.GetNumElements() / reshapedDimensions[1];
3522 armnn::TensorInfo reshapedOutputTensorInfo = outputTensorInfo;
3523 if (outputTensorInfo.GetNumElements() % reshapedDimensions[1] != 0)
3524 {
3525 throw ParseException(
3526 fmt::format("Failed to deduce output tensor shape from filter size {} {}",
3527 reshapedDimensions[1],
3528 CHECK_LOCATION().AsString()));
3529 }
3530 reshapedOutputTensorInfo.SetShape(armnn::TensorShape{ 2, reshapedDimensions.data() });
3531 layer->GetOutputSlot(0).SetTensorInfo(reshapedOutputTensorInfo);
3532
3533 std::string reshapeLayerName = fmt::format("ExpandDims:{}:{}", subgraphIndex, operatorIndex);
3534 layer = AddReshapeLayer(layer, 0, reshapeLayerName, outputTensorInfo);
3535 }
3536
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003537 // we need to add the activation layer and fortunately we don't need to care about the data layout
3538 armnn::IConnectableLayer* fusedActivationLayer = AddFusedActivationLayer(layer, 0,
3539 options->fused_activation_function);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003540
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003541 // register the output connection slots for the layer, connections are made after all layers have been created
3542 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3543 RegisterOutputSlots(subgraphIndex, operatorIndex, fusedActivationLayer, {outputTensorIndexes[0]});
Mike Kelly04d82292023-01-19 18:29:40 +00003544
3545 m_TensorInfos[outputTensorIndexes[0]] = layer->GetOutputSlot(0).GetTensorInfo();
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003546}
3547
Kevin May7d96b162021-02-03 17:38:41 +00003548void TfLiteParserImpl::ParseDetectionPostProcess(size_t subgraphIndex, size_t operatorIndex)
keidav011b3e2ea2019-02-21 10:07:37 +00003549{
3550 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3551
Mike Kelly0d77ae12022-01-07 17:42:27 +00003552 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
keidav011b3e2ea2019-02-21 10:07:37 +00003553
3554 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3555 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3556 CHECK_VALID_SIZE(outputs.size(), 4);
3557
3558 // Obtain custom options from flexbuffers
3559 auto custom_options = operatorPtr->custom_options;
3560 const flexbuffers::Map& m = flexbuffers::GetRoot(custom_options.data(), custom_options.size()).AsMap();
3561
3562 // Obtain descriptor information from tf lite
3563 DetectionPostProcessDescriptor desc;
3564 desc.m_MaxDetections = m["max_detections"].AsUInt32();
3565 desc.m_MaxClassesPerDetection = m["max_classes_per_detection"].AsUInt32();
3566 desc.m_NmsScoreThreshold = m["nms_score_threshold"].AsFloat();
3567 desc.m_NmsIouThreshold = m["nms_iou_threshold"].AsFloat();
3568 desc.m_NumClasses = m["num_classes"].AsUInt32();
3569 desc.m_ScaleH = m["h_scale"].AsFloat();
3570 desc.m_ScaleW = m["w_scale"].AsFloat();
3571 desc.m_ScaleX = m["x_scale"].AsFloat();
3572 desc.m_ScaleY = m["y_scale"].AsFloat();
3573
keidav0107d58c72019-02-26 11:57:39 +00003574 if (!(m["use_regular_nms"].IsNull()))
keidav011b3e2ea2019-02-21 10:07:37 +00003575 {
keidav0107d58c72019-02-26 11:57:39 +00003576 desc.m_UseRegularNms = m["use_regular_nms"].AsBool();
keidav011b3e2ea2019-02-21 10:07:37 +00003577 }
3578 if (!(m["detections_per_class"].IsNull()))
3579 {
3580 desc.m_DetectionsPerClass = m["detections_per_class"].AsUInt32();
3581 }
3582
3583 if (desc.m_NmsIouThreshold <= 0.0f || desc.m_NmsIouThreshold > 1.0f)
3584 {
3585 throw InvalidArgumentException("DetectionPostProcessTFLiteParser: Intersection over union threshold "
3586 "must be positive and less than or equal to 1.");
3587 }
3588
Mike Kelly377fb212023-01-10 15:55:28 +00003589 armnn::TensorInfo anchorTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Finn Williamsd4fa5452021-03-01 12:31:41 +00003590 auto anchorTensorAndData = CreateConstTensorNonPermuted(inputs[2], anchorTensorInfo);
keidav011b3e2ea2019-02-21 10:07:37 +00003591
James Ward58dec6b2020-09-11 17:32:44 +01003592 auto layerName = fmt::format("DetectionPostProcess:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsd4fa5452021-03-01 12:31:41 +00003593 IConnectableLayer* layer = m_Network->AddDetectionPostProcessLayer(desc, anchorTensorAndData,
keidav011b3e2ea2019-02-21 10:07:37 +00003594 layerName.c_str());
3595
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01003596 ARMNN_ASSERT(layer != nullptr);
keidav011b3e2ea2019-02-21 10:07:37 +00003597
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00003598 // The model does not specify the output shapes.
3599 // The output shapes are calculated from the max_detection and max_classes_per_detection.
3600 unsigned int numDetectedBox = desc.m_MaxDetections * desc.m_MaxClassesPerDetection;
Mike Kelly377fb212023-01-10 15:55:28 +00003601 m_OverriddenOutputShapes.push_back({ 1, numDetectedBox, 4 });
3602 m_OverriddenOutputShapes.push_back({ 1, numDetectedBox });
3603 m_OverriddenOutputShapes.push_back({ 1, numDetectedBox });
3604 m_OverriddenOutputShapes.push_back({ 1 });
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00003605
keidav011b3e2ea2019-02-21 10:07:37 +00003606 for (unsigned int i = 0 ; i < outputs.size() ; ++i)
3607 {
Mike Kelly377fb212023-01-10 15:55:28 +00003608 armnn::TensorInfo detectionBoxOutputTensorInfo = ToTensorInfo(outputs[i], m_OverriddenOutputShapes[i]);
keidav011b3e2ea2019-02-21 10:07:37 +00003609 layer->GetOutputSlot(i).SetTensorInfo(detectionBoxOutputTensorInfo);
3610 }
3611
3612 // Register the input connection slots for the layer, connections are made after all layers have been created
3613 // only the tensors for the inputs are relevant, exclude the const tensors
3614 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3615 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
3616
3617 // Register the output connection slots for the layer, connections are made after all layers have been created
3618 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3619 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0],
3620 outputTensorIndexes[1],
3621 outputTensorIndexes[2],
3622 outputTensorIndexes[3]});
3623}
3624
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003625/// The TfLite Pack operator is equivalent to the ArmNN Stack operator
Kevin May7d96b162021-02-03 17:38:41 +00003626void TfLiteParserImpl::ParsePack(size_t subgraphIndex, size_t operatorIndex)
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003627{
3628 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3629
3630 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3631 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3632 CHECK_VALID_SIZE(outputs.size(), 1);
3633
3634 if (inputs.size() < 1)
3635 {
3636 throw ParseException("Pack must have at least one input.");
3637 }
3638
3639 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3640 const auto* options = operatorPtr->builtin_options.AsPackOptions();
3641
3642 StackDescriptor desc;
3643 desc.m_Axis = static_cast<uint32_t>(options->axis);
3644 desc.m_NumInputs = static_cast<uint32_t>(inputs.size());
3645
3646 // Use the tensor shape of the first input as the "correct" input shape in the descriptor
Mike Kelly377fb212023-01-10 15:55:28 +00003647 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003648 desc.m_InputShape = inputTensorInfo.GetShape();
3649
James Ward58dec6b2020-09-11 17:32:44 +01003650 auto layerName = fmt::format("Pack:{}:{}", subgraphIndex, operatorIndex);
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003651 IConnectableLayer* layer = m_Network->AddStackLayer(desc, layerName.c_str());
3652
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01003653 ARMNN_ASSERT(layer != nullptr);
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003654
Mike Kelly377fb212023-01-10 15:55:28 +00003655 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {});
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003656 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3657
3658 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3659 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes});
3660
3661 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3662 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3663}
3664
Mike Kelly5880b912022-01-28 16:18:54 +00003665void TfLiteParserImpl::ParseUnidirectionalSequenceLSTM(size_t subgraphIndex, size_t operatorIndex)
3666{
3667 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3668
3669 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3670 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3671
3672 if (inputs.size() < 2)
3673 {
3674 throw ParseException("UnidirectionalSequenceLSTM must have at least 2 input.");
3675 }
3676
3677 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3678 const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex];
3679 const auto nodeParams = operatorPtr->builtin_options.AsUnidirectionalSequenceLSTMOptions();
3680 CHECK_SUPPORTED_FUSED_ACTIVATION(nodeParams, subgraphIndex, operatorIndex);
Mike Kelly377fb212023-01-10 15:55:28 +00003681 auto inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Mike Kelly5880b912022-01-28 16:18:54 +00003682 auto outputTensorInfo = ToTensorInfo(outputs[0]);
3683
3684 // Set the params structure for the AddUnidirectionalSequenceLstmLayer call
3685 // Please refer to each operand at
3686 // https://www.tensorflow.org/mlir/tfl_ops#tflunidirectional_sequence_lstm_tflunidirectionalsequencelstmop
3687 armnn::LstmInputParams params;
3688
3689 if (IsOptionalOperandPresent(operatorPtr->inputs[1]))
3690 {
3691 params.m_InputToInputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[1]].get(),
3692 inputTensorInfo).first;
3693 }
3694
3695 params.m_InputToForgetWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[2]].get(),
3696 inputTensorInfo).first;
3697 params.m_InputToCellWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[3]].get(),
3698 inputTensorInfo).first;
3699 params.m_InputToOutputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[4]].get(),
3700 inputTensorInfo).first;
3701
3702 // Recurrent weight tensors of size {n_cell, n_output}
3703 if (IsOptionalOperandPresent(operatorPtr->inputs[5]))
3704 {
3705 params.m_RecurrentToInputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[5]].get(),
3706 inputTensorInfo).first;
3707 }
3708
3709 params.m_RecurrentToForgetWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[6]].get(),
3710 inputTensorInfo).first;
3711 params.m_RecurrentToCellWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[7]].get(),
3712 inputTensorInfo).first;
3713 params.m_RecurrentToOutputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[8]].get(),
3714 inputTensorInfo).first;
3715
3716 // Peephole weights tensors of size {n_cell}, representing a diagonal matrix.
3717 if (IsOptionalOperandPresent(operatorPtr->inputs[9]))
3718 {
3719 params.m_CellToInputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[9]].get(),
3720 inputTensorInfo).first;
3721 }
3722
3723 if (IsOptionalOperandPresent(operatorPtr->inputs[10]))
3724 {
3725 params.m_CellToForgetWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[10]].get(),
3726 inputTensorInfo).first;
3727 }
3728
3729 if (IsOptionalOperandPresent(operatorPtr->inputs[11]))
3730 {
3731 params.m_CellToOutputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[11]].get(),
3732 inputTensorInfo).first;
3733 }
3734
3735 // Gates bias tensors of size {n_cell}
3736 if (IsOptionalOperandPresent(operatorPtr->inputs[12]))
3737 {
3738 params.m_InputGateBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[12]].get(),
3739 inputTensorInfo).first;
3740 }
3741
3742 params.m_ForgetGateBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[13]].get(),
3743 inputTensorInfo).first;
3744 params.m_CellBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[14]].get(),
3745 inputTensorInfo).first;
3746 params.m_OutputGateBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[15]].get(),
3747 inputTensorInfo).first;
3748
3749 // Projection weight tensor of size {n_output, n_cell}
3750 if (IsOptionalOperandPresent(operatorPtr->inputs[16]))
3751 {
3752 params.m_ProjectionWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[16]].get(),
3753 inputTensorInfo).first;
3754 }
3755 // Projection bias tensor of size {n_output}
3756 if (IsOptionalOperandPresent(operatorPtr->inputs[17]))
3757 {
3758 params.m_ProjectionBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[17]].get(),
3759 inputTensorInfo).first;
3760 }
3761
3762 // These state tensors are defined as variable tensors, and will be modified by this op.
3763 armnn::TensorInfo outputStateInInfo = ToTensorInfo(subgraphPtr->tensors[operatorPtr->inputs[18]].get());
3764 m_ConstantsToBeCreated.push_back(operatorPtr->inputs[18]);
3765 armnn::TensorInfo cellStateInInfo = ToTensorInfo(subgraphPtr->tensors[operatorPtr->inputs[19]].get());
3766 m_ConstantsToBeCreated.push_back(operatorPtr->inputs[19]);
3767
3768 // Layer norm coefficient tensors of size {n_cell}, representing a diagonal matrix.
3769 if (inputs.size() >= 21 && IsOptionalOperandPresent(operatorPtr->inputs[20]))
3770 {
3771 params.m_InputLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[20]].get(),
3772 inputTensorInfo).first;
3773 }
3774
3775 if (inputs.size() >= 22 && IsOptionalOperandPresent(operatorPtr->inputs[21]))
3776 {
3777 params.m_ForgetLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[21]].get(),
3778 inputTensorInfo).first;
3779 }
3780
3781 if (inputs.size() >= 23 && IsOptionalOperandPresent(operatorPtr->inputs[22]))
3782 {
3783 params.m_CellLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[22]].get(),
3784 inputTensorInfo).first;
3785 }
3786
3787 if (inputs.size() >= 24 && IsOptionalOperandPresent(operatorPtr->inputs[23]))
3788 {
3789 params.m_OutputLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[23]].get(),
3790 inputTensorInfo).first;
3791 }
3792
3793 // set the layer descriptor
3794 armnn::UnidirectionalSequenceLstmDescriptor desc;
3795 desc.m_ActivationFunc = nodeParams->fused_activation_function;
3796 desc.m_ClippingThresCell = nodeParams->cell_clip;
3797 desc.m_ClippingThresProj = nodeParams->proj_clip;
3798 desc.m_CifgEnabled = (params.m_InputToInputWeights == nullptr
3799 || params.m_RecurrentToInputWeights == nullptr
3800 || params.m_InputGateBias == nullptr);
3801 desc.m_PeepholeEnabled = (params.m_CellToForgetWeights != nullptr || params.m_CellToOutputWeights != nullptr);
3802 desc.m_ProjectionEnabled = (params.m_ProjectionWeights != nullptr);
3803 desc.m_LayerNormEnabled = (params.m_InputLayerNormWeights != nullptr
3804 || params.m_ForgetLayerNormWeights != nullptr
3805 || params.m_CellLayerNormWeights != nullptr
3806 || params.m_OutputLayerNormWeights != nullptr);
3807 desc.m_TimeMajor = nodeParams->time_major;
3808
Mike Kellyc0800a32022-06-15 10:57:52 +01003809 if (operatorPtr->intermediates.size() > 3 && desc.m_LayerNormEnabled)
Mike Kelly5880b912022-01-28 16:18:54 +00003810 {
3811 auto inputIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[0]].get(),
3812 inputTensorInfo).first;
3813 auto inputIntermediateTensorInfo = inputIntermediate->GetInfo();
3814 desc.m_InputIntermediateScale = inputIntermediateTensorInfo.GetQuantizationScale();
3815
3816 auto forgetIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[1]].get(),
3817 inputTensorInfo).first;
3818 auto forgetIntermediateTensorInfo = forgetIntermediate->GetInfo();
3819 desc.m_ForgetIntermediateScale = forgetIntermediateTensorInfo.GetQuantizationScale();
3820
3821 auto cellIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[2]].get(),
3822 inputTensorInfo).first;
3823 auto cellIntermediateTensorInfo = cellIntermediate->GetInfo();
3824 desc.m_CellIntermediateScale = cellIntermediateTensorInfo.GetQuantizationScale();
3825
3826 auto outputIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[3]].get(),
3827 inputTensorInfo).first;
3828 auto outputIntermediateTensorInfo = outputIntermediate->GetInfo();
3829 desc.m_OutputIntermediateScale = outputIntermediateTensorInfo.GetQuantizationScale();
3830 }
3831 else
3832 {
3833 float defaultIntermediate = std::pow(2, -12);
3834 desc.m_InputIntermediateScale = defaultIntermediate;
3835 desc.m_ForgetIntermediateScale = defaultIntermediate;
3836 desc.m_CellIntermediateScale = defaultIntermediate;
3837 desc.m_OutputIntermediateScale = defaultIntermediate;
3838 }
3839
Mike Kellyc0800a32022-06-15 10:57:52 +01003840 if (operatorPtr->intermediates.size() > 4)
3841 {
3842 auto hiddentensor = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[4]].get(),
3843 inputTensorInfo).first;
Mike Kelly5880b912022-01-28 16:18:54 +00003844
Mike Kellyc0800a32022-06-15 10:57:52 +01003845 desc.m_HiddenStateScale = hiddentensor->GetInfo().GetQuantizationScale();
3846 desc.m_HiddenStateZeroPoint = hiddentensor->GetInfo().GetQuantizationOffset();
3847 }
Mike Kelly5880b912022-01-28 16:18:54 +00003848 unsigned int batchSize = inputTensorInfo.GetShape()[0];
3849 unsigned int outputSize = outputTensorInfo.GetShape()[2];
3850 unsigned int numUnits = cellStateInInfo.GetShape()[1];
3851
3852 armnn::DataType dataType = inputTensorInfo.GetDataType();
3853 float qScale = inputTensorInfo.GetQuantizationScale();
3854 float qOffset = inputTensorInfo.GetQuantizationOffset();
3855
3856 armnn::TensorInfo scratchBufferTensorInfo({batchSize, numUnits * 3}, dataType, qScale, qOffset);
3857 if (!desc.m_CifgEnabled)
3858 {
3859 scratchBufferTensorInfo = armnn::TensorInfo({batchSize, numUnits * 4}, dataType, qScale, qOffset);
3860 }
3861 armnn::TensorInfo cellStateOutTensorInfo({batchSize, numUnits},
3862 cellStateInInfo.GetDataType(),
3863 cellStateInInfo.GetQuantizationScale(),
3864 cellStateInInfo.GetQuantizationOffset());
3865 armnn::TensorInfo outputStateOutTensorInfo({batchSize, outputSize}, dataType, qScale, qOffset);
3866
3867 armnn::LstmInputParamsInfo paramsInfo;
3868 paramsInfo.m_InputToForgetWeights = &(params.m_InputToForgetWeights->GetInfo());
3869 paramsInfo.m_InputToCellWeights = &(params.m_InputToCellWeights->GetInfo());
3870 paramsInfo.m_InputToOutputWeights = &(params.m_InputToOutputWeights->GetInfo());
3871 paramsInfo.m_RecurrentToForgetWeights = &(params.m_RecurrentToForgetWeights->GetInfo());
3872 paramsInfo.m_RecurrentToCellWeights = &(params.m_RecurrentToCellWeights->GetInfo());
3873 paramsInfo.m_RecurrentToOutputWeights = &(params.m_RecurrentToOutputWeights->GetInfo());
3874 paramsInfo.m_ForgetGateBias = &(params.m_ForgetGateBias->GetInfo());
3875 paramsInfo.m_CellBias = &(params.m_CellBias->GetInfo());
3876 paramsInfo.m_OutputGateBias = &(params.m_OutputGateBias->GetInfo());
3877
3878 if (!desc.m_CifgEnabled)
3879 {
3880 paramsInfo.m_InputToInputWeights = &(params.m_InputToInputWeights->GetInfo());
3881 paramsInfo.m_RecurrentToInputWeights = &(params.m_RecurrentToInputWeights->GetInfo());
3882 if (params.m_CellToInputWeights != nullptr)
3883 {
3884 paramsInfo.m_CellToInputWeights = &(params.m_CellToInputWeights->GetInfo());
3885 }
3886 paramsInfo.m_InputGateBias = &(params.m_InputGateBias->GetInfo());
3887 }
3888
3889 if (desc.m_ProjectionEnabled)
3890 {
3891 paramsInfo.m_ProjectionWeights = &(params.m_ProjectionWeights->GetInfo());
3892 if (params.m_ProjectionBias != nullptr)
3893 {
3894 paramsInfo.m_ProjectionBias = &(params.m_ProjectionBias->GetInfo());
3895 }
3896 }
3897
3898 if (desc.m_PeepholeEnabled)
3899 {
3900 paramsInfo.m_CellToForgetWeights = &(params.m_CellToForgetWeights->GetInfo());
3901 paramsInfo.m_CellToOutputWeights = &(params.m_CellToOutputWeights->GetInfo());
3902 }
3903
3904 if (desc.m_LayerNormEnabled)
3905 {
3906 if(!desc.m_CifgEnabled)
3907 {
3908 paramsInfo.m_InputLayerNormWeights = &(params.m_InputLayerNormWeights->GetInfo());
3909 }
3910 paramsInfo.m_ForgetLayerNormWeights = &(params.m_ForgetLayerNormWeights->GetInfo());
3911 paramsInfo.m_CellLayerNormWeights = &(params.m_CellLayerNormWeights->GetInfo());
3912 paramsInfo.m_OutputLayerNormWeights = &(params.m_OutputLayerNormWeights->GetInfo());
3913 }
3914
3915 auto layerName = fmt::format("UnidirectionalSequenceLSTM:{}:{}", subgraphIndex, operatorIndex);
3916 armnn::IConnectableLayer* layer = m_Network->AddUnidirectionalSequenceLstmLayer(desc, params);
3917 ARMNN_ASSERT(layer != nullptr);
3918
3919 // register the input connection slots for the layer, connections are made after all layers have been created
3920 // only the tensors for the inputs are relevant, exclude the const tensors
3921 auto inputTensorIndexes = AsUnsignedVector({operatorPtr->inputs[0],
3922 operatorPtr->inputs[18],
3923 operatorPtr->inputs[19]});
3924 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0],
3925 inputTensorIndexes[1],
3926 inputTensorIndexes[2]});
3927
3928 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3929
3930 layer->GetOutputSlot(0).SetTensorInfo(outputStateOutTensorInfo);
3931 layer->GetOutputSlot(1).SetTensorInfo(cellStateOutTensorInfo);
3932 layer->GetOutputSlot(2).SetTensorInfo(outputTensorInfo);
3933
3934 unsigned int tensorIndex = outputTensorIndexes[0];
3935 armnn::IOutputSlot* slot = &(layer->GetOutputSlot(2));
3936 RegisterProducerOfTensor(subgraphIndex, tensorIndex, slot);
3937}
3938
Kevin May7d96b162021-02-03 17:38:41 +00003939void TfLiteParserImpl::ParseUnpack(size_t subgraphIndex, size_t operatorIndex)
Nina Drozd200e3802019-04-15 09:47:39 +01003940{
3941 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3942
Mike Kelly0d77ae12022-01-07 17:42:27 +00003943 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3944 const auto* options = operatorPtr->builtin_options.AsUnpackOptions();
Nina Drozd200e3802019-04-15 09:47:39 +01003945
3946 // This unpackAxis indicates the axis to unpack
3947 const unsigned int unpackAxis = CHECKED_NON_NEGATIVE(options->axis);
3948
3949 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3950 CHECK_VALID_SIZE(inputs.size(), 1);
3951
Mike Kelly377fb212023-01-10 15:55:28 +00003952 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003953
3954 if (unpackAxis >= inputTensorInfo.GetNumDimensions())
3955 {
3956 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003957 fmt::format("The unpack axis: {} cannot be greater than or equal to "
3958 "the number of input dimension {} {}",
3959 unpackAxis,
3960 inputTensorInfo.GetNumDimensions(),
3961 CHECK_LOCATION().AsString()));
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003962 }
3963
Nina Drozd200e3802019-04-15 09:47:39 +01003964 unsigned int unpackNum = CHECKED_NON_NEGATIVE(options->num);
3965 // If num is not defined, automatically infer from the length of the dimension axis.
3966 if(unpackNum == 0)
3967 {
3968 unpackNum = inputTensorInfo.GetShape()[unpackAxis];
3969 }
3970
3971 // If unpack number cannot be inferred and is still zero, throw ParseException.
3972 if(unpackNum == 0)
3973 {
3974 throw ParseException("Number to unpack must greater than zero.");
3975 }
3976
3977 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3978 CHECK_VALID_SIZE(outputs.size(), unpackNum);
3979
3980 auto inputDimSize = inputTensorInfo.GetNumDimensions();
3981 std::vector<unsigned int> unpackDimSizes(inputDimSize);
3982
3983 // Add current input shape to unpackDimSizes
3984 for (unsigned int i = 0; i < inputDimSize; ++i)
3985 {
3986 unpackDimSizes[i] = inputTensorInfo.GetShape()[i];
3987 }
3988
3989 if (unpackDimSizes[unpackAxis] != unpackNum)
3990 {
3991 throw ParseException("Number to unpack must be the same as length of the dimension to "
3992 "unpack along.");
3993 }
3994
3995 unpackDimSizes[unpackAxis] /= unpackNum;
3996
3997 SplitterDescriptor splitDesc(unpackNum, static_cast<unsigned int>(unpackDimSizes.size()));
3998 for (unsigned int j = 0; j < unpackNum; ++j)
3999 {
4000 // Set the size of the views.
4001 for (unsigned int dimIdx = 0; dimIdx < unpackDimSizes.size(); ++dimIdx)
4002 {
4003 splitDesc.SetViewSize(j, dimIdx, unpackDimSizes[dimIdx]);
4004 }
4005 splitDesc.SetViewOriginCoord(j, unpackAxis, unpackDimSizes[unpackAxis] * j);
4006 }
4007
James Ward58dec6b2020-09-11 17:32:44 +01004008 auto layerName = fmt::format("Unpack:{}:{}", subgraphIndex, operatorIndex);
Nina Drozd200e3802019-04-15 09:47:39 +01004009 IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01004010 ARMNN_ASSERT(layer != nullptr);
Nina Drozd200e3802019-04-15 09:47:39 +01004011
Narumol Prangnawarat672de572019-04-23 15:28:06 +01004012 TensorShape splitOutShape = TensorShape(static_cast<unsigned int>(unpackDimSizes.size()),
4013 unpackDimSizes.data());
4014
Nina Drozd200e3802019-04-15 09:47:39 +01004015 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4016 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4017
Finn Williamsb49ed182021-06-29 15:50:08 +01004018 std::vector<unsigned int> reshapeDims;
4019 for (unsigned int axis = 0; axis < splitOutShape.GetNumDimensions(); ++axis)
4020 {
4021 if (axis != unpackAxis)
4022 {
4023 reshapeDims.push_back(splitOutShape[axis]);
4024 }
4025 }
4026
4027 TensorShape reshapeOutputShape(splitOutShape.GetNumDimensions() -1, reshapeDims.data());
4028
Narumol Prangnawarat672de572019-04-23 15:28:06 +01004029 // Create reshape to remove the unpacked dimension for unpack operator of each output from Splitter.
4030 for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
4031 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01004032 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[k], true);
James Ward58dec6b2020-09-11 17:32:44 +01004033 std::string reshapeLayerName = fmt::format("Reshape_for:{}", layer->GetName());
Narumol Prangnawarat672de572019-04-23 15:28:06 +01004034 armnn::ReshapeDescriptor desc;
Finn Williamsb49ed182021-06-29 15:50:08 +01004035 desc.m_TargetShape = reshapeOutputShape;
Narumol Prangnawarat672de572019-04-23 15:28:06 +01004036 armnn::IConnectableLayer* reshapeLayer = m_Network->AddReshapeLayer(desc, layerName.c_str());
4037
Narumol Prangnawarat2c526462019-10-21 14:58:26 +01004038 layer->GetOutputSlot(k).SetTensorInfo(armnn::TensorInfo(splitOutShape,
4039 outputTensorInfo.GetDataType(),
4040 outputTensorInfo.GetQuantizationScale(),
4041 outputTensorInfo.GetQuantizationOffset()));
Narumol Prangnawarat672de572019-04-23 15:28:06 +01004042 layer->GetOutputSlot(k).Connect(reshapeLayer->GetInputSlot(0));
4043
Narumol Prangnawarat2c526462019-10-21 14:58:26 +01004044 reshapeLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
Narumol Prangnawarat672de572019-04-23 15:28:06 +01004045
4046 uint32_t reshapedOutputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[k]);
4047 armnn::IOutputSlot* slot = &(reshapeLayer->GetOutputSlot(0));
4048 RegisterProducerOfTensor(subgraphIndex, reshapedOutputId, slot);
4049 }
Nina Drozd200e3802019-04-15 09:47:39 +01004050}
4051
Kevin May7d96b162021-02-03 17:38:41 +00004052void TfLiteParserImpl::ParseSplit(size_t subgraphIndex, size_t operatorIndex)
Nina Drozd0324f482019-04-08 10:52:10 +01004053{
4054 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4055
Mike Kelly0d77ae12022-01-07 17:42:27 +00004056 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4057 const auto* options = operatorPtr->builtin_options.AsSplitOptions();
Nina Drozd0324f482019-04-08 10:52:10 +01004058
4059 const unsigned int numSplits = CHECKED_NON_NEGATIVE(options->num_splits);
4060
Nina Drozd200e3802019-04-15 09:47:39 +01004061 // If number of splits cannot be inferred and is zero, throw ParseException.
4062 if(numSplits == 0)
4063 {
4064 throw ParseException("Number to splits must greater than zero.");
4065 }
4066
Nina Drozd0324f482019-04-08 10:52:10 +01004067 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4068 CHECK_VALID_SIZE(inputs.size(), 2);
4069 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4070 CHECK_VALID_SIZE(outputs.size(), numSplits);
4071
Mike Kelly377fb212023-01-10 15:55:28 +00004072 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
4073 armnn::TensorInfo axisTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004074 ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
Nina Drozd0324f482019-04-08 10:52:10 +01004075
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01004076 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[0]->buffer);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004077 if (axisBufferPtr == nullptr)
4078 {
4079 throw ParseException(
4080 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
4081 CHECK_LOCATION().AsString()));
4082 }
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01004083
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004084 std::vector<int32_t> axisData(axisTensorInfo.GetNumElements());
4085 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
4086 int32_t axis = axisData[0];
4087
4088 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
4089 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
4090 {
4091 // Square bracket denotes inclusive n while parenthesis denotes exclusive n
4092 // E.g. Rank 4 tensor can have axis in range [-4, 3)
4093 // -1 == 3, -2 == 2, -3 == 1, -4 == 0
4094 throw ParseException(
4095 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
4096 axis,
4097 CHECK_LOCATION().AsString()));
4098 }
4099
4100 const unsigned int splitDim = armnnUtils::GetUnsignedAxis(inputTensorInfo.GetNumDimensions(), axis);
Nina Drozd0324f482019-04-08 10:52:10 +01004101
Nina Drozd0324f482019-04-08 10:52:10 +01004102 auto inputDimSize = inputTensorInfo.GetNumDimensions();
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01004103 if (inputDimSize > MaxNumOfTensorDimensions)
Nina Drozd0324f482019-04-08 10:52:10 +01004104 {
4105 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01004106 fmt::format("The number of dimensions: {} for input tensors of the split op cannot be greater than {} {}",
4107 inputTensorInfo.GetNumDimensions(),
4108 MaxNumOfTensorDimensions,
4109 CHECK_LOCATION().AsString()));
Nina Drozd0324f482019-04-08 10:52:10 +01004110 }
4111
4112 std::vector<unsigned int> splitterDimSizes(inputDimSize);
4113
4114 // Add current input shape to splitterDimSizes
4115 for (unsigned int i = 0; i < inputDimSize; ++i)
4116 {
4117 splitterDimSizes[i] = inputTensorInfo.GetShape()[i];
4118 }
4119
4120 if (splitterDimSizes[splitDim] % numSplits != 0)
4121 {
4122 throw ParseException("Number of splits must evenly divide the dimension");
4123 }
4124 splitterDimSizes[splitDim] /= numSplits;
4125
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01004126 SplitterDescriptor splitDesc(numSplits, inputDimSize);
Nina Drozd0324f482019-04-08 10:52:10 +01004127 for (unsigned int j = 0; j < numSplits; ++j)
4128 {
4129 // Set the size of the views.
4130 for (unsigned int dimIdx = 0; dimIdx < splitterDimSizes.size(); ++dimIdx)
4131 {
4132 splitDesc.SetViewSize(j, dimIdx, splitterDimSizes[dimIdx]);
4133 }
4134 splitDesc.SetViewOriginCoord(j, splitDim, splitterDimSizes[splitDim] * j);
4135 }
4136
James Ward58dec6b2020-09-11 17:32:44 +01004137 auto layerName = fmt::format("Split:{}:{}", subgraphIndex, operatorIndex);
Nina Drozd0324f482019-04-08 10:52:10 +01004138 IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01004139 ARMNN_ASSERT(layer != nullptr);
Nina Drozd0324f482019-04-08 10:52:10 +01004140
4141 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01004142 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[1]});
Nina Drozd0324f482019-04-08 10:52:10 +01004143
Nina Drozd0324f482019-04-08 10:52:10 +01004144 for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
4145 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01004146 armnn::TensorInfo tensorInfo = ToTensorInfo(outputs[k], true);
Francis Murtagh98d6b3d2019-10-21 10:52:54 +01004147 layer->GetOutputSlot(k).SetTensorInfo(tensorInfo);
Nina Drozd0324f482019-04-08 10:52:10 +01004148 }
4149
4150 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4151 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4152}
4153
Derek Lambertif0176992020-04-28 13:37:49 +01004154unsigned int ComputeWrappedIndex(int idx, unsigned int numDimsIn)
4155{
4156 int numDims = armnn::numeric_cast<int>(numDimsIn);
4157 int v = idx < 0 ? numDims + idx : idx;
4158 ARMNN_ASSERT(v >= 0);
4159 ARMNN_ASSERT(v < numDims);
4160
4161 return static_cast<unsigned int>(v);
4162}
4163
Kevin May7d96b162021-02-03 17:38:41 +00004164void TfLiteParserImpl::ParseSplitV(size_t subgraphIndex, size_t operatorIndex)
Derek Lambertif0176992020-04-28 13:37:49 +01004165{
4166 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4167
Mike Kelly0d77ae12022-01-07 17:42:27 +00004168 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4169 const auto* options = operatorPtr->builtin_options.AsSplitVOptions();
Derek Lambertif0176992020-04-28 13:37:49 +01004170
4171 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4172 CHECK_VALID_SIZE(inputs.size(), 3);
4173
4174 auto& inputTensor = inputs[0];
4175 auto& splitsTensor = inputs[1];
4176 auto& axisTensor = inputs[2];
4177
4178 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputTensor);
4179 armnn::TensorInfo splitsInfo = ToTensorInfo(splitsTensor);
4180 armnn::TensorInfo axisTensorInfo = ToTensorInfo(axisTensor);
4181 ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
4182
4183 // Inputs
4184 auto inputDimSize = inputTensorInfo.GetNumDimensions();
4185 if (inputDimSize > MaxNumOfTensorDimensions)
4186 {
4187 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01004188 fmt::format("The number of dimensions: {} for input tensors of the "
4189 "SplitV op cannot be greater than {} {}",
4190 inputTensorInfo.GetNumDimensions(),
4191 MaxNumOfTensorDimensions,
4192 CHECK_LOCATION().AsString()));
Derek Lambertif0176992020-04-28 13:37:49 +01004193 }
4194
4195 // Get split axis
4196 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, axisTensor->buffer);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004197 if (axisBufferPtr == nullptr)
4198 {
4199 throw ParseException(
4200 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
4201 CHECK_LOCATION().AsString()));
4202 }
4203
Derek Lambertif0176992020-04-28 13:37:49 +01004204 std::vector<int> axisData(axisTensorInfo.GetNumElements());
4205 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004206 int32_t axis = axisData[0];
4207
4208 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
4209 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
4210 {
4211 // Square bracket denotes inclusive n while parenthesis denotes exclusive n
4212 // E.g. Rank 4 tensor can have axis in range [-4, 3)
4213 // -1 == 3, -2 == 2, -3 == 1, -4 == 0
4214 throw ParseException(
4215 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
4216 axis,
4217 CHECK_LOCATION().AsString()));
4218 }
4219 const unsigned int splitDim = ComputeWrappedIndex(axis, inputTensorInfo.GetNumDimensions());
Derek Lambertif0176992020-04-28 13:37:49 +01004220
Derek Lambertif0176992020-04-28 13:37:49 +01004221 // Set split sizes
Derek Lambertif0176992020-04-28 13:37:49 +01004222 CHECK_VALID_SIZE(splitsInfo.GetNumDimensions(), 1);
Ryan OShea86704732020-05-26 11:41:04 +01004223 unsigned int numSplits{0};
4224
4225 if(options)
Derek Lambertif0176992020-04-28 13:37:49 +01004226 {
4227 numSplits = CHECKED_NON_NEGATIVE(options->num_splits);
Derek Lambertif0176992020-04-28 13:37:49 +01004228 }
4229 else
4230 {
Ryan OShea86704732020-05-26 11:41:04 +01004231 numSplits = splitsInfo.GetNumElements();
Derek Lambertif0176992020-04-28 13:37:49 +01004232 }
4233
4234 if (numSplits <=0)
4235 {
4236 throw ParseException("SplitV has invalid number of splits");
4237 }
4238
Jan Eilersc0761e92020-06-29 16:48:44 +01004239 std::vector<int> splitsData(numSplits);
Ryan OShea86704732020-05-26 11:41:04 +01004240 BufferRawPtr splitsBufferPtr = GetBuffer(m_Model, splitsTensor->buffer);
Jan Eilersc0761e92020-06-29 16:48:44 +01004241 ::memcpy(splitsData.data(), splitsBufferPtr->data.data(), splitsInfo.GetNumBytes());
Ryan OShea86704732020-05-26 11:41:04 +01004242
Jan Eilersc0761e92020-06-29 16:48:44 +01004243 unsigned int idx = 0;
Ryan OShea86704732020-05-26 11:41:04 +01004244 int numInferred{0};
4245 unsigned int inferIdx{0};
4246 int splitSum{0};
4247 for (auto split : splitsData)
4248 {
4249 if (split < 0)
4250 {
4251 numInferred++;
4252 inferIdx = idx;
4253 }
4254 else
4255 {
4256 splitSum += split;
4257 }
4258 idx++;
4259 }
4260 // Check for inferred Axis
4261 if (numInferred == 0)
4262 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +01004263 if (splitSum != armnn::numeric_cast<int>(inputTensorInfo.GetShape()[splitDim]))
Ryan OShea86704732020-05-26 11:41:04 +01004264 {
4265 throw ParseException("SplitV split_sizes does not sum to the dimension of value along split_dim.");
4266 }
4267 }
4268 else if (numInferred == 1)
4269 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +01004270 splitsData[inferIdx] = armnn::numeric_cast<int>(inputTensorInfo.GetShape()[splitDim]) - splitSum;
Ryan OShea86704732020-05-26 11:41:04 +01004271 }
4272 else
4273 {
4274 throw ParseException("Cannot infer split size for more than one split");
4275 }
4276
Derek Lambertif0176992020-04-28 13:37:49 +01004277 //Ouput size validation
4278 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4279 CHECK_VALID_SIZE(outputs.size(), numSplits);
4280
4281 // Setup Armnn descriptor
4282 SplitterDescriptor splitDesc(numSplits, inputDimSize);
4283 unsigned int accumSplit = 0;
4284 for (unsigned int j = 0; j < numSplits; ++j)
4285 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +01004286 unsigned int splitSize = armnn::numeric_cast<unsigned int>(splitsData[j]);
Derek Lambertif0176992020-04-28 13:37:49 +01004287
4288 // Set the size of the views.
4289 for (unsigned int dimIdx = 0; dimIdx < inputTensorInfo.GetNumDimensions(); ++dimIdx)
4290 {
4291 unsigned int dimSize = inputTensorInfo.GetShape()[dimIdx];
4292 if (dimIdx == splitDim)
4293 {
4294 dimSize = splitSize;
4295 }
4296 splitDesc.SetViewSize(j, dimIdx, dimSize);
4297 }
4298
4299 splitDesc.SetViewOriginCoord(j, splitDim, accumSplit);
4300 accumSplit += splitSize;
4301 }
4302
James Ward58dec6b2020-09-11 17:32:44 +01004303 auto layerName = fmt::format("SplitV:{}:{}", subgraphIndex, operatorIndex);
Derek Lambertif0176992020-04-28 13:37:49 +01004304 IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01004305 ARMNN_ASSERT(layer != nullptr);
Derek Lambertif0176992020-04-28 13:37:49 +01004306
4307 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4308 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4309
4310 for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
4311 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01004312 armnn::TensorInfo tensorInfo = ToTensorInfo(outputs[k], true);
Derek Lambertif0176992020-04-28 13:37:49 +01004313 layer->GetOutputSlot(k).SetTensorInfo(tensorInfo);
4314 }
4315
4316 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4317 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4318}
4319
Matthew Sloyan28f177c2021-04-09 14:38:52 +01004320void TfLiteParserImpl::ParseArgMin(size_t subgraphIndex, size_t operatorIndex)
4321{
4322 ParseArgMinMax(subgraphIndex, operatorIndex, armnn::ArgMinMaxFunction::Min);
4323}
4324
Kevin May7d96b162021-02-03 17:38:41 +00004325void TfLiteParserImpl::ParseArgMax(size_t subgraphIndex, size_t operatorIndex)
Inki Daed4619e22020-09-10 15:33:54 +09004326{
Matthew Sloyan28f177c2021-04-09 14:38:52 +01004327 ParseArgMinMax(subgraphIndex, operatorIndex, armnn::ArgMinMaxFunction::Max);
4328}
4329
4330void TfLiteParserImpl::ParseArgMinMax(size_t subgraphIndex, size_t operatorIndex, ArgMinMaxFunction argMinMaxFunction)
4331{
Inki Daed4619e22020-09-10 15:33:54 +09004332 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4333 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4334 CHECK_VALID_SIZE(inputs.size(), 2);
4335
4336 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4337 CHECK_VALID_SIZE(outputs.size(), 1);
4338
Mike Kelly377fb212023-01-10 15:55:28 +00004339 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4340 armnn::TensorInfo axisTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Inki Daed4619e22020-09-10 15:33:54 +09004341 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004342 ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
Matthew Sloyan28f177c2021-04-09 14:38:52 +01004343
4344 // Check if output tensor type is Signed32 or Signed64
Mike Kelly1f140f72021-04-06 12:25:55 +01004345 if (outputTensorInfo.GetDataType() != armnn::DataType::Signed32 &&
4346 outputTensorInfo.GetDataType() != armnn::DataType::Signed64)
4347 {
4348 throw ParseException(
4349 fmt::format(
4350 "Output tensor data type is not supported. (Supported types: Signed32 & Signed64) {}",
4351 CHECK_LOCATION().AsString()));
4352 }
Matthew Sloyan28f177c2021-04-09 14:38:52 +01004353
4354 // Get const axis value from model and set it to descriptor.
4355 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
4356 if (axisBufferPtr == nullptr)
4357 {
4358 throw ParseException(
4359 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
4360 CHECK_LOCATION().AsString()));
4361 }
4362
4363 std::vector<int32_t> axisData(axisTensorInfo.GetNumElements());
4364 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
4365 int32_t axis = axisData.front();
4366
4367 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
4368 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
4369 {
4370 // Square bracket denotes inclusive n while parenthesis denotes exclusive n
4371 // E.g. Rank 4 tensor can have axis in range [-4, 3)
4372 // -1 == 3, -2 == 2, -3 == 1, -4 == 0
4373 throw ParseException(
4374 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
4375 axis,
4376 CHECK_LOCATION().AsString()));
4377 }
4378
4379 ArgMinMaxDescriptor desc;
4380 desc.m_Axis = axis;
4381 desc.m_Function = argMinMaxFunction;
4382
4383 // Register a ArgMin/ArgMax layer.
4384 auto layerName = argMinMaxFunction == ArgMinMaxFunction::Max ? "ArgMax:{}:{}" : "ArgMin:{}:{}";
4385 auto layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4386 IConnectableLayer *layer = m_Network->AddArgMinMaxLayer(desc, layerNameFormatted.c_str());
4387 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00004388 outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Inki Daed4619e22020-09-10 15:33:54 +09004389 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4390
4391 // Register input tensor to the layer.
4392 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4393 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4394
4395 // Register output tensor to the layer.
4396 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4397 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4398}
4399
Kevin May7d96b162021-02-03 17:38:41 +00004400void TfLiteParserImpl::ParseGather(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan26868492021-01-22 14:25:31 +00004401{
4402 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4403
Kevin May7d96b162021-02-03 17:38:41 +00004404 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00004405 CHECK_VALID_SIZE(inputs.size(), 2);
Kevin May7d96b162021-02-03 17:38:41 +00004406 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00004407 CHECK_VALID_SIZE(outputs.size(), 1);
4408
Mike Kelly377fb212023-01-10 15:55:28 +00004409 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4410 armnn::TensorInfo indicesTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
4411 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
Sadik Armagan26868492021-01-22 14:25:31 +00004412
4413 armnn::GatherDescriptor gatherDescriptor;
4414
Mike Kelly0d77ae12022-01-07 17:42:27 +00004415 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4416 const auto* options = operatorPtr->builtin_options.AsGatherOptions();
Sadik Armagan26868492021-01-22 14:25:31 +00004417 auto axis = options->axis;
4418
Mike Kelly377fb212023-01-10 15:55:28 +00004419 auto layerName = fmt::format("Gather:{}:{}", subgraphIndex, operatorIndex);
4420
Sadik Armagan26868492021-01-22 14:25:31 +00004421 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
4422 auto indicesDimensions = indicesTensorInfo.GetNumDimensions();
4423 auto outputDimensions = outputTensorInfo.GetNumDimensions();
4424 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
4425 {
4426 throw ParseException(
4427 fmt::format("Operation has invalid axis: {} It is out of bounds [ -{}, {} ) {}",
4428 axis,
4429 inputDimensions, inputDimensions,
4430 CHECK_LOCATION().AsString()));
4431 }
4432 if (outputDimensions != static_cast<unsigned int>(inputDimensions) + indicesDimensions - 1)
4433 {
4434 throw ParseException(
4435 fmt::format("Operation has invalid output dimensions: {} Output must be an ({} + {} - 1) -D tensor {}",
4436 outputDimensions,
4437 inputDimensions, indicesDimensions,
4438 CHECK_LOCATION().AsString()));
4439 }
4440
4441 gatherDescriptor.m_Axis = axis;
4442
Sadik Armagan26868492021-01-22 14:25:31 +00004443 IConnectableLayer* layer = m_Network->AddGatherLayer(gatherDescriptor, layerName.c_str());
4444 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00004445 outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Sadik Armagan26868492021-01-22 14:25:31 +00004446 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4447
4448 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4449 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4450
4451 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4452 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4453}
4454
Teresa Charlin91a53ea2022-04-25 15:47:29 +01004455void TfLiteParserImpl::ParseGatherNd(size_t subgraphIndex, size_t operatorIndex)
4456{
4457 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4458
4459 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4460 CHECK_VALID_SIZE(inputs.size(), 2);
4461 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4462 CHECK_VALID_SIZE(outputs.size(), 1);
4463
Mike Kelly377fb212023-01-10 15:55:28 +00004464 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4465 armnn::TensorInfo indicesTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Teresa Charlin91a53ea2022-04-25 15:47:29 +01004466
4467 auto layerName = fmt::format("GatherNd:{}:{}", subgraphIndex, operatorIndex);
4468 IConnectableLayer* layer = m_Network->AddGatherNdLayer(layerName.c_str());
4469 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00004470 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Teresa Charlin91a53ea2022-04-25 15:47:29 +01004471 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4472
4473 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4474 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4475
4476 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4477 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4478}
4479
Kevin May7d96b162021-02-03 17:38:41 +00004480void TfLiteParserImpl::ParseDepthToSpace(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan26868492021-01-22 14:25:31 +00004481{
4482 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4483
Kevin May7d96b162021-02-03 17:38:41 +00004484 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00004485 CHECK_VALID_SIZE(inputs.size(), 1);
Kevin May7d96b162021-02-03 17:38:41 +00004486 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00004487 CHECK_VALID_SIZE(outputs.size(), 1);
4488
4489 armnn::DepthToSpaceDescriptor descriptor;
4490
Mike Kelly0d77ae12022-01-07 17:42:27 +00004491 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4492 const auto* options = operatorPtr->builtin_options.AsDepthToSpaceOptions();
Sadik Armagan26868492021-01-22 14:25:31 +00004493 auto blockSize = options->block_size;
4494 if (blockSize < 2)
4495 {
4496 throw ParseException(
4497 fmt::format("Operation has invalid block size: {} Block size should be >= 2 {}",
4498 blockSize,
4499 CHECK_LOCATION().AsString()));
4500 }
4501 descriptor.m_BlockSize = armnn::numeric_cast<uint32_t>(blockSize);
4502
4503 auto layerName = fmt::format("DepthToSpace:{}:{}", subgraphIndex, operatorIndex);
4504 IConnectableLayer* layer = m_Network->AddDepthToSpaceLayer(descriptor, layerName.c_str());
4505 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00004506 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Sadik Armagan26868492021-01-22 14:25:31 +00004507 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4508
4509 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4510 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4511
4512 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4513 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4514}
4515
Kevin May7d96b162021-02-03 17:38:41 +00004516void TfLiteParserImpl::ParseSum(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004517{
Sadik Armagana2747482021-02-09 10:28:54 +00004518 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Sum);
4519}
4520
Teresa Charlin4e3e8312021-08-05 12:34:37 +01004521void TfLiteParserImpl::ParseReduceProd(size_t subgraphIndex, size_t operatorIndex)
4522{
4523 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Prod);
4524}
4525
Sadik Armagana2747482021-02-09 10:28:54 +00004526void TfLiteParserImpl::ParseReduceMax(size_t subgraphIndex, size_t operatorIndex)
4527{
4528 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Max);
4529}
4530
4531void TfLiteParserImpl::ParseReduceMin(size_t subgraphIndex, size_t operatorIndex)
4532{
4533 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Min);
4534}
4535
4536void TfLiteParserImpl::ParseReduce(size_t subgraphIndex, size_t operatorIndex, ReduceOperation reduceOperation)
4537{
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004538 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4539
Mike Kelly0d77ae12022-01-07 17:42:27 +00004540 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4541 const auto* options = operatorPtr->builtin_options.AsReducerOptions();
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004542
4543 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4544 CHECK_VALID_SIZE(inputs.size(), 2);
4545
4546 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4547 CHECK_VALID_SIZE(outputs.size(), 1);
4548
Sadik Armagana2747482021-02-09 10:28:54 +00004549 auto layerName = fmt::format("Reduce:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004550
Mike Kelly377fb212023-01-10 15:55:28 +00004551 armnn::TensorInfo inputTensorInfo0 = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4552 armnn::TensorInfo inputTensorInfo1 = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004553
4554 ReduceDescriptor desc;
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004555 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
4556 // Get const axis value from model and set it to descriptor.
4557 if (axisBufferPtr != nullptr)
4558 {
Sadik Armagan49bdb792021-02-11 13:57:07 +00004559 std::vector<int32_t> axisData(inputTensorInfo1.GetNumElements());
4560 ::memcpy(axisData.data(), axisBufferPtr->data.data(), inputTensorInfo1.GetNumBytes());
4561
4562 // Convert the axis to unsigned int and remove duplicates.
4563 auto rank = static_cast<int32_t>(inputTensorInfo0.GetNumDimensions());
4564 std::set<unsigned int> uniqueAxis;
4565 std::transform(axisData.begin(),
4566 axisData.end(),
4567 std::inserter(uniqueAxis, uniqueAxis.begin()),
4568 [rank](int i)->unsigned int{
4569 return static_cast<uint32_t>(((i + rank) % rank)); });
4570 desc.m_vAxis.assign(uniqueAxis.begin(), uniqueAxis.end());
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004571 }
Sadik Armagana2747482021-02-09 10:28:54 +00004572 else
4573 {
4574 for (uint32_t i = 0; i < inputTensorInfo0.GetNumDimensions(); ++i)
4575 {
4576 desc.m_vAxis.push_back(i);
4577 }
4578 }
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004579
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004580 desc.m_KeepDims = options->keep_dims;
Sadik Armagana2747482021-02-09 10:28:54 +00004581 desc.m_ReduceOperation = reduceOperation;
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004582
4583 // Register a new layer object, Sum.
Mike Kelly0d77ae12022-01-07 17:42:27 +00004584 IConnectableLayer* layer = m_Network->AddReduceLayer(desc, layerName.c_str());
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004585
Mike Kelly377fb212023-01-10 15:55:28 +00004586 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004587 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4588
4589 // Register input tensor to the layer.
4590 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4591 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4592
4593 // Register output tensor to the layer.
4594 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4595 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4596}
4597
Mike Kelly31dce2b2021-09-01 21:22:37 +01004598void TfLiteParserImpl::ParseLocalResponseNormalization(size_t subgraphIndex, size_t operatorIndex)
4599{
4600 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4601
4602 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4603 CHECK_VALID_SIZE(inputs.size(), 1);
4604
4605 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4606 CHECK_VALID_SIZE(outputs.size(), 1);
4607
4608 auto layerName = fmt::format("LRN:{}:{}", subgraphIndex, operatorIndex);
4609 std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4610
Mike Kelly377fb212023-01-10 15:55:28 +00004611 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Mike Kelly31dce2b2021-09-01 21:22:37 +01004612
4613 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4614 const auto* options = operatorPtr->builtin_options.AsLocalResponseNormalizationOptions();
4615
4616 armnn::NormalizationDescriptor descriptor;
4617 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
4618 descriptor.m_NormChannelType = armnn::NormalizationAlgorithmChannel::Across;
4619 descriptor.m_NormMethodType = armnn::NormalizationAlgorithmMethod::LocalBrightness;
4620 descriptor.m_NormSize = static_cast<uint32_t>(options->radius);
4621 descriptor.m_K = options->bias;
4622 descriptor.m_Alpha = options->alpha;
4623 descriptor.m_Beta = options->beta;
4624
4625 // ArmNN expects normSize to be the full size of the normalization
4626 // window rather than the radius as in TfLite.
4627 descriptor.m_NormSize = 1 + (2 * descriptor.m_NormSize);
4628
4629 IConnectableLayer* layer = m_Network->AddNormalizationLayer(descriptor, layerNameFormatted.c_str());
4630 ARMNN_ASSERT(layer != nullptr);
4631
Mike Kelly377fb212023-01-10 15:55:28 +00004632 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Mike Kelly31dce2b2021-09-01 21:22:37 +01004633 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4634
4635 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4636 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4637
4638 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4639 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4640}
4641
Teresa Charlin28aa6692022-07-12 11:18:44 +01004642void TfLiteParserImpl::ParseAbs(size_t subgraphIndex, size_t operatorIndex)
4643{
4644 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Abs);
4645}
4646
Teresa Charlin93f0ad02023-03-23 15:28:02 +00004647void TfLiteParserImpl::ParseCeil(size_t subgraphIndex, size_t operatorIndex)
4648{
4649 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Ceil);
4650}
4651
Teresa Charlin28aa6692022-07-12 11:18:44 +01004652void TfLiteParserImpl::ParseExp(size_t subgraphIndex, size_t operatorIndex)
4653{
4654 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Exp);
4655}
4656
4657void TfLiteParserImpl::ParseLog(size_t subgraphIndex, size_t operatorIndex)
4658{
4659 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Log);
4660}
4661
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004662void TfLiteParserImpl::ParseLogicalNot(size_t subgraphIndex, size_t operatorIndex)
4663{
4664 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::LogicalNot);
4665}
4666
4667void TfLiteParserImpl::ParseNeg(size_t subgraphIndex, size_t operatorIndex)
4668{
4669 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Neg);
4670}
4671
John Mcloughlin0ec00872023-05-15 17:03:49 +01004672void TfLiteParserImpl::ParsePower(size_t subgraphIndex, size_t operatorIndex)
4673{
4674 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4675
4676 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4677 CHECK_VALID_SIZE(inputs.size(), 2);
4678
4679 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4680 CHECK_VALID_SIZE(outputs.size(), 1);
4681
4682 auto layerName = fmt::format("Power:{}:{}", subgraphIndex, operatorIndex);
4683
4684 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4685 TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
4686 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
4687
4688 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Power, layerName.c_str());
4689 ARMNN_ASSERT(layer != nullptr);
4690
4691 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
4692 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
4693 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4694
4695 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4696 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4697
4698 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4699 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4700}
4701
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004702void TfLiteParserImpl::ParseRsqrt(size_t subgraphIndex, size_t operatorIndex)
4703{
4704 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Rsqrt);
4705}
4706
Teresa Charlin28aa6692022-07-12 11:18:44 +01004707void TfLiteParserImpl::ParseSin(size_t subgraphIndex, size_t operatorIndex)
4708{
4709 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Sin);
4710}
4711
Teresa Charlinf0fce5b2022-05-04 17:24:43 +01004712void TfLiteParserImpl::ParseSqrt(size_t subgraphIndex, size_t operatorIndex)
4713{
4714 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Sqrt);
4715}
4716
Teresa Charlin6963b332023-07-11 11:35:41 +01004717void TfLiteParserImpl::ParseSquare(size_t subgraphIndex, size_t operatorIndex)
4718{
4719 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4720
4721 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4722 CHECK_VALID_SIZE(inputs.size(), 1);
4723
4724 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4725 CHECK_VALID_SIZE(outputs.size(), 1);
4726
4727 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4728
4729 auto layerName = fmt::format("Square:{}:{}", subgraphIndex, operatorIndex);
4730 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Mul, layerName.c_str());
4731 ARMNN_ASSERT(layer != nullptr);
4732
4733 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 0});
4734 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
4735 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4736
4737 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4738 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[0]});
4739
4740 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4741 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4742}
4743
John Mcloughlin0ec00872023-05-15 17:03:49 +01004744void TfLiteParserImpl::ParseSquaredDifference(size_t subgraphIndex, size_t operatorIndex)
4745{
4746 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4747
4748 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4749 CHECK_VALID_SIZE(inputs.size(), 2);
4750
4751 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4752 CHECK_VALID_SIZE(outputs.size(), 1);
4753
4754 auto layerName = fmt::format("SquaredDifference:{}:{}", subgraphIndex, operatorIndex);
4755
4756 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4757 TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
4758 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
4759
4760 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::SqDiff, layerName.c_str());
4761 ARMNN_ASSERT(layer != nullptr);
4762
4763 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
4764 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
4765 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4766
4767 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4768 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4769
4770 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4771 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4772}
4773
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004774void TfLiteParserImpl::ParseElementwiseUnary(size_t subgraphIndex, size_t operatorIndex, UnaryOperation unaryOperation)
4775{
4776 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4777
4778 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4779 CHECK_VALID_SIZE(inputs.size(), 1);
4780
4781 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4782 CHECK_VALID_SIZE(outputs.size(), 1);
4783
4784 std::string layerName = std::string(GetUnaryOperationAsCString(unaryOperation)) + ":{}:{}";
4785 std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4786
4787 ElementwiseUnaryDescriptor desc;
4788 desc.m_Operation = unaryOperation;
4789 IConnectableLayer* layer = m_Network->AddElementwiseUnaryLayer(desc, layerNameFormatted.c_str());
4790 ARMNN_ASSERT(layer != nullptr);
4791
Mike Kelly377fb212023-01-10 15:55:28 +00004792 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004793 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4794
4795 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4796 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4797
4798 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4799 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4800}
4801
Bruno Goncalves2d0eb862021-07-11 14:10:15 -03004802void TfLiteParserImpl::ParseEqual(size_t subgraphIndex, size_t operatorIndex)
4803{
4804 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::Equal);
4805}
4806
4807void TfLiteParserImpl::ParseNotEqual(size_t subgraphIndex, size_t operatorIndex)
4808{
4809 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::NotEqual);
4810}
4811
4812void TfLiteParserImpl::ParseGreater(size_t subgraphIndex, size_t operatorIndex)
4813{
4814 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::Greater);
4815}
4816
4817void TfLiteParserImpl::ParseGreaterOrEqual(size_t subgraphIndex, size_t operatorIndex)
4818{
4819 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::GreaterOrEqual);
4820}
4821
4822void TfLiteParserImpl::ParseLess(size_t subgraphIndex, size_t operatorIndex)
4823{
4824 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::Less);
4825}
4826
4827void TfLiteParserImpl::ParseLessOrEqual(size_t subgraphIndex, size_t operatorIndex)
4828{
4829 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::LessOrEqual);
4830}
4831
4832void TfLiteParserImpl::ParseComparison(size_t subgraphIndex, size_t operatorIndex,
4833 ComparisonOperation comparisonOperation)
4834{
4835 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4836
4837 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4838 CHECK_VALID_SIZE(inputs.size(), 2);
4839
4840 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4841 CHECK_VALID_SIZE(outputs.size(), 1);
4842
4843 auto layerName = std::string(GetComparisonOperationAsCString(comparisonOperation)) + ":{}:{}";
4844 std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4845
Mike Kelly377fb212023-01-10 15:55:28 +00004846 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4847 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves2d0eb862021-07-11 14:10:15 -03004848 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerNameFormatted, "Input 0", "Input 1");
4849
4850 ComparisonDescriptor desc;
4851 desc.m_Operation = comparisonOperation;
4852 IConnectableLayer* layer = m_Network->AddComparisonLayer(desc, layerNameFormatted.c_str());
4853 ARMNN_ASSERT(layer != nullptr);
4854
Mike Kelly377fb212023-01-10 15:55:28 +00004855 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Bruno Goncalves2d0eb862021-07-11 14:10:15 -03004856 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4857
4858 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4859 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4860
4861 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4862 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4863}
4864
Mike Kelly04d82292023-01-19 18:29:40 +00004865armnn::IConnectableLayer* TfLiteParserImpl::AddReshapeLayer(armnn::IConnectableLayer* layer,
4866 unsigned int outputSlot,
4867 std::string reshapeLayerName,
4868 armnn::TensorInfo outputShape)
4869{
4870 ReshapeDescriptor desc;
4871 desc.m_TargetShape = outputShape.GetShape();
4872
4873 IConnectableLayer* reshapeLayer =
4874 m_Network->AddReshapeLayer(desc, reshapeLayerName.c_str());
4875
4876 auto & prevOutputSlot = layer->GetOutputSlot(outputSlot);
4877 prevOutputSlot.Connect(reshapeLayer->GetInputSlot(0));
4878 reshapeLayer->GetOutputSlot(0).SetTensorInfo(outputShape);
4879 return reshapeLayer;
4880}
4881
Kevin May7d96b162021-02-03 17:38:41 +00004882armnn::IConnectableLayer* TfLiteParserImpl::AddFusedActivationLayer(armnn::IConnectableLayer* prevLayer,
4883 unsigned int outputSlot,
4884 tflite::ActivationFunctionType activationType)
telsoa01c577f2c2018-08-31 09:22:23 +01004885{
4886 ActivationDescriptor activationDesc;
4887 std::string layerName = prevLayer->GetName();
4888
4889 switch(activationType)
4890 {
4891 case tflite::ActivationFunctionType_NONE:
4892 {
4893 // this is a no-op: return previous layer
4894 return prevLayer;
4895 }
4896 case tflite::ActivationFunctionType_RELU:
4897 {
4898 activationDesc.m_Function = ActivationFunction::ReLu;
4899 layerName += ":RELU";
4900 break;
4901 }
4902 case tflite::ActivationFunctionType_RELU6:
4903 {
4904 activationDesc.m_Function = ActivationFunction::BoundedReLu;
4905 activationDesc.m_A = 6.0f;
4906 activationDesc.m_B = 0.0f;
4907 layerName += ":RELU6";
4908 break;
4909 }
4910 case tflite::ActivationFunctionType_TANH:
4911 {
4912 activationDesc.m_Function = ActivationFunction::TanH;
4913 activationDesc.m_A = 1.0f;
4914 activationDesc.m_B = 1.0f;
4915 layerName += ":TANH";
4916 break;
4917 }
4918
4919 // I only put these here as a reminder what others we could support
4920 case tflite::ActivationFunctionType_RELU_N1_TO_1:
4921 case tflite::ActivationFunctionType_SIGN_BIT:
4922 default:
4923 {
4924 throw ParseException(
Mike Kelly377fb212023-01-10 15:55:28 +00004925 fmt::format("TfLite parser doesn't support fused activation: "
James Ward58dec6b2020-09-11 17:32:44 +01004926 "{}/{} {} ",
4927 activationType,
4928 tflite::EnumNameActivationFunctionType(activationType),
4929 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01004930
4931 }
4932 }
4933
4934 IConnectableLayer* activationLayer =
4935 m_Network->AddActivationLayer(activationDesc, layerName.c_str());
4936
4937 auto & prevOutputSlot = prevLayer->GetOutputSlot(outputSlot);
4938 prevOutputSlot.Connect(activationLayer->GetInputSlot(0));
4939 activationLayer->GetOutputSlot(0).SetTensorInfo(prevOutputSlot.GetTensorInfo());
4940 return activationLayer;
4941}
4942
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004943armnn::IConnectableLayer* TfLiteParserImpl::AddFusedFloorLayer(armnn::IConnectableLayer* prevLayer,
4944 unsigned int outputSlot)
4945{
Teresa Charlin725728e2022-05-05 13:33:33 +01004946
4947 auto& prevOutputSlot = prevLayer->GetOutputSlot(outputSlot);
4948 DataType dataType = prevOutputSlot.GetTensorInfo().GetDataType();
4949
4950 if (dataType == DataType::Signed32)
4951 {
4952 return prevLayer;
4953 }
4954
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004955 std::string layerName = prevLayer->GetName();
4956 IConnectableLayer* floorLayer = m_Network->AddFloorLayer(layerName.c_str());
4957
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004958 prevOutputSlot.Connect(floorLayer->GetInputSlot(0));
4959 floorLayer->GetOutputSlot(0).SetTensorInfo(prevOutputSlot.GetTensorInfo());
Teresa Charlin725728e2022-05-05 13:33:33 +01004960
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004961 return floorLayer;
4962}
4963
Mike Kelly0d77ae12022-01-07 17:42:27 +00004964TfLiteParserImpl::ModelPtr TfLiteParserImpl::LoadModelFromFile(const char* fileName)
telsoa01c577f2c2018-08-31 09:22:23 +01004965{
4966 if (fileName == nullptr)
4967 {
James Ward58dec6b2020-09-11 17:32:44 +01004968 throw InvalidArgumentException(fmt::format("Invalid (null) file name {}",
telsoa01c577f2c2018-08-31 09:22:23 +01004969 CHECK_LOCATION().AsString()));
4970 }
Francis Murtagh532a29d2020-06-29 11:50:01 +01004971 std::error_code errorCode;
4972 fs::path pathToFile(fileName);
4973 if (!fs::exists(pathToFile, errorCode))
telsoa01c577f2c2018-08-31 09:22:23 +01004974 {
James Ward58dec6b2020-09-11 17:32:44 +01004975 //fmt::format() could not be used here (format error)
4976 std::stringstream msg;
4977 msg << "Cannot find the file (" << fileName << ") errorCode: " << errorCode
4978 << " " << CHECK_LOCATION().AsString();
James Ward58dec6b2020-09-11 17:32:44 +01004979 throw FileNotFoundException(msg.str());
telsoa01c577f2c2018-08-31 09:22:23 +01004980 }
Colm Donelan0dfb2652023-06-22 10:19:17 +01004981 if (!fs::is_regular_file(pathToFile))
4982 {
4983 // Exclude non regular files.
4984 throw InvalidArgumentException(fmt::format("File \"{}\" is not a regular file and cannot be loaded.",
4985 pathToFile.c_str()));
4986 }
4987
telsoa01c577f2c2018-08-31 09:22:23 +01004988 std::ifstream file(fileName, std::ios::binary);
4989 std::string fileContent((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
4990 return LoadModelFromBinary(reinterpret_cast<const uint8_t *>(fileContent.c_str()),
4991 fileContent.size());
4992}
4993
Mike Kelly0d77ae12022-01-07 17:42:27 +00004994TfLiteParserImpl::ModelPtr TfLiteParserImpl::LoadModelFromBinary(const uint8_t* binaryContent, size_t len)
telsoa01c577f2c2018-08-31 09:22:23 +01004995{
4996 if (binaryContent == nullptr)
4997 {
James Ward58dec6b2020-09-11 17:32:44 +01004998 throw InvalidArgumentException(fmt::format("Invalid (null) binary content {}",
telsoa01c577f2c2018-08-31 09:22:23 +01004999 CHECK_LOCATION().AsString()));
5000 }
5001 flatbuffers::Verifier verifier(binaryContent, len);
5002 if (verifier.VerifyBuffer<tflite::Model>() == false)
5003 {
5004 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01005005 fmt::format("Buffer doesn't conform to the expected Tensorflow Lite "
5006 "flatbuffers format. size:{} {}",
5007 len,
5008 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01005009 }
5010 return tflite::UnPackModel(binaryContent);
5011}
5012
Mike Kelly0d77ae12022-01-07 17:42:27 +00005013TfLiteParserImpl::TensorRawPtrVector TfLiteParserImpl::GetInputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00005014 size_t subgraphIndex,
5015 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005016{
5017 CHECK_MODEL(model, subgraphIndex, operatorIndex);
5018
Mike Kelly0d77ae12022-01-07 17:42:27 +00005019 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
5020 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01005021
5022 size_t inputCount = operatorPtr->inputs.size();
mathad01c21025d2021-04-26 10:09:37 +01005023 TensorRawPtrVector result;
Mike Kelly0d77ae12022-01-07 17:42:27 +00005024 for (size_t i = 0; i < inputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01005025 {
mathad01c21025d2021-04-26 10:09:37 +01005026 // If the input location is -1 then assume input is turned off.
5027 if (operatorPtr->inputs[i] == -1)
5028 {
5029 continue;
5030 }
5031 else
5032 {
5033 uint32_t inputId = CHECKED_NON_NEGATIVE(operatorPtr->inputs[i]);
5034 result.push_back(subgraphPtr->tensors[inputId].get());
5035 }
telsoa01c577f2c2018-08-31 09:22:23 +01005036 }
5037 return result;
5038}
5039
Mike Kelly0d77ae12022-01-07 17:42:27 +00005040TfLiteParserImpl::TensorRawPtrVector TfLiteParserImpl::GetOutputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00005041 size_t subgraphIndex,
5042 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005043{
5044 CHECK_MODEL(model, subgraphIndex, operatorIndex);
5045
Mike Kelly0d77ae12022-01-07 17:42:27 +00005046 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
5047 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01005048
5049 size_t outputCount = operatorPtr->outputs.size();
5050 TensorRawPtrVector result(outputCount);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005051 for (size_t i = 0; i < outputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01005052 {
5053 uint32_t outputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[i]);
5054 CHECK_TENSOR(model, subgraphIndex, outputId);
Derek Lambertiff05cc52019-04-26 13:05:17 +01005055 result[i] = subgraphPtr->tensors[outputId].get();
telsoa01c577f2c2018-08-31 09:22:23 +01005056 }
5057 return result;
5058}
5059
Mike Kelly0d77ae12022-01-07 17:42:27 +00005060TfLiteParserImpl::TensorIdRawPtrVector TfLiteParserImpl::GetSubgraphInputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00005061 size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005062{
5063 CHECK_SUBGRAPH(model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005064 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01005065
Derek Lambertiff05cc52019-04-26 13:05:17 +01005066 size_t inputCount = subgraphPtr->inputs.size();
telsoa01c577f2c2018-08-31 09:22:23 +01005067 TensorIdRawPtrVector result(inputCount);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005068 for (size_t i = 0; i < inputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01005069 {
Derek Lambertiff05cc52019-04-26 13:05:17 +01005070 uint32_t inputId = CHECKED_NON_NEGATIVE(subgraphPtr->inputs[i]);
telsoa01c577f2c2018-08-31 09:22:23 +01005071 CHECK_TENSOR(model, subgraphIndex, inputId);
Derek Lambertiff05cc52019-04-26 13:05:17 +01005072 result[i] = std::make_pair(inputId, subgraphPtr->tensors[inputId].get());
telsoa01c577f2c2018-08-31 09:22:23 +01005073 }
5074 return result;
5075}
5076
Mike Kelly0d77ae12022-01-07 17:42:27 +00005077TfLiteParserImpl::TensorIdRawPtrVector TfLiteParserImpl::GetSubgraphOutputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00005078 size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005079{
5080 CHECK_SUBGRAPH(model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005081 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01005082
Derek Lambertiff05cc52019-04-26 13:05:17 +01005083 size_t outputCount = subgraphPtr->outputs.size();
telsoa01c577f2c2018-08-31 09:22:23 +01005084 TensorIdRawPtrVector result(outputCount);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005085 for (size_t i = 0; i < outputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01005086 {
Derek Lambertiff05cc52019-04-26 13:05:17 +01005087 uint32_t outputId = CHECKED_NON_NEGATIVE(subgraphPtr->outputs[i]);
5088 result[i] = std::make_pair(outputId, subgraphPtr->tensors[outputId].get());
telsoa01c577f2c2018-08-31 09:22:23 +01005089 }
5090 return result;
5091}
5092
Kevin May7d96b162021-02-03 17:38:41 +00005093std::vector<int32_t>& TfLiteParserImpl::GetInputTensorIds(const ModelPtr& model,
5094 size_t subgraphIndex,
5095 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005096{
5097 CHECK_MODEL(model, subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005098 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
5099 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01005100 return operatorPtr->inputs;
5101}
5102
Kevin May7d96b162021-02-03 17:38:41 +00005103std::vector<int32_t>& TfLiteParserImpl::GetOutputTensorIds(const ModelPtr& model,
5104 size_t subgraphIndex,
5105 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005106{
5107 CHECK_MODEL(model, subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005108 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
5109 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01005110 return operatorPtr->outputs;
5111}
5112
Kevin May7d96b162021-02-03 17:38:41 +00005113void TfLiteParserImpl::RegisterInputSlots(size_t subgraphIndex,
5114 size_t operatorIndex,
5115 IConnectableLayer* layer,
Finn Williamsd4fa5452021-03-01 12:31:41 +00005116 const std::vector<unsigned int>& tensorIndexes,
5117 unsigned int startingSlotIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005118{
5119 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01005120 ARMNN_ASSERT(layer != nullptr);
Matthew Sloyan81beae32021-07-13 19:46:11 +01005121
Finn Williamsd4fa5452021-03-01 12:31:41 +00005122 if (tensorIndexes.size() + startingSlotIndex != layer->GetNumInputSlots())
telsoa01c577f2c2018-08-31 09:22:23 +01005123 {
5124 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01005125 fmt::format("The number of tensor inputs ({}) does not match the number expected ({})"
5126 " for subgraph:{} operator index:{} {}",
5127 tensorIndexes.size(),
5128 layer->GetNumInputSlots(),
5129 subgraphIndex,
5130 operatorIndex,
5131 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01005132 }
5133
Finn Williamsd4fa5452021-03-01 12:31:41 +00005134 for (unsigned int index = 0; index < tensorIndexes.size() ; ++index)
telsoa01c577f2c2018-08-31 09:22:23 +01005135 {
Finn Williamsd4fa5452021-03-01 12:31:41 +00005136 unsigned int tensorIndex = tensorIndexes[index];
5137 armnn::IInputSlot* slot = &(layer->GetInputSlot(startingSlotIndex + index));
telsoa01c577f2c2018-08-31 09:22:23 +01005138 RegisterConsumerOfTensor(subgraphIndex, tensorIndex, slot);
5139 }
5140}
5141
Kevin May7d96b162021-02-03 17:38:41 +00005142void TfLiteParserImpl::RegisterOutputSlots(size_t subgraphIndex,
5143 size_t operatorIndex,
5144 IConnectableLayer* layer,
5145 const std::vector<unsigned int>& tensorIndexes)
telsoa01c577f2c2018-08-31 09:22:23 +01005146{
5147 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01005148 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01005149 if (tensorIndexes.size() != layer->GetNumOutputSlots())
5150 {
5151 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01005152 fmt::format("The number of tensor outputs ({}) does not match the number expected ({})"
5153 " for subgraph:{} operator index:{} {}",
5154 tensorIndexes.size(),
5155 layer->GetNumOutputSlots(),
5156 subgraphIndex,
5157 operatorIndex,
5158 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01005159 }
5160
5161 for (unsigned int slotIndex = 0; slotIndex < layer->GetNumOutputSlots(); ++slotIndex)
5162 {
5163 unsigned int tensorIndex = tensorIndexes[slotIndex];
5164 armnn::IOutputSlot* slot = &(layer->GetOutputSlot(slotIndex));
5165 RegisterProducerOfTensor(subgraphIndex, tensorIndex, slot);
5166 }
5167}
5168
Mike Kelly377fb212023-01-10 15:55:28 +00005169void TfLiteParserImpl::SetupInputLayerTensorInfos(size_t subgraphIndex)
5170{
5171 CHECK_SUBGRAPH(m_Model, subgraphIndex);
5172
5173 auto inputs = GetSubgraphInputs(m_Model, subgraphIndex);
5174 for (auto const& tensorIdAndPtr : inputs)
5175 {
5176 auto tensorInfo = ToTensorInfo(tensorIdAndPtr.second);
5177 m_TensorInfos.insert({tensorIdAndPtr.first, tensorInfo});
5178 }
5179}
5180
Kevin May7d96b162021-02-03 17:38:41 +00005181void TfLiteParserImpl::SetupInputLayers(size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005182{
5183 CHECK_SUBGRAPH(m_Model, subgraphIndex);
5184
5185 auto inputs = GetSubgraphInputs(m_Model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005186 for (auto const& tensorIdAndPtr : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005187 {
5188 auto bindingId = GenerateLayerBindingId(subgraphIndex, tensorIdAndPtr.first);
5189 IConnectableLayer* layer =
5190 m_Network->AddInputLayer(bindingId, tensorIdAndPtr.second->name.c_str());
5191
5192 auto tensorInfo = ToTensorInfo(tensorIdAndPtr.second);
5193 layer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
5194
5195 RegisterOutputSlots(subgraphIndex,
5196 VIRTUAL_OPERATOR_ID,
5197 layer,
5198 { static_cast<uint32_t>(tensorIdAndPtr.first) });
5199 }
5200}
5201
Kevin May7d96b162021-02-03 17:38:41 +00005202void TfLiteParserImpl::SetupOutputLayers(size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005203{
5204 CHECK_SUBGRAPH(m_Model, subgraphIndex);
5205
5206 auto outputs = GetSubgraphOutputs(m_Model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005207 for (auto const& tensorIdAndPtr : outputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005208 {
5209 auto bindingId = GenerateLayerBindingId(subgraphIndex, tensorIdAndPtr.first);
5210 IConnectableLayer* layer =
5211 m_Network->AddOutputLayer(bindingId, tensorIdAndPtr.second->name.c_str());
5212
5213 RegisterInputSlots(subgraphIndex,
5214 VIRTUAL_OPERATOR_ID,
5215 layer,
5216 { static_cast<uint32_t>(tensorIdAndPtr.first) });
5217 }
5218}
5219
Mike Kelly377fb212023-01-10 15:55:28 +00005220void TfLiteParserImpl::SetupConstantLayerTensorInfos(size_t subgraph)
5221{
5222 CHECK_SUBGRAPH(m_Model, subgraph);
5223
5224 const auto & subgraphPtr = m_Model->subgraphs[subgraph];
5225 for (unsigned int subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex)
5226 {
5227 for (unsigned int tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex)
5228 {
5229 if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot == nullptr &&
5230 m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size() > 0)
5231 {
5232 TensorRawPtr tensorPtr = subgraphPtr->tensors[tensorIndex].get();
5233
5234 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
5235
5236 m_TensorInfos.insert({tensorIndex, tensorInfo});
5237 }
5238 }
5239 }
5240}
5241
Mike Kelly5880b912022-01-28 16:18:54 +00005242void TfLiteParserImpl::SetupConstantLayers(size_t subgraph)
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005243{
Mike Kelly5880b912022-01-28 16:18:54 +00005244 CHECK_SUBGRAPH(m_Model, subgraph);
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005245
Mike Kelly5880b912022-01-28 16:18:54 +00005246 const auto & subgraphPtr = m_Model->subgraphs[subgraph];
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005247 for (unsigned int subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex)
5248 {
5249 for (unsigned int tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex)
5250 {
5251 if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot == nullptr &&
5252 m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size() > 0)
5253 {
Derek Lambertiff05cc52019-04-26 13:05:17 +01005254 TensorRawPtr tensorPtr = subgraphPtr->tensors[tensorIndex].get();
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005255
Mike Kelly5880b912022-01-28 16:18:54 +00005256 if (IsConstTensor(tensorPtr))
Matthew Sloyan81beae32021-07-13 19:46:11 +01005257 {
5258 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
Mike Kelly5880b912022-01-28 16:18:54 +00005259 armnn::DataType dataType = tensorInfo.GetDataType();
5260
5261 if (std::find(m_ConstantsToDequantize.begin(), m_ConstantsToDequantize.end(), tensorPtr->buffer)
5262 != m_ConstantsToDequantize.end())
5263 {
5264 dataType = DataType::Float32;
5265 }
5266 auto tensorAndData = CreateConstTensorNonPermuted(tensorPtr, tensorInfo, dataType);
5267
5268 std::string layerName = fmt::format("Constant:{}", tensorPtr->name);
5269 IConnectableLayer *layer = m_Network->AddConstantLayer(tensorAndData.first, layerName.c_str());
5270
5271 layer->GetOutputSlot(0).SetTensorInfo(tensorAndData.first.GetInfo());
5272 RegisterOutputSlots(subgraphIndex,
5273 VIRTUAL_OPERATOR_ID,
5274 layer,
5275 { tensorIndex });
5276 }
5277 else if (ShouldConstantTensorBeCreated(tensorIndex))
5278 {
5279 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
5280 armnn::DataType dataType = tensorInfo.GetDataType();
5281
5282 if (std::find(m_ConstantsToDequantize.begin(), m_ConstantsToDequantize.end(), tensorPtr->buffer)
5283 != m_ConstantsToDequantize.end())
5284 {
5285 dataType = DataType::Float32;
5286 }
5287 // Make sure isConstant flag is set.
5288 tensorInfo.SetConstant();
5289 tensorInfo.SetDataType(dataType);
5290
5291 auto tensorAndData = ConstTensor(tensorInfo, std::vector<uint8_t>(tensorInfo.GetNumBytes()));
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005292
Matthew Sloyan81beae32021-07-13 19:46:11 +01005293 std::string layerName = fmt::format("Constant:{}", tensorPtr->name);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005294 IConnectableLayer* layer = m_Network->AddConstantLayer(tensorAndData, layerName.c_str());
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005295
Matthew Sloyan81beae32021-07-13 19:46:11 +01005296 layer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
5297 RegisterOutputSlots(subgraphIndex,
5298 VIRTUAL_OPERATOR_ID,
5299 layer,
Mike Kelly5880b912022-01-28 16:18:54 +00005300 {tensorIndex});
Matthew Sloyan81beae32021-07-13 19:46:11 +01005301 }
5302 else
5303 {
5304 throw ParseException(
5305 fmt::format("Invalid Tensor: Tensor should be constant. {}",
5306 CHECK_LOCATION().AsString()));
5307 }
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005308 }
5309 }
5310 }
5311}
5312
telsoa01c577f2c2018-08-31 09:22:23 +01005313// example usage: BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[0]->buffer);
Kevin May7d96b162021-02-03 17:38:41 +00005314TfLiteParserImpl::BufferRawPtr TfLiteParserImpl::GetBuffer(const ModelPtr& model, size_t bufferIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005315{
5316 CHECK_BUFFER(model, bufferIndex);
5317 return model->buffers[bufferIndex].get();
5318}
5319
Matteo Martincigh747ef822018-12-18 09:26:39 +00005320template<typename T>
Kevin May7d96b162021-02-03 17:38:41 +00005321std::pair<armnn::ConstTensor, TfLiteParserImpl::SupportedDataStorage>
5322TfLiteParserImpl::CreateConstTensorAndStoreData(TfLiteParserImpl::BufferRawPtr bufferPtr,
5323 TfLiteParserImpl::TensorRawPtr tensorPtr,
Matteo Martincigh747ef822018-12-18 09:26:39 +00005324 armnn::TensorInfo& tensorInfo,
5325 armnn::Optional<armnn::PermutationVector&> permutationVector)
5326{
Matthew Sloyan81beae32021-07-13 19:46:11 +01005327 // Make sure isConstant flag is set.
5328 tensorInfo.SetConstant();
5329
Matteo Martincigh747ef822018-12-18 09:26:39 +00005330 auto constData = CreateConstTensorImpl<T>(bufferPtr,
5331 tensorPtr,
5332 tensorInfo,
5333 permutationVector);
Kevin May7d96b162021-02-03 17:38:41 +00005334 TfLiteParserImpl::SupportedDataStorage storage(std::move(constData.second));
Matteo Martincigh747ef822018-12-18 09:26:39 +00005335 return std::make_pair(constData.first, std::move(storage));
5336}
5337
Mike Kelly5880b912022-01-28 16:18:54 +00005338bool TfLiteParserImpl::ShouldConstantTensorBeCreated(unsigned int tensorIndex)
5339{
5340 // If the TensorIndex appears in the list of ConstantsToBeCreated then return true
5341 return (std::find(m_ConstantsToBeCreated.begin(), m_ConstantsToBeCreated.end(), tensorIndex)
5342 != m_ConstantsToBeCreated.end());
5343}
5344
Finn Williamsd4fa5452021-03-01 12:31:41 +00005345bool TfLiteParserImpl::IsConstTensor(TensorRawPtr tensorPtr)
5346{
5347 CHECK_TENSOR_PTR(tensorPtr);
mathad01bf7edb62021-04-20 16:12:45 +01005348 bool isConst = true;
5349
5350 auto buffer = GetBuffer(m_Model, tensorPtr->buffer);
5351 if (buffer->data.size() == 0)
5352 {
5353 isConst = false;
5354 }
5355
5356 return isConst;
Finn Williamsd4fa5452021-03-01 12:31:41 +00005357}
5358
Kevin May7d96b162021-02-03 17:38:41 +00005359std::pair<armnn::ConstTensor, TfLiteParserImpl::SupportedDataStorage>
Finn Williamsd4fa5452021-03-01 12:31:41 +00005360TfLiteParserImpl::CreateConstTensorPermuted(TensorRawPtr tensorPtr,
5361 armnn::TensorInfo& tensorInfo,
5362 armnn::Optional<armnn::PermutationVector&> permutationVector)
telsoa01c577f2c2018-08-31 09:22:23 +01005363{
5364 CHECK_TENSOR_PTR(tensorPtr);
5365 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5366 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5367
Matthew Sloyan81beae32021-07-13 19:46:11 +01005368 // Make sure isConstant flag is set.
5369 tensorInfo.SetConstant();
5370
telsoa01c577f2c2018-08-31 09:22:23 +01005371 switch (tensorInfo.GetDataType())
5372 {
5373 case armnn::DataType::Float32:
Matteo Martincigh747ef822018-12-18 09:26:39 +00005374 return CreateConstTensorAndStoreData<float>(bufferPtr,
5375 tensorPtr,
5376 tensorInfo,
5377 permutationVector);
Derek Lambertif90c56d2020-01-10 17:14:08 +00005378 case armnn::DataType::QAsymmU8:
Matteo Martincigh747ef822018-12-18 09:26:39 +00005379 return CreateConstTensorAndStoreData<uint8_t>(bufferPtr,
5380 tensorPtr,
5381 tensorInfo,
5382 permutationVector);
Keith Davisd305e1a2020-01-22 11:57:54 +00005383 case armnn::DataType::QSymmS8:
5384 return CreateConstTensorAndStoreData<int8_t>(bufferPtr,
5385 tensorPtr,
5386 tensorInfo,
5387 permutationVector);
Keith Davis67e6c542020-02-19 10:08:33 +00005388 case armnn::DataType::QAsymmS8:
5389 return CreateConstTensorAndStoreData<int8_t>(bufferPtr,
5390 tensorPtr,
5391 tensorInfo,
5392 permutationVector);
telsoa01c577f2c2018-08-31 09:22:23 +01005393 case armnn::DataType::Signed32:
Matteo Martincigh747ef822018-12-18 09:26:39 +00005394 return CreateConstTensorAndStoreData<int32_t>(bufferPtr,
5395 tensorPtr,
5396 tensorInfo,
5397 permutationVector);
telsoa01c577f2c2018-08-31 09:22:23 +01005398 default:
5399 {
5400 std::stringstream errString;
5401 errString << "Unexpected datatype when creating const tensor: "
5402 << armnn::GetDataTypeName(tensorInfo.GetDataType())
5403 << " shape:" << tensorInfo.GetShape()
5404 << CHECK_LOCATION().AsString();
5405 throw ParseException(errString.str());
5406 }
5407 }
5408}
5409
Finn Williamsd4fa5452021-03-01 12:31:41 +00005410armnn::ConstTensor TfLiteParserImpl::CreateConstTensorNonPermuted(TensorRawPtr tensorPtr,
5411 armnn::TensorInfo& tensorInfo)
5412{
5413 CHECK_TENSOR_PTR(tensorPtr);
5414 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5415 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5416
Matthew Sloyan81beae32021-07-13 19:46:11 +01005417 // Make sure isConstant flag is set.
5418 tensorInfo.SetConstant();
5419
Finn Williamsd4fa5452021-03-01 12:31:41 +00005420 return ConstTensor(tensorInfo, bufferPtr->data.data());
5421}
5422
Mike Kelly5880b912022-01-28 16:18:54 +00005423std::pair<armnn::ConstTensor, std::unique_ptr<float[]>>
5424TfLiteParserImpl::CreateConstTensorNonPermuted(TensorRawPtr tensorPtr,
5425 armnn::TensorInfo& tensorInfo,
5426 armnn::DataType inputDataType)
5427{
5428 CHECK_TENSOR_PTR(tensorPtr);
5429 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5430 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5431
5432 // Make sure isConstant flag is set.
5433 tensorInfo.SetConstant();
5434
Mike Kelly0506ef02023-01-03 16:29:44 +00005435 if (inputDataType == DataType::Float32 && tensorInfo.GetDataType() != DataType::Float32)
Mike Kelly5880b912022-01-28 16:18:54 +00005436 {
Mike Kelly0506ef02023-01-03 16:29:44 +00005437 try
5438 {
5439 TensorInfo constTensorInfo(tensorInfo.GetShape(), DataType::Float32, 0.0f, 0, true);
5440 std::unique_ptr<float[]> data = armnnUtils::ToFloatArray(bufferPtr->data, tensorInfo);
5441 return std::make_pair(ConstTensor(constTensorInfo, data.get()), std::move(data));
5442 }
Cathal Corbett9c843c32023-01-09 17:51:37 +00005443 catch (InvalidArgumentException&)
Mike Kelly0506ef02023-01-03 16:29:44 +00005444 {
5445 throw ParseException(
5446 fmt::format("Unsupported input/weights combination: Input {} not supported with Weights {}",
5447 GetDataTypeName(DataType::Float32),
5448 GetDataTypeName(tensorInfo.GetDataType()),
5449 CHECK_LOCATION().AsString()));
5450 }
Mike Kelly5880b912022-01-28 16:18:54 +00005451 }
5452 else
5453 {
5454 return std::make_pair(ConstTensor(tensorInfo, bufferPtr->data.data()), std::unique_ptr<float[]>());
5455 }
5456}
5457
5458std::pair<armnn::ConstTensor*, std::unique_ptr<float[]>>
5459TfLiteParserImpl::CreateConstTensorPtr(TensorRawPtr tensorPtr, armnn::TensorInfo& inputTensorInfo)
5460{
5461 CHECK_TENSOR_PTR(tensorPtr);
5462 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
5463 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5464 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5465
5466 // Make sure isConstant flag is set.
5467 tensorInfo.SetConstant();
5468
5469 if (inputTensorInfo.GetDataType() == DataType::Float32 && tensorInfo.GetDataType() != DataType::Float32)
5470 {
Mike Kelly0506ef02023-01-03 16:29:44 +00005471 try
5472 {
5473 TensorInfo constTensorInfo(tensorInfo.GetShape(), DataType::Float32, 0.0f, 0, true);
5474 std::unique_ptr<float[]> data = armnnUtils::ToFloatArray(bufferPtr->data, tensorInfo);
5475 return std::make_pair(new ConstTensor(constTensorInfo, data.get()), std::move(data));
5476 }
Cathal Corbett9c843c32023-01-09 17:51:37 +00005477 catch (InvalidArgumentException&)
Mike Kelly0506ef02023-01-03 16:29:44 +00005478 {
5479 throw ParseException(
5480 fmt::format("Unsupported input/weights combination: Input {} not supported with Weights {}",
5481 GetDataTypeName(DataType::Float32),
5482 GetDataTypeName(tensorInfo.GetDataType()),
5483 CHECK_LOCATION().AsString()));
5484 }
Mike Kelly5880b912022-01-28 16:18:54 +00005485 }
5486 else
5487 {
5488 return std::make_pair(new ConstTensor(tensorInfo, bufferPtr->data.data()), std::unique_ptr<float[]>());
5489 }
5490}
5491
Kevin May7d96b162021-02-03 17:38:41 +00005492BindingPointInfo TfLiteParserImpl::GetNetworkInputBindingInfo(size_t subgraphId,
5493 const std::string& name) const
telsoa01c577f2c2018-08-31 09:22:23 +01005494{
5495 CHECK_SUBGRAPH(m_Model, subgraphId);
5496 auto inputs = GetSubgraphInputs(m_Model, subgraphId);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005497 for (auto const& input : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005498 {
5499 if (input.second->name == name)
5500 {
5501 auto bindingId = GenerateLayerBindingId(subgraphId, input.first);
Colm Donelan4bc993b2021-11-09 20:39:10 +00005502 auto inputTensorInfo = ToTensorInfo(input.second);
5503 // Input tensors are always treated as constant tensors during network execution.
5504 inputTensorInfo.SetConstant(true);
5505 return std::make_pair(bindingId, inputTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +01005506 }
5507 }
5508
5509 std::stringstream bindings;
Mike Kelly0d77ae12022-01-07 17:42:27 +00005510 for (auto const& input : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005511 {
5512 bindings << "'" << input.second->name << "' ";
5513 }
5514
5515 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01005516 fmt::format("No input binding found for subgraph:{} and name:{}. "
5517 "Possible inputs are: [{}] {}",
5518 subgraphId,
5519 name,
5520 bindings.str(),
5521 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01005522}
5523
Kevin May7d96b162021-02-03 17:38:41 +00005524BindingPointInfo TfLiteParserImpl::GetNetworkOutputBindingInfo(size_t subgraphId,
5525 const std::string& name) const
telsoa01c577f2c2018-08-31 09:22:23 +01005526{
5527 CHECK_SUBGRAPH(m_Model, subgraphId);
5528 auto outputs = GetSubgraphOutputs(m_Model, subgraphId);
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00005529 for (unsigned int i = 0; i < outputs.size(); ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01005530 {
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00005531 auto const output = outputs[i];
telsoa01c577f2c2018-08-31 09:22:23 +01005532 if (output.second->name == name)
5533 {
5534 auto bindingId = GenerateLayerBindingId(subgraphId, output.first);
Mike Kelly377fb212023-01-10 15:55:28 +00005535 std::vector<unsigned int> shape = m_OverriddenOutputShapes.size() > 0 ?
5536 m_OverriddenOutputShapes[i] : AsUnsignedVector(output.second->shape);
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00005537 return std::make_pair(bindingId, ToTensorInfo(output.second, shape));
telsoa01c577f2c2018-08-31 09:22:23 +01005538 }
5539 }
5540
5541 std::stringstream bindings;
Mike Kelly0d77ae12022-01-07 17:42:27 +00005542 for (auto const& output : outputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005543 {
5544 bindings << "'" << output.second->name << "' ";
5545 }
5546
5547 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01005548 fmt::format("No output binding found for subgraph:{} and name:{}. "
5549 "Possible outputs are: [{}] {}",
5550 subgraphId,
5551 name,
5552 bindings.str(),
5553 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01005554}
5555
Kevin May7d96b162021-02-03 17:38:41 +00005556size_t TfLiteParserImpl::GetSubgraphCount() const
telsoa01c577f2c2018-08-31 09:22:23 +01005557{
5558 return m_Model->subgraphs.size();
5559}
5560
Kevin May7d96b162021-02-03 17:38:41 +00005561std::vector<std::string> TfLiteParserImpl::GetSubgraphInputTensorNames(size_t subgraphId) const
telsoa01c577f2c2018-08-31 09:22:23 +01005562{
5563 CHECK_SUBGRAPH(m_Model, subgraphId);
5564 auto inputs = GetSubgraphInputs(m_Model, subgraphId);
5565 std::vector<std::string> result;
5566 result.reserve(inputs.size());
Mike Kelly0d77ae12022-01-07 17:42:27 +00005567 for (auto const& input : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005568 {
5569 result.push_back(input.second->name);
5570 }
5571 return result;
5572}
5573
Kevin May7d96b162021-02-03 17:38:41 +00005574std::vector<std::string> TfLiteParserImpl::GetSubgraphOutputTensorNames(size_t subgraphId) const
telsoa01c577f2c2018-08-31 09:22:23 +01005575{
5576 CHECK_SUBGRAPH(m_Model, subgraphId);
5577 auto outputs = GetSubgraphOutputs(m_Model, subgraphId);
5578 std::vector<std::string> result;
5579 result.reserve(outputs.size());
Mike Kelly0d77ae12022-01-07 17:42:27 +00005580 for (auto const& output : outputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005581 {
5582 result.push_back(output.second->name);
5583 }
5584 return result;
5585}
5586
Matthew Sloyanac001ee2021-02-03 10:43:04 +00005587const std::string TfLiteParserImpl::GetVersion()
5588{
5589 return TFLITE_PARSER_VERSION;
5590}
5591
Mike Kelly0d77ae12022-01-07 17:42:27 +00005592TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<float[]>&& data)
telsoa01c577f2c2018-08-31 09:22:23 +01005593: m_FloatData(std::move(data))
5594, m_Uint8Data(nullptr)
Keith Davisd305e1a2020-01-22 11:57:54 +00005595, m_Int8Data(nullptr)
telsoa01c577f2c2018-08-31 09:22:23 +01005596, m_Int32Data(nullptr)
5597{
5598}
5599
Mike Kelly0d77ae12022-01-07 17:42:27 +00005600TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<uint8_t[]>&& data)
telsoa01c577f2c2018-08-31 09:22:23 +01005601: m_FloatData(nullptr)
5602, m_Uint8Data(std::move(data))
Keith Davisd305e1a2020-01-22 11:57:54 +00005603, m_Int8Data(nullptr)
5604, m_Int32Data(nullptr)
5605{
5606}
5607
Mike Kelly0d77ae12022-01-07 17:42:27 +00005608TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<int8_t[]>&& data)
Keith Davisd305e1a2020-01-22 11:57:54 +00005609: m_FloatData(nullptr)
5610, m_Uint8Data(nullptr)
5611, m_Int8Data(std::move(data))
telsoa01c577f2c2018-08-31 09:22:23 +01005612, m_Int32Data(nullptr)
5613{
5614}
5615
Mike Kelly0d77ae12022-01-07 17:42:27 +00005616TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<int32_t[]>&& data)
telsoa01c577f2c2018-08-31 09:22:23 +01005617: m_FloatData(nullptr)
5618, m_Uint8Data(nullptr)
Keith Davisd305e1a2020-01-22 11:57:54 +00005619, m_Int8Data(nullptr)
telsoa01c577f2c2018-08-31 09:22:23 +01005620, m_Int32Data(std::move(data))
5621{
5622}
5623
5624} // armnnTfLiteParser