blob: c0e52b21135fe5b1cf26838d855bdabf912c503f [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());
David Monahan39085f72023-07-28 11:37:29 +01002392 if (beginBufferPtr->data.data() != nullptr)
2393 {
2394 ::memcpy(begin.data(), beginBufferPtr->data.data(), beginTensorInfo.GetNumBytes());
2395 }
2396 else
2397 {
2398 throw ParseException("ParseStridedSlice: Invalid input - the begin vector is null");
2399 }
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002400
Mike Kelly377fb212023-01-10 15:55:28 +00002401 armnn::TensorInfo endTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002402 BufferRawPtr endBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
2403
2404 std::vector<int> end(endTensorInfo.GetNumElements());
David Monahan39085f72023-07-28 11:37:29 +01002405 if (endBufferPtr->data.data() != nullptr)
2406 {
2407 ::memcpy(end.data(), endBufferPtr->data.data(), endTensorInfo.GetNumBytes());
2408 }
2409 else
2410 {
2411 throw ParseException("ParseStridedSlice: Invalid input - the end vector is null");
2412 }
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002413
Mike Kelly377fb212023-01-10 15:55:28 +00002414 armnn::TensorInfo strideTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 3);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002415 BufferRawPtr strideBufferPtr = GetBuffer(m_Model, inputs[3]->buffer);
2416
2417 std::vector<int> stride(strideTensorInfo.GetNumElements());
David Monahan39085f72023-07-28 11:37:29 +01002418
2419 if (strideBufferPtr->data.data() != nullptr)
2420 {
2421 ::memcpy(stride.data(), strideBufferPtr->data.data(), strideTensorInfo.GetNumBytes());
2422 }
2423 else
2424 {
2425 throw ParseException("ParseStridedSlice: Invalid input - the stride vector is null");
2426 }
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002427
2428 desc.m_Begin = begin;
2429 desc.m_End = end;
2430 desc.m_Stride = stride;
2431
James Ward58dec6b2020-09-11 17:32:44 +01002432 auto layerName = fmt::format("StridedSlice:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002433 IConnectableLayer* layer = m_Network->AddStridedSliceLayer(desc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002434 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002435
Mike Kelly377fb212023-01-10 15:55:28 +00002436 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002437 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2438
2439 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2440 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2441
2442 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2443 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2444}
2445
Kevin May7d96b162021-02-03 17:38:41 +00002446void TfLiteParserImpl::ParseSub(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002447{
2448 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2449
Mike Kelly0d77ae12022-01-07 17:42:27 +00002450 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2451 const auto* options = operatorPtr->builtin_options.AsSubOptions();
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002452
2453 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2454 CHECK_VALID_SIZE(inputs.size(), 2);
2455
2456 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2457 CHECK_VALID_SIZE(outputs.size(), 1);
2458
Mike Kelly377fb212023-01-10 15:55:28 +00002459 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2460 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002461
James Ward58dec6b2020-09-11 17:32:44 +01002462 auto layerName = fmt::format("Sub:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +00002463 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Sub, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002464 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002465
Mike Kelly377fb212023-01-10 15:55:28 +00002466 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002467 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2468
2469 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002470 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Teresa Charlind04873f2023-05-23 14:16:28 +01002471 if (options)
2472 {
2473 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2474 }
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002475
2476 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2477 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2478}
2479
Kevin May7d96b162021-02-03 17:38:41 +00002480void TfLiteParserImpl::ParseDiv(size_t subgraphIndex, size_t operatorIndex)
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302481{
2482 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2483
Mike Kelly0d77ae12022-01-07 17:42:27 +00002484 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2485 const auto* options = operatorPtr->builtin_options.AsDivOptions();
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302486
2487 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2488 CHECK_VALID_SIZE(inputs.size(), 2);
2489
2490 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2491 CHECK_VALID_SIZE(outputs.size(), 1);
2492
Mike Kelly377fb212023-01-10 15:55:28 +00002493 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2494 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302495
James Ward58dec6b2020-09-11 17:32:44 +01002496 auto layerName = fmt::format("Div:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +00002497 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Div, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002498 ARMNN_ASSERT(layer != nullptr);
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302499
Mike Kelly377fb212023-01-10 15:55:28 +00002500 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302501 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2502
2503 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002504 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Teresa Charlind04873f2023-05-23 14:16:28 +01002505 if (options)
2506 {
2507 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2508 }
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302509
2510 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2511 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2512}
2513
Teresa Charlincdbd40b2022-02-25 13:21:55 +00002514void TfLiteParserImpl::ParseFloorDiv(size_t subgraphIndex, size_t operatorIndex)
2515{
2516 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2517
2518 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2519 CHECK_VALID_SIZE(inputs.size(), 2);
2520
2521 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2522 CHECK_VALID_SIZE(outputs.size(), 1);
2523
Mike Kelly377fb212023-01-10 15:55:28 +00002524 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2525 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Teresa Charlincdbd40b2022-02-25 13:21:55 +00002526
2527 auto layerName = fmt::format("Div:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +00002528 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Div, layerName.c_str());
Teresa Charlincdbd40b2022-02-25 13:21:55 +00002529 ARMNN_ASSERT(layer != nullptr);
2530
Mike Kelly377fb212023-01-10 15:55:28 +00002531 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Teresa Charlincdbd40b2022-02-25 13:21:55 +00002532 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2533
2534 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2535 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
2536 layer = AddFusedFloorLayer(layer, 0);
2537
2538 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2539 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2540}
2541
Kevin May7d96b162021-02-03 17:38:41 +00002542void TfLiteParserImpl::ParseAdd(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002543{
2544 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2545
Mike Kelly0d77ae12022-01-07 17:42:27 +00002546 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2547 const auto* options = operatorPtr->builtin_options.AsAddOptions();
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002548
2549 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2550 CHECK_VALID_SIZE(inputs.size(), 2);
2551
2552 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2553 CHECK_VALID_SIZE(outputs.size(), 1);
2554
Mike Kelly377fb212023-01-10 15:55:28 +00002555 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2556 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves9c761a62018-12-27 14:20:35 -02002557
James Ward58dec6b2020-09-11 17:32:44 +01002558 auto layerName = fmt::format("Add:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +00002559 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Add, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002560 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002561
Mike Kelly377fb212023-01-10 15:55:28 +00002562 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002563 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2564
2565 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002566 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Teresa Charlind04873f2023-05-23 14:16:28 +01002567 if (options)
2568 {
2569 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2570 }
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002571
2572 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2573 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2574}
2575
Kevin May7d96b162021-02-03 17:38:41 +00002576void TfLiteParserImpl::ParseMul(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002577{
2578 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2579
Mike Kelly0d77ae12022-01-07 17:42:27 +00002580 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2581 const auto* options = operatorPtr->builtin_options.AsMulOptions();
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002582
2583 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2584 CHECK_VALID_SIZE(inputs.size(), 2);
2585
2586 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2587 CHECK_VALID_SIZE(outputs.size(), 1);
2588
Mike Kelly377fb212023-01-10 15:55:28 +00002589 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2590 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves9c761a62018-12-27 14:20:35 -02002591
James Ward58dec6b2020-09-11 17:32:44 +01002592 auto layerName = fmt::format("Mul:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +00002593 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Mul, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002594 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002595
Mike Kelly377fb212023-01-10 15:55:28 +00002596 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002597 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2598
2599 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002600 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Teresa Charlind04873f2023-05-23 14:16:28 +01002601 if (options)
2602 {
2603 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2604 }
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002605
2606 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2607 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2608}
2609
Kevin May7d96b162021-02-03 17:38:41 +00002610void TfLiteParserImpl::ParseMean(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002611{
2612 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2613
2614 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2615
2616 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2617 CHECK_VALID_SIZE(outputs.size(), 1);
2618
Teresa Charlin046e2cb2023-03-28 17:20:19 +01002619 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2620 TensorInfo dimTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002621
2622 armnn::MeanDescriptor desc;
Teresa Charlin046e2cb2023-03-28 17:20:19 +01002623 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2624 // Get const axis value from model and set it to descriptor.
2625 if (axisBufferPtr != nullptr)
2626 {
2627 std::vector<int32_t> axisData(dimTensorInfo.GetNumElements());
2628 ::memcpy(axisData.data(), axisBufferPtr->data.data(), dimTensorInfo.GetNumBytes());
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002629
Teresa Charlin046e2cb2023-03-28 17:20:19 +01002630 // Convert the axis to unsigned int and remove duplicates.
2631 auto rank = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
2632 std::set<unsigned int> uniqueAxis;
2633 std::transform(axisData.begin(),
2634 axisData.end(),
2635 std::inserter(uniqueAxis, uniqueAxis.begin()),
2636 [rank](int i)->unsigned int{
2637 return static_cast<uint32_t>(((i + rank) % rank)); });
2638 desc.m_Axis.assign(uniqueAxis.begin(), uniqueAxis.end());
2639 }
2640 else
2641 {
2642 for (uint32_t i = 0; i < inputTensorInfo.GetNumDimensions(); ++i)
2643 {
2644 desc.m_Axis.push_back(i);
2645 }
2646 }
2647
Sadik Armagand109a4d2020-07-28 10:42:13 +01002648 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002649
Teresa Charlin046e2cb2023-03-28 17:20:19 +01002650 desc.m_KeepDims = inputTensorInfo.GetNumDimensions() == outputTensorInfo.GetNumDimensions() ? true : false;
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002651
James Ward58dec6b2020-09-11 17:32:44 +01002652 auto layerName = fmt::format("Mean:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002653 IConnectableLayer* layer = m_Network->AddMeanLayer(desc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002654 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002655
Mike Kelly377fb212023-01-10 15:55:28 +00002656 outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002657 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2658
2659 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2660 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2661
2662 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2663 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2664}
2665
Kevin May7d96b162021-02-03 17:38:41 +00002666void TfLiteParserImpl::ParsePad(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002667{
2668 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2669
Kevin May7d96b162021-02-03 17:38:41 +00002670 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002671
Kevin May7d96b162021-02-03 17:38:41 +00002672 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002673 CHECK_VALID_SIZE(outputs.size(), 1);
2674
Mike Kelly377fb212023-01-10 15:55:28 +00002675 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2676 armnn::TensorInfo padTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002677
Mike Kelly0d77ae12022-01-07 17:42:27 +00002678 std::vector<unsigned int> padBuffer = GetUIntBuffer(padTensorInfo, m_Model, inputs[1]->buffer);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002679
2680 size_t step = 2;
2681 armnn::PadDescriptor desc;
Mike Kelly0d77ae12022-01-07 17:42:27 +00002682 auto opcode = GetOpCode(m_Model, subgraphIndex, operatorIndex);
2683
2684 if (opcode == tflite::BuiltinOperator_PAD)
Narumol Prangnawarat8719d222020-11-27 16:57:56 +00002685 {
Mike Kelly0d77ae12022-01-07 17:42:27 +00002686 CHECK_VALID_SIZE(inputs.size(), 2);
2687
2688 if (inputTensorInfo.IsQuantized())
2689 {
2690 desc.m_PadValue = static_cast<float>(inputTensorInfo.GetQuantizationOffset());
2691 }
Narumol Prangnawarat8719d222020-11-27 16:57:56 +00002692 }
Mike Kelly0d77ae12022-01-07 17:42:27 +00002693 else if (opcode == tflite::BuiltinOperator_PADV2)
2694 {
2695 CHECK_VALID_SIZE(inputs.size(), 3);
2696
Mike Kelly377fb212023-01-10 15:55:28 +00002697 armnn::TensorInfo padValueTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Mike Kelly0d77ae12022-01-07 17:42:27 +00002698
2699 if (padValueTensorInfo.GetNumElements() != 1)
2700 {
2701 ARMNN_THROW_PARSE_EXCEPTION("Multiple padding values are not supported in PADV2");
2702 }
2703 BufferRawPtr padValueBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
2704
2705 // Get the pad value from the input tensor
2706 if (padValueBufferPtr->data.size() > 0)
2707 {
2708 switch (padValueTensorInfo.GetDataType())
2709 {
2710 case armnn::DataType::Float32:
2711 {
2712 std::vector<float> padValueBuffer(padValueTensorInfo.GetNumElements());
2713 ::memcpy(padValueBuffer.data(), padValueBufferPtr->data.data(), padValueBufferPtr->data.size());
2714 desc.m_PadValue = padValueBuffer[0];
2715 break;
2716 }
2717 case armnn::DataType::QAsymmU8:
2718 {
2719 std::vector<uint8_t> padValueBuffer(padValueTensorInfo.GetNumElements());
2720 ::memcpy(padValueBuffer.data(), padValueBufferPtr->data.data(), padValueBufferPtr->data.size());
2721 desc.m_PadValue = armnn::Dequantize<uint8_t>(padValueBuffer[0],
2722 padValueTensorInfo.GetQuantizationScale(),
2723 padValueTensorInfo.GetQuantizationOffset());
2724 break;
2725 }
2726 case armnn::DataType::QAsymmS8:
2727 case armnn::DataType::QSymmS8:
2728 {
2729 std::vector<int8_t> padValueBuffer(padValueTensorInfo.GetNumElements());
2730 ::memcpy(padValueBuffer.data(), padValueBufferPtr->data.data(), padValueBufferPtr->data.size());
2731 desc.m_PadValue = armnn::Dequantize<int8_t>(padValueBuffer[0],
2732 padValueTensorInfo.GetQuantizationScale(),
2733 padValueTensorInfo.GetQuantizationOffset());
2734 break;
2735 }
2736 default: ARMNN_THROW_PARSE_EXCEPTION("Unsupported DataType");
2737 }
2738 }
2739 else if (inputTensorInfo.IsQuantized())
2740 {
2741 desc.m_PadValue = static_cast<float>(inputTensorInfo.GetQuantizationOffset());
2742 }
2743 }
2744
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002745 for (unsigned int i = 0; i < padTensorInfo.GetNumElements() / step; ++i)
2746 {
2747 desc.m_PadList.emplace_back(padBuffer[i * step], padBuffer[i * step + 1]);
2748 }
2749
Mike Kelly0d77ae12022-01-07 17:42:27 +00002750 auto layerName = (opcode == tflite::BuiltinOperator_PAD) ? fmt::format("Pad:{}:{}", subgraphIndex, operatorIndex)
2751 : fmt::format("PadV2:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01002752
2753 IConnectableLayer* layer = m_Network->AddPadLayer(desc, layerName.c_str());
2754 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00002755 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002756 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2757
2758 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2759 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2760
2761 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2762 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2763}
2764
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002765void TfLiteParserImpl::ParseMirrorPad(size_t subgraphIndex, size_t operatorIndex)
2766{
2767 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2768
2769 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2770 CHECK_VALID_SIZE(inputs.size(), 2);
2771
2772 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2773 CHECK_VALID_SIZE(outputs.size(), 1);
2774
Mike Kelly377fb212023-01-10 15:55:28 +00002775 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002776
Mike Kelly377fb212023-01-10 15:55:28 +00002777 armnn::TensorInfo padTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002778 BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2779
2780 std::vector<unsigned int> padBuffer(padTensorInfo.GetNumElements());
2781 ::memcpy(padBuffer.data(), bufferPtr->data.data(), padTensorInfo.GetNumBytes());
2782
2783 size_t step = 2;
2784 armnn::PadDescriptor desc;
2785 for (unsigned int i = 0; i < padTensorInfo.GetNumElements() / step; ++i)
2786 {
2787 desc.m_PadList.emplace_back(padBuffer[i * step], padBuffer[i * step + 1]);
2788 }
2789
2790 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2791 const auto* options = operatorPtr->builtin_options.AsMirrorPadOptions();
2792
2793 if (options->mode == tflite::MirrorPadMode_REFLECT)
2794 {
2795 desc.m_PaddingMode = PaddingMode::Reflect;
2796 }
2797 else if (options->mode == tflite::MirrorPadMode_SYMMETRIC)
2798 {
2799 desc.m_PaddingMode = PaddingMode::Symmetric;
2800 }
2801 else
2802 {
2803 ARMNN_THROW_PARSE_EXCEPTION("PaddingMode must be either REFLECT or SYMMETRIC");
2804 }
2805
2806 // If padding mode is Reflect then both paddings must be no greater than inputShape(i) - 1.
2807 // If padding mode is Symmetric then both paddings must be no greater than inputShape(i).
2808 auto inputShape = inputTensorInfo.GetShape();
2809 auto padList = desc.m_PadList;
2810
2811 const unsigned int isReflect = static_cast<unsigned int>(desc.m_PaddingMode == PaddingMode::Reflect);
2812 for(unsigned int i = 0; i < padList.size(); ++i)
2813 {
2814 if(padList.at(i).first > (inputShape[i] - isReflect) ||
2815 padList.at(i).second > (inputShape[i] - isReflect))
2816 {
2817 ARMNN_THROW_PARSE_EXCEPTION("Padding values must be less (Reflect) or "
2818 "equal (Symmetric) to the dimension size.");
2819 }
2820 }
2821
2822 auto layerName = fmt::format("MirrorPad:{}:{}", subgraphIndex, operatorIndex);
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002823
2824 IConnectableLayer* layer = m_Network->AddPadLayer(desc, layerName.c_str());
2825 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00002826 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002827 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2828
2829 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2830 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2831
2832 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2833 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2834}
2835
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002836void TfLiteParserImpl::ParsePrelu(size_t subgraphIndex, size_t operatorIndex)
2837{
2838 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2839
2840 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2841 CHECK_VALID_SIZE(inputs.size(), 2);
2842
2843 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2844 CHECK_VALID_SIZE(outputs.size(), 1);
2845
2846 auto layerName = fmt::format("Prelu:{}:{}", subgraphIndex, operatorIndex);
2847
Mike Kelly377fb212023-01-10 15:55:28 +00002848 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2849 armnn::TensorInfo alphaTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002850
2851 IConnectableLayer* layer = m_Network->AddPreluLayer(layerName.c_str());
2852 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00002853
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002854
2855 if (IsConstTensor(inputs[1]))
2856 {
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002857 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawaratbf99b5f2021-05-27 09:55:43 +01002858 armnn::IInputSlot* slot = &(layer->GetInputSlot(0));
2859 RegisterConsumerOfTensor(subgraphIndex, inputTensorIndexes[0], slot);
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002860
Mike Kelly5880b912022-01-28 16:18:54 +00002861 auto alphaTensorAndData = CreateConstTensorNonPermuted(inputs[1], alphaTensorInfo,
2862 inputTensorInfo.GetDataType());
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002863 std::string constLayerName = fmt::format("Constant:{}", inputs[1]->name);
2864 IConnectableLayer* constLayer =
Mike Kelly5880b912022-01-28 16:18:54 +00002865 m_Network->AddConstantLayer(alphaTensorAndData.first, constLayerName.c_str());
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002866 ARMNN_ASSERT(constLayer != nullptr);
2867
2868 constLayer->GetOutputSlot(0).SetTensorInfo(alphaTensorInfo);
2869 constLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1));
2870 RegisterOutputSlots(subgraphIndex,
2871 VIRTUAL_OPERATOR_ID,
2872 constLayer,
2873 { inputTensorIndexes[1] });
2874 }
2875 else
2876 {
2877 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2878 RegisterInputSlots(subgraphIndex, operatorIndex, layer, inputTensorIndexes);
2879 }
2880
Mike Kelly377fb212023-01-10 15:55:28 +00002881 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
2882 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
2883 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2884
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002885 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2886 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2887}
2888
Kevin May7d96b162021-02-03 17:38:41 +00002889void TfLiteParserImpl::ParseQuantize(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan66dedc72019-12-10 16:32:07 +00002890{
2891 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2892
2893 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2894 CHECK_VALID_SIZE(inputs.size(), 1);
2895
2896 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2897 CHECK_VALID_SIZE(outputs.size(), 1);
2898
James Ward58dec6b2020-09-11 17:32:44 +01002899 auto layerName = fmt::format("Quantize:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan66dedc72019-12-10 16:32:07 +00002900
2901 IConnectableLayer* layer = m_Network->AddQuantizeLayer(layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01002902 ARMNN_ASSERT(layer != nullptr);
Sadik Armagan66dedc72019-12-10 16:32:07 +00002903
Mike Kelly377fb212023-01-10 15:55:28 +00002904 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Sadik Armagan66dedc72019-12-10 16:32:07 +00002905 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2906
2907 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2908 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2909
2910 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2911 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2912}
Finn Williamsc42c3842019-01-22 14:18:11 +00002913
Kevin May7d96b162021-02-03 17:38:41 +00002914void TfLiteParserImpl::ParseRelu(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan58f39192018-09-17 14:14:39 +01002915{
Finn Williamsc42c3842019-01-22 14:18:11 +00002916 ParseActivation(subgraphIndex,operatorIndex, ActivationFunction::ReLu);
Sadik Armagan58f39192018-09-17 14:14:39 +01002917}
2918
Kevin May7d96b162021-02-03 17:38:41 +00002919void TfLiteParserImpl::ParseRelu6(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan58f39192018-09-17 14:14:39 +01002920{
Finn Williamsc42c3842019-01-22 14:18:11 +00002921 ParseActivation(subgraphIndex,operatorIndex, ActivationFunction::BoundedReLu);
2922}
Sadik Armagan58f39192018-09-17 14:14:39 +01002923
Kevin May7d96b162021-02-03 17:38:41 +00002924void TfLiteParserImpl::ParseLeakyRelu(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan12239e72020-05-27 11:06:17 +01002925{
Jan Eilers2f746b32020-07-28 14:00:06 +01002926 ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::LeakyReLu);
Sadik Armagan12239e72020-05-27 11:06:17 +01002927}
2928
Kevin May7d96b162021-02-03 17:38:41 +00002929void TfLiteParserImpl::ParseLogistic(size_t subgraphIndex, size_t operatorIndex)
Finn Williamsc42c3842019-01-22 14:18:11 +00002930{
2931 ParseActivation(subgraphIndex,operatorIndex,ActivationFunction::Sigmoid);
2932}
2933
Kevin May7d96b162021-02-03 17:38:41 +00002934void TfLiteParserImpl::ParseTanH(size_t subgraphIndex, size_t operatorIndex)
Nina Drozd99851762019-04-09 09:37:38 +01002935{
2936 ParseActivation(subgraphIndex,operatorIndex,ActivationFunction::TanH);
2937}
2938
Kevin May7d96b162021-02-03 17:38:41 +00002939void TfLiteParserImpl::ParseElu(size_t subgraphIndex, size_t operatorIndex)
Matthew Sloyan7515d072020-12-16 12:50:01 +00002940{
2941 ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::Elu);
2942}
2943
Kevin May7d96b162021-02-03 17:38:41 +00002944void TfLiteParserImpl::ParseHardSwish(size_t subgraphIndex, size_t operatorIndex)
Jan Eilers2f746b32020-07-28 14:00:06 +01002945{
2946 ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::HardSwish);
2947}
Finn Williamsc42c3842019-01-22 14:18:11 +00002948
Kevin May7d96b162021-02-03 17:38:41 +00002949void TfLiteParserImpl::ParseActivation(size_t subgraphIndex, size_t operatorIndex, ActivationFunction activationType)
Finn Williamsc42c3842019-01-22 14:18:11 +00002950{
2951 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00002952 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
Jan Eilers8eb25602020-03-09 12:13:48 +00002953 IgnoreUnused(operatorPtr);
Sadik Armagan58f39192018-09-17 14:14:39 +01002954
2955 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2956 CHECK_VALID_SIZE(inputs.size(), 1);
2957
2958 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2959 CHECK_VALID_SIZE(outputs.size(), 1);
2960
James Ward58dec6b2020-09-11 17:32:44 +01002961 auto layerName = fmt::format("Activation:");
Sadik Armagan58f39192018-09-17 14:14:39 +01002962 ActivationDescriptor activationDesc;
Finn Williamsc42c3842019-01-22 14:18:11 +00002963 activationDesc.m_Function = activationType;
2964
2965 switch (activationType)
2966 {
2967 case ActivationFunction::ReLu:
2968 {
James Ward58dec6b2020-09-11 17:32:44 +01002969 layerName += fmt::format("RELU:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsc42c3842019-01-22 14:18:11 +00002970 break;
2971 }
2972 case ActivationFunction::BoundedReLu:
2973 {
James Ward58dec6b2020-09-11 17:32:44 +01002974 layerName += fmt::format("RELU6:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsc42c3842019-01-22 14:18:11 +00002975 activationDesc.m_A = 6.0f;
2976 activationDesc.m_B = 0.0f;
2977 break;
2978 }
2979 case ActivationFunction::Sigmoid:
2980 {
James Ward58dec6b2020-09-11 17:32:44 +01002981 layerName += fmt::format("SIGMOID:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsc42c3842019-01-22 14:18:11 +00002982 break;
2983 }
Nina Drozd99851762019-04-09 09:37:38 +01002984 case ActivationFunction::TanH:
2985 {
James Ward58dec6b2020-09-11 17:32:44 +01002986 layerName += fmt::format("TANH:{}:{}", subgraphIndex, operatorIndex);
Nina Drozd99851762019-04-09 09:37:38 +01002987 activationDesc.m_A = 1.0f;
2988 activationDesc.m_B = 1.0f;
2989 break;
2990 }
Sadik Armagan12239e72020-05-27 11:06:17 +01002991 case ActivationFunction::LeakyReLu:
2992 {
James Ward58dec6b2020-09-11 17:32:44 +01002993 layerName += fmt::format("LEAKYRELU:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00002994 const auto* options = operatorPtr->builtin_options.AsLeakyReluOptions();
Sadik Armagan12239e72020-05-27 11:06:17 +01002995 activationDesc.m_A = options->alpha;
2996 break;
2997 }
Matthew Sloyan7515d072020-12-16 12:50:01 +00002998 case ActivationFunction::Elu:
2999 {
3000 layerName += fmt::format("ELU:{}:{}", subgraphIndex, operatorIndex);
3001 activationDesc.m_A = 1.0f;
3002 break;
3003 }
Jan Eilers2f746b32020-07-28 14:00:06 +01003004 case ActivationFunction::HardSwish:
Matthew Sloyan7515d072020-12-16 12:50:01 +00003005 {
James Ward58dec6b2020-09-11 17:32:44 +01003006 layerName += fmt::format("HARDSWISH:{}:{}", subgraphIndex, operatorIndex);
Jan Eilers2f746b32020-07-28 14:00:06 +01003007 break;
Matthew Sloyan7515d072020-12-16 12:50:01 +00003008 }
Finn Williamsc42c3842019-01-22 14:18:11 +00003009 default:
3010 {
3011 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003012 fmt::format("Unexpected ActivationFunction[{}] when creating layerName {} ",
3013 static_cast<int>(activationType), CHECK_LOCATION().AsString()));
Finn Williamsc42c3842019-01-22 14:18:11 +00003014 }
3015 }
3016
3017 IConnectableLayer* const layer = m_Network->AddActivationLayer(activationDesc, layerName.c_str());
Sadik Armagan58f39192018-09-17 14:14:39 +01003018
Mike Kelly377fb212023-01-10 15:55:28 +00003019 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Sadik Armagan58f39192018-09-17 14:14:39 +01003020 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3021
3022 // register the input connection slots for the layer, connections are made after all layers have been created
3023 // only the tensors for the inputs are relevant, exclude the const tensors
3024 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3025 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3026
3027 // register the output connection slots for the layer, connections are made after all layers have been created
3028 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3029 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3030}
Mike Kelly0d77ae12022-01-07 17:42:27 +00003031armnn::TensorInfo TfLiteParserImpl::OutputShapeOfReshape(const armnn::TensorInfo& inputTensorInfo,
3032 const std::vector<int32_t>& targetDimsIn)
Sadikb94967b2018-09-19 15:30:00 +01003033{
3034 std::vector<unsigned int> outputDims(targetDimsIn.begin(), targetDimsIn.end());
3035 const auto stretchDim = std::find(targetDimsIn.begin(), targetDimsIn.end(), -1);
3036
3037 if (stretchDim != targetDimsIn.end())
3038 {
3039 if (std::find(std::next(stretchDim), targetDimsIn.end(), -1) != targetDimsIn.end())
3040 {
3041 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003042 fmt::format("At most one component of shape can be -1 {}", CHECK_LOCATION().AsString()));
Sadikb94967b2018-09-19 15:30:00 +01003043 }
3044
3045 auto targetNumElements =
Matthew Sloyan589e3e82020-09-11 16:17:48 +01003046 armnn::numeric_cast<unsigned int>(
Sadikb94967b2018-09-19 15:30:00 +01003047 std::accumulate(targetDimsIn.begin(), targetDimsIn.end(), -1, std::multiplies<int32_t>()));
3048
3049 auto stretchIndex = static_cast<size_t>(std::distance(targetDimsIn.begin(), stretchDim));
3050 outputDims[stretchIndex] = inputTensorInfo.GetNumElements() / targetNumElements;
3051 }
3052
3053 TensorShape outputShape = TensorShape(static_cast<unsigned int>(outputDims.size()), outputDims.data());
3054
3055 TensorInfo reshapeInfo = inputTensorInfo;
3056 reshapeInfo.SetShape(outputShape);
3057
3058 return reshapeInfo;
3059}
3060
Kevin May7d96b162021-02-03 17:38:41 +00003061void TfLiteParserImpl::ParseReshape(size_t subgraphIndex, size_t operatorIndex)
Sadikb94967b2018-09-19 15:30:00 +01003062{
3063 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3064
3065 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Sadikb94967b2018-09-19 15:30:00 +01003066
3067 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3068 CHECK_VALID_SIZE(outputs.size(), 1);
3069
Mike Kelly0d77ae12022-01-07 17:42:27 +00003070 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3071 const auto* options = operatorPtr->builtin_options.AsReshapeOptions();
James Ward58dec6b2020-09-11 17:32:44 +01003072 auto layerName = fmt::format("Reshape:{}:{}", subgraphIndex, operatorIndex);
Sadikb94967b2018-09-19 15:30:00 +01003073
Mike Kelly377fb212023-01-10 15:55:28 +00003074 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
kevmay0171972a82018-12-17 14:28:03 +00003075 armnn::TensorInfo actualOutputTensorInfo = ToTensorInfo(outputs[0]);
James Conroy05102392020-06-24 15:39:55 +01003076 CheckMatchingQuantization(inputTensorInfo, actualOutputTensorInfo, layerName, "Input 0", "Output 0");
Derek Lambertic9e52792020-03-11 11:42:26 +00003077
Jan Eilersbac9b352020-07-13 13:40:24 +01003078 // Extracting new shape for the output
3079 // There are two ways it can be passed
3080 // * First is to define the target shape in the operator built-in options
3081 // * Second is to pass it as a second input tensor
Derek Lambertic9e52792020-03-11 11:42:26 +00003082 std::vector<int32_t> targetShape;
Jan Eilersbac9b352020-07-13 13:40:24 +01003083 bool targetShapeFound = false;
3084 // Check if built-in options were given
3085 if (options != nullptr)
Derek Lambertic9e52792020-03-11 11:42:26 +00003086 {
Jan Eilersbac9b352020-07-13 13:40:24 +01003087 // make sure the parameter is given
3088 if (options->new_shape.empty() == false)
Derek Lambertic9e52792020-03-11 11:42:26 +00003089 {
Jan Eilersbac9b352020-07-13 13:40:24 +01003090 targetShape = options->new_shape;
3091 targetShapeFound = true;
Derek Lambertif4a953f2020-03-17 14:25:57 +00003092 }
Derek Lambertic9e52792020-03-11 11:42:26 +00003093 }
Jan Eilersbac9b352020-07-13 13:40:24 +01003094
3095 // If there is no built-in option given or if the built-in new_shape parameter was empty
3096 if (!targetShapeFound)
Derek Lambertic9e52792020-03-11 11:42:26 +00003097 {
Teresa Charlin6a056a42021-12-01 10:25:43 +00003098 // Check for a second input tensor
3099 if (inputs.size() > 1 && inputs[1] != nullptr)
Jan Eilersbac9b352020-07-13 13:40:24 +01003100 {
3101 if (inputs[1]->is_variable)
3102 {
3103 ARMNN_THROW_PARSE_EXCEPTION( "Target shapes defined in non-const input tensors is not supported");
3104 }
3105
3106 if (inputs[1]->shape.size() != 1)
3107 {
3108 ARMNN_THROW_PARSE_EXCEPTION("Target 'shape' input is not a 1D tensor");
3109 }
3110
3111 if (inputs[1]->type != tflite::TensorType_INT32)
3112 {
3113 ARMNN_THROW_PARSE_EXCEPTION("Target 'shape' input is not an int32 type");
3114 }
3115
Teresa Charlin6a056a42021-12-01 10:25:43 +00003116 // Extract target shape from input
3117 auto bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
3118 auto values = reinterpret_cast<const int32_t*>(bufferPtr->data.data());
Cathal Corbettd2f73232021-12-10 13:38:52 +00003119 if (values)
Sadik Armagan19a1c032021-01-20 12:17:00 +00003120 {
Cathal Corbettd2f73232021-12-10 13:38:52 +00003121 for (int i = 0; i < inputs[1]->shape[0]; ++i)
3122 {
3123 targetShape.push_back(values[i]);
3124 }
Sadik Armagan19a1c032021-01-20 12:17:00 +00003125 }
Cathal Corbettd2f73232021-12-10 13:38:52 +00003126 else
Jan Eilersbac9b352020-07-13 13:40:24 +01003127 {
Cathal Corbettd2f73232021-12-10 13:38:52 +00003128 try
3129 {
3130 // We attempt to infer during Runtime.
Mike Kelly04d82292023-01-19 18:29:40 +00003131 TensorShape reshapeShapes = ToTensorInfo(inputs[1]).GetShape();
3132
3133 if (reshapeShapes[0] == actualOutputTensorInfo.GetNumDimensions())
3134 {
3135 for (unsigned int i = 0; i < actualOutputTensorInfo.GetShape().GetNumDimensions(); ++i)
3136 {
3137 targetShape.push_back(actualOutputTensorInfo.GetShape()[i]);
3138 }
3139 }
Cathal Corbettd2f73232021-12-10 13:38:52 +00003140 // The parser only supports shape (batch, -1) or (-1) for non-constant shape input.
Mike Kelly04d82292023-01-19 18:29:40 +00003141 else if (reshapeShapes[0] > 2)
Cathal Corbettd2f73232021-12-10 13:38:52 +00003142 {
3143 throw ParseException(fmt::format("Invalid input shape '{}' in Reshape layer '{}' {}. "
3144 "When inferring during runtime, the parser only supports "
3145 "shape (batch, -1) or (-1) for target shape input.",
3146 reshapeShapes[0],
3147 layerName,
3148 CHECK_LOCATION().AsString()));
3149 }
Mike Kelly04d82292023-01-19 18:29:40 +00003150 else
Cathal Corbettd2f73232021-12-10 13:38:52 +00003151 {
Mike Kelly04d82292023-01-19 18:29:40 +00003152 const int32_t numInputElements = inputTensorInfo.GetNumElements();
3153 const int32_t inputTensorShape = inputTensorInfo.GetShape()[0];
3154 if (reshapeShapes[0] == 1)
3155 {
3156 targetShape = {numInputElements};
3157 }
3158 else if (reshapeShapes[0] == 2)
3159 {
3160 targetShape = {inputTensorShape, numInputElements / inputTensorShape};
3161 }
Cathal Corbettd2f73232021-12-10 13:38:52 +00003162 }
3163 }
3164 catch (const std::exception& exc)
3165 {
3166 ARMNN_THROW_PARSE_EXCEPTION("Failed attempt to infer during runtime the target shape input for "
3167 "Reshape operation. Reshape operator target shape input buffer data "
3168 "is null. " << exc.what());
3169 }
Jan Eilersbac9b352020-07-13 13:40:24 +01003170 }
3171 }
3172 else
Derek Lambertic9e52792020-03-11 11:42:26 +00003173 {
3174 ARMNN_THROW_PARSE_EXCEPTION("Target shape not defined in reshape parameters or input tensor. "
3175 "At least one method required");
3176 }
Derek Lambertic9e52792020-03-11 11:42:26 +00003177 }
3178
kevmay0171972a82018-12-17 14:28:03 +00003179 armnn::TensorInfo reshapeOutputTensorInfo =
Kevin May7d96b162021-02-03 17:38:41 +00003180 TfLiteParserImpl::OutputShapeOfReshape(inputTensorInfo, targetShape);
Sadikb94967b2018-09-19 15:30:00 +01003181
kevmay0171972a82018-12-17 14:28:03 +00003182 // Check for valid input size and that reshape parameters equal output shape
Cathal Corbett2b922e22022-09-23 15:49:24 +01003183 // The output shape can be provided to us in 2 ways:
3184 // 1. through the normal 'shape' parameter given by outputs[indx]->shape
3185 // 2. through additional parameter 'shape_signature' given by outputs[indx]->buffer.
3186 // This parameter can sometimes contain -1 value not visible in the 'shape' parameter.
Aron Virginas-Tar70672f62019-01-23 14:00:00 +00003187 const armnn::TensorShape& reshapeOutputTensorShape = reshapeOutputTensorInfo.GetShape();
3188 if (inputs.size() > 1 && !CheckShape(reshapeOutputTensorShape, outputs[0]->shape))
kevmay0171972a82018-12-17 14:28:03 +00003189 {
Cathal Corbett2b922e22022-09-23 15:49:24 +01003190 // Attempt to extract output shape from secondary 'shape_signature'
3191 // parameter and try to CheckShape() with this param.
3192 std::vector<int32_t> secondaryOutputTargetShape = outputs[0]->shape_signature;
3193
3194 // if outputs[0]->shape_signature contain a -1 value, we need to compute its actual value
3195 // from reshape input in order to correctly verify reshape parameters equal output shape
3196 armnn::TensorInfo secondaryReshapeOutputTensorInfo =
3197 TfLiteParserImpl::OutputShapeOfReshape(inputTensorInfo, secondaryOutputTargetShape);
3198
3199 if (!CheckShape(reshapeOutputTensorShape, secondaryReshapeOutputTensorInfo.GetShape()))
3200 {
3201 std::stringstream ss;
3202 ss << "New shape defined in reshape parameters "
3203 << reshapeOutputTensorShape
3204 << " does not equal output shape "
3205 << actualOutputTensorInfo.GetShape()
3206 << ": "
3207 << CHECK_LOCATION().AsString();
3208 throw ParseException(ss.str());
3209 }
kevmay0171972a82018-12-17 14:28:03 +00003210 }
Mike Kelly377fb212023-01-10 15:55:28 +00003211 auto outputTensorIds = GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex);
kevmay0171972a82018-12-17 14:28:03 +00003212
Sadikb94967b2018-09-19 15:30:00 +01003213 ReshapeDescriptor reshapeDesc;
kevmay0171972a82018-12-17 14:28:03 +00003214 reshapeDesc.m_TargetShape = reshapeOutputTensorInfo.GetShape();
Mike Kelly377fb212023-01-10 15:55:28 +00003215 m_TensorInfos[outputTensorIds[0]] = reshapeOutputTensorInfo;
Sadikb94967b2018-09-19 15:30:00 +01003216
Sadikb94967b2018-09-19 15:30:00 +01003217 IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01003218 ARMNN_ASSERT(layer != nullptr);
kevmay0171972a82018-12-17 14:28:03 +00003219 layer->GetOutputSlot(0).SetTensorInfo(reshapeOutputTensorInfo);
Sadikb94967b2018-09-19 15:30:00 +01003220
3221 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3222 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3223
3224 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3225 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3226}
3227
Kevin May7d96b162021-02-03 17:38:41 +00003228void TfLiteParserImpl::ParseResizeBilinear(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003229{
Sadik Armagana3b31f02019-12-05 09:08:53 +00003230 ParseResize(subgraphIndex, operatorIndex, ResizeMethod::Bilinear);
3231}
3232
Kevin May7d96b162021-02-03 17:38:41 +00003233void TfLiteParserImpl::ParseResizeNearestNeighbor(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagana3b31f02019-12-05 09:08:53 +00003234{
3235 ParseResize(subgraphIndex, operatorIndex, ResizeMethod::NearestNeighbor);
3236}
3237
Kevin May7d96b162021-02-03 17:38:41 +00003238void TfLiteParserImpl::ParseResize(size_t subgraphIndex, size_t operatorIndex, ResizeMethod resizeMethod)
Sadik Armagana3b31f02019-12-05 09:08:53 +00003239{
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003240 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3241
3242 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3243 CHECK_VALID_SIZE(inputs.size(), 2);
3244
3245 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3246 CHECK_VALID_SIZE(outputs.size(), 1);
3247
Mike Kelly377fb212023-01-10 15:55:28 +00003248 armnn::TensorInfo sizeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003249
3250 // Data for the parsed tensor args (size) must be stored locally.
3251 std::vector<int32_t> sizeTensorData(sizeTensorInfo.GetNumElements());
3252
3253 BufferRawPtr sizeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
3254 ::memcpy(sizeTensorData.data(), sizeBufferPtr->data.data(), sizeTensorInfo.GetNumBytes());
3255
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01003256 ResizeDescriptor desc;
Sadik Armagana3b31f02019-12-05 09:08:53 +00003257 desc.m_Method = resizeMethod;
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003258 desc.m_TargetHeight = static_cast<uint32_t> (sizeTensorData[0]);
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01003259 desc.m_TargetWidth = static_cast<uint32_t> (sizeTensorData[1]);
3260 desc.m_DataLayout = armnn::DataLayout::NHWC;
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003261
James Ward58dec6b2020-09-11 17:32:44 +01003262 auto layerName = fmt::format("Resize:");
Sadik Armagana3b31f02019-12-05 09:08:53 +00003263
3264 switch (resizeMethod)
3265 {
3266 case ResizeMethod::Bilinear:
3267 {
James Ward58dec6b2020-09-11 17:32:44 +01003268 layerName += fmt::format("BILINEAR:{}:{}", subgraphIndex, operatorIndex);
Sang-Hoon Park820eb142020-01-08 10:25:24 +00003269
3270 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3271 const auto * options = operatorPtr->builtin_options.AsResizeBilinearOptions();
3272
David Monahan4a0c9b92020-05-30 09:48:39 +01003273 desc.m_AlignCorners = options->align_corners;
Sadik Armagana3b31f02019-12-05 09:08:53 +00003274 break;
3275 }
3276 case ResizeMethod::NearestNeighbor:
3277 {
James Ward58dec6b2020-09-11 17:32:44 +01003278 layerName += fmt::format("NEARESTNEIGHBOR:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagana3b31f02019-12-05 09:08:53 +00003279 break;
3280 }
3281 default:
3282 {
3283 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003284 fmt::format("Unexpected ResizeMethod[{}] when creating layerName {} ",
3285 static_cast<int>(resizeMethod), CHECK_LOCATION().AsString()));
Sadik Armagana3b31f02019-12-05 09:08:53 +00003286 }
3287 }
3288
Mike Kelly377fb212023-01-10 15:55:28 +00003289 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
James Conroy05102392020-06-24 15:39:55 +01003290
3291 IConnectableLayer* layer = m_Network->AddResizeLayer(desc, layerName.c_str());
3292 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00003293 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
3294 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003295 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3296
3297 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3298 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3299
3300 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3301 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
3302}
3303
Tianle Chenge5a30ff2023-07-03 11:24:12 +01003304void TfLiteParserImpl::ParseReverseV2(size_t subgraphIndex, size_t operatorIndex)
3305{
3306 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3307
3308 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3309 CHECK_VALID_SIZE(inputs.size(), 2);
3310
3311 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3312 CHECK_VALID_SIZE(outputs.size(), 1);
3313
3314 auto layerName = fmt::format("ReverseV2:{}:{}", subgraphIndex, operatorIndex);
3315
3316 TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
3317 TensorInfo axisTensorInfo = ToTensorInfo(inputs[1]);
3318 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
3319
Tracy Narinebb8d7592023-07-13 16:50:54 +01003320 IConnectableLayer* layer = m_Network->AddReverseV2Layer(layerName.c_str());
Tianle Chenge5a30ff2023-07-03 11:24:12 +01003321 ARMNN_ASSERT(layer != nullptr);
3322
3323 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3324
3325 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Tracy Narinebb8d7592023-07-13 16:50:54 +01003326 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Tianle Chenge5a30ff2023-07-03 11:24:12 +01003327
3328 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3329 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3330}
3331
Teresa Charlin777008b2023-07-26 10:07:55 +01003332void TfLiteParserImpl::ParseTile(size_t subgraphIndex, size_t operatorIndex)
3333{
3334 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3335
3336 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3337 CHECK_VALID_SIZE(inputs.size(), 2);
3338
3339 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3340 CHECK_VALID_SIZE(outputs.size(), 1);
3341
3342 TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
3343 TensorInfo multiplesTensorInfo = ToTensorInfo(inputs[1]);
3344 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
3345
3346 auto layerName = fmt::format("Tile:{}:{}", subgraphIndex, operatorIndex);
3347
3348 TileDescriptor descriptor;
3349
3350 BufferRawPtr multiplesBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
3351 if (multiplesBufferPtr != nullptr)
3352 {
3353 std::vector<int32_t> multiplesData(multiplesTensorInfo.GetNumElements());
3354 ::memcpy(multiplesData.data(), multiplesBufferPtr->data.data(), multiplesTensorInfo.GetNumBytes());
3355 descriptor.m_Multiples.assign(multiplesData.begin(), multiplesData.end());
3356 }
3357 else
3358 {
3359 ARMNN_THROW_PARSE_EXCEPTION("For Tile layer, Multiples data was not found in the buffer.");
3360 }
3361
3362 IConnectableLayer* layer = m_Network->AddTileLayer(descriptor, layerName.c_str());
3363 ARMNN_ASSERT(layer != nullptr);
3364
3365 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3366
3367 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3368 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3369
3370 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3371 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3372}
3373
Kevin May7d96b162021-02-03 17:38:41 +00003374void TfLiteParserImpl::ParseConcatenation(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan479045b2018-10-01 11:51:37 +01003375{
3376 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3377
Mike Kelly0d77ae12022-01-07 17:42:27 +00003378 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3379 const auto* options = operatorPtr->builtin_options.AsConcatenationOptions();
Sadik Armagan479045b2018-10-01 11:51:37 +01003380
3381 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
3382
3383 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3384 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Mike Kelly377fb212023-01-10 15:55:28 +00003385 auto inputTensorIds = GetInputTensorIds(m_Model, subgraphIndex, operatorIndex);
3386
Sadik Armagan479045b2018-10-01 11:51:37 +01003387 CHECK_VALID_SIZE(outputs.size(), 1);
3388
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003389 unsigned int numConcatView = static_cast<unsigned int>(inputs.size());
Mike Kelly377fb212023-01-10 15:55:28 +00003390 uint32_t inputRank = InputTensorInfo(subgraphIndex, operatorIndex, 0).GetNumDimensions();
Sadik Armagan479045b2018-10-01 11:51:37 +01003391
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003392 const unsigned int concatDimInput = static_cast<unsigned int>(
Mike Kelly377fb212023-01-10 15:55:28 +00003393 (static_cast<int>(inputRank) + options->axis) % static_cast<int>(inputRank));
Sadik Armagan479045b2018-10-01 11:51:37 +01003394
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003395 OriginsDescriptor concatDescriptor(static_cast<uint32_t>(numConcatView), inputRank);
3396 concatDescriptor.SetConcatAxis(concatDimInput);
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003397 unsigned int mergeDimOrigin = 0;
Sadik Armagan479045b2018-10-01 11:51:37 +01003398
3399 for (unsigned int viewIndex = 0; viewIndex < numConcatView; ++viewIndex)
3400 {
Mike Kelly377fb212023-01-10 15:55:28 +00003401 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, viewIndex);
Sadik Armagan479045b2018-10-01 11:51:37 +01003402
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003403 // This set up concatDescriptor view origin
3404 armnnUtils::ProcessConcatInputTensorInfo(
Mike Kelly377fb212023-01-10 15:55:28 +00003405 inputTensorInfo, concatDescriptor, concatDimInput, viewIndex, mergeDimOrigin);
Sadik Armagan479045b2018-10-01 11:51:37 +01003406 }
3407
James Ward58dec6b2020-09-11 17:32:44 +01003408 auto layerName = fmt::format("Concatenation:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01003409
Jim Flynn906f9462019-05-10 13:55:21 +01003410 IConnectableLayer* layer = m_Network->AddConcatLayer(concatDescriptor, layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01003411 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00003412 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {});
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003413 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
Sadik Armagan479045b2018-10-01 11:51:37 +01003414
James Conroy05102392020-06-24 15:39:55 +01003415 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003416 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes});
Sadik Armagan479045b2018-10-01 11:51:37 +01003417
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003418 // add fused activation layer
3419 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
Sadik Armagan479045b2018-10-01 11:51:37 +01003420
Sadik Armagan479045b2018-10-01 11:51:37 +01003421 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3422 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3423}
3424
Kevin May7d96b162021-02-03 17:38:41 +00003425void TfLiteParserImpl::ParseFullyConnected(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003426{
3427 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3428
Mike Kelly0d77ae12022-01-07 17:42:27 +00003429 const auto& operatorRfr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003430 const auto options = operatorRfr->builtin_options.AsFullyConnectedOptions();
3431
3432 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
3433
3434 FullyConnectedDescriptor desc;
3435 desc.m_BiasEnabled = false;
Nattapat Chaimanowongd8eee592018-10-26 10:24:14 +01003436 desc.m_TransposeWeightMatrix = true;
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003437
3438 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3439 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3440 CHECK_VALID_SIZE(outputs.size(), 1);
3441
Mike Kelly377fb212023-01-10 15:55:28 +00003442 armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003443
3444 // Fully Connected Layer accepts two dimensional weights input
3445 int32_t weightsDimension = static_cast<int32_t>(filterTensorInfo.GetNumDimensions());
3446 if (weightsDimension != 2)
3447 {
3448 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003449 fmt::format("Dimension {} for Fully Connected weights is not supported by Armnn. "
3450 "Node {}",
3451 weightsDimension,
3452 CHECK_LOCATION().AsString()));
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003453 }
3454
Matthew Jackson74bf7da2019-08-16 16:51:42 +01003455 armnn::IConnectableLayer* layer = nullptr;
James Ward58dec6b2020-09-11 17:32:44 +01003456 auto layerName = fmt::format("FullyConnected:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003457
Matthew Sloyan81beae32021-07-13 19:46:11 +01003458 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3459 // Add the first input tensor to the registration list
3460 std::vector<unsigned int> tensorIndexesToRegister = {inputTensorIndexes[0]};
Mike Kelly377fb212023-01-10 15:55:28 +00003461 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Finn Williamsd4fa5452021-03-01 12:31:41 +00003462
3463 desc.m_ConstantWeights = IsConstTensor(inputs[1]);
3464
Matthew Sloyan81beae32021-07-13 19:46:11 +01003465 // Add the weights input to the registration list, constant layers will be added by SetupConstantLayers if constant.
3466 tensorIndexesToRegister.emplace_back(inputTensorIndexes[1]);
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003467
Mike Kelly0506ef02023-01-03 16:29:44 +00003468 if (ShouldConstantTensorBeConverted(inputs[1], inputTensorInfo.GetDataType(), filterTensorInfo.GetDataType()))
Mike Kelly5880b912022-01-28 16:18:54 +00003469 {
3470 m_ConstantsToDequantize.emplace_back(inputs[1]->buffer);
3471 }
3472
Finn Williamsd4fa5452021-03-01 12:31:41 +00003473 if (inputs.size() == 3)
3474 {
3475 desc.m_BiasEnabled = true;
Mike Kelly377fb212023-01-10 15:55:28 +00003476 armnn::TensorInfo biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Matthew Sloyan81beae32021-07-13 19:46:11 +01003477
3478 // Add the biases input to the registration list, constant layer will be added by SetupConstantLayers.
3479 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
Mike Kelly5880b912022-01-28 16:18:54 +00003480
Mike Kelly0506ef02023-01-03 16:29:44 +00003481 if (ShouldConstantTensorBeConverted(inputs[2], inputTensorInfo.GetDataType(), biasTensorInfo.GetDataType()))
Mike Kelly5880b912022-01-28 16:18:54 +00003482 {
3483 m_ConstantsToDequantize.emplace_back(inputs[2]->buffer);
3484 }
Finn Williamsd4fa5452021-03-01 12:31:41 +00003485 }
3486
Matthew Sloyan81beae32021-07-13 19:46:11 +01003487 // Filters and biases are always passed to fully connected as inputs
3488 layer = m_Network->AddFullyConnectedLayer(desc, layerName.c_str());
Finn Williamsd4fa5452021-03-01 12:31:41 +00003489
3490 ARMNN_ASSERT(layer != nullptr);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003491
Finn Williamsd4fa5452021-03-01 12:31:41 +00003492 unsigned int startingSlotIndex = 0;
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003493 if (inputTensorInfo.GetNumDimensions() > 2)
3494 {
3495 // Add reshape to flatten to 2D [batch_size, input_size],
3496 // where "input_size" corresponds to the number of inputs to the layer,
3497 // matching the second dimension of weights,
3498 // and "batch_size" is calculated by dividing the number of elements by "input_size".
3499 std::vector<unsigned int> reshapedDimensions(2);
3500 reshapedDimensions[1] = filterTensorInfo.GetShape()[1];
3501 reshapedDimensions[0] = inputTensorInfo.GetNumElements() / reshapedDimensions[1];
3502
3503 if (inputTensorInfo.GetNumElements() % reshapedDimensions[1] != 0)
3504 {
3505 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003506 fmt::format("Failed to deduce input tensor shape from filter size {} {}",
3507 reshapedDimensions[1],
3508 CHECK_LOCATION().AsString()));
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003509 }
3510
Mike Kelly377fb212023-01-10 15:55:28 +00003511 armnn::TensorInfo reshapedTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003512 reshapedTensorInfo.SetShape(armnn::TensorShape{ 2, reshapedDimensions.data() });
Mike Kelly377fb212023-01-10 15:55:28 +00003513 inputTensorInfo = reshapedTensorInfo;
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003514
James Ward58dec6b2020-09-11 17:32:44 +01003515 std::string reshapeLayerName = fmt::format("Reshape_for:{}", layer->GetName());
Finn Williamsd4fa5452021-03-01 12:31:41 +00003516 armnn::ReshapeDescriptor reshapeDescriptor;
3517 reshapeDescriptor.m_TargetShape = reshapedTensorInfo.GetShape();
Mike Kelly04d82292023-01-19 18:29:40 +00003518 armnn::IConnectableLayer* reshapeLayer = m_Network->AddReshapeLayer(reshapeDescriptor,
3519 reshapeLayerName.c_str());
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003520
3521 reshapeLayer->GetOutputSlot(0).SetTensorInfo(reshapedTensorInfo);
3522 reshapeLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
3523
3524 RegisterInputSlots(subgraphIndex, operatorIndex, reshapeLayer, {inputTensorIndexes[0]});
Finn Williamsd4fa5452021-03-01 12:31:41 +00003525 // Fc layer connects to the reshape layer, so we skip the first input slot when registering fc's input slots
3526 tensorIndexesToRegister.erase(tensorIndexesToRegister.begin());
3527 startingSlotIndex = 1;
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003528 }
Finn Williamsd4fa5452021-03-01 12:31:41 +00003529
3530 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister, startingSlotIndex);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003531
Mike Kelly377fb212023-01-10 15:55:28 +00003532 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromShapes(subgraphIndex, operatorIndex, layer, 0,
3533 { inputTensorInfo.GetShape(),
3534 filterTensorInfo.GetShape() });
Mike Kelly04d82292023-01-19 18:29:40 +00003535
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003536 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3537
Mike Kelly04d82292023-01-19 18:29:40 +00003538 if (outputTensorInfo.GetNumDimensions() > 2)
3539 {
3540 // Calculate reshape to flatten to 2D [batch_size, input_size]
3541 std::vector<unsigned int> reshapedDimensions(2);
3542 reshapedDimensions[1] = filterTensorInfo.GetShape()[0];
3543 reshapedDimensions[0] = outputTensorInfo.GetNumElements() / reshapedDimensions[1];
3544 armnn::TensorInfo reshapedOutputTensorInfo = outputTensorInfo;
3545 if (outputTensorInfo.GetNumElements() % reshapedDimensions[1] != 0)
3546 {
3547 throw ParseException(
3548 fmt::format("Failed to deduce output tensor shape from filter size {} {}",
3549 reshapedDimensions[1],
3550 CHECK_LOCATION().AsString()));
3551 }
3552 reshapedOutputTensorInfo.SetShape(armnn::TensorShape{ 2, reshapedDimensions.data() });
3553 layer->GetOutputSlot(0).SetTensorInfo(reshapedOutputTensorInfo);
3554
3555 std::string reshapeLayerName = fmt::format("ExpandDims:{}:{}", subgraphIndex, operatorIndex);
3556 layer = AddReshapeLayer(layer, 0, reshapeLayerName, outputTensorInfo);
3557 }
3558
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003559 // we need to add the activation layer and fortunately we don't need to care about the data layout
3560 armnn::IConnectableLayer* fusedActivationLayer = AddFusedActivationLayer(layer, 0,
3561 options->fused_activation_function);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003562
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003563 // register the output connection slots for the layer, connections are made after all layers have been created
3564 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3565 RegisterOutputSlots(subgraphIndex, operatorIndex, fusedActivationLayer, {outputTensorIndexes[0]});
Mike Kelly04d82292023-01-19 18:29:40 +00003566
3567 m_TensorInfos[outputTensorIndexes[0]] = layer->GetOutputSlot(0).GetTensorInfo();
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003568}
3569
Kevin May7d96b162021-02-03 17:38:41 +00003570void TfLiteParserImpl::ParseDetectionPostProcess(size_t subgraphIndex, size_t operatorIndex)
keidav011b3e2ea2019-02-21 10:07:37 +00003571{
3572 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3573
Mike Kelly0d77ae12022-01-07 17:42:27 +00003574 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
keidav011b3e2ea2019-02-21 10:07:37 +00003575
3576 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3577 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3578 CHECK_VALID_SIZE(outputs.size(), 4);
3579
3580 // Obtain custom options from flexbuffers
3581 auto custom_options = operatorPtr->custom_options;
3582 const flexbuffers::Map& m = flexbuffers::GetRoot(custom_options.data(), custom_options.size()).AsMap();
3583
3584 // Obtain descriptor information from tf lite
3585 DetectionPostProcessDescriptor desc;
3586 desc.m_MaxDetections = m["max_detections"].AsUInt32();
3587 desc.m_MaxClassesPerDetection = m["max_classes_per_detection"].AsUInt32();
3588 desc.m_NmsScoreThreshold = m["nms_score_threshold"].AsFloat();
3589 desc.m_NmsIouThreshold = m["nms_iou_threshold"].AsFloat();
3590 desc.m_NumClasses = m["num_classes"].AsUInt32();
3591 desc.m_ScaleH = m["h_scale"].AsFloat();
3592 desc.m_ScaleW = m["w_scale"].AsFloat();
3593 desc.m_ScaleX = m["x_scale"].AsFloat();
3594 desc.m_ScaleY = m["y_scale"].AsFloat();
3595
keidav0107d58c72019-02-26 11:57:39 +00003596 if (!(m["use_regular_nms"].IsNull()))
keidav011b3e2ea2019-02-21 10:07:37 +00003597 {
keidav0107d58c72019-02-26 11:57:39 +00003598 desc.m_UseRegularNms = m["use_regular_nms"].AsBool();
keidav011b3e2ea2019-02-21 10:07:37 +00003599 }
3600 if (!(m["detections_per_class"].IsNull()))
3601 {
3602 desc.m_DetectionsPerClass = m["detections_per_class"].AsUInt32();
3603 }
3604
3605 if (desc.m_NmsIouThreshold <= 0.0f || desc.m_NmsIouThreshold > 1.0f)
3606 {
3607 throw InvalidArgumentException("DetectionPostProcessTFLiteParser: Intersection over union threshold "
3608 "must be positive and less than or equal to 1.");
3609 }
3610
Mike Kelly377fb212023-01-10 15:55:28 +00003611 armnn::TensorInfo anchorTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Finn Williamsd4fa5452021-03-01 12:31:41 +00003612 auto anchorTensorAndData = CreateConstTensorNonPermuted(inputs[2], anchorTensorInfo);
keidav011b3e2ea2019-02-21 10:07:37 +00003613
James Ward58dec6b2020-09-11 17:32:44 +01003614 auto layerName = fmt::format("DetectionPostProcess:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsd4fa5452021-03-01 12:31:41 +00003615 IConnectableLayer* layer = m_Network->AddDetectionPostProcessLayer(desc, anchorTensorAndData,
keidav011b3e2ea2019-02-21 10:07:37 +00003616 layerName.c_str());
3617
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01003618 ARMNN_ASSERT(layer != nullptr);
keidav011b3e2ea2019-02-21 10:07:37 +00003619
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00003620 // The model does not specify the output shapes.
3621 // The output shapes are calculated from the max_detection and max_classes_per_detection.
3622 unsigned int numDetectedBox = desc.m_MaxDetections * desc.m_MaxClassesPerDetection;
Mike Kelly377fb212023-01-10 15:55:28 +00003623 m_OverriddenOutputShapes.push_back({ 1, numDetectedBox, 4 });
3624 m_OverriddenOutputShapes.push_back({ 1, numDetectedBox });
3625 m_OverriddenOutputShapes.push_back({ 1, numDetectedBox });
3626 m_OverriddenOutputShapes.push_back({ 1 });
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00003627
keidav011b3e2ea2019-02-21 10:07:37 +00003628 for (unsigned int i = 0 ; i < outputs.size() ; ++i)
3629 {
Mike Kelly377fb212023-01-10 15:55:28 +00003630 armnn::TensorInfo detectionBoxOutputTensorInfo = ToTensorInfo(outputs[i], m_OverriddenOutputShapes[i]);
keidav011b3e2ea2019-02-21 10:07:37 +00003631 layer->GetOutputSlot(i).SetTensorInfo(detectionBoxOutputTensorInfo);
3632 }
3633
3634 // Register the input connection slots for the layer, connections are made after all layers have been created
3635 // only the tensors for the inputs are relevant, exclude the const tensors
3636 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3637 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
3638
3639 // Register the output connection slots for the layer, connections are made after all layers have been created
3640 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3641 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0],
3642 outputTensorIndexes[1],
3643 outputTensorIndexes[2],
3644 outputTensorIndexes[3]});
3645}
3646
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003647/// The TfLite Pack operator is equivalent to the ArmNN Stack operator
Kevin May7d96b162021-02-03 17:38:41 +00003648void TfLiteParserImpl::ParsePack(size_t subgraphIndex, size_t operatorIndex)
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003649{
3650 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3651
3652 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3653 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3654 CHECK_VALID_SIZE(outputs.size(), 1);
3655
3656 if (inputs.size() < 1)
3657 {
3658 throw ParseException("Pack must have at least one input.");
3659 }
3660
3661 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3662 const auto* options = operatorPtr->builtin_options.AsPackOptions();
3663
3664 StackDescriptor desc;
3665 desc.m_Axis = static_cast<uint32_t>(options->axis);
3666 desc.m_NumInputs = static_cast<uint32_t>(inputs.size());
3667
3668 // Use the tensor shape of the first input as the "correct" input shape in the descriptor
Mike Kelly377fb212023-01-10 15:55:28 +00003669 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003670 desc.m_InputShape = inputTensorInfo.GetShape();
3671
James Ward58dec6b2020-09-11 17:32:44 +01003672 auto layerName = fmt::format("Pack:{}:{}", subgraphIndex, operatorIndex);
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003673 IConnectableLayer* layer = m_Network->AddStackLayer(desc, layerName.c_str());
3674
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01003675 ARMNN_ASSERT(layer != nullptr);
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003676
Mike Kelly377fb212023-01-10 15:55:28 +00003677 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {});
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003678 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3679
3680 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3681 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes});
3682
3683 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3684 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3685}
3686
Mike Kelly5880b912022-01-28 16:18:54 +00003687void TfLiteParserImpl::ParseUnidirectionalSequenceLSTM(size_t subgraphIndex, size_t operatorIndex)
3688{
3689 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3690
3691 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3692 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3693
3694 if (inputs.size() < 2)
3695 {
3696 throw ParseException("UnidirectionalSequenceLSTM must have at least 2 input.");
3697 }
3698
3699 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3700 const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex];
3701 const auto nodeParams = operatorPtr->builtin_options.AsUnidirectionalSequenceLSTMOptions();
3702 CHECK_SUPPORTED_FUSED_ACTIVATION(nodeParams, subgraphIndex, operatorIndex);
Mike Kelly377fb212023-01-10 15:55:28 +00003703 auto inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Mike Kelly5880b912022-01-28 16:18:54 +00003704 auto outputTensorInfo = ToTensorInfo(outputs[0]);
3705
3706 // Set the params structure for the AddUnidirectionalSequenceLstmLayer call
3707 // Please refer to each operand at
3708 // https://www.tensorflow.org/mlir/tfl_ops#tflunidirectional_sequence_lstm_tflunidirectionalsequencelstmop
3709 armnn::LstmInputParams params;
3710
3711 if (IsOptionalOperandPresent(operatorPtr->inputs[1]))
3712 {
3713 params.m_InputToInputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[1]].get(),
3714 inputTensorInfo).first;
3715 }
3716
3717 params.m_InputToForgetWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[2]].get(),
3718 inputTensorInfo).first;
3719 params.m_InputToCellWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[3]].get(),
3720 inputTensorInfo).first;
3721 params.m_InputToOutputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[4]].get(),
3722 inputTensorInfo).first;
3723
3724 // Recurrent weight tensors of size {n_cell, n_output}
3725 if (IsOptionalOperandPresent(operatorPtr->inputs[5]))
3726 {
3727 params.m_RecurrentToInputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[5]].get(),
3728 inputTensorInfo).first;
3729 }
3730
3731 params.m_RecurrentToForgetWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[6]].get(),
3732 inputTensorInfo).first;
3733 params.m_RecurrentToCellWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[7]].get(),
3734 inputTensorInfo).first;
3735 params.m_RecurrentToOutputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[8]].get(),
3736 inputTensorInfo).first;
3737
3738 // Peephole weights tensors of size {n_cell}, representing a diagonal matrix.
3739 if (IsOptionalOperandPresent(operatorPtr->inputs[9]))
3740 {
3741 params.m_CellToInputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[9]].get(),
3742 inputTensorInfo).first;
3743 }
3744
3745 if (IsOptionalOperandPresent(operatorPtr->inputs[10]))
3746 {
3747 params.m_CellToForgetWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[10]].get(),
3748 inputTensorInfo).first;
3749 }
3750
3751 if (IsOptionalOperandPresent(operatorPtr->inputs[11]))
3752 {
3753 params.m_CellToOutputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[11]].get(),
3754 inputTensorInfo).first;
3755 }
3756
3757 // Gates bias tensors of size {n_cell}
3758 if (IsOptionalOperandPresent(operatorPtr->inputs[12]))
3759 {
3760 params.m_InputGateBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[12]].get(),
3761 inputTensorInfo).first;
3762 }
3763
3764 params.m_ForgetGateBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[13]].get(),
3765 inputTensorInfo).first;
3766 params.m_CellBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[14]].get(),
3767 inputTensorInfo).first;
3768 params.m_OutputGateBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[15]].get(),
3769 inputTensorInfo).first;
3770
3771 // Projection weight tensor of size {n_output, n_cell}
3772 if (IsOptionalOperandPresent(operatorPtr->inputs[16]))
3773 {
3774 params.m_ProjectionWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[16]].get(),
3775 inputTensorInfo).first;
3776 }
3777 // Projection bias tensor of size {n_output}
3778 if (IsOptionalOperandPresent(operatorPtr->inputs[17]))
3779 {
3780 params.m_ProjectionBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[17]].get(),
3781 inputTensorInfo).first;
3782 }
3783
3784 // These state tensors are defined as variable tensors, and will be modified by this op.
3785 armnn::TensorInfo outputStateInInfo = ToTensorInfo(subgraphPtr->tensors[operatorPtr->inputs[18]].get());
3786 m_ConstantsToBeCreated.push_back(operatorPtr->inputs[18]);
3787 armnn::TensorInfo cellStateInInfo = ToTensorInfo(subgraphPtr->tensors[operatorPtr->inputs[19]].get());
3788 m_ConstantsToBeCreated.push_back(operatorPtr->inputs[19]);
3789
3790 // Layer norm coefficient tensors of size {n_cell}, representing a diagonal matrix.
3791 if (inputs.size() >= 21 && IsOptionalOperandPresent(operatorPtr->inputs[20]))
3792 {
3793 params.m_InputLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[20]].get(),
3794 inputTensorInfo).first;
3795 }
3796
3797 if (inputs.size() >= 22 && IsOptionalOperandPresent(operatorPtr->inputs[21]))
3798 {
3799 params.m_ForgetLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[21]].get(),
3800 inputTensorInfo).first;
3801 }
3802
3803 if (inputs.size() >= 23 && IsOptionalOperandPresent(operatorPtr->inputs[22]))
3804 {
3805 params.m_CellLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[22]].get(),
3806 inputTensorInfo).first;
3807 }
3808
3809 if (inputs.size() >= 24 && IsOptionalOperandPresent(operatorPtr->inputs[23]))
3810 {
3811 params.m_OutputLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[23]].get(),
3812 inputTensorInfo).first;
3813 }
3814
3815 // set the layer descriptor
3816 armnn::UnidirectionalSequenceLstmDescriptor desc;
3817 desc.m_ActivationFunc = nodeParams->fused_activation_function;
3818 desc.m_ClippingThresCell = nodeParams->cell_clip;
3819 desc.m_ClippingThresProj = nodeParams->proj_clip;
3820 desc.m_CifgEnabled = (params.m_InputToInputWeights == nullptr
3821 || params.m_RecurrentToInputWeights == nullptr
3822 || params.m_InputGateBias == nullptr);
3823 desc.m_PeepholeEnabled = (params.m_CellToForgetWeights != nullptr || params.m_CellToOutputWeights != nullptr);
3824 desc.m_ProjectionEnabled = (params.m_ProjectionWeights != nullptr);
3825 desc.m_LayerNormEnabled = (params.m_InputLayerNormWeights != nullptr
3826 || params.m_ForgetLayerNormWeights != nullptr
3827 || params.m_CellLayerNormWeights != nullptr
3828 || params.m_OutputLayerNormWeights != nullptr);
3829 desc.m_TimeMajor = nodeParams->time_major;
3830
Mike Kellyc0800a32022-06-15 10:57:52 +01003831 if (operatorPtr->intermediates.size() > 3 && desc.m_LayerNormEnabled)
Mike Kelly5880b912022-01-28 16:18:54 +00003832 {
3833 auto inputIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[0]].get(),
3834 inputTensorInfo).first;
3835 auto inputIntermediateTensorInfo = inputIntermediate->GetInfo();
3836 desc.m_InputIntermediateScale = inputIntermediateTensorInfo.GetQuantizationScale();
3837
3838 auto forgetIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[1]].get(),
3839 inputTensorInfo).first;
3840 auto forgetIntermediateTensorInfo = forgetIntermediate->GetInfo();
3841 desc.m_ForgetIntermediateScale = forgetIntermediateTensorInfo.GetQuantizationScale();
3842
3843 auto cellIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[2]].get(),
3844 inputTensorInfo).first;
3845 auto cellIntermediateTensorInfo = cellIntermediate->GetInfo();
3846 desc.m_CellIntermediateScale = cellIntermediateTensorInfo.GetQuantizationScale();
3847
3848 auto outputIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[3]].get(),
3849 inputTensorInfo).first;
3850 auto outputIntermediateTensorInfo = outputIntermediate->GetInfo();
3851 desc.m_OutputIntermediateScale = outputIntermediateTensorInfo.GetQuantizationScale();
3852 }
3853 else
3854 {
3855 float defaultIntermediate = std::pow(2, -12);
3856 desc.m_InputIntermediateScale = defaultIntermediate;
3857 desc.m_ForgetIntermediateScale = defaultIntermediate;
3858 desc.m_CellIntermediateScale = defaultIntermediate;
3859 desc.m_OutputIntermediateScale = defaultIntermediate;
3860 }
3861
Mike Kellyc0800a32022-06-15 10:57:52 +01003862 if (operatorPtr->intermediates.size() > 4)
3863 {
3864 auto hiddentensor = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[4]].get(),
3865 inputTensorInfo).first;
Mike Kelly5880b912022-01-28 16:18:54 +00003866
Mike Kellyc0800a32022-06-15 10:57:52 +01003867 desc.m_HiddenStateScale = hiddentensor->GetInfo().GetQuantizationScale();
3868 desc.m_HiddenStateZeroPoint = hiddentensor->GetInfo().GetQuantizationOffset();
3869 }
Mike Kelly5880b912022-01-28 16:18:54 +00003870 unsigned int batchSize = inputTensorInfo.GetShape()[0];
3871 unsigned int outputSize = outputTensorInfo.GetShape()[2];
3872 unsigned int numUnits = cellStateInInfo.GetShape()[1];
3873
3874 armnn::DataType dataType = inputTensorInfo.GetDataType();
3875 float qScale = inputTensorInfo.GetQuantizationScale();
3876 float qOffset = inputTensorInfo.GetQuantizationOffset();
3877
3878 armnn::TensorInfo scratchBufferTensorInfo({batchSize, numUnits * 3}, dataType, qScale, qOffset);
3879 if (!desc.m_CifgEnabled)
3880 {
3881 scratchBufferTensorInfo = armnn::TensorInfo({batchSize, numUnits * 4}, dataType, qScale, qOffset);
3882 }
3883 armnn::TensorInfo cellStateOutTensorInfo({batchSize, numUnits},
3884 cellStateInInfo.GetDataType(),
3885 cellStateInInfo.GetQuantizationScale(),
3886 cellStateInInfo.GetQuantizationOffset());
3887 armnn::TensorInfo outputStateOutTensorInfo({batchSize, outputSize}, dataType, qScale, qOffset);
3888
3889 armnn::LstmInputParamsInfo paramsInfo;
3890 paramsInfo.m_InputToForgetWeights = &(params.m_InputToForgetWeights->GetInfo());
3891 paramsInfo.m_InputToCellWeights = &(params.m_InputToCellWeights->GetInfo());
3892 paramsInfo.m_InputToOutputWeights = &(params.m_InputToOutputWeights->GetInfo());
3893 paramsInfo.m_RecurrentToForgetWeights = &(params.m_RecurrentToForgetWeights->GetInfo());
3894 paramsInfo.m_RecurrentToCellWeights = &(params.m_RecurrentToCellWeights->GetInfo());
3895 paramsInfo.m_RecurrentToOutputWeights = &(params.m_RecurrentToOutputWeights->GetInfo());
3896 paramsInfo.m_ForgetGateBias = &(params.m_ForgetGateBias->GetInfo());
3897 paramsInfo.m_CellBias = &(params.m_CellBias->GetInfo());
3898 paramsInfo.m_OutputGateBias = &(params.m_OutputGateBias->GetInfo());
3899
3900 if (!desc.m_CifgEnabled)
3901 {
3902 paramsInfo.m_InputToInputWeights = &(params.m_InputToInputWeights->GetInfo());
3903 paramsInfo.m_RecurrentToInputWeights = &(params.m_RecurrentToInputWeights->GetInfo());
3904 if (params.m_CellToInputWeights != nullptr)
3905 {
3906 paramsInfo.m_CellToInputWeights = &(params.m_CellToInputWeights->GetInfo());
3907 }
3908 paramsInfo.m_InputGateBias = &(params.m_InputGateBias->GetInfo());
3909 }
3910
3911 if (desc.m_ProjectionEnabled)
3912 {
3913 paramsInfo.m_ProjectionWeights = &(params.m_ProjectionWeights->GetInfo());
3914 if (params.m_ProjectionBias != nullptr)
3915 {
3916 paramsInfo.m_ProjectionBias = &(params.m_ProjectionBias->GetInfo());
3917 }
3918 }
3919
3920 if (desc.m_PeepholeEnabled)
3921 {
3922 paramsInfo.m_CellToForgetWeights = &(params.m_CellToForgetWeights->GetInfo());
3923 paramsInfo.m_CellToOutputWeights = &(params.m_CellToOutputWeights->GetInfo());
3924 }
3925
3926 if (desc.m_LayerNormEnabled)
3927 {
3928 if(!desc.m_CifgEnabled)
3929 {
3930 paramsInfo.m_InputLayerNormWeights = &(params.m_InputLayerNormWeights->GetInfo());
3931 }
3932 paramsInfo.m_ForgetLayerNormWeights = &(params.m_ForgetLayerNormWeights->GetInfo());
3933 paramsInfo.m_CellLayerNormWeights = &(params.m_CellLayerNormWeights->GetInfo());
3934 paramsInfo.m_OutputLayerNormWeights = &(params.m_OutputLayerNormWeights->GetInfo());
3935 }
3936
3937 auto layerName = fmt::format("UnidirectionalSequenceLSTM:{}:{}", subgraphIndex, operatorIndex);
3938 armnn::IConnectableLayer* layer = m_Network->AddUnidirectionalSequenceLstmLayer(desc, params);
3939 ARMNN_ASSERT(layer != nullptr);
3940
3941 // register the input connection slots for the layer, connections are made after all layers have been created
3942 // only the tensors for the inputs are relevant, exclude the const tensors
3943 auto inputTensorIndexes = AsUnsignedVector({operatorPtr->inputs[0],
3944 operatorPtr->inputs[18],
3945 operatorPtr->inputs[19]});
3946 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0],
3947 inputTensorIndexes[1],
3948 inputTensorIndexes[2]});
3949
3950 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3951
3952 layer->GetOutputSlot(0).SetTensorInfo(outputStateOutTensorInfo);
3953 layer->GetOutputSlot(1).SetTensorInfo(cellStateOutTensorInfo);
3954 layer->GetOutputSlot(2).SetTensorInfo(outputTensorInfo);
3955
3956 unsigned int tensorIndex = outputTensorIndexes[0];
3957 armnn::IOutputSlot* slot = &(layer->GetOutputSlot(2));
3958 RegisterProducerOfTensor(subgraphIndex, tensorIndex, slot);
3959}
3960
Kevin May7d96b162021-02-03 17:38:41 +00003961void TfLiteParserImpl::ParseUnpack(size_t subgraphIndex, size_t operatorIndex)
Nina Drozd200e3802019-04-15 09:47:39 +01003962{
3963 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3964
Mike Kelly0d77ae12022-01-07 17:42:27 +00003965 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3966 const auto* options = operatorPtr->builtin_options.AsUnpackOptions();
Nina Drozd200e3802019-04-15 09:47:39 +01003967
3968 // This unpackAxis indicates the axis to unpack
3969 const unsigned int unpackAxis = CHECKED_NON_NEGATIVE(options->axis);
3970
3971 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3972 CHECK_VALID_SIZE(inputs.size(), 1);
3973
Mike Kelly377fb212023-01-10 15:55:28 +00003974 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003975
3976 if (unpackAxis >= inputTensorInfo.GetNumDimensions())
3977 {
3978 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003979 fmt::format("The unpack axis: {} cannot be greater than or equal to "
3980 "the number of input dimension {} {}",
3981 unpackAxis,
3982 inputTensorInfo.GetNumDimensions(),
3983 CHECK_LOCATION().AsString()));
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003984 }
3985
Nina Drozd200e3802019-04-15 09:47:39 +01003986 unsigned int unpackNum = CHECKED_NON_NEGATIVE(options->num);
3987 // If num is not defined, automatically infer from the length of the dimension axis.
3988 if(unpackNum == 0)
3989 {
3990 unpackNum = inputTensorInfo.GetShape()[unpackAxis];
3991 }
3992
3993 // If unpack number cannot be inferred and is still zero, throw ParseException.
3994 if(unpackNum == 0)
3995 {
3996 throw ParseException("Number to unpack must greater than zero.");
3997 }
3998
3999 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4000 CHECK_VALID_SIZE(outputs.size(), unpackNum);
4001
4002 auto inputDimSize = inputTensorInfo.GetNumDimensions();
4003 std::vector<unsigned int> unpackDimSizes(inputDimSize);
4004
4005 // Add current input shape to unpackDimSizes
4006 for (unsigned int i = 0; i < inputDimSize; ++i)
4007 {
4008 unpackDimSizes[i] = inputTensorInfo.GetShape()[i];
4009 }
4010
4011 if (unpackDimSizes[unpackAxis] != unpackNum)
4012 {
4013 throw ParseException("Number to unpack must be the same as length of the dimension to "
4014 "unpack along.");
4015 }
4016
4017 unpackDimSizes[unpackAxis] /= unpackNum;
4018
4019 SplitterDescriptor splitDesc(unpackNum, static_cast<unsigned int>(unpackDimSizes.size()));
4020 for (unsigned int j = 0; j < unpackNum; ++j)
4021 {
4022 // Set the size of the views.
4023 for (unsigned int dimIdx = 0; dimIdx < unpackDimSizes.size(); ++dimIdx)
4024 {
4025 splitDesc.SetViewSize(j, dimIdx, unpackDimSizes[dimIdx]);
4026 }
4027 splitDesc.SetViewOriginCoord(j, unpackAxis, unpackDimSizes[unpackAxis] * j);
4028 }
4029
James Ward58dec6b2020-09-11 17:32:44 +01004030 auto layerName = fmt::format("Unpack:{}:{}", subgraphIndex, operatorIndex);
Nina Drozd200e3802019-04-15 09:47:39 +01004031 IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01004032 ARMNN_ASSERT(layer != nullptr);
Nina Drozd200e3802019-04-15 09:47:39 +01004033
Narumol Prangnawarat672de572019-04-23 15:28:06 +01004034 TensorShape splitOutShape = TensorShape(static_cast<unsigned int>(unpackDimSizes.size()),
4035 unpackDimSizes.data());
4036
Nina Drozd200e3802019-04-15 09:47:39 +01004037 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4038 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4039
Finn Williamsb49ed182021-06-29 15:50:08 +01004040 std::vector<unsigned int> reshapeDims;
4041 for (unsigned int axis = 0; axis < splitOutShape.GetNumDimensions(); ++axis)
4042 {
4043 if (axis != unpackAxis)
4044 {
4045 reshapeDims.push_back(splitOutShape[axis]);
4046 }
4047 }
4048
4049 TensorShape reshapeOutputShape(splitOutShape.GetNumDimensions() -1, reshapeDims.data());
4050
Narumol Prangnawarat672de572019-04-23 15:28:06 +01004051 // Create reshape to remove the unpacked dimension for unpack operator of each output from Splitter.
4052 for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
4053 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01004054 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[k], true);
James Ward58dec6b2020-09-11 17:32:44 +01004055 std::string reshapeLayerName = fmt::format("Reshape_for:{}", layer->GetName());
Narumol Prangnawarat672de572019-04-23 15:28:06 +01004056 armnn::ReshapeDescriptor desc;
Finn Williamsb49ed182021-06-29 15:50:08 +01004057 desc.m_TargetShape = reshapeOutputShape;
Narumol Prangnawarat672de572019-04-23 15:28:06 +01004058 armnn::IConnectableLayer* reshapeLayer = m_Network->AddReshapeLayer(desc, layerName.c_str());
4059
Narumol Prangnawarat2c526462019-10-21 14:58:26 +01004060 layer->GetOutputSlot(k).SetTensorInfo(armnn::TensorInfo(splitOutShape,
4061 outputTensorInfo.GetDataType(),
4062 outputTensorInfo.GetQuantizationScale(),
4063 outputTensorInfo.GetQuantizationOffset()));
Narumol Prangnawarat672de572019-04-23 15:28:06 +01004064 layer->GetOutputSlot(k).Connect(reshapeLayer->GetInputSlot(0));
4065
Narumol Prangnawarat2c526462019-10-21 14:58:26 +01004066 reshapeLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
Narumol Prangnawarat672de572019-04-23 15:28:06 +01004067
4068 uint32_t reshapedOutputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[k]);
4069 armnn::IOutputSlot* slot = &(reshapeLayer->GetOutputSlot(0));
4070 RegisterProducerOfTensor(subgraphIndex, reshapedOutputId, slot);
4071 }
Nina Drozd200e3802019-04-15 09:47:39 +01004072}
4073
Kevin May7d96b162021-02-03 17:38:41 +00004074void TfLiteParserImpl::ParseSplit(size_t subgraphIndex, size_t operatorIndex)
Nina Drozd0324f482019-04-08 10:52:10 +01004075{
4076 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4077
Mike Kelly0d77ae12022-01-07 17:42:27 +00004078 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4079 const auto* options = operatorPtr->builtin_options.AsSplitOptions();
Nina Drozd0324f482019-04-08 10:52:10 +01004080
4081 const unsigned int numSplits = CHECKED_NON_NEGATIVE(options->num_splits);
4082
Nina Drozd200e3802019-04-15 09:47:39 +01004083 // If number of splits cannot be inferred and is zero, throw ParseException.
4084 if(numSplits == 0)
4085 {
4086 throw ParseException("Number to splits must greater than zero.");
4087 }
4088
Nina Drozd0324f482019-04-08 10:52:10 +01004089 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4090 CHECK_VALID_SIZE(inputs.size(), 2);
4091 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4092 CHECK_VALID_SIZE(outputs.size(), numSplits);
4093
Mike Kelly377fb212023-01-10 15:55:28 +00004094 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
4095 armnn::TensorInfo axisTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004096 ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
Nina Drozd0324f482019-04-08 10:52:10 +01004097
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01004098 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[0]->buffer);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004099 if (axisBufferPtr == nullptr)
4100 {
4101 throw ParseException(
4102 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
4103 CHECK_LOCATION().AsString()));
4104 }
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01004105
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004106 std::vector<int32_t> axisData(axisTensorInfo.GetNumElements());
4107 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
4108 int32_t axis = axisData[0];
4109
4110 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
4111 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
4112 {
4113 // Square bracket denotes inclusive n while parenthesis denotes exclusive n
4114 // E.g. Rank 4 tensor can have axis in range [-4, 3)
4115 // -1 == 3, -2 == 2, -3 == 1, -4 == 0
4116 throw ParseException(
4117 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
4118 axis,
4119 CHECK_LOCATION().AsString()));
4120 }
4121
4122 const unsigned int splitDim = armnnUtils::GetUnsignedAxis(inputTensorInfo.GetNumDimensions(), axis);
Nina Drozd0324f482019-04-08 10:52:10 +01004123
Nina Drozd0324f482019-04-08 10:52:10 +01004124 auto inputDimSize = inputTensorInfo.GetNumDimensions();
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01004125 if (inputDimSize > MaxNumOfTensorDimensions)
Nina Drozd0324f482019-04-08 10:52:10 +01004126 {
4127 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01004128 fmt::format("The number of dimensions: {} for input tensors of the split op cannot be greater than {} {}",
4129 inputTensorInfo.GetNumDimensions(),
4130 MaxNumOfTensorDimensions,
4131 CHECK_LOCATION().AsString()));
Nina Drozd0324f482019-04-08 10:52:10 +01004132 }
4133
4134 std::vector<unsigned int> splitterDimSizes(inputDimSize);
4135
4136 // Add current input shape to splitterDimSizes
4137 for (unsigned int i = 0; i < inputDimSize; ++i)
4138 {
4139 splitterDimSizes[i] = inputTensorInfo.GetShape()[i];
4140 }
4141
4142 if (splitterDimSizes[splitDim] % numSplits != 0)
4143 {
4144 throw ParseException("Number of splits must evenly divide the dimension");
4145 }
4146 splitterDimSizes[splitDim] /= numSplits;
4147
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01004148 SplitterDescriptor splitDesc(numSplits, inputDimSize);
Nina Drozd0324f482019-04-08 10:52:10 +01004149 for (unsigned int j = 0; j < numSplits; ++j)
4150 {
4151 // Set the size of the views.
4152 for (unsigned int dimIdx = 0; dimIdx < splitterDimSizes.size(); ++dimIdx)
4153 {
4154 splitDesc.SetViewSize(j, dimIdx, splitterDimSizes[dimIdx]);
4155 }
4156 splitDesc.SetViewOriginCoord(j, splitDim, splitterDimSizes[splitDim] * j);
4157 }
4158
James Ward58dec6b2020-09-11 17:32:44 +01004159 auto layerName = fmt::format("Split:{}:{}", subgraphIndex, operatorIndex);
Nina Drozd0324f482019-04-08 10:52:10 +01004160 IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01004161 ARMNN_ASSERT(layer != nullptr);
Nina Drozd0324f482019-04-08 10:52:10 +01004162
4163 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01004164 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[1]});
Nina Drozd0324f482019-04-08 10:52:10 +01004165
Nina Drozd0324f482019-04-08 10:52:10 +01004166 for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
4167 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01004168 armnn::TensorInfo tensorInfo = ToTensorInfo(outputs[k], true);
Francis Murtagh98d6b3d2019-10-21 10:52:54 +01004169 layer->GetOutputSlot(k).SetTensorInfo(tensorInfo);
Nina Drozd0324f482019-04-08 10:52:10 +01004170 }
4171
4172 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4173 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4174}
4175
Derek Lambertif0176992020-04-28 13:37:49 +01004176unsigned int ComputeWrappedIndex(int idx, unsigned int numDimsIn)
4177{
4178 int numDims = armnn::numeric_cast<int>(numDimsIn);
4179 int v = idx < 0 ? numDims + idx : idx;
4180 ARMNN_ASSERT(v >= 0);
4181 ARMNN_ASSERT(v < numDims);
4182
4183 return static_cast<unsigned int>(v);
4184}
4185
Kevin May7d96b162021-02-03 17:38:41 +00004186void TfLiteParserImpl::ParseSplitV(size_t subgraphIndex, size_t operatorIndex)
Derek Lambertif0176992020-04-28 13:37:49 +01004187{
4188 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4189
Mike Kelly0d77ae12022-01-07 17:42:27 +00004190 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4191 const auto* options = operatorPtr->builtin_options.AsSplitVOptions();
Derek Lambertif0176992020-04-28 13:37:49 +01004192
4193 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4194 CHECK_VALID_SIZE(inputs.size(), 3);
4195
4196 auto& inputTensor = inputs[0];
4197 auto& splitsTensor = inputs[1];
4198 auto& axisTensor = inputs[2];
4199
4200 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputTensor);
4201 armnn::TensorInfo splitsInfo = ToTensorInfo(splitsTensor);
4202 armnn::TensorInfo axisTensorInfo = ToTensorInfo(axisTensor);
4203 ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
4204
4205 // Inputs
4206 auto inputDimSize = inputTensorInfo.GetNumDimensions();
4207 if (inputDimSize > MaxNumOfTensorDimensions)
4208 {
4209 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01004210 fmt::format("The number of dimensions: {} for input tensors of the "
4211 "SplitV op cannot be greater than {} {}",
4212 inputTensorInfo.GetNumDimensions(),
4213 MaxNumOfTensorDimensions,
4214 CHECK_LOCATION().AsString()));
Derek Lambertif0176992020-04-28 13:37:49 +01004215 }
4216
4217 // Get split axis
4218 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, axisTensor->buffer);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004219 if (axisBufferPtr == nullptr)
4220 {
4221 throw ParseException(
4222 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
4223 CHECK_LOCATION().AsString()));
4224 }
4225
Derek Lambertif0176992020-04-28 13:37:49 +01004226 std::vector<int> axisData(axisTensorInfo.GetNumElements());
4227 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004228 int32_t axis = axisData[0];
4229
4230 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
4231 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
4232 {
4233 // Square bracket denotes inclusive n while parenthesis denotes exclusive n
4234 // E.g. Rank 4 tensor can have axis in range [-4, 3)
4235 // -1 == 3, -2 == 2, -3 == 1, -4 == 0
4236 throw ParseException(
4237 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
4238 axis,
4239 CHECK_LOCATION().AsString()));
4240 }
4241 const unsigned int splitDim = ComputeWrappedIndex(axis, inputTensorInfo.GetNumDimensions());
Derek Lambertif0176992020-04-28 13:37:49 +01004242
Derek Lambertif0176992020-04-28 13:37:49 +01004243 // Set split sizes
Derek Lambertif0176992020-04-28 13:37:49 +01004244 CHECK_VALID_SIZE(splitsInfo.GetNumDimensions(), 1);
Ryan OShea86704732020-05-26 11:41:04 +01004245 unsigned int numSplits{0};
4246
4247 if(options)
Derek Lambertif0176992020-04-28 13:37:49 +01004248 {
4249 numSplits = CHECKED_NON_NEGATIVE(options->num_splits);
Derek Lambertif0176992020-04-28 13:37:49 +01004250 }
4251 else
4252 {
Ryan OShea86704732020-05-26 11:41:04 +01004253 numSplits = splitsInfo.GetNumElements();
Derek Lambertif0176992020-04-28 13:37:49 +01004254 }
4255
4256 if (numSplits <=0)
4257 {
4258 throw ParseException("SplitV has invalid number of splits");
4259 }
4260
Jan Eilersc0761e92020-06-29 16:48:44 +01004261 std::vector<int> splitsData(numSplits);
Ryan OShea86704732020-05-26 11:41:04 +01004262 BufferRawPtr splitsBufferPtr = GetBuffer(m_Model, splitsTensor->buffer);
Jan Eilersc0761e92020-06-29 16:48:44 +01004263 ::memcpy(splitsData.data(), splitsBufferPtr->data.data(), splitsInfo.GetNumBytes());
Ryan OShea86704732020-05-26 11:41:04 +01004264
Jan Eilersc0761e92020-06-29 16:48:44 +01004265 unsigned int idx = 0;
Ryan OShea86704732020-05-26 11:41:04 +01004266 int numInferred{0};
4267 unsigned int inferIdx{0};
4268 int splitSum{0};
4269 for (auto split : splitsData)
4270 {
4271 if (split < 0)
4272 {
4273 numInferred++;
4274 inferIdx = idx;
4275 }
4276 else
4277 {
4278 splitSum += split;
4279 }
4280 idx++;
4281 }
4282 // Check for inferred Axis
4283 if (numInferred == 0)
4284 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +01004285 if (splitSum != armnn::numeric_cast<int>(inputTensorInfo.GetShape()[splitDim]))
Ryan OShea86704732020-05-26 11:41:04 +01004286 {
4287 throw ParseException("SplitV split_sizes does not sum to the dimension of value along split_dim.");
4288 }
4289 }
4290 else if (numInferred == 1)
4291 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +01004292 splitsData[inferIdx] = armnn::numeric_cast<int>(inputTensorInfo.GetShape()[splitDim]) - splitSum;
Ryan OShea86704732020-05-26 11:41:04 +01004293 }
4294 else
4295 {
4296 throw ParseException("Cannot infer split size for more than one split");
4297 }
4298
Derek Lambertif0176992020-04-28 13:37:49 +01004299 //Ouput size validation
4300 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4301 CHECK_VALID_SIZE(outputs.size(), numSplits);
4302
4303 // Setup Armnn descriptor
4304 SplitterDescriptor splitDesc(numSplits, inputDimSize);
4305 unsigned int accumSplit = 0;
4306 for (unsigned int j = 0; j < numSplits; ++j)
4307 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +01004308 unsigned int splitSize = armnn::numeric_cast<unsigned int>(splitsData[j]);
Derek Lambertif0176992020-04-28 13:37:49 +01004309
4310 // Set the size of the views.
4311 for (unsigned int dimIdx = 0; dimIdx < inputTensorInfo.GetNumDimensions(); ++dimIdx)
4312 {
4313 unsigned int dimSize = inputTensorInfo.GetShape()[dimIdx];
4314 if (dimIdx == splitDim)
4315 {
4316 dimSize = splitSize;
4317 }
4318 splitDesc.SetViewSize(j, dimIdx, dimSize);
4319 }
4320
4321 splitDesc.SetViewOriginCoord(j, splitDim, accumSplit);
4322 accumSplit += splitSize;
4323 }
4324
James Ward58dec6b2020-09-11 17:32:44 +01004325 auto layerName = fmt::format("SplitV:{}:{}", subgraphIndex, operatorIndex);
Derek Lambertif0176992020-04-28 13:37:49 +01004326 IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01004327 ARMNN_ASSERT(layer != nullptr);
Derek Lambertif0176992020-04-28 13:37:49 +01004328
4329 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4330 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4331
4332 for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
4333 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01004334 armnn::TensorInfo tensorInfo = ToTensorInfo(outputs[k], true);
Derek Lambertif0176992020-04-28 13:37:49 +01004335 layer->GetOutputSlot(k).SetTensorInfo(tensorInfo);
4336 }
4337
4338 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4339 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4340}
4341
Matthew Sloyan28f177c2021-04-09 14:38:52 +01004342void TfLiteParserImpl::ParseArgMin(size_t subgraphIndex, size_t operatorIndex)
4343{
4344 ParseArgMinMax(subgraphIndex, operatorIndex, armnn::ArgMinMaxFunction::Min);
4345}
4346
Kevin May7d96b162021-02-03 17:38:41 +00004347void TfLiteParserImpl::ParseArgMax(size_t subgraphIndex, size_t operatorIndex)
Inki Daed4619e22020-09-10 15:33:54 +09004348{
Matthew Sloyan28f177c2021-04-09 14:38:52 +01004349 ParseArgMinMax(subgraphIndex, operatorIndex, armnn::ArgMinMaxFunction::Max);
4350}
4351
4352void TfLiteParserImpl::ParseArgMinMax(size_t subgraphIndex, size_t operatorIndex, ArgMinMaxFunction argMinMaxFunction)
4353{
Inki Daed4619e22020-09-10 15:33:54 +09004354 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4355 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4356 CHECK_VALID_SIZE(inputs.size(), 2);
4357
4358 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4359 CHECK_VALID_SIZE(outputs.size(), 1);
4360
Mike Kelly377fb212023-01-10 15:55:28 +00004361 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4362 armnn::TensorInfo axisTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Inki Daed4619e22020-09-10 15:33:54 +09004363 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004364 ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
Matthew Sloyan28f177c2021-04-09 14:38:52 +01004365
4366 // Check if output tensor type is Signed32 or Signed64
Mike Kelly1f140f72021-04-06 12:25:55 +01004367 if (outputTensorInfo.GetDataType() != armnn::DataType::Signed32 &&
4368 outputTensorInfo.GetDataType() != armnn::DataType::Signed64)
4369 {
4370 throw ParseException(
4371 fmt::format(
4372 "Output tensor data type is not supported. (Supported types: Signed32 & Signed64) {}",
4373 CHECK_LOCATION().AsString()));
4374 }
Matthew Sloyan28f177c2021-04-09 14:38:52 +01004375
4376 // Get const axis value from model and set it to descriptor.
4377 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
4378 if (axisBufferPtr == nullptr)
4379 {
4380 throw ParseException(
4381 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
4382 CHECK_LOCATION().AsString()));
4383 }
4384
4385 std::vector<int32_t> axisData(axisTensorInfo.GetNumElements());
4386 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
4387 int32_t axis = axisData.front();
4388
4389 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
4390 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
4391 {
4392 // Square bracket denotes inclusive n while parenthesis denotes exclusive n
4393 // E.g. Rank 4 tensor can have axis in range [-4, 3)
4394 // -1 == 3, -2 == 2, -3 == 1, -4 == 0
4395 throw ParseException(
4396 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
4397 axis,
4398 CHECK_LOCATION().AsString()));
4399 }
4400
4401 ArgMinMaxDescriptor desc;
4402 desc.m_Axis = axis;
4403 desc.m_Function = argMinMaxFunction;
4404
4405 // Register a ArgMin/ArgMax layer.
4406 auto layerName = argMinMaxFunction == ArgMinMaxFunction::Max ? "ArgMax:{}:{}" : "ArgMin:{}:{}";
4407 auto layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4408 IConnectableLayer *layer = m_Network->AddArgMinMaxLayer(desc, layerNameFormatted.c_str());
4409 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00004410 outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Inki Daed4619e22020-09-10 15:33:54 +09004411 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4412
4413 // Register input tensor to the layer.
4414 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4415 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4416
4417 // Register output tensor to the layer.
4418 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4419 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4420}
4421
Kevin May7d96b162021-02-03 17:38:41 +00004422void TfLiteParserImpl::ParseGather(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan26868492021-01-22 14:25:31 +00004423{
4424 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4425
Kevin May7d96b162021-02-03 17:38:41 +00004426 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00004427 CHECK_VALID_SIZE(inputs.size(), 2);
Kevin May7d96b162021-02-03 17:38:41 +00004428 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00004429 CHECK_VALID_SIZE(outputs.size(), 1);
4430
Mike Kelly377fb212023-01-10 15:55:28 +00004431 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4432 armnn::TensorInfo indicesTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
4433 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
Sadik Armagan26868492021-01-22 14:25:31 +00004434
4435 armnn::GatherDescriptor gatherDescriptor;
4436
Mike Kelly0d77ae12022-01-07 17:42:27 +00004437 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4438 const auto* options = operatorPtr->builtin_options.AsGatherOptions();
Sadik Armagan26868492021-01-22 14:25:31 +00004439 auto axis = options->axis;
4440
Mike Kelly377fb212023-01-10 15:55:28 +00004441 auto layerName = fmt::format("Gather:{}:{}", subgraphIndex, operatorIndex);
4442
Sadik Armagan26868492021-01-22 14:25:31 +00004443 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
4444 auto indicesDimensions = indicesTensorInfo.GetNumDimensions();
4445 auto outputDimensions = outputTensorInfo.GetNumDimensions();
4446 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
4447 {
4448 throw ParseException(
4449 fmt::format("Operation has invalid axis: {} It is out of bounds [ -{}, {} ) {}",
4450 axis,
4451 inputDimensions, inputDimensions,
4452 CHECK_LOCATION().AsString()));
4453 }
4454 if (outputDimensions != static_cast<unsigned int>(inputDimensions) + indicesDimensions - 1)
4455 {
4456 throw ParseException(
4457 fmt::format("Operation has invalid output dimensions: {} Output must be an ({} + {} - 1) -D tensor {}",
4458 outputDimensions,
4459 inputDimensions, indicesDimensions,
4460 CHECK_LOCATION().AsString()));
4461 }
4462
4463 gatherDescriptor.m_Axis = axis;
4464
Sadik Armagan26868492021-01-22 14:25:31 +00004465 IConnectableLayer* layer = m_Network->AddGatherLayer(gatherDescriptor, layerName.c_str());
4466 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00004467 outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Sadik Armagan26868492021-01-22 14:25:31 +00004468 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4469
4470 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4471 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4472
4473 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4474 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4475}
4476
Teresa Charlin91a53ea2022-04-25 15:47:29 +01004477void TfLiteParserImpl::ParseGatherNd(size_t subgraphIndex, size_t operatorIndex)
4478{
4479 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4480
4481 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4482 CHECK_VALID_SIZE(inputs.size(), 2);
4483 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4484 CHECK_VALID_SIZE(outputs.size(), 1);
4485
Mike Kelly377fb212023-01-10 15:55:28 +00004486 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4487 armnn::TensorInfo indicesTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Teresa Charlin91a53ea2022-04-25 15:47:29 +01004488
4489 auto layerName = fmt::format("GatherNd:{}:{}", subgraphIndex, operatorIndex);
4490 IConnectableLayer* layer = m_Network->AddGatherNdLayer(layerName.c_str());
4491 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00004492 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Teresa Charlin91a53ea2022-04-25 15:47:29 +01004493 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4494
4495 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4496 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4497
4498 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4499 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4500}
4501
Kevin May7d96b162021-02-03 17:38:41 +00004502void TfLiteParserImpl::ParseDepthToSpace(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan26868492021-01-22 14:25:31 +00004503{
4504 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4505
Kevin May7d96b162021-02-03 17:38:41 +00004506 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00004507 CHECK_VALID_SIZE(inputs.size(), 1);
Kevin May7d96b162021-02-03 17:38:41 +00004508 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00004509 CHECK_VALID_SIZE(outputs.size(), 1);
4510
4511 armnn::DepthToSpaceDescriptor descriptor;
4512
Mike Kelly0d77ae12022-01-07 17:42:27 +00004513 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4514 const auto* options = operatorPtr->builtin_options.AsDepthToSpaceOptions();
Sadik Armagan26868492021-01-22 14:25:31 +00004515 auto blockSize = options->block_size;
4516 if (blockSize < 2)
4517 {
4518 throw ParseException(
4519 fmt::format("Operation has invalid block size: {} Block size should be >= 2 {}",
4520 blockSize,
4521 CHECK_LOCATION().AsString()));
4522 }
4523 descriptor.m_BlockSize = armnn::numeric_cast<uint32_t>(blockSize);
4524
4525 auto layerName = fmt::format("DepthToSpace:{}:{}", subgraphIndex, operatorIndex);
4526 IConnectableLayer* layer = m_Network->AddDepthToSpaceLayer(descriptor, layerName.c_str());
4527 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00004528 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Sadik Armagan26868492021-01-22 14:25:31 +00004529 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4530
4531 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4532 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4533
4534 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4535 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4536}
4537
Kevin May7d96b162021-02-03 17:38:41 +00004538void TfLiteParserImpl::ParseSum(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004539{
Sadik Armagana2747482021-02-09 10:28:54 +00004540 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Sum);
4541}
4542
Teresa Charlin4e3e8312021-08-05 12:34:37 +01004543void TfLiteParserImpl::ParseReduceProd(size_t subgraphIndex, size_t operatorIndex)
4544{
4545 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Prod);
4546}
4547
Sadik Armagana2747482021-02-09 10:28:54 +00004548void TfLiteParserImpl::ParseReduceMax(size_t subgraphIndex, size_t operatorIndex)
4549{
4550 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Max);
4551}
4552
4553void TfLiteParserImpl::ParseReduceMin(size_t subgraphIndex, size_t operatorIndex)
4554{
4555 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Min);
4556}
4557
4558void TfLiteParserImpl::ParseReduce(size_t subgraphIndex, size_t operatorIndex, ReduceOperation reduceOperation)
4559{
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004560 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4561
Mike Kelly0d77ae12022-01-07 17:42:27 +00004562 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4563 const auto* options = operatorPtr->builtin_options.AsReducerOptions();
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004564
4565 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4566 CHECK_VALID_SIZE(inputs.size(), 2);
4567
4568 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4569 CHECK_VALID_SIZE(outputs.size(), 1);
4570
Sadik Armagana2747482021-02-09 10:28:54 +00004571 auto layerName = fmt::format("Reduce:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004572
Mike Kelly377fb212023-01-10 15:55:28 +00004573 armnn::TensorInfo inputTensorInfo0 = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4574 armnn::TensorInfo inputTensorInfo1 = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004575
4576 ReduceDescriptor desc;
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004577 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
4578 // Get const axis value from model and set it to descriptor.
4579 if (axisBufferPtr != nullptr)
4580 {
Sadik Armagan49bdb792021-02-11 13:57:07 +00004581 std::vector<int32_t> axisData(inputTensorInfo1.GetNumElements());
4582 ::memcpy(axisData.data(), axisBufferPtr->data.data(), inputTensorInfo1.GetNumBytes());
4583
4584 // Convert the axis to unsigned int and remove duplicates.
4585 auto rank = static_cast<int32_t>(inputTensorInfo0.GetNumDimensions());
4586 std::set<unsigned int> uniqueAxis;
4587 std::transform(axisData.begin(),
4588 axisData.end(),
4589 std::inserter(uniqueAxis, uniqueAxis.begin()),
4590 [rank](int i)->unsigned int{
4591 return static_cast<uint32_t>(((i + rank) % rank)); });
4592 desc.m_vAxis.assign(uniqueAxis.begin(), uniqueAxis.end());
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004593 }
Sadik Armagana2747482021-02-09 10:28:54 +00004594 else
4595 {
4596 for (uint32_t i = 0; i < inputTensorInfo0.GetNumDimensions(); ++i)
4597 {
4598 desc.m_vAxis.push_back(i);
4599 }
4600 }
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004601
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004602 desc.m_KeepDims = options->keep_dims;
Sadik Armagana2747482021-02-09 10:28:54 +00004603 desc.m_ReduceOperation = reduceOperation;
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004604
4605 // Register a new layer object, Sum.
Mike Kelly0d77ae12022-01-07 17:42:27 +00004606 IConnectableLayer* layer = m_Network->AddReduceLayer(desc, layerName.c_str());
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004607
Mike Kelly377fb212023-01-10 15:55:28 +00004608 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004609 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4610
4611 // Register input tensor to the layer.
4612 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4613 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4614
4615 // Register output tensor to the layer.
4616 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4617 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4618}
4619
Mike Kelly31dce2b2021-09-01 21:22:37 +01004620void TfLiteParserImpl::ParseLocalResponseNormalization(size_t subgraphIndex, size_t operatorIndex)
4621{
4622 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4623
4624 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4625 CHECK_VALID_SIZE(inputs.size(), 1);
4626
4627 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4628 CHECK_VALID_SIZE(outputs.size(), 1);
4629
4630 auto layerName = fmt::format("LRN:{}:{}", subgraphIndex, operatorIndex);
4631 std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4632
Mike Kelly377fb212023-01-10 15:55:28 +00004633 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Mike Kelly31dce2b2021-09-01 21:22:37 +01004634
4635 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4636 const auto* options = operatorPtr->builtin_options.AsLocalResponseNormalizationOptions();
4637
4638 armnn::NormalizationDescriptor descriptor;
4639 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
4640 descriptor.m_NormChannelType = armnn::NormalizationAlgorithmChannel::Across;
4641 descriptor.m_NormMethodType = armnn::NormalizationAlgorithmMethod::LocalBrightness;
4642 descriptor.m_NormSize = static_cast<uint32_t>(options->radius);
4643 descriptor.m_K = options->bias;
4644 descriptor.m_Alpha = options->alpha;
4645 descriptor.m_Beta = options->beta;
4646
4647 // ArmNN expects normSize to be the full size of the normalization
4648 // window rather than the radius as in TfLite.
4649 descriptor.m_NormSize = 1 + (2 * descriptor.m_NormSize);
4650
4651 IConnectableLayer* layer = m_Network->AddNormalizationLayer(descriptor, layerNameFormatted.c_str());
4652 ARMNN_ASSERT(layer != nullptr);
4653
Mike Kelly377fb212023-01-10 15:55:28 +00004654 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Mike Kelly31dce2b2021-09-01 21:22:37 +01004655 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4656
4657 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4658 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4659
4660 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4661 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4662}
4663
Teresa Charlin28aa6692022-07-12 11:18:44 +01004664void TfLiteParserImpl::ParseAbs(size_t subgraphIndex, size_t operatorIndex)
4665{
4666 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Abs);
4667}
4668
Teresa Charlin93f0ad02023-03-23 15:28:02 +00004669void TfLiteParserImpl::ParseCeil(size_t subgraphIndex, size_t operatorIndex)
4670{
4671 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Ceil);
4672}
4673
Teresa Charlin28aa6692022-07-12 11:18:44 +01004674void TfLiteParserImpl::ParseExp(size_t subgraphIndex, size_t operatorIndex)
4675{
4676 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Exp);
4677}
4678
4679void TfLiteParserImpl::ParseLog(size_t subgraphIndex, size_t operatorIndex)
4680{
4681 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Log);
4682}
4683
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004684void TfLiteParserImpl::ParseLogicalNot(size_t subgraphIndex, size_t operatorIndex)
4685{
4686 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::LogicalNot);
4687}
4688
4689void TfLiteParserImpl::ParseNeg(size_t subgraphIndex, size_t operatorIndex)
4690{
4691 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Neg);
4692}
4693
John Mcloughlin0ec00872023-05-15 17:03:49 +01004694void TfLiteParserImpl::ParsePower(size_t subgraphIndex, size_t operatorIndex)
4695{
4696 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4697
4698 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4699 CHECK_VALID_SIZE(inputs.size(), 2);
4700
4701 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4702 CHECK_VALID_SIZE(outputs.size(), 1);
4703
4704 auto layerName = fmt::format("Power:{}:{}", subgraphIndex, operatorIndex);
4705
4706 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4707 TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
4708 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
4709
4710 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Power, layerName.c_str());
4711 ARMNN_ASSERT(layer != nullptr);
4712
4713 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
4714 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
4715 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4716
4717 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4718 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4719
4720 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4721 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4722}
4723
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004724void TfLiteParserImpl::ParseRsqrt(size_t subgraphIndex, size_t operatorIndex)
4725{
4726 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Rsqrt);
4727}
4728
Teresa Charlin28aa6692022-07-12 11:18:44 +01004729void TfLiteParserImpl::ParseSin(size_t subgraphIndex, size_t operatorIndex)
4730{
4731 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Sin);
4732}
4733
Teresa Charlinf0fce5b2022-05-04 17:24:43 +01004734void TfLiteParserImpl::ParseSqrt(size_t subgraphIndex, size_t operatorIndex)
4735{
4736 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Sqrt);
4737}
4738
Teresa Charlin6963b332023-07-11 11:35:41 +01004739void TfLiteParserImpl::ParseSquare(size_t subgraphIndex, size_t operatorIndex)
4740{
4741 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4742
4743 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4744 CHECK_VALID_SIZE(inputs.size(), 1);
4745
4746 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4747 CHECK_VALID_SIZE(outputs.size(), 1);
4748
4749 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4750
4751 auto layerName = fmt::format("Square:{}:{}", subgraphIndex, operatorIndex);
4752 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Mul, layerName.c_str());
4753 ARMNN_ASSERT(layer != nullptr);
4754
4755 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 0});
4756 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
4757 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4758
4759 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4760 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[0]});
4761
4762 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4763 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4764}
4765
John Mcloughlin0ec00872023-05-15 17:03:49 +01004766void TfLiteParserImpl::ParseSquaredDifference(size_t subgraphIndex, size_t operatorIndex)
4767{
4768 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4769
4770 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4771 CHECK_VALID_SIZE(inputs.size(), 2);
4772
4773 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4774 CHECK_VALID_SIZE(outputs.size(), 1);
4775
4776 auto layerName = fmt::format("SquaredDifference:{}:{}", subgraphIndex, operatorIndex);
4777
4778 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4779 TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
4780 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
4781
4782 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::SqDiff, layerName.c_str());
4783 ARMNN_ASSERT(layer != nullptr);
4784
4785 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
4786 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
4787 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4788
4789 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4790 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4791
4792 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4793 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4794}
4795
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004796void TfLiteParserImpl::ParseElementwiseUnary(size_t subgraphIndex, size_t operatorIndex, UnaryOperation unaryOperation)
4797{
4798 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4799
4800 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4801 CHECK_VALID_SIZE(inputs.size(), 1);
4802
4803 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4804 CHECK_VALID_SIZE(outputs.size(), 1);
4805
4806 std::string layerName = std::string(GetUnaryOperationAsCString(unaryOperation)) + ":{}:{}";
4807 std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4808
4809 ElementwiseUnaryDescriptor desc;
4810 desc.m_Operation = unaryOperation;
4811 IConnectableLayer* layer = m_Network->AddElementwiseUnaryLayer(desc, layerNameFormatted.c_str());
4812 ARMNN_ASSERT(layer != nullptr);
4813
Mike Kelly377fb212023-01-10 15:55:28 +00004814 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004815 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4816
4817 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4818 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4819
4820 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4821 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4822}
4823
Bruno Goncalves2d0eb862021-07-11 14:10:15 -03004824void TfLiteParserImpl::ParseEqual(size_t subgraphIndex, size_t operatorIndex)
4825{
4826 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::Equal);
4827}
4828
4829void TfLiteParserImpl::ParseNotEqual(size_t subgraphIndex, size_t operatorIndex)
4830{
4831 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::NotEqual);
4832}
4833
4834void TfLiteParserImpl::ParseGreater(size_t subgraphIndex, size_t operatorIndex)
4835{
4836 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::Greater);
4837}
4838
4839void TfLiteParserImpl::ParseGreaterOrEqual(size_t subgraphIndex, size_t operatorIndex)
4840{
4841 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::GreaterOrEqual);
4842}
4843
4844void TfLiteParserImpl::ParseLess(size_t subgraphIndex, size_t operatorIndex)
4845{
4846 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::Less);
4847}
4848
4849void TfLiteParserImpl::ParseLessOrEqual(size_t subgraphIndex, size_t operatorIndex)
4850{
4851 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::LessOrEqual);
4852}
4853
4854void TfLiteParserImpl::ParseComparison(size_t subgraphIndex, size_t operatorIndex,
4855 ComparisonOperation comparisonOperation)
4856{
4857 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4858
4859 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4860 CHECK_VALID_SIZE(inputs.size(), 2);
4861
4862 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4863 CHECK_VALID_SIZE(outputs.size(), 1);
4864
4865 auto layerName = std::string(GetComparisonOperationAsCString(comparisonOperation)) + ":{}:{}";
4866 std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4867
Mike Kelly377fb212023-01-10 15:55:28 +00004868 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4869 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves2d0eb862021-07-11 14:10:15 -03004870 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerNameFormatted, "Input 0", "Input 1");
4871
4872 ComparisonDescriptor desc;
4873 desc.m_Operation = comparisonOperation;
4874 IConnectableLayer* layer = m_Network->AddComparisonLayer(desc, layerNameFormatted.c_str());
4875 ARMNN_ASSERT(layer != nullptr);
4876
Mike Kelly377fb212023-01-10 15:55:28 +00004877 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Bruno Goncalves2d0eb862021-07-11 14:10:15 -03004878 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4879
4880 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4881 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4882
4883 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4884 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4885}
4886
Mike Kelly04d82292023-01-19 18:29:40 +00004887armnn::IConnectableLayer* TfLiteParserImpl::AddReshapeLayer(armnn::IConnectableLayer* layer,
4888 unsigned int outputSlot,
4889 std::string reshapeLayerName,
4890 armnn::TensorInfo outputShape)
4891{
4892 ReshapeDescriptor desc;
4893 desc.m_TargetShape = outputShape.GetShape();
4894
4895 IConnectableLayer* reshapeLayer =
4896 m_Network->AddReshapeLayer(desc, reshapeLayerName.c_str());
4897
4898 auto & prevOutputSlot = layer->GetOutputSlot(outputSlot);
4899 prevOutputSlot.Connect(reshapeLayer->GetInputSlot(0));
4900 reshapeLayer->GetOutputSlot(0).SetTensorInfo(outputShape);
4901 return reshapeLayer;
4902}
4903
Kevin May7d96b162021-02-03 17:38:41 +00004904armnn::IConnectableLayer* TfLiteParserImpl::AddFusedActivationLayer(armnn::IConnectableLayer* prevLayer,
4905 unsigned int outputSlot,
4906 tflite::ActivationFunctionType activationType)
telsoa01c577f2c2018-08-31 09:22:23 +01004907{
4908 ActivationDescriptor activationDesc;
4909 std::string layerName = prevLayer->GetName();
4910
4911 switch(activationType)
4912 {
4913 case tflite::ActivationFunctionType_NONE:
4914 {
4915 // this is a no-op: return previous layer
4916 return prevLayer;
4917 }
4918 case tflite::ActivationFunctionType_RELU:
4919 {
4920 activationDesc.m_Function = ActivationFunction::ReLu;
4921 layerName += ":RELU";
4922 break;
4923 }
4924 case tflite::ActivationFunctionType_RELU6:
4925 {
4926 activationDesc.m_Function = ActivationFunction::BoundedReLu;
4927 activationDesc.m_A = 6.0f;
4928 activationDesc.m_B = 0.0f;
4929 layerName += ":RELU6";
4930 break;
4931 }
4932 case tflite::ActivationFunctionType_TANH:
4933 {
4934 activationDesc.m_Function = ActivationFunction::TanH;
4935 activationDesc.m_A = 1.0f;
4936 activationDesc.m_B = 1.0f;
4937 layerName += ":TANH";
4938 break;
4939 }
4940
4941 // I only put these here as a reminder what others we could support
4942 case tflite::ActivationFunctionType_RELU_N1_TO_1:
4943 case tflite::ActivationFunctionType_SIGN_BIT:
4944 default:
4945 {
4946 throw ParseException(
Mike Kelly377fb212023-01-10 15:55:28 +00004947 fmt::format("TfLite parser doesn't support fused activation: "
James Ward58dec6b2020-09-11 17:32:44 +01004948 "{}/{} {} ",
4949 activationType,
4950 tflite::EnumNameActivationFunctionType(activationType),
4951 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01004952
4953 }
4954 }
4955
4956 IConnectableLayer* activationLayer =
4957 m_Network->AddActivationLayer(activationDesc, layerName.c_str());
4958
4959 auto & prevOutputSlot = prevLayer->GetOutputSlot(outputSlot);
4960 prevOutputSlot.Connect(activationLayer->GetInputSlot(0));
4961 activationLayer->GetOutputSlot(0).SetTensorInfo(prevOutputSlot.GetTensorInfo());
4962 return activationLayer;
4963}
4964
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004965armnn::IConnectableLayer* TfLiteParserImpl::AddFusedFloorLayer(armnn::IConnectableLayer* prevLayer,
4966 unsigned int outputSlot)
4967{
Teresa Charlin725728e2022-05-05 13:33:33 +01004968
4969 auto& prevOutputSlot = prevLayer->GetOutputSlot(outputSlot);
4970 DataType dataType = prevOutputSlot.GetTensorInfo().GetDataType();
4971
4972 if (dataType == DataType::Signed32)
4973 {
4974 return prevLayer;
4975 }
4976
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004977 std::string layerName = prevLayer->GetName();
4978 IConnectableLayer* floorLayer = m_Network->AddFloorLayer(layerName.c_str());
4979
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004980 prevOutputSlot.Connect(floorLayer->GetInputSlot(0));
4981 floorLayer->GetOutputSlot(0).SetTensorInfo(prevOutputSlot.GetTensorInfo());
Teresa Charlin725728e2022-05-05 13:33:33 +01004982
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004983 return floorLayer;
4984}
4985
Mike Kelly0d77ae12022-01-07 17:42:27 +00004986TfLiteParserImpl::ModelPtr TfLiteParserImpl::LoadModelFromFile(const char* fileName)
telsoa01c577f2c2018-08-31 09:22:23 +01004987{
4988 if (fileName == nullptr)
4989 {
James Ward58dec6b2020-09-11 17:32:44 +01004990 throw InvalidArgumentException(fmt::format("Invalid (null) file name {}",
telsoa01c577f2c2018-08-31 09:22:23 +01004991 CHECK_LOCATION().AsString()));
4992 }
Francis Murtagh532a29d2020-06-29 11:50:01 +01004993 std::error_code errorCode;
4994 fs::path pathToFile(fileName);
4995 if (!fs::exists(pathToFile, errorCode))
telsoa01c577f2c2018-08-31 09:22:23 +01004996 {
James Ward58dec6b2020-09-11 17:32:44 +01004997 //fmt::format() could not be used here (format error)
4998 std::stringstream msg;
4999 msg << "Cannot find the file (" << fileName << ") errorCode: " << errorCode
5000 << " " << CHECK_LOCATION().AsString();
James Ward58dec6b2020-09-11 17:32:44 +01005001 throw FileNotFoundException(msg.str());
telsoa01c577f2c2018-08-31 09:22:23 +01005002 }
Colm Donelan0dfb2652023-06-22 10:19:17 +01005003 if (!fs::is_regular_file(pathToFile))
5004 {
5005 // Exclude non regular files.
5006 throw InvalidArgumentException(fmt::format("File \"{}\" is not a regular file and cannot be loaded.",
5007 pathToFile.c_str()));
5008 }
5009
telsoa01c577f2c2018-08-31 09:22:23 +01005010 std::ifstream file(fileName, std::ios::binary);
5011 std::string fileContent((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
5012 return LoadModelFromBinary(reinterpret_cast<const uint8_t *>(fileContent.c_str()),
5013 fileContent.size());
5014}
5015
Mike Kelly0d77ae12022-01-07 17:42:27 +00005016TfLiteParserImpl::ModelPtr TfLiteParserImpl::LoadModelFromBinary(const uint8_t* binaryContent, size_t len)
telsoa01c577f2c2018-08-31 09:22:23 +01005017{
5018 if (binaryContent == nullptr)
5019 {
James Ward58dec6b2020-09-11 17:32:44 +01005020 throw InvalidArgumentException(fmt::format("Invalid (null) binary content {}",
telsoa01c577f2c2018-08-31 09:22:23 +01005021 CHECK_LOCATION().AsString()));
5022 }
5023 flatbuffers::Verifier verifier(binaryContent, len);
5024 if (verifier.VerifyBuffer<tflite::Model>() == false)
5025 {
5026 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01005027 fmt::format("Buffer doesn't conform to the expected Tensorflow Lite "
5028 "flatbuffers format. size:{} {}",
5029 len,
5030 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01005031 }
5032 return tflite::UnPackModel(binaryContent);
5033}
5034
Mike Kelly0d77ae12022-01-07 17:42:27 +00005035TfLiteParserImpl::TensorRawPtrVector TfLiteParserImpl::GetInputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00005036 size_t subgraphIndex,
5037 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005038{
5039 CHECK_MODEL(model, subgraphIndex, operatorIndex);
5040
Mike Kelly0d77ae12022-01-07 17:42:27 +00005041 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
5042 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01005043
5044 size_t inputCount = operatorPtr->inputs.size();
mathad01c21025d2021-04-26 10:09:37 +01005045 TensorRawPtrVector result;
Mike Kelly0d77ae12022-01-07 17:42:27 +00005046 for (size_t i = 0; i < inputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01005047 {
mathad01c21025d2021-04-26 10:09:37 +01005048 // If the input location is -1 then assume input is turned off.
5049 if (operatorPtr->inputs[i] == -1)
5050 {
5051 continue;
5052 }
5053 else
5054 {
5055 uint32_t inputId = CHECKED_NON_NEGATIVE(operatorPtr->inputs[i]);
5056 result.push_back(subgraphPtr->tensors[inputId].get());
5057 }
telsoa01c577f2c2018-08-31 09:22:23 +01005058 }
5059 return result;
5060}
5061
Mike Kelly0d77ae12022-01-07 17:42:27 +00005062TfLiteParserImpl::TensorRawPtrVector TfLiteParserImpl::GetOutputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00005063 size_t subgraphIndex,
5064 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005065{
5066 CHECK_MODEL(model, subgraphIndex, operatorIndex);
5067
Mike Kelly0d77ae12022-01-07 17:42:27 +00005068 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
5069 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01005070
5071 size_t outputCount = operatorPtr->outputs.size();
5072 TensorRawPtrVector result(outputCount);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005073 for (size_t i = 0; i < outputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01005074 {
5075 uint32_t outputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[i]);
5076 CHECK_TENSOR(model, subgraphIndex, outputId);
Derek Lambertiff05cc52019-04-26 13:05:17 +01005077 result[i] = subgraphPtr->tensors[outputId].get();
telsoa01c577f2c2018-08-31 09:22:23 +01005078 }
5079 return result;
5080}
5081
Mike Kelly0d77ae12022-01-07 17:42:27 +00005082TfLiteParserImpl::TensorIdRawPtrVector TfLiteParserImpl::GetSubgraphInputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00005083 size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005084{
5085 CHECK_SUBGRAPH(model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005086 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01005087
Derek Lambertiff05cc52019-04-26 13:05:17 +01005088 size_t inputCount = subgraphPtr->inputs.size();
telsoa01c577f2c2018-08-31 09:22:23 +01005089 TensorIdRawPtrVector result(inputCount);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005090 for (size_t i = 0; i < inputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01005091 {
Derek Lambertiff05cc52019-04-26 13:05:17 +01005092 uint32_t inputId = CHECKED_NON_NEGATIVE(subgraphPtr->inputs[i]);
telsoa01c577f2c2018-08-31 09:22:23 +01005093 CHECK_TENSOR(model, subgraphIndex, inputId);
Derek Lambertiff05cc52019-04-26 13:05:17 +01005094 result[i] = std::make_pair(inputId, subgraphPtr->tensors[inputId].get());
telsoa01c577f2c2018-08-31 09:22:23 +01005095 }
5096 return result;
5097}
5098
Mike Kelly0d77ae12022-01-07 17:42:27 +00005099TfLiteParserImpl::TensorIdRawPtrVector TfLiteParserImpl::GetSubgraphOutputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00005100 size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005101{
5102 CHECK_SUBGRAPH(model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005103 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01005104
Derek Lambertiff05cc52019-04-26 13:05:17 +01005105 size_t outputCount = subgraphPtr->outputs.size();
telsoa01c577f2c2018-08-31 09:22:23 +01005106 TensorIdRawPtrVector result(outputCount);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005107 for (size_t i = 0; i < outputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01005108 {
Derek Lambertiff05cc52019-04-26 13:05:17 +01005109 uint32_t outputId = CHECKED_NON_NEGATIVE(subgraphPtr->outputs[i]);
5110 result[i] = std::make_pair(outputId, subgraphPtr->tensors[outputId].get());
telsoa01c577f2c2018-08-31 09:22:23 +01005111 }
5112 return result;
5113}
5114
Kevin May7d96b162021-02-03 17:38:41 +00005115std::vector<int32_t>& TfLiteParserImpl::GetInputTensorIds(const ModelPtr& model,
5116 size_t subgraphIndex,
5117 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005118{
5119 CHECK_MODEL(model, subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005120 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
5121 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01005122 return operatorPtr->inputs;
5123}
5124
Kevin May7d96b162021-02-03 17:38:41 +00005125std::vector<int32_t>& TfLiteParserImpl::GetOutputTensorIds(const ModelPtr& model,
5126 size_t subgraphIndex,
5127 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005128{
5129 CHECK_MODEL(model, subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005130 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
5131 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01005132 return operatorPtr->outputs;
5133}
5134
Kevin May7d96b162021-02-03 17:38:41 +00005135void TfLiteParserImpl::RegisterInputSlots(size_t subgraphIndex,
5136 size_t operatorIndex,
5137 IConnectableLayer* layer,
Finn Williamsd4fa5452021-03-01 12:31:41 +00005138 const std::vector<unsigned int>& tensorIndexes,
5139 unsigned int startingSlotIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005140{
5141 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01005142 ARMNN_ASSERT(layer != nullptr);
Matthew Sloyan81beae32021-07-13 19:46:11 +01005143
Finn Williamsd4fa5452021-03-01 12:31:41 +00005144 if (tensorIndexes.size() + startingSlotIndex != layer->GetNumInputSlots())
telsoa01c577f2c2018-08-31 09:22:23 +01005145 {
5146 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01005147 fmt::format("The number of tensor inputs ({}) does not match the number expected ({})"
5148 " for subgraph:{} operator index:{} {}",
5149 tensorIndexes.size(),
5150 layer->GetNumInputSlots(),
5151 subgraphIndex,
5152 operatorIndex,
5153 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01005154 }
5155
Finn Williamsd4fa5452021-03-01 12:31:41 +00005156 for (unsigned int index = 0; index < tensorIndexes.size() ; ++index)
telsoa01c577f2c2018-08-31 09:22:23 +01005157 {
Finn Williamsd4fa5452021-03-01 12:31:41 +00005158 unsigned int tensorIndex = tensorIndexes[index];
5159 armnn::IInputSlot* slot = &(layer->GetInputSlot(startingSlotIndex + index));
telsoa01c577f2c2018-08-31 09:22:23 +01005160 RegisterConsumerOfTensor(subgraphIndex, tensorIndex, slot);
5161 }
5162}
5163
Kevin May7d96b162021-02-03 17:38:41 +00005164void TfLiteParserImpl::RegisterOutputSlots(size_t subgraphIndex,
5165 size_t operatorIndex,
5166 IConnectableLayer* layer,
5167 const std::vector<unsigned int>& tensorIndexes)
telsoa01c577f2c2018-08-31 09:22:23 +01005168{
5169 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01005170 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01005171 if (tensorIndexes.size() != layer->GetNumOutputSlots())
5172 {
5173 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01005174 fmt::format("The number of tensor outputs ({}) does not match the number expected ({})"
5175 " for subgraph:{} operator index:{} {}",
5176 tensorIndexes.size(),
5177 layer->GetNumOutputSlots(),
5178 subgraphIndex,
5179 operatorIndex,
5180 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01005181 }
5182
5183 for (unsigned int slotIndex = 0; slotIndex < layer->GetNumOutputSlots(); ++slotIndex)
5184 {
5185 unsigned int tensorIndex = tensorIndexes[slotIndex];
5186 armnn::IOutputSlot* slot = &(layer->GetOutputSlot(slotIndex));
5187 RegisterProducerOfTensor(subgraphIndex, tensorIndex, slot);
5188 }
5189}
5190
Mike Kelly377fb212023-01-10 15:55:28 +00005191void TfLiteParserImpl::SetupInputLayerTensorInfos(size_t subgraphIndex)
5192{
5193 CHECK_SUBGRAPH(m_Model, subgraphIndex);
5194
5195 auto inputs = GetSubgraphInputs(m_Model, subgraphIndex);
5196 for (auto const& tensorIdAndPtr : inputs)
5197 {
5198 auto tensorInfo = ToTensorInfo(tensorIdAndPtr.second);
5199 m_TensorInfos.insert({tensorIdAndPtr.first, tensorInfo});
5200 }
5201}
5202
Kevin May7d96b162021-02-03 17:38:41 +00005203void TfLiteParserImpl::SetupInputLayers(size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005204{
5205 CHECK_SUBGRAPH(m_Model, subgraphIndex);
5206
5207 auto inputs = GetSubgraphInputs(m_Model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005208 for (auto const& tensorIdAndPtr : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005209 {
5210 auto bindingId = GenerateLayerBindingId(subgraphIndex, tensorIdAndPtr.first);
5211 IConnectableLayer* layer =
5212 m_Network->AddInputLayer(bindingId, tensorIdAndPtr.second->name.c_str());
5213
5214 auto tensorInfo = ToTensorInfo(tensorIdAndPtr.second);
5215 layer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
5216
5217 RegisterOutputSlots(subgraphIndex,
5218 VIRTUAL_OPERATOR_ID,
5219 layer,
5220 { static_cast<uint32_t>(tensorIdAndPtr.first) });
5221 }
5222}
5223
Kevin May7d96b162021-02-03 17:38:41 +00005224void TfLiteParserImpl::SetupOutputLayers(size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005225{
5226 CHECK_SUBGRAPH(m_Model, subgraphIndex);
5227
5228 auto outputs = GetSubgraphOutputs(m_Model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005229 for (auto const& tensorIdAndPtr : outputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005230 {
5231 auto bindingId = GenerateLayerBindingId(subgraphIndex, tensorIdAndPtr.first);
5232 IConnectableLayer* layer =
5233 m_Network->AddOutputLayer(bindingId, tensorIdAndPtr.second->name.c_str());
5234
5235 RegisterInputSlots(subgraphIndex,
5236 VIRTUAL_OPERATOR_ID,
5237 layer,
5238 { static_cast<uint32_t>(tensorIdAndPtr.first) });
5239 }
5240}
5241
Mike Kelly377fb212023-01-10 15:55:28 +00005242void TfLiteParserImpl::SetupConstantLayerTensorInfos(size_t subgraph)
5243{
5244 CHECK_SUBGRAPH(m_Model, subgraph);
5245
5246 const auto & subgraphPtr = m_Model->subgraphs[subgraph];
5247 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 {
5254 TensorRawPtr tensorPtr = subgraphPtr->tensors[tensorIndex].get();
5255
5256 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
5257
5258 m_TensorInfos.insert({tensorIndex, tensorInfo});
5259 }
5260 }
5261 }
5262}
5263
Mike Kelly5880b912022-01-28 16:18:54 +00005264void TfLiteParserImpl::SetupConstantLayers(size_t subgraph)
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005265{
Mike Kelly5880b912022-01-28 16:18:54 +00005266 CHECK_SUBGRAPH(m_Model, subgraph);
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005267
Mike Kelly5880b912022-01-28 16:18:54 +00005268 const auto & subgraphPtr = m_Model->subgraphs[subgraph];
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005269 for (unsigned int subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex)
5270 {
5271 for (unsigned int tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex)
5272 {
5273 if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot == nullptr &&
5274 m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size() > 0)
5275 {
Derek Lambertiff05cc52019-04-26 13:05:17 +01005276 TensorRawPtr tensorPtr = subgraphPtr->tensors[tensorIndex].get();
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005277
Mike Kelly5880b912022-01-28 16:18:54 +00005278 if (IsConstTensor(tensorPtr))
Matthew Sloyan81beae32021-07-13 19:46:11 +01005279 {
5280 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
Mike Kelly5880b912022-01-28 16:18:54 +00005281 armnn::DataType dataType = tensorInfo.GetDataType();
5282
5283 if (std::find(m_ConstantsToDequantize.begin(), m_ConstantsToDequantize.end(), tensorPtr->buffer)
5284 != m_ConstantsToDequantize.end())
5285 {
5286 dataType = DataType::Float32;
5287 }
5288 auto tensorAndData = CreateConstTensorNonPermuted(tensorPtr, tensorInfo, dataType);
5289
5290 std::string layerName = fmt::format("Constant:{}", tensorPtr->name);
5291 IConnectableLayer *layer = m_Network->AddConstantLayer(tensorAndData.first, layerName.c_str());
5292
5293 layer->GetOutputSlot(0).SetTensorInfo(tensorAndData.first.GetInfo());
5294 RegisterOutputSlots(subgraphIndex,
5295 VIRTUAL_OPERATOR_ID,
5296 layer,
5297 { tensorIndex });
5298 }
5299 else if (ShouldConstantTensorBeCreated(tensorIndex))
5300 {
5301 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
5302 armnn::DataType dataType = tensorInfo.GetDataType();
5303
5304 if (std::find(m_ConstantsToDequantize.begin(), m_ConstantsToDequantize.end(), tensorPtr->buffer)
5305 != m_ConstantsToDequantize.end())
5306 {
5307 dataType = DataType::Float32;
5308 }
5309 // Make sure isConstant flag is set.
5310 tensorInfo.SetConstant();
5311 tensorInfo.SetDataType(dataType);
5312
5313 auto tensorAndData = ConstTensor(tensorInfo, std::vector<uint8_t>(tensorInfo.GetNumBytes()));
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005314
Matthew Sloyan81beae32021-07-13 19:46:11 +01005315 std::string layerName = fmt::format("Constant:{}", tensorPtr->name);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005316 IConnectableLayer* layer = m_Network->AddConstantLayer(tensorAndData, layerName.c_str());
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005317
Matthew Sloyan81beae32021-07-13 19:46:11 +01005318 layer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
5319 RegisterOutputSlots(subgraphIndex,
5320 VIRTUAL_OPERATOR_ID,
5321 layer,
Mike Kelly5880b912022-01-28 16:18:54 +00005322 {tensorIndex});
Matthew Sloyan81beae32021-07-13 19:46:11 +01005323 }
5324 else
5325 {
5326 throw ParseException(
5327 fmt::format("Invalid Tensor: Tensor should be constant. {}",
5328 CHECK_LOCATION().AsString()));
5329 }
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005330 }
5331 }
5332 }
5333}
5334
telsoa01c577f2c2018-08-31 09:22:23 +01005335// example usage: BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[0]->buffer);
Kevin May7d96b162021-02-03 17:38:41 +00005336TfLiteParserImpl::BufferRawPtr TfLiteParserImpl::GetBuffer(const ModelPtr& model, size_t bufferIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005337{
5338 CHECK_BUFFER(model, bufferIndex);
5339 return model->buffers[bufferIndex].get();
5340}
5341
Matteo Martincigh747ef822018-12-18 09:26:39 +00005342template<typename T>
Kevin May7d96b162021-02-03 17:38:41 +00005343std::pair<armnn::ConstTensor, TfLiteParserImpl::SupportedDataStorage>
5344TfLiteParserImpl::CreateConstTensorAndStoreData(TfLiteParserImpl::BufferRawPtr bufferPtr,
5345 TfLiteParserImpl::TensorRawPtr tensorPtr,
Matteo Martincigh747ef822018-12-18 09:26:39 +00005346 armnn::TensorInfo& tensorInfo,
5347 armnn::Optional<armnn::PermutationVector&> permutationVector)
5348{
Matthew Sloyan81beae32021-07-13 19:46:11 +01005349 // Make sure isConstant flag is set.
5350 tensorInfo.SetConstant();
5351
Matteo Martincigh747ef822018-12-18 09:26:39 +00005352 auto constData = CreateConstTensorImpl<T>(bufferPtr,
5353 tensorPtr,
5354 tensorInfo,
5355 permutationVector);
Kevin May7d96b162021-02-03 17:38:41 +00005356 TfLiteParserImpl::SupportedDataStorage storage(std::move(constData.second));
Matteo Martincigh747ef822018-12-18 09:26:39 +00005357 return std::make_pair(constData.first, std::move(storage));
5358}
5359
Mike Kelly5880b912022-01-28 16:18:54 +00005360bool TfLiteParserImpl::ShouldConstantTensorBeCreated(unsigned int tensorIndex)
5361{
5362 // If the TensorIndex appears in the list of ConstantsToBeCreated then return true
5363 return (std::find(m_ConstantsToBeCreated.begin(), m_ConstantsToBeCreated.end(), tensorIndex)
5364 != m_ConstantsToBeCreated.end());
5365}
5366
Finn Williamsd4fa5452021-03-01 12:31:41 +00005367bool TfLiteParserImpl::IsConstTensor(TensorRawPtr tensorPtr)
5368{
5369 CHECK_TENSOR_PTR(tensorPtr);
mathad01bf7edb62021-04-20 16:12:45 +01005370 bool isConst = true;
5371
5372 auto buffer = GetBuffer(m_Model, tensorPtr->buffer);
5373 if (buffer->data.size() == 0)
5374 {
5375 isConst = false;
5376 }
5377
5378 return isConst;
Finn Williamsd4fa5452021-03-01 12:31:41 +00005379}
5380
Kevin May7d96b162021-02-03 17:38:41 +00005381std::pair<armnn::ConstTensor, TfLiteParserImpl::SupportedDataStorage>
Finn Williamsd4fa5452021-03-01 12:31:41 +00005382TfLiteParserImpl::CreateConstTensorPermuted(TensorRawPtr tensorPtr,
5383 armnn::TensorInfo& tensorInfo,
5384 armnn::Optional<armnn::PermutationVector&> permutationVector)
telsoa01c577f2c2018-08-31 09:22:23 +01005385{
5386 CHECK_TENSOR_PTR(tensorPtr);
5387 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5388 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5389
Matthew Sloyan81beae32021-07-13 19:46:11 +01005390 // Make sure isConstant flag is set.
5391 tensorInfo.SetConstant();
5392
telsoa01c577f2c2018-08-31 09:22:23 +01005393 switch (tensorInfo.GetDataType())
5394 {
5395 case armnn::DataType::Float32:
Matteo Martincigh747ef822018-12-18 09:26:39 +00005396 return CreateConstTensorAndStoreData<float>(bufferPtr,
5397 tensorPtr,
5398 tensorInfo,
5399 permutationVector);
Derek Lambertif90c56d2020-01-10 17:14:08 +00005400 case armnn::DataType::QAsymmU8:
Matteo Martincigh747ef822018-12-18 09:26:39 +00005401 return CreateConstTensorAndStoreData<uint8_t>(bufferPtr,
5402 tensorPtr,
5403 tensorInfo,
5404 permutationVector);
Keith Davisd305e1a2020-01-22 11:57:54 +00005405 case armnn::DataType::QSymmS8:
5406 return CreateConstTensorAndStoreData<int8_t>(bufferPtr,
5407 tensorPtr,
5408 tensorInfo,
5409 permutationVector);
Keith Davis67e6c542020-02-19 10:08:33 +00005410 case armnn::DataType::QAsymmS8:
5411 return CreateConstTensorAndStoreData<int8_t>(bufferPtr,
5412 tensorPtr,
5413 tensorInfo,
5414 permutationVector);
telsoa01c577f2c2018-08-31 09:22:23 +01005415 case armnn::DataType::Signed32:
Matteo Martincigh747ef822018-12-18 09:26:39 +00005416 return CreateConstTensorAndStoreData<int32_t>(bufferPtr,
5417 tensorPtr,
5418 tensorInfo,
5419 permutationVector);
telsoa01c577f2c2018-08-31 09:22:23 +01005420 default:
5421 {
5422 std::stringstream errString;
5423 errString << "Unexpected datatype when creating const tensor: "
5424 << armnn::GetDataTypeName(tensorInfo.GetDataType())
5425 << " shape:" << tensorInfo.GetShape()
5426 << CHECK_LOCATION().AsString();
5427 throw ParseException(errString.str());
5428 }
5429 }
5430}
5431
Finn Williamsd4fa5452021-03-01 12:31:41 +00005432armnn::ConstTensor TfLiteParserImpl::CreateConstTensorNonPermuted(TensorRawPtr tensorPtr,
5433 armnn::TensorInfo& tensorInfo)
5434{
5435 CHECK_TENSOR_PTR(tensorPtr);
5436 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5437 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5438
Matthew Sloyan81beae32021-07-13 19:46:11 +01005439 // Make sure isConstant flag is set.
5440 tensorInfo.SetConstant();
5441
Finn Williamsd4fa5452021-03-01 12:31:41 +00005442 return ConstTensor(tensorInfo, bufferPtr->data.data());
5443}
5444
Mike Kelly5880b912022-01-28 16:18:54 +00005445std::pair<armnn::ConstTensor, std::unique_ptr<float[]>>
5446TfLiteParserImpl::CreateConstTensorNonPermuted(TensorRawPtr tensorPtr,
5447 armnn::TensorInfo& tensorInfo,
5448 armnn::DataType inputDataType)
5449{
5450 CHECK_TENSOR_PTR(tensorPtr);
5451 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5452 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5453
5454 // Make sure isConstant flag is set.
5455 tensorInfo.SetConstant();
5456
Mike Kelly0506ef02023-01-03 16:29:44 +00005457 if (inputDataType == DataType::Float32 && tensorInfo.GetDataType() != DataType::Float32)
Mike Kelly5880b912022-01-28 16:18:54 +00005458 {
Mike Kelly0506ef02023-01-03 16:29:44 +00005459 try
5460 {
5461 TensorInfo constTensorInfo(tensorInfo.GetShape(), DataType::Float32, 0.0f, 0, true);
5462 std::unique_ptr<float[]> data = armnnUtils::ToFloatArray(bufferPtr->data, tensorInfo);
5463 return std::make_pair(ConstTensor(constTensorInfo, data.get()), std::move(data));
5464 }
Cathal Corbett9c843c32023-01-09 17:51:37 +00005465 catch (InvalidArgumentException&)
Mike Kelly0506ef02023-01-03 16:29:44 +00005466 {
5467 throw ParseException(
5468 fmt::format("Unsupported input/weights combination: Input {} not supported with Weights {}",
5469 GetDataTypeName(DataType::Float32),
5470 GetDataTypeName(tensorInfo.GetDataType()),
5471 CHECK_LOCATION().AsString()));
5472 }
Mike Kelly5880b912022-01-28 16:18:54 +00005473 }
5474 else
5475 {
5476 return std::make_pair(ConstTensor(tensorInfo, bufferPtr->data.data()), std::unique_ptr<float[]>());
5477 }
5478}
5479
5480std::pair<armnn::ConstTensor*, std::unique_ptr<float[]>>
5481TfLiteParserImpl::CreateConstTensorPtr(TensorRawPtr tensorPtr, armnn::TensorInfo& inputTensorInfo)
5482{
5483 CHECK_TENSOR_PTR(tensorPtr);
5484 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
5485 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5486 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5487
5488 // Make sure isConstant flag is set.
5489 tensorInfo.SetConstant();
5490
5491 if (inputTensorInfo.GetDataType() == DataType::Float32 && tensorInfo.GetDataType() != DataType::Float32)
5492 {
Mike Kelly0506ef02023-01-03 16:29:44 +00005493 try
5494 {
5495 TensorInfo constTensorInfo(tensorInfo.GetShape(), DataType::Float32, 0.0f, 0, true);
5496 std::unique_ptr<float[]> data = armnnUtils::ToFloatArray(bufferPtr->data, tensorInfo);
5497 return std::make_pair(new ConstTensor(constTensorInfo, data.get()), std::move(data));
5498 }
Cathal Corbett9c843c32023-01-09 17:51:37 +00005499 catch (InvalidArgumentException&)
Mike Kelly0506ef02023-01-03 16:29:44 +00005500 {
5501 throw ParseException(
5502 fmt::format("Unsupported input/weights combination: Input {} not supported with Weights {}",
5503 GetDataTypeName(DataType::Float32),
5504 GetDataTypeName(tensorInfo.GetDataType()),
5505 CHECK_LOCATION().AsString()));
5506 }
Mike Kelly5880b912022-01-28 16:18:54 +00005507 }
5508 else
5509 {
5510 return std::make_pair(new ConstTensor(tensorInfo, bufferPtr->data.data()), std::unique_ptr<float[]>());
5511 }
5512}
5513
Kevin May7d96b162021-02-03 17:38:41 +00005514BindingPointInfo TfLiteParserImpl::GetNetworkInputBindingInfo(size_t subgraphId,
5515 const std::string& name) const
telsoa01c577f2c2018-08-31 09:22:23 +01005516{
5517 CHECK_SUBGRAPH(m_Model, subgraphId);
5518 auto inputs = GetSubgraphInputs(m_Model, subgraphId);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005519 for (auto const& input : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005520 {
5521 if (input.second->name == name)
5522 {
5523 auto bindingId = GenerateLayerBindingId(subgraphId, input.first);
Colm Donelan4bc993b2021-11-09 20:39:10 +00005524 auto inputTensorInfo = ToTensorInfo(input.second);
5525 // Input tensors are always treated as constant tensors during network execution.
5526 inputTensorInfo.SetConstant(true);
5527 return std::make_pair(bindingId, inputTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +01005528 }
5529 }
5530
5531 std::stringstream bindings;
Mike Kelly0d77ae12022-01-07 17:42:27 +00005532 for (auto const& input : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005533 {
5534 bindings << "'" << input.second->name << "' ";
5535 }
5536
5537 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01005538 fmt::format("No input binding found for subgraph:{} and name:{}. "
5539 "Possible inputs are: [{}] {}",
5540 subgraphId,
5541 name,
5542 bindings.str(),
5543 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01005544}
5545
Kevin May7d96b162021-02-03 17:38:41 +00005546BindingPointInfo TfLiteParserImpl::GetNetworkOutputBindingInfo(size_t subgraphId,
5547 const std::string& name) const
telsoa01c577f2c2018-08-31 09:22:23 +01005548{
5549 CHECK_SUBGRAPH(m_Model, subgraphId);
5550 auto outputs = GetSubgraphOutputs(m_Model, subgraphId);
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00005551 for (unsigned int i = 0; i < outputs.size(); ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01005552 {
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00005553 auto const output = outputs[i];
telsoa01c577f2c2018-08-31 09:22:23 +01005554 if (output.second->name == name)
5555 {
5556 auto bindingId = GenerateLayerBindingId(subgraphId, output.first);
Mike Kelly377fb212023-01-10 15:55:28 +00005557 std::vector<unsigned int> shape = m_OverriddenOutputShapes.size() > 0 ?
5558 m_OverriddenOutputShapes[i] : AsUnsignedVector(output.second->shape);
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00005559 return std::make_pair(bindingId, ToTensorInfo(output.second, shape));
telsoa01c577f2c2018-08-31 09:22:23 +01005560 }
5561 }
5562
5563 std::stringstream bindings;
Mike Kelly0d77ae12022-01-07 17:42:27 +00005564 for (auto const& output : outputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005565 {
5566 bindings << "'" << output.second->name << "' ";
5567 }
5568
5569 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01005570 fmt::format("No output binding found for subgraph:{} and name:{}. "
5571 "Possible outputs are: [{}] {}",
5572 subgraphId,
5573 name,
5574 bindings.str(),
5575 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01005576}
5577
Kevin May7d96b162021-02-03 17:38:41 +00005578size_t TfLiteParserImpl::GetSubgraphCount() const
telsoa01c577f2c2018-08-31 09:22:23 +01005579{
5580 return m_Model->subgraphs.size();
5581}
5582
Kevin May7d96b162021-02-03 17:38:41 +00005583std::vector<std::string> TfLiteParserImpl::GetSubgraphInputTensorNames(size_t subgraphId) const
telsoa01c577f2c2018-08-31 09:22:23 +01005584{
5585 CHECK_SUBGRAPH(m_Model, subgraphId);
5586 auto inputs = GetSubgraphInputs(m_Model, subgraphId);
5587 std::vector<std::string> result;
5588 result.reserve(inputs.size());
Mike Kelly0d77ae12022-01-07 17:42:27 +00005589 for (auto const& input : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005590 {
5591 result.push_back(input.second->name);
5592 }
5593 return result;
5594}
5595
Kevin May7d96b162021-02-03 17:38:41 +00005596std::vector<std::string> TfLiteParserImpl::GetSubgraphOutputTensorNames(size_t subgraphId) const
telsoa01c577f2c2018-08-31 09:22:23 +01005597{
5598 CHECK_SUBGRAPH(m_Model, subgraphId);
5599 auto outputs = GetSubgraphOutputs(m_Model, subgraphId);
5600 std::vector<std::string> result;
5601 result.reserve(outputs.size());
Mike Kelly0d77ae12022-01-07 17:42:27 +00005602 for (auto const& output : outputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005603 {
5604 result.push_back(output.second->name);
5605 }
5606 return result;
5607}
5608
Matthew Sloyanac001ee2021-02-03 10:43:04 +00005609const std::string TfLiteParserImpl::GetVersion()
5610{
5611 return TFLITE_PARSER_VERSION;
5612}
5613
Mike Kelly0d77ae12022-01-07 17:42:27 +00005614TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<float[]>&& data)
telsoa01c577f2c2018-08-31 09:22:23 +01005615: m_FloatData(std::move(data))
5616, m_Uint8Data(nullptr)
Keith Davisd305e1a2020-01-22 11:57:54 +00005617, m_Int8Data(nullptr)
telsoa01c577f2c2018-08-31 09:22:23 +01005618, m_Int32Data(nullptr)
5619{
5620}
5621
Mike Kelly0d77ae12022-01-07 17:42:27 +00005622TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<uint8_t[]>&& data)
telsoa01c577f2c2018-08-31 09:22:23 +01005623: m_FloatData(nullptr)
5624, m_Uint8Data(std::move(data))
Keith Davisd305e1a2020-01-22 11:57:54 +00005625, m_Int8Data(nullptr)
5626, m_Int32Data(nullptr)
5627{
5628}
5629
Mike Kelly0d77ae12022-01-07 17:42:27 +00005630TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<int8_t[]>&& data)
Keith Davisd305e1a2020-01-22 11:57:54 +00005631: m_FloatData(nullptr)
5632, m_Uint8Data(nullptr)
5633, m_Int8Data(std::move(data))
telsoa01c577f2c2018-08-31 09:22:23 +01005634, m_Int32Data(nullptr)
5635{
5636}
5637
Mike Kelly0d77ae12022-01-07 17:42:27 +00005638TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<int32_t[]>&& data)
telsoa01c577f2c2018-08-31 09:22:23 +01005639: m_FloatData(nullptr)
5640, m_Uint8Data(nullptr)
Keith Davisd305e1a2020-01-22 11:57:54 +00005641, m_Int8Data(nullptr)
telsoa01c577f2c2018-08-31 09:22:23 +01005642, m_Int32Data(std::move(data))
5643{
5644}
5645
5646} // armnnTfLiteParser