blob: 244f1fa197589ceacb3ac8837cd8b2d6b5b2fb86 [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;
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +0100800 m_ParserFunctions[tflite::BuiltinOperator_PRELU] = &TfLiteParserImpl::ParsePrelu;
Kevin May7d96b162021-02-03 17:38:41 +0000801 m_ParserFunctions[tflite::BuiltinOperator_QUANTIZE] = &TfLiteParserImpl::ParseQuantize;
802 m_ParserFunctions[tflite::BuiltinOperator_RELU] = &TfLiteParserImpl::ParseRelu;
803 m_ParserFunctions[tflite::BuiltinOperator_RELU6] = &TfLiteParserImpl::ParseRelu6;
Sadik Armagana2747482021-02-09 10:28:54 +0000804 m_ParserFunctions[tflite::BuiltinOperator_REDUCE_MAX] = &TfLiteParserImpl::ParseReduceMax;
805 m_ParserFunctions[tflite::BuiltinOperator_REDUCE_MIN] = &TfLiteParserImpl::ParseReduceMin;
Teresa Charlin4e3e8312021-08-05 12:34:37 +0100806 m_ParserFunctions[tflite::BuiltinOperator_REDUCE_PROD] = &TfLiteParserImpl::ParseReduceProd;
Kevin May7d96b162021-02-03 17:38:41 +0000807 m_ParserFunctions[tflite::BuiltinOperator_RESHAPE] = &TfLiteParserImpl::ParseReshape;
808 m_ParserFunctions[tflite::BuiltinOperator_RESIZE_BILINEAR] = &TfLiteParserImpl::ParseResizeBilinear;
809 m_ParserFunctions[tflite::BuiltinOperator_RESIZE_NEAREST_NEIGHBOR] = &TfLiteParserImpl::ParseResizeNearestNeighbor;
Matthew Sloyaned7fce42021-04-15 20:46:24 +0100810 m_ParserFunctions[tflite::BuiltinOperator_RSQRT] = &TfLiteParserImpl::ParseRsqrt;
Teresa Charlinf0fce5b2022-05-04 17:24:43 +0100811 m_ParserFunctions[tflite::BuiltinOperator_SQRT] = &TfLiteParserImpl::ParseSqrt;
Keith Davis0176fd82021-06-01 17:36:32 +0100812 m_ParserFunctions[tflite::BuiltinOperator_SHAPE] = &TfLiteParserImpl::ParseShape;
Teresa Charlin28aa6692022-07-12 11:18:44 +0100813 m_ParserFunctions[tflite::BuiltinOperator_SIN] = &TfLiteParserImpl::ParseSin;
Kevin May7d96b162021-02-03 17:38:41 +0000814 m_ParserFunctions[tflite::BuiltinOperator_SLICE] = &TfLiteParserImpl::ParseSlice;
815 m_ParserFunctions[tflite::BuiltinOperator_SOFTMAX] = &TfLiteParserImpl::ParseSoftmax;
816 m_ParserFunctions[tflite::BuiltinOperator_SPACE_TO_BATCH_ND] = &TfLiteParserImpl::ParseSpaceToBatchND;
Teresa Charlin2a764ad2023-02-24 18:17:31 +0000817 m_ParserFunctions[tflite::BuiltinOperator_SPACE_TO_DEPTH] = &TfLiteParserImpl::ParseSpaceToDepth;
Kevin May7d96b162021-02-03 17:38:41 +0000818 m_ParserFunctions[tflite::BuiltinOperator_SPLIT] = &TfLiteParserImpl::ParseSplit;
819 m_ParserFunctions[tflite::BuiltinOperator_SPLIT_V] = &TfLiteParserImpl::ParseSplitV;
820 m_ParserFunctions[tflite::BuiltinOperator_SQUEEZE] = &TfLiteParserImpl::ParseSqueeze;
821 m_ParserFunctions[tflite::BuiltinOperator_STRIDED_SLICE] = &TfLiteParserImpl::ParseStridedSlice;
822 m_ParserFunctions[tflite::BuiltinOperator_SUB] = &TfLiteParserImpl::ParseSub;
823 m_ParserFunctions[tflite::BuiltinOperator_SUM] = &TfLiteParserImpl::ParseSum;
824 m_ParserFunctions[tflite::BuiltinOperator_TANH] = &TfLiteParserImpl::ParseTanH;
825 m_ParserFunctions[tflite::BuiltinOperator_TRANSPOSE] = &TfLiteParserImpl::ParseTranspose;
826 m_ParserFunctions[tflite::BuiltinOperator_TRANSPOSE_CONV] = &TfLiteParserImpl::ParseTransposeConv;
Mike Kelly5880b912022-01-28 16:18:54 +0000827 m_ParserFunctions[tflite::BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM]
828 = &TfLiteParserImpl::ParseUnidirectionalSequenceLSTM;
Kevin May7d96b162021-02-03 17:38:41 +0000829 m_ParserFunctions[tflite::BuiltinOperator_UNPACK] = &TfLiteParserImpl::ParseUnpack;
Matthew Sloyan28f177c2021-04-09 14:38:52 +0100830
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100831 // register supported custom operators
Kevin May7d96b162021-02-03 17:38:41 +0000832 m_CustomParserFunctions["TFLite_Detection_PostProcess"] = &TfLiteParserImpl::ParseDetectionPostProcess;
telsoa01c577f2c2018-08-31 09:22:23 +0100833}
834
Mike Kelly377fb212023-01-10 15:55:28 +0000835armnn::TensorInfo TfLiteParserImpl::InputTensorInfo(size_t subgraphIndex,
836 size_t operatorIndex,
837 int input)
838{
839 const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex];
840 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
841
842 uint32_t inputId = CHECKED_NON_NEGATIVE(operatorPtr->inputs[input]);
843 auto search = armnnTfLiteParser::TfLiteParserImpl::m_TensorInfos.find(inputId);
844
845 if (search != m_TensorInfos.end())
846 {
847 return m_TensorInfos[inputId];
848 }
849 else
850 {
851 auto tensorInfo = ::armnnTfLiteParser::ToTensorInfo(subgraphPtr->tensors[inputId].get());
852 m_TensorInfos.insert({ inputId, tensorInfo });
853 return tensorInfo;
854 }
855}
856
857armnn::TensorInfo TfLiteParserImpl::OutputTensorInfoFromInputs(size_t subgraphIndex,
858 size_t operatorIndex,
859 armnn::IConnectableLayer* layer,
860 int output,
861 std::vector<int> inputs)
862{
863 const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex];
864 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
865
866 uint32_t outputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[output]);
867
868 auto outputSearch = armnnTfLiteParser::TfLiteParserImpl::m_TensorInfos.find(outputId);
869
870 if (outputSearch != m_TensorInfos.end())
871 {
872 return m_TensorInfos[outputId];
873 }
874
875 const auto& outputTensorPtr = subgraphPtr->tensors[outputId].get();
876 TensorInfo tensor = ::armnnTfLiteParser::ToTensorInfo(outputTensorPtr, true);
877
878 if (IsDynamic(outputTensorPtr))
879 {
880 if (inputs.empty())
881 {
882 for (unsigned int i = 0; i < layer->GetNumInputSlots(); ++i)
883 {
884 inputs.emplace_back(i);
885 }
886 }
887 auto inputTensorIds = GetInputTensorIds(m_Model, subgraphIndex, operatorIndex);
888 std::vector<armnn::TensorShape> inputShapes;
889
890 for (unsigned int i = 0; i < inputs.size(); ++i)
891 {
892 uint32_t inputId = CHECKED_NON_NEGATIVE(operatorPtr->inputs[inputs[i]]);
893 auto search = armnnTfLiteParser::TfLiteParserImpl::m_TensorInfos.find(inputId);
894
895 if (search != m_TensorInfos.end())
896 {
897 auto &inputTensorInfo = m_TensorInfos[inputId];
898 inputShapes.push_back(inputTensorInfo.GetShape());
899 }
900 else
901 {
902 m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
903 auto inputTensorInfo = ::armnnTfLiteParser::ToTensorInfo(subgraphPtr->tensors[inputId].get());
904 m_TensorInfos.insert({ inputId, inputTensorInfo});
905 inputShapes.push_back(inputTensorInfo.GetShape());
906 }
907 }
908 const auto outputShape = layer->InferOutputShapes(inputShapes)[output];
909 tensor.SetShape(outputShape);
910 }
911 m_TensorInfos.insert({ outputId, tensor});
912 return tensor;
913}
914
915armnn::TensorInfo TfLiteParserImpl::OutputTensorInfoFromShapes(size_t subgraphIndex,
916 size_t operatorIndex,
917 armnn::IConnectableLayer* layer,
918 int output,
919 std::vector<armnn::TensorShape> inputShapes)
920{
921 const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex];
922 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
923
924 uint32_t outputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[output]);
925 const auto& outputTensorPtr = subgraphPtr->tensors[outputId].get();
926 TensorInfo tensor = ::armnnTfLiteParser::ToTensorInfo(outputTensorPtr, true);
927
928 if (IsDynamic(outputTensorPtr))
929 {
930 const auto outputShape = layer->InferOutputShapes(inputShapes)[output];
931 tensor.SetShape(outputShape);
932 }
933 m_TensorInfos.insert({ outputId, tensor});
934 return tensor;
935}
936
Kevin May7d96b162021-02-03 17:38:41 +0000937void TfLiteParserImpl::ResetParser()
telsoa01c577f2c2018-08-31 09:22:23 +0100938{
939 m_Network = armnn::INetworkPtr(nullptr, nullptr);
940 m_Model = nullptr;
941 m_SubgraphConnections.clear();
Mike Kelly377fb212023-01-10 15:55:28 +0000942 m_OverriddenOutputShapes.clear();
Mike Kelly5880b912022-01-28 16:18:54 +0000943 m_ConstantsToDequantize.clear();
944 m_ConstantsToBeCreated.clear();
Mike Kelly377fb212023-01-10 15:55:28 +0000945 m_TensorInfos.clear();
telsoa01c577f2c2018-08-31 09:22:23 +0100946}
947
Kevin May7d96b162021-02-03 17:38:41 +0000948INetworkPtr TfLiteParserImpl::CreateNetworkFromBinaryFile(const char* graphFile)
telsoa01c577f2c2018-08-31 09:22:23 +0100949{
950 ResetParser();
951 m_Model = LoadModelFromFile(graphFile);
952 return CreateNetworkFromModel();
953}
954
Mike Kelly0d77ae12022-01-07 17:42:27 +0000955INetworkPtr TfLiteParserImpl::CreateNetworkFromBinary(const std::vector<uint8_t>& binaryContent)
telsoa01c577f2c2018-08-31 09:22:23 +0100956{
957 ResetParser();
958 m_Model = LoadModelFromBinary(binaryContent.data(), binaryContent.size());
959 return CreateNetworkFromModel();
960}
961
Finn Williamsb49ed182021-06-29 15:50:08 +0100962
963armnn::INetworkPtr TfLiteParserImpl::LoadModel(std::unique_ptr<tflite::ModelT> model)
964{
965 ResetParser();
966 m_Model = std::move(model);
967
968 return CreateNetworkFromModel();
969}
970
Kevin May7d96b162021-02-03 17:38:41 +0000971INetworkPtr TfLiteParserImpl::CreateNetworkFromModel()
telsoa01c577f2c2018-08-31 09:22:23 +0100972{
Sadik Armagand109a4d2020-07-28 10:42:13 +0100973
974 using NetworkOptions = std::vector<BackendOptions>;
975 NetworkOptions networkOptions = {};
Mike Kelly80512b02022-05-16 23:10:42 +0100976 if (m_Options)
Sadik Armagand109a4d2020-07-28 10:42:13 +0100977 {
Mike Kelly80512b02022-05-16 23:10:42 +0100978 if (m_Options.value().m_InferAndValidate)
979 {
980 BackendOptions shapeInferenceMethodOption("ShapeInferenceMethod",
981 {
982 { "InferAndValidate", true }
983 });
Sadik Armagand109a4d2020-07-28 10:42:13 +0100984
Mike Kelly80512b02022-05-16 23:10:42 +0100985 networkOptions.push_back(shapeInferenceMethodOption);
986 }
987 if (m_Options.value().m_AllowExpandedDims)
988 {
989 BackendOptions shapeInferenceMethodOption("AllowExpandedDims",
990 {
991 { "AllowExpandedDims", true }
992 });
993
994 networkOptions.push_back(shapeInferenceMethodOption);
995 }
Sadik Armagand109a4d2020-07-28 10:42:13 +0100996 }
Sadik Armagand109a4d2020-07-28 10:42:13 +0100997 m_Network = INetwork::Create(networkOptions);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100998 ARMNN_ASSERT(m_Model.get() != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +0100999
telsoa01c577f2c2018-08-31 09:22:23 +01001000 if (m_Model->subgraphs.size() != 1)
1001 {
1002 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01001003 fmt::format("Current TfLite parser only supports 1 subgraph. Current one has: {} {}",
1004 m_Model->subgraphs.size(),
1005 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01001006 }
1007
1008 size_t subgraphIndex = 0;
Colm Donelan6350d272020-06-09 16:56:25 +01001009 size_t operatorIndex = 0;
1010 try
telsoa01c577f2c2018-08-31 09:22:23 +01001011 {
Colm Donelan6350d272020-06-09 16:56:25 +01001012 for (SubgraphPtr const& subgraph : m_Model->subgraphs)
telsoa01c577f2c2018-08-31 09:22:23 +01001013 {
Mike Kelly377fb212023-01-10 15:55:28 +00001014 SetupInputLayerTensorInfos(subgraphIndex);
1015 SetupConstantLayerTensorInfos(subgraphIndex);
1016
Colm Donelan6350d272020-06-09 16:56:25 +01001017 m_SubgraphConnections.emplace_back(subgraph->tensors.size());
1018 for (OperatorPtr const& op : subgraph->operators)
telsoa01c577f2c2018-08-31 09:22:23 +01001019 {
Colm Donelan6350d272020-06-09 16:56:25 +01001020 auto const& opCodePtr = m_Model->operator_codes[op->opcode_index];
Jim Flynnfca233e2021-09-23 12:16:53 +01001021
1022// 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 +01001023#if defined(ARMNN_POST_TFLITE_2_3)
Jim Flynnfca233e2021-09-23 12:16:53 +01001024 auto builtinCode = std::max(opCodePtr->builtin_code,
1025 static_cast<tflite::BuiltinOperator>(opCodePtr->deprecated_builtin_code));
1026#else
telsoa01c577f2c2018-08-31 09:22:23 +01001027 auto builtinCode = opCodePtr->builtin_code;
Jim Flynnfca233e2021-09-23 12:16:53 +01001028#endif
telsoa01c577f2c2018-08-31 09:22:23 +01001029
1030 if (builtinCode > tflite::BuiltinOperator_MAX)
1031 {
James Ward58dec6b2020-09-11 17:32:44 +01001032 throw ParseException(fmt::format("Operator code {} is out of range 0-{}. "
1033 "subgraph:{} operator idx:{}. {}",
1034 builtinCode, tflite::BuiltinOperator_MAX, subgraphIndex,
1035 operatorIndex, CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01001036 }
1037
1038 // lookup and call the parser function
Colm Donelan6350d272020-06-09 16:56:25 +01001039 auto& parserFunction = m_ParserFunctions[builtinCode];
telsoa01c577f2c2018-08-31 09:22:23 +01001040 (this->*parserFunction)(subgraphIndex, operatorIndex);
Colm Donelan6350d272020-06-09 16:56:25 +01001041 ++operatorIndex;
telsoa01c577f2c2018-08-31 09:22:23 +01001042 }
telsoa01c577f2c2018-08-31 09:22:23 +01001043
Colm Donelan6350d272020-06-09 16:56:25 +01001044 SetupInputLayers(subgraphIndex);
1045 SetupOutputLayers(subgraphIndex);
1046 SetupConstantLayers(subgraphIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001047
Colm Donelan6350d272020-06-09 16:56:25 +01001048 ++subgraphIndex;
1049 operatorIndex = 0;
telsoa01c577f2c2018-08-31 09:22:23 +01001050 }
telsoa01c577f2c2018-08-31 09:22:23 +01001051 }
Colm Donelan6350d272020-06-09 16:56:25 +01001052 catch (const ParseException& e)
telsoa01c577f2c2018-08-31 09:22:23 +01001053 {
Colm Donelan6350d272020-06-09 16:56:25 +01001054 std::stringstream errorString;
1055 errorString << "Failed to parse operator #" << operatorIndex << " within subgraph #"
1056 << subgraphIndex << " error: " << e.what();
1057 ARMNN_LOG(error) << errorString.str();
1058 std::stringstream errors;
1059 errors << errorString.str() << "\n";
telsoa01c577f2c2018-08-31 09:22:23 +01001060 throw ParseException(errors.str());
1061 }
1062
1063 // establish the connections from the layer outputs to the inputs of the subsequent layers
Colm Donelan6350d272020-06-09 16:56:25 +01001064 for (subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001065 {
1066 for (size_t tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex)
1067 {
1068 if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot != nullptr)
1069 {
1070 for (size_t inputSlotIdx = 0;
1071 inputSlotIdx < m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size();
1072 ++inputSlotIdx)
1073 {
1074 m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot->Connect(
1075 *(m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots[inputSlotIdx]));
1076 }
1077 }
1078 }
1079 }
telsoa01c577f2c2018-08-31 09:22:23 +01001080 return std::move(m_Network);
1081}
1082
Mike Kelly0506ef02023-01-03 16:29:44 +00001083bool TfLiteParserImpl::ShouldConstantTensorBeConverted(TfLiteParserImpl::TensorRawPtr tensorPtr,
1084 armnn::DataType inputDataType,
1085 armnn::DataType tensorDataType)
Mike Kelly5880b912022-01-28 16:18:54 +00001086{
Mike Kelly0506ef02023-01-03 16:29:44 +00001087 return (TfLiteParserImpl::IsConstTensor(tensorPtr) && inputDataType == DataType::Float32 &&
1088 (tensorDataType == DataType::QAsymmU8 ||
1089 tensorDataType == DataType::QAsymmS8 ||
1090 tensorDataType == DataType::QSymmS8 ||
1091 tensorDataType == DataType::Signed32 ||
1092 tensorDataType == DataType::Signed64));
Mike Kelly5880b912022-01-28 16:18:54 +00001093}
1094
Kevin May7d96b162021-02-03 17:38:41 +00001095void TfLiteParserImpl::RegisterProducerOfTensor(size_t subgraphIndex,
1096 size_t tensorIndex,
1097 armnn::IOutputSlot* slot)
telsoa01c577f2c2018-08-31 09:22:23 +01001098{
1099 CHECK_TENSOR(m_Model, subgraphIndex, tensorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001100 ARMNN_ASSERT(m_SubgraphConnections.size() > subgraphIndex);
1101 ARMNN_ASSERT(m_SubgraphConnections[subgraphIndex].size() > tensorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001102
1103 TensorSlots & tensorSlots = m_SubgraphConnections[subgraphIndex][tensorIndex];
1104
Nikhil Rajd4d1c312022-08-03 18:20:59 +01001105 if (slot->GetOwningIConnectableLayer().GetType() != LayerType::Constant)
telsoa01c577f2c2018-08-31 09:22:23 +01001106 {
telsoa01c577f2c2018-08-31 09:22:23 +01001107
Nikhil Rajd4d1c312022-08-03 18:20:59 +01001108 // assuming there is only one producer for that tensor
1109 if (tensorSlots.outputSlot != nullptr)
1110 {
1111 throw ParseException(fmt::format("Another layer has already registered itself as the producer of "
1112 "subgraph:{} tensor:{} {}",
1113 subgraphIndex,
1114 tensorIndex,
1115 CHECK_LOCATION().AsString()));
1116 }
1117 }
telsoa01c577f2c2018-08-31 09:22:23 +01001118 tensorSlots.outputSlot = slot;
1119}
1120
Kevin May7d96b162021-02-03 17:38:41 +00001121void TfLiteParserImpl::RegisterConsumerOfTensor(size_t subgraphIndex,
1122 size_t tensorIndex,
1123 armnn::IInputSlot* slot)
telsoa01c577f2c2018-08-31 09:22:23 +01001124{
1125 CHECK_TENSOR(m_Model, subgraphIndex, tensorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001126 ARMNN_ASSERT(m_SubgraphConnections.size() > subgraphIndex);
1127 ARMNN_ASSERT(m_SubgraphConnections[subgraphIndex].size() > tensorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001128
Finn Williamsd4fa5452021-03-01 12:31:41 +00001129 TensorSlots& tensorSlots = m_SubgraphConnections[subgraphIndex][tensorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01001130 tensorSlots.inputSlots.push_back(slot);
1131}
1132
Kevin May7d96b162021-02-03 17:38:41 +00001133void TfLiteParserImpl::ParseCustomOperator(size_t subgraphIndex, size_t operatorIndex)
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001134{
1135 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1136
1137 // NOTE: By default we presume the custom operator is not supported
Kevin May7d96b162021-02-03 17:38:41 +00001138 auto customParserFunction = &TfLiteParserImpl::ParseUnsupportedOperator;
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001139
1140 // Identify custom code defined for custom operator
1141 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1142 const auto& customCode = m_Model->operator_codes[operatorPtr->opcode_index]->custom_code;
1143
Mike Kelly377fb212023-01-10 15:55:28 +00001144 // Find parser function that corresponds to custom code (if any)
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001145 auto iterator = m_CustomParserFunctions.find(customCode);
1146 if (iterator != m_CustomParserFunctions.end())
1147 {
1148 customParserFunction = iterator->second;
1149 }
1150
1151 // Run parser function
1152 (this->*customParserFunction)(subgraphIndex, operatorIndex);
1153}
1154
Kevin May7d96b162021-02-03 17:38:41 +00001155void TfLiteParserImpl::ParseUnsupportedOperator(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001156{
1157 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001158
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001159 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1160
1161 auto opcodeIndex = operatorPtr->opcode_index;
Jim Flynnfca233e2021-09-23 12:16:53 +01001162
1163// 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 +01001164#if defined(ARMNN_POST_TFLITE_2_3)
Jim Flynnfca233e2021-09-23 12:16:53 +01001165 auto opcode = std::max(m_Model->operator_codes[opcodeIndex]->builtin_code,
1166 static_cast<tflite::BuiltinOperator>(m_Model->operator_codes[opcodeIndex]->deprecated_builtin_code));
1167#else
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001168 auto opcode = m_Model->operator_codes[opcodeIndex]->builtin_code;
Jim Flynnfca233e2021-09-23 12:16:53 +01001169#endif
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001170
1171 if (!m_Options || !m_Options.value().m_StandInLayerForUnsupported)
1172 {
1173 // Do not add StandInLayer, throw ParseException instead
1174 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01001175 fmt::format("Operator not supported. "
1176 "subgraph:{} operator:{} "
1177 "opcode_index:{} opcode:{} / {} {}",
1178 subgraphIndex,
1179 operatorIndex,
1180 opcodeIndex,
1181 opcode,
1182 tflite::EnumNameBuiltinOperator(opcode),
1183 CHECK_LOCATION().AsString()));
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001184 }
1185
1186 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1187 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1188
Matthew Sloyan589e3e82020-09-11 16:17:48 +01001189 const unsigned int numInputs = armnn::numeric_cast<unsigned int>(inputs.size());
1190 const unsigned int numOutputs = armnn::numeric_cast<unsigned int>(outputs.size());
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001191
1192 StandInDescriptor descriptor(numInputs, numOutputs);
James Ward58dec6b2020-09-11 17:32:44 +01001193 auto layerName = fmt::format("StandIn:{}:{}:{}", subgraphIndex, operatorIndex, opcode);
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001194
1195 // Add a non-executable StandInLayer as a placeholder for any unsupported operator
1196 IConnectableLayer* layer = m_Network->AddStandInLayer(descriptor, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01001197 ARMNN_ASSERT(layer != nullptr);
1198
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001199 for (unsigned int i = 0u; i < numOutputs; ++i)
1200 {
Mike Kelly04d82292023-01-19 18:29:40 +00001201 layer->GetOutputSlot(i).SetTensorInfo(ToTensorInfo(outputs[0], true));
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001202 }
1203
1204 auto inputTensorIds = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1205 auto outputTensorIds = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1206
1207 RegisterInputSlots(subgraphIndex, operatorIndex, layer, inputTensorIds);
1208 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIds);
telsoa01c577f2c2018-08-31 09:22:23 +01001209}
1210
mathad01b392e982021-04-07 12:07:30 +01001211void TfLiteParserImpl::ParseCast(size_t subgraphIndex, size_t operatorIndex)
1212{
1213 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1214
1215 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1216 CHECK_VALID_SIZE(inputs.size(), 1);
1217 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1218 CHECK_VALID_SIZE(outputs.size(), 1);
1219
1220 auto layerName = fmt::format("Cast:{}:{}", subgraphIndex, operatorIndex);
1221
1222 IConnectableLayer* layer = m_Network->AddCastLayer(layerName.c_str());
1223 ARMNN_ASSERT(layer != nullptr);
1224
Mike Kelly377fb212023-01-10 15:55:28 +00001225 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
mathad01b392e982021-04-07 12:07:30 +01001226 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1227
1228 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1229 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1230
1231 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1232 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
1233}
1234
Kevin May7d96b162021-02-03 17:38:41 +00001235void TfLiteParserImpl::ParseConv2D(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001236{
1237 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1238
Mike Kelly0d77ae12022-01-07 17:42:27 +00001239 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1240 const auto* options = operatorPtr->builtin_options.AsConv2DOptions();
telsoa01c577f2c2018-08-31 09:22:23 +01001241
1242 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1243
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001244 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1245 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1246 CHECK_VALID_SIZE(outputs.size(), 1);
1247
telsoa01c577f2c2018-08-31 09:22:23 +01001248 Convolution2dDescriptor desc;
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001249 inputs.size() == 3 ?
1250 desc.m_BiasEnabled = true : desc.m_BiasEnabled = false;
telsoa01c577f2c2018-08-31 09:22:23 +01001251 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1252 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
jimfly01c25411c2018-11-14 17:47:22 +00001253 desc.m_DataLayout = armnn::DataLayout::NHWC;
Pablo Tellof0bd6832019-04-26 17:58:13 +01001254 desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
1255 desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
Kevin May83add212019-03-26 11:39:19 +00001256
Mike Kelly377fb212023-01-10 15:55:28 +00001257 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1258 armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
telsoa01c577f2c2018-08-31 09:22:23 +01001259
1260 // assuming input is NHWC
1261 unsigned int inputHeight = inputTensorInfo.GetShape()[1];
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001262 unsigned int inputWidth = inputTensorInfo.GetShape()[2];
telsoa01c577f2c2018-08-31 09:22:23 +01001263
1264 // assuming the filter is OHWI : Output, H, W, Input
1265 // which is essentially the same as NHWC
1266 unsigned int filterHeight = filterTensorInfo.GetShape()[1];
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001267 unsigned int filterWidth = filterTensorInfo.GetShape()[2];
telsoa01c577f2c2018-08-31 09:22:23 +01001268
Pablo Tellof0bd6832019-04-26 17:58:13 +01001269 CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
1270 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
1271 CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
1272 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
telsoa01c577f2c2018-08-31 09:22:23 +01001273
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001274 // Add the first input and weights tensor to the registration list.
1275 // The constant weights will be added by SetupConstantLayers.
1276 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1277 std::vector<unsigned int> tensorIndexesToRegister = { inputTensorIndexes[0], inputTensorIndexes[1] };
telsoa01c577f2c2018-08-31 09:22:23 +01001278
James Ward58dec6b2020-09-11 17:32:44 +01001279 auto layerName = fmt::format("Conv2D:{}:{}", subgraphIndex, operatorIndex);
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001280 armnn::IConnectableLayer* layer = m_Network->AddConvolution2dLayer(desc, layerName.c_str());
telsoa01c577f2c2018-08-31 09:22:23 +01001281
Mike Kelly0506ef02023-01-03 16:29:44 +00001282 if (ShouldConstantTensorBeConverted(inputs[1], inputTensorInfo.GetDataType(), filterTensorInfo.GetDataType()))
telsoa01c577f2c2018-08-31 09:22:23 +01001283 {
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001284 m_ConstantsToDequantize.emplace_back(inputs[1]->buffer);
telsoa01c577f2c2018-08-31 09:22:23 +01001285 }
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001286
1287 if (desc.m_BiasEnabled)
telsoa01c577f2c2018-08-31 09:22:23 +01001288 {
Mike Kelly377fb212023-01-10 15:55:28 +00001289 armnn::TensorInfo biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001290
1291 // Add the biases input to the registration list, a constant layer will be added by SetupConstantLayers.
1292 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
1293
Mike Kelly0506ef02023-01-03 16:29:44 +00001294 if (ShouldConstantTensorBeConverted(inputs[2], inputTensorInfo.GetDataType(), biasTensorInfo.GetDataType()))
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001295 {
1296 m_ConstantsToDequantize.emplace_back(inputs[2]->buffer);
1297 }
telsoa01c577f2c2018-08-31 09:22:23 +01001298 }
1299
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001300 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01001301
Mike Kelly377fb212023-01-10 15:55:28 +00001302 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
jimfly01c25411c2018-11-14 17:47:22 +00001303 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +01001304
1305 // register the input connection slots for the layer, connections are made after all layers have been created
1306 // only the tensors for the inputs are relevant, exclude the const tensors
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001307 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister);
telsoa01c577f2c2018-08-31 09:22:23 +01001308
jimfly01c25411c2018-11-14 17:47:22 +00001309 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
telsoa01c577f2c2018-08-31 09:22:23 +01001310 // register the output connection slots for the layer, connections are made after all layers have been created
1311 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001312 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, { outputTensorIndexes[0] });
telsoa01c577f2c2018-08-31 09:22:23 +01001313}
1314
Matthew Sloyan4d217c02021-10-07 11:48:58 +01001315// Conv3D support was added in TF 2.5, so for backwards compatibility a hash define is needed.
Cathal Corbett80b4ef02022-05-25 11:21:11 +01001316#if defined(ARMNN_POST_TFLITE_2_4)
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001317void TfLiteParserImpl::ParseConv3D(size_t subgraphIndex, size_t operatorIndex)
1318{
1319 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1320
1321 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1322 const auto* options = operatorPtr->builtin_options.AsConv3DOptions();
1323
1324 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1325
1326 Convolution3dDescriptor desc;
1327 desc.m_BiasEnabled = false;
1328 desc.m_DataLayout = armnn::DataLayout::NDHWC;
1329 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1330 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1331 desc.m_StrideZ = CHECKED_NON_NEGATIVE(options->stride_d);
1332 desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
1333 desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
1334 desc.m_DilationZ = CHECKED_NON_NEGATIVE(options->dilation_d_factor);
1335
1336 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1337 CHECK_VALID_SIZE(inputs.size(), 2, 3);
1338
1339 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1340 CHECK_VALID_SIZE(outputs.size(), 1);
1341
Mike Kelly377fb212023-01-10 15:55:28 +00001342 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1343 armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001344
1345 // Assuming input is NDHWC
1346 unsigned int inputDepth = inputTensorInfo.GetShape()[1];
1347 unsigned int inputHeight = inputTensorInfo.GetShape()[2];
1348 unsigned int inputWidth = inputTensorInfo.GetShape()[3];
1349
1350 // Assuming the filter is DHWIO : Depth, Height, Width, OutputChannels, InputChannels
1351 unsigned int filterDepth = filterTensorInfo.GetShape()[0];
1352 unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1353 unsigned int filterWidth = filterTensorInfo.GetShape()[2];
1354
1355 CalcPadding(inputDepth, filterDepth, desc.m_StrideZ,
Teresa Charlin502ab942022-03-23 17:23:07 +00001356 desc.m_DilationZ, desc.m_PadFront, desc.m_PadBack, options->padding);
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001357 CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
1358 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
1359 CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
1360 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
1361
Mike Kelly5880b912022-01-28 16:18:54 +00001362 auto filterTensorAndData = CreateConstTensorNonPermuted(inputs[1], filterTensorInfo, inputTensorInfo.GetDataType());
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001363
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001364 auto layerName = fmt::format("Conv3D:{}:{}", subgraphIndex, operatorIndex);
1365
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001366 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1367 // Add the first input and weights tensor to the registration list.
1368 // The constant weights will be added by SetupConstantLayers.
1369 std::vector<unsigned int> tensorIndexesToRegister = {inputTensorIndexes[0], inputTensorIndexes[1]};
1370
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001371 if (inputs.size() == 3)
1372 {
1373 desc.m_BiasEnabled = true;
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001374
1375 // Add the biases input to the registration list, a constant layer will be added by SetupConstantLayers.
1376 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001377 }
1378
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001379 armnn::IConnectableLayer* layer = m_Network->AddConvolution3dLayer(desc, layerName.c_str());
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001380 ARMNN_ASSERT(layer != nullptr);
1381
Mike Kelly377fb212023-01-10 15:55:28 +00001382 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001383 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1384
1385 // Register the input connection slots for the layer, connections are made after all layers have been created
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001386 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister);
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001387
1388 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
1389 // Register the output connection slots for the layer, connections are made after all layers have been created
1390 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1391 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1392}
Matthew Sloyan4d217c02021-10-07 11:48:58 +01001393#endif
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001394
Kevin May7d96b162021-02-03 17:38:41 +00001395void TfLiteParserImpl::ParseDepthwiseConv2D(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001396{
1397 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1398
Mike Kelly0d77ae12022-01-07 17:42:27 +00001399 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1400 const auto* options = operatorPtr->builtin_options.AsDepthwiseConv2DOptions();
telsoa01c577f2c2018-08-31 09:22:23 +01001401
1402 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1403
1404 DepthwiseConvolution2dDescriptor desc;
telsoa01c577f2c2018-08-31 09:22:23 +01001405 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1406 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
jimfly01c25411c2018-11-14 17:47:22 +00001407 desc.m_DataLayout = armnn::DataLayout::NHWC;
Matthew Jacksond6a9dee2019-07-22 13:53:24 +01001408 CHECKED_NON_NEGATIVE(options->depth_multiplier);
telsoa01c577f2c2018-08-31 09:22:23 +01001409
1410 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1411 CHECK_VALID_SIZE(inputs.size(), 2, 3);
Cathal Corbett06902652022-04-14 17:55:11 +01001412 if (inputs.size() == 3)
1413 {
1414 desc.m_BiasEnabled = true;
1415 }
1416
telsoa01c577f2c2018-08-31 09:22:23 +01001417 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1418 CHECK_VALID_SIZE(outputs.size(), 1);
Pablo Tellof0bd6832019-04-26 17:58:13 +01001419 desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
1420 desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
Kevin May83add212019-03-26 11:39:19 +00001421
Mike Kelly377fb212023-01-10 15:55:28 +00001422 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1423 armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
telsoa01c577f2c2018-08-31 09:22:23 +01001424
Matteo Martincigh747ef822018-12-18 09:26:39 +00001425 // Assuming input is NHWC
telsoa01c577f2c2018-08-31 09:22:23 +01001426 unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1427 unsigned int inputWidth = inputTensorInfo.GetShape()[2];
Matteo Martincigh747ef822018-12-18 09:26:39 +00001428
1429 // TensorflowLite weights come in the format [1, H, W, I * M]
telsoa01c577f2c2018-08-31 09:22:23 +01001430 unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1431 unsigned int filterWidth = filterTensorInfo.GetShape()[2];
1432
Pablo Tellof0bd6832019-04-26 17:58:13 +01001433 CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
1434 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
1435 CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
1436 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
telsoa01c577f2c2018-08-31 09:22:23 +01001437
Jan Eilers53ef7952021-06-02 12:01:25 +01001438 // 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 +01001439 auto layerName = fmt::format("DepthwiseConv2D:{}:{}", subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001440
Cathal Corbett06902652022-04-14 17:55:11 +01001441 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1442 // Add the first input and weights tensor to the registration list.
1443 // The constant weights will be added by SetupConstantLayers.
1444 std::vector<unsigned int> tensorIndexesToRegister = {inputTensorIndexes[0], inputTensorIndexes[1]};
1445
1446 armnn::IConnectableLayer* layer = m_Network->AddDepthwiseConvolution2dLayer(desc, layerName.c_str());
1447
1448 if (desc.m_BiasEnabled)
telsoa01c577f2c2018-08-31 09:22:23 +01001449 {
1450 desc.m_BiasEnabled = true;
Mike Kelly377fb212023-01-10 15:55:28 +00001451 TensorInfo biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Cathal Corbett06902652022-04-14 17:55:11 +01001452
1453 // Add the biases input to the registration list, a constant layer will be added by SetupConstantLayers.
1454 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
telsoa01c577f2c2018-08-31 09:22:23 +01001455 }
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001456 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01001457
Mike Kelly377fb212023-01-10 15:55:28 +00001458 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
jimfly01c25411c2018-11-14 17:47:22 +00001459 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +01001460
1461 // register the input connection slots for the layer, connections are made after all layers have been created
1462 // only the tensors for the inputs are relevant, exclude the const tensors
Cathal Corbett06902652022-04-14 17:55:11 +01001463 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister);
telsoa01c577f2c2018-08-31 09:22:23 +01001464
jimfly01c25411c2018-11-14 17:47:22 +00001465 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
telsoa01c577f2c2018-08-31 09:22:23 +01001466 // register the output connection slots for the layer, connections are made after all layers have been created
1467 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1468 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1469}
1470
Kevin May7d96b162021-02-03 17:38:41 +00001471void TfLiteParserImpl::ParseDequantize(size_t subgraphIndex, size_t operatorIndex)
Finn Williamsed66d142019-12-06 09:55:55 +00001472{
1473 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1474
1475 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1476 CHECK_VALID_SIZE(inputs.size(), 1);
1477
1478 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1479 CHECK_VALID_SIZE(outputs.size(), 1);
1480
James Ward58dec6b2020-09-11 17:32:44 +01001481 auto layerName = fmt::format("Dequantize:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsed66d142019-12-06 09:55:55 +00001482
1483 IConnectableLayer* layer = m_Network->AddDequantizeLayer(layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001484 ARMNN_ASSERT(layer != nullptr);
Finn Williamsed66d142019-12-06 09:55:55 +00001485
Mike Kelly377fb212023-01-10 15:55:28 +00001486 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Finn Williamsed66d142019-12-06 09:55:55 +00001487 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1488
1489 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1490 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1491
1492 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1493 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
1494}
1495
Teresa Charlin3ab85482021-06-08 16:59:29 +01001496void TfLiteParserImpl::ParseExpandDims(size_t subgraphIndex, size_t operatorIndex)
1497{
1498 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1499
1500 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1501 CHECK_VALID_SIZE(inputs.size(), 2);
1502
1503 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1504 CHECK_VALID_SIZE(outputs.size(), 1);
1505
1506 auto layerName = fmt::format("ExpandDims:{}:{}", subgraphIndex, operatorIndex);
1507
Mike Kelly377fb212023-01-10 15:55:28 +00001508 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Teresa Charlin3ab85482021-06-08 16:59:29 +01001509 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1510
1511 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1512
1513 ReshapeDescriptor reshapeDesc;
Finn Williamsb49ed182021-06-29 15:50:08 +01001514
1515 if (outputTensorInfo.GetShape().AreAllDimensionsSpecified())
1516 {
1517 reshapeDesc.m_TargetShape = outputTensorInfo.GetShape();
1518 }
1519 else
1520 {
1521 int32_t axis = inputs[1]->shape[0];
1522
1523 int32_t inputDimSize = static_cast<int32_t>(inputTensorInfo.GetShape().GetNumDimensions());
1524
1525 if (axis > inputDimSize || axis < 0 - (inputDimSize + 1))
1526 {
1527 throw ParseException("axis must be in range [0 - (inputDimSize + 1), inputDimSize] inclusive");
1528 }
1529
1530 if(axis < 0)
1531 {
1532 axis = inputDimSize + axis + 1;
1533 }
1534
Rob Hughesd812a312021-08-06 13:10:53 +01001535 std::vector<unsigned int> shape(static_cast<unsigned int>(inputDimSize) + 1);
Finn Williamsb49ed182021-06-29 15:50:08 +01001536 unsigned int inputShapeIndex = 0;
1537 for (unsigned int i = 0; i < static_cast<unsigned int>(inputDimSize + 1); ++i)
1538 {
1539 if (i == static_cast<unsigned int>(axis))
1540 {
1541 shape[i] = 1;
1542 }
1543 else
1544 {
1545 shape[i] = inputTensorInfo.GetShape()[inputShapeIndex];
1546 ++inputShapeIndex;
1547 }
1548 }
1549
Rob Hughesd812a312021-08-06 13:10:53 +01001550 reshapeDesc.m_TargetShape = TensorShape(static_cast<unsigned int>(inputDimSize + 1), shape.data());
Finn Williamsb49ed182021-06-29 15:50:08 +01001551 }
Teresa Charlin3ab85482021-06-08 16:59:29 +01001552
1553 IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
1554 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00001555
1556 reshapeDesc.m_TargetShape = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0}).GetShape();
1557 outputTensorInfo.SetShape(reshapeDesc.m_TargetShape);
1558
Teresa Charlin3ab85482021-06-08 16:59:29 +01001559 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1560
1561 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1562 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1563
1564 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1565 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1566}
1567
Kevin May7d96b162021-02-03 17:38:41 +00001568void TfLiteParserImpl::ParseTranspose(size_t subgraphIndex, size_t operatorIndex)
Keith Davis4cd29a02019-09-09 14:49:20 +01001569{
1570 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1571
1572 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Kevin May85d92602019-09-27 17:21:06 +01001573 CHECK_VALID_SIZE(inputs.size(), 1, 2);
Keith Davis4cd29a02019-09-09 14:49:20 +01001574
1575 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1576 CHECK_VALID_SIZE(outputs.size(), 1);
1577
James Ward58dec6b2020-09-11 17:32:44 +01001578 auto layerName = fmt::format("Transpose:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly08759e22020-03-02 11:41:31 +00001579 TransposeDescriptor desc;
Keith Davis4cd29a02019-09-09 14:49:20 +01001580
josh minorba424d22019-11-13 10:55:17 -06001581 if (inputs.size() == 2)
Kevin May85d92602019-09-27 17:21:06 +01001582 {
Mike Kelly377fb212023-01-10 15:55:28 +00001583 armnn::TensorInfo permuteTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Kevin May85d92602019-09-27 17:21:06 +01001584 BufferRawPtr permuteBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
josh minorba424d22019-11-13 10:55:17 -06001585 auto numPermVecElements = permuteTensorInfo.GetNumElements();
1586 std::vector<unsigned int> permuteShape(numPermVecElements);
Kevin May85d92602019-09-27 17:21:06 +01001587 ::memcpy(permuteShape.data(), permuteBufferPtr->data.data(), permuteTensorInfo.GetNumBytes());
Mike Kelly08759e22020-03-02 11:41:31 +00001588 PermutationVector permutationVector(permuteShape.data(), permuteTensorInfo.GetNumElements());
Kevin May85d92602019-09-27 17:21:06 +01001589
Mike Kelly08759e22020-03-02 11:41:31 +00001590 desc = TransposeDescriptor(permutationVector);
Kevin May85d92602019-09-27 17:21:06 +01001591 }
Mike Kelly377fb212023-01-10 15:55:28 +00001592 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Keith Davis4cd29a02019-09-09 14:49:20 +01001593
James Conroy05102392020-06-24 15:39:55 +01001594 IConnectableLayer* layer = m_Network->AddTransposeLayer(desc, layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001595 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00001596
1597 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
1598 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Keith Davis4cd29a02019-09-09 14:49:20 +01001599 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1600
1601 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1602 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1603
1604 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1605 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1606}
1607
Kevin May7d96b162021-02-03 17:38:41 +00001608void TfLiteParserImpl::ParseTransposeConv(size_t subgraphIndex, size_t operatorIndex)
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001609{
1610 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1611
Mike Kelly0d77ae12022-01-07 17:42:27 +00001612 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1613 const auto* options = operatorPtr->builtin_options.AsTransposeConvOptions();
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001614
1615 TransposeConvolution2dDescriptor desc;
1616 desc.m_BiasEnabled = false;
1617 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1618 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1619 desc.m_DataLayout = armnn::DataLayout::NHWC;
1620
1621 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
David Monahan61683802021-01-12 09:11:07 +00001622 if (inputs.size() == 4)
1623 {
1624 desc.m_BiasEnabled = true;
1625 }
1626 else
1627 {
1628 CHECK_VALID_SIZE(inputs.size(), 3);
1629 }
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001630
1631 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1632 CHECK_VALID_SIZE(outputs.size(), 1);
1633
Teresa Charlin024ef0b2023-04-26 11:19:03 +01001634
1635 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
1636 armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
1637
1638 // TfLite uses NHWC tensors
1639 const unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1640 const unsigned int inputWidth = inputTensorInfo.GetShape()[2];
1641
1642 const unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1643 const unsigned int filterWidth = filterTensorInfo.GetShape()[2];
1644
Ryan OSheaf0a35b82023-02-21 18:32:30 +00001645 // This block determines the output shape of the transpose convolution. If the output shape tensor ptr is not null
1646 // And the tensor is a constant, we can access the data at load time and set the output shape of the
1647 // layer. If this is not constant, We do not have access to the shape data, so we have to use
1648 // infer output shape and skip this code block.
1649 if (inputs[0] && IsConstTensor(inputs[0]))
Colm Donelan0ad3ef12020-07-03 15:54:28 +01001650 {
Mike Kelly377fb212023-01-10 15:55:28 +00001651 armnn::TensorInfo tensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Colm Donelan0ad3ef12020-07-03 15:54:28 +01001652 std::vector<int> output_shape(tensorInfo.GetNumElements());
Mike Kelly377fb212023-01-10 15:55:28 +00001653
Colm Donelan0ad3ef12020-07-03 15:54:28 +01001654 if (tensorInfo.GetDataType() == DataType::Signed32)
1655 {
1656 ::memcpy(output_shape.data(), GetBuffer(m_Model, inputs[0]->buffer)->data.data(), tensorInfo.GetNumBytes());
1657 }
1658 if (tensorInfo.GetDataType() == DataType::QAsymmU8)
1659 {
1660 for(unsigned int i=0; i < tensorInfo.GetNumElements(); i++)
1661 {
1662 output_shape[i] = GetBuffer(m_Model, inputs[0]->buffer)->data.data()[i];
1663 }
1664 }
1665 // Change from signed to unsigned int to store in TransposeConvolution2dDescriptor.
1666 for (int dimension : output_shape)
1667 {
1668 desc.m_OutputShape.push_back(static_cast<unsigned int>(dimension));
1669 }
1670 desc.m_OutputShapeEnabled = true;
Teresa Charlin024ef0b2023-04-26 11:19:03 +01001671
1672 // TfLite uses NHWC tensors
1673 const unsigned int outputHeight = desc.m_OutputShape[1];
1674 const unsigned int outputWidth = desc.m_OutputShape[2];
1675
1676 CalcPadding(inputHeight,
1677 filterHeight,
1678 desc.m_StrideY,
1679 1, // DilationY
1680 desc.m_PadTop,
1681 desc.m_PadBottom,
1682 options->padding,
1683 outputHeight);
1684
1685 CalcPadding(inputWidth,
1686 filterWidth,
1687 desc.m_StrideX,
1688 1, // DilationX
1689 desc.m_PadLeft,
1690 desc.m_PadRight,
1691 options->padding,
1692 outputWidth);
Colm Donelan0ad3ef12020-07-03 15:54:28 +01001693 }
Teresa Charlin024ef0b2023-04-26 11:19:03 +01001694 else
1695 {
1696 CalcPadding(inputHeight,
1697 filterHeight,
1698 desc.m_StrideY,
1699 1, // DilationY
1700 desc.m_PadTop,
1701 desc.m_PadBottom,
1702 options->padding);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001703
Teresa Charlin024ef0b2023-04-26 11:19:03 +01001704 CalcPadding(inputWidth,
1705 filterWidth,
1706 desc.m_StrideX,
1707 1, // DilationX
1708 desc.m_PadLeft,
1709 desc.m_PadRight,
1710 options->padding);
1711 }
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001712
Mike Kelly5880b912022-01-28 16:18:54 +00001713 auto filterTensorAndData = CreateConstTensorNonPermuted(inputs[1], filterTensorInfo, inputTensorInfo.GetDataType());
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001714
1715 armnn::IConnectableLayer* layer = nullptr;
James Ward58dec6b2020-09-11 17:32:44 +01001716 auto layerName = fmt::format("TransposeConv:{}:{}", subgraphIndex, operatorIndex);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001717
David Monahan61683802021-01-12 09:11:07 +00001718 if (desc.m_BiasEnabled)
1719 {
Mike Kelly377fb212023-01-10 15:55:28 +00001720 auto biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 3);
Mike Kelly5880b912022-01-28 16:18:54 +00001721 auto biasConstTensor = CreateConstTensorNonPermuted(inputs[3], biasTensorInfo, inputTensorInfo.GetDataType());
David Monahan61683802021-01-12 09:11:07 +00001722 layer = m_Network->AddTransposeConvolution2dLayer(desc,
Mike Kelly5880b912022-01-28 16:18:54 +00001723 filterTensorAndData.first,
1724 biasConstTensor.first,
David Monahan61683802021-01-12 09:11:07 +00001725 layerName.c_str());
1726 }
1727 else
1728 {
1729 layer = m_Network->AddTransposeConvolution2dLayer(desc,
Mike Kelly5880b912022-01-28 16:18:54 +00001730 filterTensorAndData.first,
David Monahan61683802021-01-12 09:11:07 +00001731 EmptyOptional(),
1732 layerName.c_str());
1733 }
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001734
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001735 ARMNN_ASSERT(layer != nullptr);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001736
Mike Kelly377fb212023-01-10 15:55:28 +00001737 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0 , { 2, 1 });
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001738 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1739
1740 // only the tensors for the inputs are relevant, exclude the const (filter) tensor
1741 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Matthew Jacksonccb25ea2019-08-20 17:18:33 +01001742 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[2]});
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001743
1744 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1745 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1746}
1747
Kevin May7d96b162021-02-03 17:38:41 +00001748void TfLiteParserImpl::ParseAveragePool2D(size_t subgraphIndex, size_t operatorIndex)
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001749{
1750 ParsePool(subgraphIndex, operatorIndex, PoolingAlgorithm::Average);
1751}
1752
Samuel Yapfd3ba5a2022-08-24 17:04:34 +01001753void TfLiteParserImpl::ParseBatchMatMul(size_t subgraphIndex, size_t operatorIndex)
1754{
1755 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1756
1757 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1758 CHECK_VALID_SIZE(inputs.size(), 2);
1759
1760 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1761 CHECK_VALID_SIZE(outputs.size(), 1);
1762
1763 auto layerName = fmt::format("BatchMatMul:{}:{}", subgraphIndex, operatorIndex);
1764
Mike Kelly377fb212023-01-10 15:55:28 +00001765 TensorInfo inputXTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1766 TensorInfo inputYTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Samuel Yapfd3ba5a2022-08-24 17:04:34 +01001767
1768 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1769 const auto* options = operatorPtr->builtin_options.AsBatchMatMulOptions();
1770
Teresa Charlinbc37a6b2022-09-22 10:12:58 +01001771 // Adjoint in tensorflow lite performs transpose operation
1772 BatchMatMulDescriptor descriptor(options->adj_x,
1773 options->adj_y,
Samuel Yapfd3ba5a2022-08-24 17:04:34 +01001774 false,
Teresa Charlinbc37a6b2022-09-22 10:12:58 +01001775 false);
Samuel Yapfd3ba5a2022-08-24 17:04:34 +01001776 // Arbitrary DataLayout
1777
1778 IConnectableLayer* layer = m_Network->AddBatchMatMulLayer(descriptor, layerName.c_str());
1779 ARMNN_ASSERT(layer != nullptr);
1780
Mike Kelly377fb212023-01-10 15:55:28 +00001781 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Samuel Yapfd3ba5a2022-08-24 17:04:34 +01001782 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1783
1784 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1785 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
1786
1787 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1788 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1789}
1790
Kevin May7d96b162021-02-03 17:38:41 +00001791void TfLiteParserImpl::ParseBatchToSpaceND(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001792{
1793 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1794
1795 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1796 CHECK_VALID_SIZE(inputs.size(), 3);
1797
1798 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1799 CHECK_VALID_SIZE(outputs.size(), 1);
1800
Mike Kelly377fb212023-01-10 15:55:28 +00001801 armnn::TensorInfo blockShapeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001802 BufferRawPtr blockShapeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1803
Mike Kelly377fb212023-01-10 15:55:28 +00001804 armnn::TensorInfo cropsTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001805 BufferRawPtr cropsBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
1806
1807 std::vector<unsigned int> blockShape(blockShapeTensorInfo.GetNumElements());
1808 ::memcpy(blockShape.data(), blockShapeBufferPtr->data.data(), blockShapeTensorInfo.GetNumBytes());
1809
1810 std::vector<unsigned int> cropsVector(cropsTensorInfo.GetNumElements());
1811 ::memcpy(cropsVector.data(), cropsBufferPtr->data.data(), cropsTensorInfo.GetNumBytes());
1812
1813 size_t step = 2;
1814 std::vector<std::pair<unsigned int, unsigned int>> crops;
1815 for (unsigned int i = 0; i < cropsTensorInfo.GetNumElements() / step; ++i)
1816 {
1817 crops.emplace_back(cropsVector[i * step], cropsVector[i * step + 1]);
1818 }
1819
1820 armnn::BatchToSpaceNdDescriptor desc;
1821 desc.m_BlockShape = blockShape;
1822 desc.m_Crops = crops;
1823 desc.m_DataLayout = armnn::DataLayout::NHWC;
1824
James Ward58dec6b2020-09-11 17:32:44 +01001825 auto layerName = fmt::format("BatchToSpaceND:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001826
Mike Kelly377fb212023-01-10 15:55:28 +00001827 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
James Conroy05102392020-06-24 15:39:55 +01001828
1829 IConnectableLayer* layer = m_Network->AddBatchToSpaceNdLayer(desc, layerName.c_str());
1830 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00001831
1832 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
1833 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001834 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1835
1836 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1837 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1838
1839 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1840 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1841}
1842
Kevin May7d96b162021-02-03 17:38:41 +00001843void TfLiteParserImpl::ParseL2Normalization(size_t subgraphIndex, size_t operatorIndex)
Matthew Jackson28c94572019-07-18 10:47:03 +01001844{
1845 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1846
1847 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1848 CHECK_VALID_SIZE(inputs.size(), 1);
1849
1850 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1851 CHECK_VALID_SIZE(outputs.size(), 1);
1852
1853 L2NormalizationDescriptor desc;
1854 desc.m_DataLayout = armnn::DataLayout::NHWC;
James Ward58dec6b2020-09-11 17:32:44 +01001855 auto layerName = fmt::format("L2Normalization:{}:{}", subgraphIndex, operatorIndex);
Matthew Jackson28c94572019-07-18 10:47:03 +01001856 IConnectableLayer* layer = m_Network->AddL2NormalizationLayer(desc, layerName.c_str());
1857
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001858 ARMNN_ASSERT(layer != nullptr);
Matthew Jackson28c94572019-07-18 10:47:03 +01001859
Mike Kelly377fb212023-01-10 15:55:28 +00001860 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Matthew Jackson28c94572019-07-18 10:47:03 +01001861 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1862
1863 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1864 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1865
1866 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1867 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1868}
1869
Kevin May7d96b162021-02-03 17:38:41 +00001870void TfLiteParserImpl::ParseMaxPool2D(size_t subgraphIndex, size_t operatorIndex)
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001871{
1872 ParsePool(subgraphIndex, operatorIndex, PoolingAlgorithm::Max);
1873}
1874
Kevin May7d96b162021-02-03 17:38:41 +00001875void TfLiteParserImpl::ParseMaximum(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001876{
1877 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1878
1879 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1880 CHECK_VALID_SIZE(inputs.size(), 2);
1881
1882 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1883 CHECK_VALID_SIZE(outputs.size(), 1);
1884
James Ward58dec6b2020-09-11 17:32:44 +01001885 auto layerName = fmt::format("Maximum:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01001886
Mike Kelly377fb212023-01-10 15:55:28 +00001887 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1888 TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
James Conroy05102392020-06-24 15:39:55 +01001889 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001890
Mike Kelly3ec30772023-03-08 13:47:17 +00001891 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Maximum, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01001892 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00001893
1894 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
1895 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001896 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1897
1898 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01001899 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001900
1901 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1902 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1903}
1904
Kevin May7d96b162021-02-03 17:38:41 +00001905void TfLiteParserImpl::ParseMinimum(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001906{
1907 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1908
1909 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1910 CHECK_VALID_SIZE(inputs.size(), 2);
1911
1912 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1913 CHECK_VALID_SIZE(outputs.size(), 1);
1914
James Ward58dec6b2020-09-11 17:32:44 +01001915 auto layerName = fmt::format("Minimum:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01001916
Mike Kelly377fb212023-01-10 15:55:28 +00001917 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1918 TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
James Conroy05102392020-06-24 15:39:55 +01001919 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001920
Mike Kelly3ec30772023-03-08 13:47:17 +00001921 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Minimum, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01001922 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00001923
1924 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
1925 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001926 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1927
1928 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01001929 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001930
1931 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1932 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1933}
1934
Kevin May7d96b162021-02-03 17:38:41 +00001935void TfLiteParserImpl::ParsePool(size_t subgraphIndex,
1936 size_t operatorIndex,
1937 PoolingAlgorithm algorithm)
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001938{
1939 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1940
Mike Kelly0d77ae12022-01-07 17:42:27 +00001941 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1942 const auto* options = operatorPtr->builtin_options.AsPool2DOptions();
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001943
1944 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1945
1946 std::string layerName;
1947
1948 switch (algorithm)
1949 {
1950 case PoolingAlgorithm::Average:
1951 layerName =
James Ward58dec6b2020-09-11 17:32:44 +01001952 fmt::format("AveragePool2D:{}:{}", subgraphIndex, operatorIndex);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001953 break;
1954 case PoolingAlgorithm::Max:
1955 layerName =
James Ward58dec6b2020-09-11 17:32:44 +01001956 fmt::format("MaxPool2D:{}:{}", subgraphIndex, operatorIndex);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001957 break;
1958 default:
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001959 ARMNN_ASSERT_MSG(false, "Unsupported Pooling Algorithm");
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001960 }
1961
1962 Pooling2dDescriptor desc;
1963
1964 desc.m_PoolType = algorithm;
1965 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1966 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1967 desc.m_PoolWidth = CHECKED_NON_NEGATIVE(options->filter_width);
1968 desc.m_PoolHeight = CHECKED_NON_NEGATIVE(options->filter_height);
1969 desc.m_PaddingMethod = PaddingMethod::Exclude;
1970 desc.m_OutputShapeRounding = OutputShapeRounding::Floor;
jimfly01c25411c2018-11-14 17:47:22 +00001971 desc.m_DataLayout = armnn::DataLayout::NHWC;
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001972
1973 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1974 CHECK_VALID_SIZE(inputs.size(), 1);
Mike Kelly377fb212023-01-10 15:55:28 +00001975 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001976
1977 // assuming input is NHWC
1978 unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1979 unsigned int inputWidth = inputTensorInfo.GetShape()[2];
1980
Pablo Tellof0bd6832019-04-26 17:58:13 +01001981 CalcPadding(inputHeight, desc.m_PoolHeight, desc.m_StrideY, 1u,
1982 desc.m_PadTop, desc.m_PadBottom, options->padding);
1983 CalcPadding(inputWidth, desc.m_PoolWidth, desc.m_StrideX, 1u,
1984 desc.m_PadLeft, desc.m_PadRight, options->padding);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001985
1986 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1987 CHECK_VALID_SIZE(outputs.size(), 1);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001988
James Conroy05102392020-06-24 15:39:55 +01001989 IConnectableLayer* layer = m_Network->AddPooling2dLayer(desc, layerName.c_str());
1990 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00001991
1992 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
1993 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
jimfly01c25411c2018-11-14 17:47:22 +00001994 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001995
1996 // register the input connection slots for the layer, connections are made after all layers have been created
1997 // only the tensors for the inputs are relevant, exclude the const tensors
1998 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
jimfly01c25411c2018-11-14 17:47:22 +00001999 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01002000
jimfly01c25411c2018-11-14 17:47:22 +00002001 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01002002 // register the output connection slots for the layer, connections are made after all layers have been created
2003 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2004 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2005}
2006
Kevin May7d96b162021-02-03 17:38:41 +00002007void TfLiteParserImpl::ParseSlice(size_t subgraphIndex, size_t operatorIndex)
josh minorba424d22019-11-13 10:55:17 -06002008{
2009 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2010
2011 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2012 CHECK_VALID_SIZE(inputs.size(), 3);
2013 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2014 CHECK_VALID_SIZE(outputs.size(), 1);
2015
2016 SliceDescriptor desc;
2017
2018 // set begin tensor info for slice descriptor
Mike Kelly377fb212023-01-10 15:55:28 +00002019 armnn::TensorInfo beginTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
josh minorba424d22019-11-13 10:55:17 -06002020 BufferRawPtr beginBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2021
2022 std::vector<unsigned int> begin(beginTensorInfo.GetNumElements());
2023 ::memcpy(begin.data(), beginBufferPtr->data.data(), beginTensorInfo.GetNumBytes());
2024
2025 // set size tensor info for slice descriptor
Mike Kelly377fb212023-01-10 15:55:28 +00002026 armnn::TensorInfo sizeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
josh minorba424d22019-11-13 10:55:17 -06002027 BufferRawPtr sizeBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
2028
Cathal Corbettde33dda2022-09-20 16:40:09 +01002029 std::vector<int> signedSize(sizeTensorInfo.GetNumElements(), 1);
2030
2031 // if size buffer data is not specified, all contents of size vector remain as values of 1
2032 if (sizeBufferPtr->data.data())
2033 {
2034 ::memcpy(signedSize.data(), sizeBufferPtr->data.data(), sizeTensorInfo.GetNumBytes());
2035 }
2036
josh minorba424d22019-11-13 10:55:17 -06002037 std::vector<unsigned int> size(sizeTensorInfo.GetNumElements());
Mike Kelly377fb212023-01-10 15:55:28 +00002038 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Mike Kelly7ba84d62021-09-10 15:27:19 +01002039
2040 for (unsigned int i = 0; i < signedSize.size(); ++i)
2041 {
2042 int signedValue = signedSize[i];
Jim Flynnfca233e2021-09-23 12:16:53 +01002043
Mike Kelly7ba84d62021-09-10 15:27:19 +01002044 if (signedValue < -1 || signedValue > static_cast<int>(inputTensorInfo.GetShape()[i] - begin[i]))
2045 {
2046 throw ParseException(fmt::format("Invalid value for size {} size must be in range "
2047 "[-1, inputDimSize - begin] [-1, {}] inclusive {}",
2048 signedValue,
2049 inputTensorInfo.GetShape()[i] - begin[i],
2050 CHECK_LOCATION().AsString()));
2051 }
2052
2053 if (signedValue == -1)
2054 {
2055 size[i] = inputTensorInfo.GetShape()[i] - begin[i];
2056 }
2057 else
2058 {
2059 size[i] = static_cast<unsigned int>(signedValue);
2060 }
2061 }
2062
josh minorba424d22019-11-13 10:55:17 -06002063 desc = SliceDescriptor(begin, size);
2064
James Ward58dec6b2020-09-11 17:32:44 +01002065 auto layerName = fmt::format("Slice:{}:{}", subgraphIndex, operatorIndex);
josh minorba424d22019-11-13 10:55:17 -06002066
James Conroy05102392020-06-24 15:39:55 +01002067 IConnectableLayer* const layer = m_Network->AddSliceLayer(desc, layerName.c_str());
Mike Kelly377fb212023-01-10 15:55:28 +00002068
2069 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
2070 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
josh minorba424d22019-11-13 10:55:17 -06002071 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2072
2073 // register the input connection slots for the layer, connections are made after all layers have been created
2074 // only the tensors for the inputs are relevant, exclude the const tensors
2075 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2076 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2077
2078 // register the output connection slots for the layer, connections are made after all layers have been created
2079 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2080 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2081}
2082
Kevin May7d96b162021-02-03 17:38:41 +00002083void TfLiteParserImpl::ParseSoftmax(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01002084{
2085 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00002086 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2087 const auto* options = operatorPtr->builtin_options.AsSoftmaxOptions();
telsoa01c577f2c2018-08-31 09:22:23 +01002088
2089 SoftmaxDescriptor desc;
2090 desc.m_Beta = options->beta;
2091
2092 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2093 CHECK_VALID_SIZE(inputs.size(), 1);
2094 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2095 CHECK_VALID_SIZE(outputs.size(), 1);
2096
James Ward58dec6b2020-09-11 17:32:44 +01002097 auto layerName = fmt::format("Softmax:{}:{}", subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01002098 IConnectableLayer* const layer = m_Network->AddSoftmaxLayer(desc, layerName.c_str());
2099
Mike Kelly377fb212023-01-10 15:55:28 +00002100 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
telsoa01c577f2c2018-08-31 09:22:23 +01002101 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2102
2103 // register the input connection slots for the layer, connections are made after all layers have been created
2104 // only the tensors for the inputs are relevant, exclude the const tensors
2105 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2106 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2107
2108 // register the output connection slots for the layer, connections are made after all layers have been created
2109 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2110 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2111}
2112
Teresa Charlinfd33a692022-06-29 15:35:57 +01002113void TfLiteParserImpl::ParseLogSoftmax(size_t subgraphIndex, size_t operatorIndex)
2114{
2115 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2116
2117 LogSoftmaxDescriptor desc;
2118
2119 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2120 CHECK_VALID_SIZE(inputs.size(), 1);
2121 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2122 CHECK_VALID_SIZE(outputs.size(), 1);
2123
2124 auto layerName = fmt::format("LogSoftmax:{}:{}", subgraphIndex, operatorIndex);
2125 IConnectableLayer* const layer = m_Network->AddLogSoftmaxLayer(desc, layerName.c_str());
2126
Mike Kelly377fb212023-01-10 15:55:28 +00002127 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Teresa Charlinfd33a692022-06-29 15:35:57 +01002128 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2129
2130 // register the input connection slots for the layer, connections are made after all layers have been created
2131 // only the tensors for the inputs are relevant, exclude the const tensors
2132 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2133 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2134
2135 // register the output connection slots for the layer, connections are made after all layers have been created
2136 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2137 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2138}
2139
Kevin May7d96b162021-02-03 17:38:41 +00002140void TfLiteParserImpl::ParseSpaceToBatchND(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesbaded142019-02-08 19:02:48 -02002141{
2142 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2143
2144 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2145 CHECK_VALID_SIZE(inputs.size(), 3);
2146
2147 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2148 CHECK_VALID_SIZE(outputs.size(), 1);
2149
Mike Kelly377fb212023-01-10 15:55:28 +00002150 armnn::TensorInfo blockShapeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalvesbaded142019-02-08 19:02:48 -02002151 BufferRawPtr blockShapeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2152
Mike Kelly377fb212023-01-10 15:55:28 +00002153 armnn::TensorInfo padListTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Bruno Goncalvesbaded142019-02-08 19:02:48 -02002154 BufferRawPtr padListBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
2155
2156 std::vector<unsigned int> blockShape(blockShapeTensorInfo.GetNumElements());
2157 ::memcpy(blockShape.data(), blockShapeBufferPtr->data.data(), blockShapeTensorInfo.GetNumBytes());
2158
2159 std::vector<unsigned int> padListVector(padListTensorInfo.GetNumElements());
2160 ::memcpy(padListVector.data(), padListBufferPtr->data.data(), padListTensorInfo.GetNumBytes());
2161
2162 size_t step = 2;
2163 std::vector<std::pair<unsigned int, unsigned int>> padList;
2164 for (unsigned int i = 0; i < padListTensorInfo.GetNumElements() / step; ++i)
2165 {
2166 padList.emplace_back(padListVector[i * step], padListVector[i * step + 1]);
2167 }
2168
2169 armnn::SpaceToBatchNdDescriptor desc;
2170 desc.m_BlockShape = blockShape;
2171 desc.m_PadList = padList;
2172 desc.m_DataLayout = armnn::DataLayout::NHWC;
2173
James Ward58dec6b2020-09-11 17:32:44 +01002174 auto layerName = fmt::format("SpaceToBatchND:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesbaded142019-02-08 19:02:48 -02002175
Mike Kelly377fb212023-01-10 15:55:28 +00002176 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
James Conroy05102392020-06-24 15:39:55 +01002177
2178 IConnectableLayer* layer = m_Network->AddSpaceToBatchNdLayer(desc, layerName.c_str());
2179 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00002180
2181 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
2182 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Bruno Goncalvesbaded142019-02-08 19:02:48 -02002183 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2184
2185 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2186 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2187
2188 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2189 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2190}
2191
Teresa Charlin2a764ad2023-02-24 18:17:31 +00002192void TfLiteParserImpl::ParseSpaceToDepth(size_t subgraphIndex, size_t operatorIndex)
2193{
2194 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2195
2196 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2197 CHECK_VALID_SIZE(inputs.size(), 1);
2198 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2199 CHECK_VALID_SIZE(outputs.size(), 1);
2200
2201 armnn::SpaceToDepthDescriptor descriptor;
2202
2203 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2204 const auto* options = operatorPtr->builtin_options.AsSpaceToDepthOptions();
2205 auto blockSize = options->block_size;
2206 if (blockSize < 2)
2207 {
2208 throw ParseException(
2209 fmt::format("Operation has invalid block size: {} Block size should be >= 2 {}",
2210 blockSize,
2211 CHECK_LOCATION().AsString()));
2212 }
2213 descriptor.m_BlockSize = armnn::numeric_cast<uint32_t>(blockSize);
2214
2215 auto layerName = fmt::format("SpaceToDepth:{}:{}", subgraphIndex, operatorIndex);
2216 IConnectableLayer* layer = m_Network->AddSpaceToDepthLayer(descriptor, layerName.c_str());
2217 ARMNN_ASSERT(layer != nullptr);
2218 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
2219 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2220
2221 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2222 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2223
2224 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2225 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2226}
2227
Teresa Charlin3ab85482021-06-08 16:59:29 +01002228armnn::TensorInfo TfLiteParserImpl::OutputShapeOfSqueeze(std::vector<uint32_t> squeezeDims,
Mike Kelly0d77ae12022-01-07 17:42:27 +00002229 const armnn::TensorInfo& inputTensorInfo)
telsoa01c577f2c2018-08-31 09:22:23 +01002230{
Teresa Charlin3ab85482021-06-08 16:59:29 +01002231 CHECK_VALID_SIZE(squeezeDims.size(), 0, 1, 2, 3, 4);
telsoa01c577f2c2018-08-31 09:22:23 +01002232 static const uint32_t dimensionSequence[] = { 0, 1, 2, 3 };
2233
2234 if (inputTensorInfo.GetNumDimensions() > 4)
2235 {
2236 std::stringstream ss;
2237 ss << "Input tensor has unexpected number of dimensions:" << inputTensorInfo.GetNumDimensions()
2238 << " shape:" << inputTensorInfo.GetShape() << " "
2239 << CHECK_LOCATION().AsString();
2240 throw ParseException(ss.str());
2241 }
2242
2243 if (squeezeDims.empty())
2244 {
2245 squeezeDims.assign(dimensionSequence,
2246 dimensionSequence+inputTensorInfo.GetNumDimensions());
2247 }
2248
2249 std::vector<uint32_t> outputDims;
2250 for(unsigned int i = 0; i < inputTensorInfo.GetNumDimensions(); i++)
2251 {
2252 bool skipSqueeze = (std::find(squeezeDims.begin(), squeezeDims.end(), i) == squeezeDims.end());
2253 auto currentDimension = inputTensorInfo.GetShape()[i];
2254 if (skipSqueeze || currentDimension != 1)
2255 {
2256 outputDims.push_back(currentDimension);
2257 }
2258 }
2259
2260 if (outputDims.size() > 4)
2261 {
2262 std::stringstream ss;
2263 ss << "Output tensor has unexpected number of dimensions:" << inputTensorInfo.GetNumDimensions()
2264 << " shape:" << inputTensorInfo.GetShape() << " "
2265 << CHECK_LOCATION().AsString();
2266 throw ParseException(ss.str());
2267 }
2268
2269 TensorShape outShape = TensorShape(static_cast<unsigned int>(outputDims.size()),
2270 outputDims.data());
2271
2272 // we need to preserve the tensor type and the quantization data as well
2273 TensorInfo outTensorInfo = inputTensorInfo;
2274 outTensorInfo.SetShape(outShape);
2275
2276 return outTensorInfo;
2277}
2278
Keith Davis0176fd82021-06-01 17:36:32 +01002279void TfLiteParserImpl::ParseShape(size_t subgraphIndex, size_t operatorIndex)
2280{
2281 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2282
2283 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2284 CHECK_VALID_SIZE(inputs.size(), 1);
2285 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2286 CHECK_VALID_SIZE(outputs.size(), 1);
2287
2288 auto layerName = fmt::format("Shape:{}:{}", subgraphIndex, operatorIndex);
2289
2290 IConnectableLayer* layer = m_Network->AddShapeLayer(layerName.c_str());
2291 ARMNN_ASSERT(layer != nullptr);
2292
Mike Kelly377fb212023-01-10 15:55:28 +00002293 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Keith Davis0176fd82021-06-01 17:36:32 +01002294 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2295
2296 // Check if output tensor type is Signed32 or Signed64
2297 if (outputTensorInfo.GetDataType() != armnn::DataType::Signed32 &&
2298 outputTensorInfo.GetDataType() != armnn::DataType::Signed64)
2299 {
2300 throw ParseException(
2301 fmt::format(
2302 "Output tensor data type is not supported. (Supported types: Signed32 & Signed64) {}",
2303 CHECK_LOCATION().AsString()));
2304 }
2305
2306 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2307 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2308
2309 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2310 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2311}
2312
Kevin May7d96b162021-02-03 17:38:41 +00002313void TfLiteParserImpl::ParseSqueeze(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01002314{
2315 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2316
2317 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2318 CHECK_VALID_SIZE(inputs.size(), 1);
2319
2320 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2321 CHECK_VALID_SIZE(outputs.size(), 1);
2322
2323 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2324 const auto * options = operatorPtr->builtin_options.AsSqueezeOptions();
James Ward58dec6b2020-09-11 17:32:44 +01002325 auto layerName = fmt::format("Squeeze:{}:{}", subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01002326
Mike Kelly377fb212023-01-10 15:55:28 +00002327 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Teresa Charlin3ab85482021-06-08 16:59:29 +01002328
2329 std::vector<uint32_t> squeezeDim;
2330 // A single negative dim index is interpreted as a negative index in python
2331 // Meaning the index will be the shape size plus the negative index value
2332 if (options->squeeze_dims.size() == 1 && options->squeeze_dims[0] < 0)
2333 {
2334 int32_t dim = static_cast<int32_t>(inputTensorInfo.GetShape().GetNumDimensions()) + options->squeeze_dims[0];
2335 squeezeDim.push_back(static_cast<uint32_t>(dim));
2336 }
2337 else
2338 {
2339 squeezeDim = AsUnsignedVector(options->squeeze_dims);
2340 }
2341
2342 armnn::TensorInfo outputTensorInfo = TfLiteParserImpl::OutputShapeOfSqueeze(squeezeDim, inputTensorInfo);
2343
James Conroy05102392020-06-24 15:39:55 +01002344 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
telsoa01c577f2c2018-08-31 09:22:23 +01002345
2346 ReshapeDescriptor reshapeDesc;
2347 reshapeDesc.m_TargetShape = outputTensorInfo.GetShape();
2348
Mike Kellyb2293702023-02-14 17:16:12 +00002349 auto outputTensorIds = GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex);
2350 m_TensorInfos[outputTensorIds[0]] = outputTensorInfo;
2351
telsoa01c577f2c2018-08-31 09:22:23 +01002352 IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002353 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01002354 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2355
2356 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2357 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2358
2359 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2360 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2361}
2362
Kevin May7d96b162021-02-03 17:38:41 +00002363void TfLiteParserImpl::ParseStridedSlice(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002364{
2365 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2366
2367 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2368 CHECK_VALID_SIZE(inputs.size(), 4);
2369
2370 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2371 CHECK_VALID_SIZE(outputs.size(), 1);
2372
Mike Kelly0d77ae12022-01-07 17:42:27 +00002373 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2374 const auto* options = operatorPtr->builtin_options.AsStridedSliceOptions();
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002375
2376 StridedSliceDescriptor desc;
2377 desc.m_BeginMask = options->begin_mask;
2378 desc.m_EllipsisMask = options->ellipsis_mask;
2379 desc.m_EndMask = options->end_mask;
2380 desc.m_NewAxisMask = options->new_axis_mask;
2381 desc.m_ShrinkAxisMask = options->shrink_axis_mask;
2382 desc.m_DataLayout = armnn::DataLayout::NHWC;
2383
Mike Kelly377fb212023-01-10 15:55:28 +00002384 armnn::TensorInfo beginTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002385 BufferRawPtr beginBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2386
2387 std::vector<int> begin(beginTensorInfo.GetNumElements());
2388 ::memcpy(begin.data(), beginBufferPtr->data.data(), beginTensorInfo.GetNumBytes());
2389
Mike Kelly377fb212023-01-10 15:55:28 +00002390 armnn::TensorInfo endTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002391 BufferRawPtr endBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
2392
2393 std::vector<int> end(endTensorInfo.GetNumElements());
2394 ::memcpy(end.data(), endBufferPtr->data.data(), endTensorInfo.GetNumBytes());
2395
Mike Kelly377fb212023-01-10 15:55:28 +00002396 armnn::TensorInfo strideTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 3);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002397 BufferRawPtr strideBufferPtr = GetBuffer(m_Model, inputs[3]->buffer);
2398
2399 std::vector<int> stride(strideTensorInfo.GetNumElements());
2400 ::memcpy(stride.data(), strideBufferPtr->data.data(), strideTensorInfo.GetNumBytes());
2401
2402 desc.m_Begin = begin;
2403 desc.m_End = end;
2404 desc.m_Stride = stride;
2405
James Ward58dec6b2020-09-11 17:32:44 +01002406 auto layerName = fmt::format("StridedSlice:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002407 IConnectableLayer* layer = m_Network->AddStridedSliceLayer(desc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002408 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002409
Mike Kelly377fb212023-01-10 15:55:28 +00002410 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002411 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2412
2413 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2414 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2415
2416 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2417 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2418}
2419
Kevin May7d96b162021-02-03 17:38:41 +00002420void TfLiteParserImpl::ParseSub(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002421{
2422 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2423
Mike Kelly0d77ae12022-01-07 17:42:27 +00002424 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2425 const auto* options = operatorPtr->builtin_options.AsSubOptions();
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002426
2427 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2428 CHECK_VALID_SIZE(inputs.size(), 2);
2429
2430 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2431 CHECK_VALID_SIZE(outputs.size(), 1);
2432
Mike Kelly377fb212023-01-10 15:55:28 +00002433 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2434 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002435
James Ward58dec6b2020-09-11 17:32:44 +01002436 auto layerName = fmt::format("Sub:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +00002437 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Sub, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002438 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002439
Mike Kelly377fb212023-01-10 15:55:28 +00002440 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002441 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2442
2443 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002444 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002445
2446 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2447
2448 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2449 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2450}
2451
Kevin May7d96b162021-02-03 17:38:41 +00002452void TfLiteParserImpl::ParseDiv(size_t subgraphIndex, size_t operatorIndex)
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302453{
2454 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2455
Mike Kelly0d77ae12022-01-07 17:42:27 +00002456 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2457 const auto* options = operatorPtr->builtin_options.AsDivOptions();
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302458
2459 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2460 CHECK_VALID_SIZE(inputs.size(), 2);
2461
2462 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2463 CHECK_VALID_SIZE(outputs.size(), 1);
2464
Mike Kelly377fb212023-01-10 15:55:28 +00002465 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2466 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302467
James Ward58dec6b2020-09-11 17:32:44 +01002468 auto layerName = fmt::format("Div:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +00002469 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Div, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002470 ARMNN_ASSERT(layer != nullptr);
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302471
Mike Kelly377fb212023-01-10 15:55:28 +00002472 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302473 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2474
2475 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002476 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302477 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2478
2479 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2480 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2481}
2482
Teresa Charlincdbd40b2022-02-25 13:21:55 +00002483void TfLiteParserImpl::ParseFloorDiv(size_t subgraphIndex, size_t operatorIndex)
2484{
2485 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2486
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);
Teresa Charlincdbd40b2022-02-25 13:21:55 +00002495
2496 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());
Teresa Charlincdbd40b2022-02-25 13:21:55 +00002498 ARMNN_ASSERT(layer != nullptr);
2499
Mike Kelly377fb212023-01-10 15:55:28 +00002500 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Teresa Charlincdbd40b2022-02-25 13:21:55 +00002501 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2502
2503 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2504 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
2505 layer = AddFusedFloorLayer(layer, 0);
2506
2507 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2508 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2509}
2510
Kevin May7d96b162021-02-03 17:38:41 +00002511void TfLiteParserImpl::ParseAdd(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002512{
2513 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2514
Mike Kelly0d77ae12022-01-07 17:42:27 +00002515 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2516 const auto* options = operatorPtr->builtin_options.AsAddOptions();
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002517
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);
Bruno Goncalves9c761a62018-12-27 14:20:35 -02002526
James Ward58dec6b2020-09-11 17:32:44 +01002527 auto layerName = fmt::format("Add:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +00002528 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Add, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002529 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002530
Mike Kelly377fb212023-01-10 15:55:28 +00002531 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002532 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2533
2534 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002535 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002536 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
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::ParseMul(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesf803f782018-12-18 13:40:30 -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.AsMulOptions();
Bruno Goncalvesf803f782018-12-18 13:40:30 -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("Mul:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +00002559 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Mul, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002560 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002561
Mike Kelly377fb212023-01-10 15:55:28 +00002562 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Bruno Goncalvesf803f782018-12-18 13:40:30 -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]});
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002567 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2568
2569 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2570 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2571}
2572
Kevin May7d96b162021-02-03 17:38:41 +00002573void TfLiteParserImpl::ParseMean(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002574{
2575 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2576
2577 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2578
2579 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2580 CHECK_VALID_SIZE(outputs.size(), 1);
2581
Teresa Charlin046e2cb2023-03-28 17:20:19 +01002582 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2583 TensorInfo dimTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002584
2585 armnn::MeanDescriptor desc;
Teresa Charlin046e2cb2023-03-28 17:20:19 +01002586 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2587 // Get const axis value from model and set it to descriptor.
2588 if (axisBufferPtr != nullptr)
2589 {
2590 std::vector<int32_t> axisData(dimTensorInfo.GetNumElements());
2591 ::memcpy(axisData.data(), axisBufferPtr->data.data(), dimTensorInfo.GetNumBytes());
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002592
Teresa Charlin046e2cb2023-03-28 17:20:19 +01002593 // Convert the axis to unsigned int and remove duplicates.
2594 auto rank = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
2595 std::set<unsigned int> uniqueAxis;
2596 std::transform(axisData.begin(),
2597 axisData.end(),
2598 std::inserter(uniqueAxis, uniqueAxis.begin()),
2599 [rank](int i)->unsigned int{
2600 return static_cast<uint32_t>(((i + rank) % rank)); });
2601 desc.m_Axis.assign(uniqueAxis.begin(), uniqueAxis.end());
2602 }
2603 else
2604 {
2605 for (uint32_t i = 0; i < inputTensorInfo.GetNumDimensions(); ++i)
2606 {
2607 desc.m_Axis.push_back(i);
2608 }
2609 }
2610
Sadik Armagand109a4d2020-07-28 10:42:13 +01002611 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002612
Teresa Charlin046e2cb2023-03-28 17:20:19 +01002613 desc.m_KeepDims = inputTensorInfo.GetNumDimensions() == outputTensorInfo.GetNumDimensions() ? true : false;
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002614
James Ward58dec6b2020-09-11 17:32:44 +01002615 auto layerName = fmt::format("Mean:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002616 IConnectableLayer* layer = m_Network->AddMeanLayer(desc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002617 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002618
Mike Kelly377fb212023-01-10 15:55:28 +00002619 outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002620 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2621
2622 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2623 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2624
2625 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2626 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2627}
2628
Kevin May7d96b162021-02-03 17:38:41 +00002629void TfLiteParserImpl::ParsePad(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002630{
2631 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2632
Kevin May7d96b162021-02-03 17:38:41 +00002633 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002634
Kevin May7d96b162021-02-03 17:38:41 +00002635 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002636 CHECK_VALID_SIZE(outputs.size(), 1);
2637
Mike Kelly377fb212023-01-10 15:55:28 +00002638 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2639 armnn::TensorInfo padTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002640
Mike Kelly0d77ae12022-01-07 17:42:27 +00002641 std::vector<unsigned int> padBuffer = GetUIntBuffer(padTensorInfo, m_Model, inputs[1]->buffer);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002642
2643 size_t step = 2;
2644 armnn::PadDescriptor desc;
Mike Kelly0d77ae12022-01-07 17:42:27 +00002645 auto opcode = GetOpCode(m_Model, subgraphIndex, operatorIndex);
2646
2647 if (opcode == tflite::BuiltinOperator_PAD)
Narumol Prangnawarat8719d222020-11-27 16:57:56 +00002648 {
Mike Kelly0d77ae12022-01-07 17:42:27 +00002649 CHECK_VALID_SIZE(inputs.size(), 2);
2650
2651 if (inputTensorInfo.IsQuantized())
2652 {
2653 desc.m_PadValue = static_cast<float>(inputTensorInfo.GetQuantizationOffset());
2654 }
Narumol Prangnawarat8719d222020-11-27 16:57:56 +00002655 }
Mike Kelly0d77ae12022-01-07 17:42:27 +00002656 else if (opcode == tflite::BuiltinOperator_PADV2)
2657 {
2658 CHECK_VALID_SIZE(inputs.size(), 3);
2659
Mike Kelly377fb212023-01-10 15:55:28 +00002660 armnn::TensorInfo padValueTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Mike Kelly0d77ae12022-01-07 17:42:27 +00002661
2662 if (padValueTensorInfo.GetNumElements() != 1)
2663 {
2664 ARMNN_THROW_PARSE_EXCEPTION("Multiple padding values are not supported in PADV2");
2665 }
2666 BufferRawPtr padValueBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
2667
2668 // Get the pad value from the input tensor
2669 if (padValueBufferPtr->data.size() > 0)
2670 {
2671 switch (padValueTensorInfo.GetDataType())
2672 {
2673 case armnn::DataType::Float32:
2674 {
2675 std::vector<float> padValueBuffer(padValueTensorInfo.GetNumElements());
2676 ::memcpy(padValueBuffer.data(), padValueBufferPtr->data.data(), padValueBufferPtr->data.size());
2677 desc.m_PadValue = padValueBuffer[0];
2678 break;
2679 }
2680 case armnn::DataType::QAsymmU8:
2681 {
2682 std::vector<uint8_t> padValueBuffer(padValueTensorInfo.GetNumElements());
2683 ::memcpy(padValueBuffer.data(), padValueBufferPtr->data.data(), padValueBufferPtr->data.size());
2684 desc.m_PadValue = armnn::Dequantize<uint8_t>(padValueBuffer[0],
2685 padValueTensorInfo.GetQuantizationScale(),
2686 padValueTensorInfo.GetQuantizationOffset());
2687 break;
2688 }
2689 case armnn::DataType::QAsymmS8:
2690 case armnn::DataType::QSymmS8:
2691 {
2692 std::vector<int8_t> padValueBuffer(padValueTensorInfo.GetNumElements());
2693 ::memcpy(padValueBuffer.data(), padValueBufferPtr->data.data(), padValueBufferPtr->data.size());
2694 desc.m_PadValue = armnn::Dequantize<int8_t>(padValueBuffer[0],
2695 padValueTensorInfo.GetQuantizationScale(),
2696 padValueTensorInfo.GetQuantizationOffset());
2697 break;
2698 }
2699 default: ARMNN_THROW_PARSE_EXCEPTION("Unsupported DataType");
2700 }
2701 }
2702 else if (inputTensorInfo.IsQuantized())
2703 {
2704 desc.m_PadValue = static_cast<float>(inputTensorInfo.GetQuantizationOffset());
2705 }
2706 }
2707
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002708 for (unsigned int i = 0; i < padTensorInfo.GetNumElements() / step; ++i)
2709 {
2710 desc.m_PadList.emplace_back(padBuffer[i * step], padBuffer[i * step + 1]);
2711 }
2712
Mike Kelly0d77ae12022-01-07 17:42:27 +00002713 auto layerName = (opcode == tflite::BuiltinOperator_PAD) ? fmt::format("Pad:{}:{}", subgraphIndex, operatorIndex)
2714 : fmt::format("PadV2:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01002715
2716 IConnectableLayer* layer = m_Network->AddPadLayer(desc, layerName.c_str());
2717 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00002718 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002719 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2720
2721 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2722 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2723
2724 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2725 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2726}
2727
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002728void TfLiteParserImpl::ParseMirrorPad(size_t subgraphIndex, size_t operatorIndex)
2729{
2730 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2731
2732 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2733 CHECK_VALID_SIZE(inputs.size(), 2);
2734
2735 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2736 CHECK_VALID_SIZE(outputs.size(), 1);
2737
Mike Kelly377fb212023-01-10 15:55:28 +00002738 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002739
Mike Kelly377fb212023-01-10 15:55:28 +00002740 armnn::TensorInfo padTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002741 BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2742
2743 std::vector<unsigned int> padBuffer(padTensorInfo.GetNumElements());
2744 ::memcpy(padBuffer.data(), bufferPtr->data.data(), padTensorInfo.GetNumBytes());
2745
2746 size_t step = 2;
2747 armnn::PadDescriptor desc;
2748 for (unsigned int i = 0; i < padTensorInfo.GetNumElements() / step; ++i)
2749 {
2750 desc.m_PadList.emplace_back(padBuffer[i * step], padBuffer[i * step + 1]);
2751 }
2752
2753 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2754 const auto* options = operatorPtr->builtin_options.AsMirrorPadOptions();
2755
2756 if (options->mode == tflite::MirrorPadMode_REFLECT)
2757 {
2758 desc.m_PaddingMode = PaddingMode::Reflect;
2759 }
2760 else if (options->mode == tflite::MirrorPadMode_SYMMETRIC)
2761 {
2762 desc.m_PaddingMode = PaddingMode::Symmetric;
2763 }
2764 else
2765 {
2766 ARMNN_THROW_PARSE_EXCEPTION("PaddingMode must be either REFLECT or SYMMETRIC");
2767 }
2768
2769 // If padding mode is Reflect then both paddings must be no greater than inputShape(i) - 1.
2770 // If padding mode is Symmetric then both paddings must be no greater than inputShape(i).
2771 auto inputShape = inputTensorInfo.GetShape();
2772 auto padList = desc.m_PadList;
2773
2774 const unsigned int isReflect = static_cast<unsigned int>(desc.m_PaddingMode == PaddingMode::Reflect);
2775 for(unsigned int i = 0; i < padList.size(); ++i)
2776 {
2777 if(padList.at(i).first > (inputShape[i] - isReflect) ||
2778 padList.at(i).second > (inputShape[i] - isReflect))
2779 {
2780 ARMNN_THROW_PARSE_EXCEPTION("Padding values must be less (Reflect) or "
2781 "equal (Symmetric) to the dimension size.");
2782 }
2783 }
2784
2785 auto layerName = fmt::format("MirrorPad:{}:{}", subgraphIndex, operatorIndex);
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002786
2787 IConnectableLayer* layer = m_Network->AddPadLayer(desc, layerName.c_str());
2788 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00002789 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002790 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2791
2792 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2793 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2794
2795 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2796 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2797}
2798
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002799void TfLiteParserImpl::ParsePrelu(size_t subgraphIndex, size_t operatorIndex)
2800{
2801 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2802
2803 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2804 CHECK_VALID_SIZE(inputs.size(), 2);
2805
2806 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2807 CHECK_VALID_SIZE(outputs.size(), 1);
2808
2809 auto layerName = fmt::format("Prelu:{}:{}", subgraphIndex, operatorIndex);
2810
Mike Kelly377fb212023-01-10 15:55:28 +00002811 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2812 armnn::TensorInfo alphaTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002813
2814 IConnectableLayer* layer = m_Network->AddPreluLayer(layerName.c_str());
2815 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00002816
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002817
2818 if (IsConstTensor(inputs[1]))
2819 {
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002820 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawaratbf99b5f2021-05-27 09:55:43 +01002821 armnn::IInputSlot* slot = &(layer->GetInputSlot(0));
2822 RegisterConsumerOfTensor(subgraphIndex, inputTensorIndexes[0], slot);
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002823
Mike Kelly5880b912022-01-28 16:18:54 +00002824 auto alphaTensorAndData = CreateConstTensorNonPermuted(inputs[1], alphaTensorInfo,
2825 inputTensorInfo.GetDataType());
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002826 std::string constLayerName = fmt::format("Constant:{}", inputs[1]->name);
2827 IConnectableLayer* constLayer =
Mike Kelly5880b912022-01-28 16:18:54 +00002828 m_Network->AddConstantLayer(alphaTensorAndData.first, constLayerName.c_str());
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002829 ARMNN_ASSERT(constLayer != nullptr);
2830
2831 constLayer->GetOutputSlot(0).SetTensorInfo(alphaTensorInfo);
2832 constLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1));
2833 RegisterOutputSlots(subgraphIndex,
2834 VIRTUAL_OPERATOR_ID,
2835 constLayer,
2836 { inputTensorIndexes[1] });
2837 }
2838 else
2839 {
2840 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2841 RegisterInputSlots(subgraphIndex, operatorIndex, layer, inputTensorIndexes);
2842 }
2843
Mike Kelly377fb212023-01-10 15:55:28 +00002844 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
2845 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
2846 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2847
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002848 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2849 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2850}
2851
Kevin May7d96b162021-02-03 17:38:41 +00002852void TfLiteParserImpl::ParseQuantize(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan66dedc72019-12-10 16:32:07 +00002853{
2854 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2855
2856 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2857 CHECK_VALID_SIZE(inputs.size(), 1);
2858
2859 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2860 CHECK_VALID_SIZE(outputs.size(), 1);
2861
James Ward58dec6b2020-09-11 17:32:44 +01002862 auto layerName = fmt::format("Quantize:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan66dedc72019-12-10 16:32:07 +00002863
2864 IConnectableLayer* layer = m_Network->AddQuantizeLayer(layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01002865 ARMNN_ASSERT(layer != nullptr);
Sadik Armagan66dedc72019-12-10 16:32:07 +00002866
Mike Kelly377fb212023-01-10 15:55:28 +00002867 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Sadik Armagan66dedc72019-12-10 16:32:07 +00002868 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2869
2870 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2871 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2872
2873 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2874 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2875}
Finn Williamsc42c3842019-01-22 14:18:11 +00002876
Kevin May7d96b162021-02-03 17:38:41 +00002877void TfLiteParserImpl::ParseRelu(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan58f39192018-09-17 14:14:39 +01002878{
Finn Williamsc42c3842019-01-22 14:18:11 +00002879 ParseActivation(subgraphIndex,operatorIndex, ActivationFunction::ReLu);
Sadik Armagan58f39192018-09-17 14:14:39 +01002880}
2881
Kevin May7d96b162021-02-03 17:38:41 +00002882void TfLiteParserImpl::ParseRelu6(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan58f39192018-09-17 14:14:39 +01002883{
Finn Williamsc42c3842019-01-22 14:18:11 +00002884 ParseActivation(subgraphIndex,operatorIndex, ActivationFunction::BoundedReLu);
2885}
Sadik Armagan58f39192018-09-17 14:14:39 +01002886
Kevin May7d96b162021-02-03 17:38:41 +00002887void TfLiteParserImpl::ParseLeakyRelu(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan12239e72020-05-27 11:06:17 +01002888{
Jan Eilers2f746b32020-07-28 14:00:06 +01002889 ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::LeakyReLu);
Sadik Armagan12239e72020-05-27 11:06:17 +01002890}
2891
Kevin May7d96b162021-02-03 17:38:41 +00002892void TfLiteParserImpl::ParseLogistic(size_t subgraphIndex, size_t operatorIndex)
Finn Williamsc42c3842019-01-22 14:18:11 +00002893{
2894 ParseActivation(subgraphIndex,operatorIndex,ActivationFunction::Sigmoid);
2895}
2896
Kevin May7d96b162021-02-03 17:38:41 +00002897void TfLiteParserImpl::ParseTanH(size_t subgraphIndex, size_t operatorIndex)
Nina Drozd99851762019-04-09 09:37:38 +01002898{
2899 ParseActivation(subgraphIndex,operatorIndex,ActivationFunction::TanH);
2900}
2901
Kevin May7d96b162021-02-03 17:38:41 +00002902void TfLiteParserImpl::ParseElu(size_t subgraphIndex, size_t operatorIndex)
Matthew Sloyan7515d072020-12-16 12:50:01 +00002903{
2904 ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::Elu);
2905}
2906
Kevin May7d96b162021-02-03 17:38:41 +00002907void TfLiteParserImpl::ParseHardSwish(size_t subgraphIndex, size_t operatorIndex)
Jan Eilers2f746b32020-07-28 14:00:06 +01002908{
2909 ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::HardSwish);
2910}
Finn Williamsc42c3842019-01-22 14:18:11 +00002911
Kevin May7d96b162021-02-03 17:38:41 +00002912void TfLiteParserImpl::ParseActivation(size_t subgraphIndex, size_t operatorIndex, ActivationFunction activationType)
Finn Williamsc42c3842019-01-22 14:18:11 +00002913{
2914 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00002915 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
Jan Eilers8eb25602020-03-09 12:13:48 +00002916 IgnoreUnused(operatorPtr);
Sadik Armagan58f39192018-09-17 14:14:39 +01002917
2918 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2919 CHECK_VALID_SIZE(inputs.size(), 1);
2920
2921 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2922 CHECK_VALID_SIZE(outputs.size(), 1);
2923
James Ward58dec6b2020-09-11 17:32:44 +01002924 auto layerName = fmt::format("Activation:");
Sadik Armagan58f39192018-09-17 14:14:39 +01002925 ActivationDescriptor activationDesc;
Finn Williamsc42c3842019-01-22 14:18:11 +00002926 activationDesc.m_Function = activationType;
2927
2928 switch (activationType)
2929 {
2930 case ActivationFunction::ReLu:
2931 {
James Ward58dec6b2020-09-11 17:32:44 +01002932 layerName += fmt::format("RELU:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsc42c3842019-01-22 14:18:11 +00002933 break;
2934 }
2935 case ActivationFunction::BoundedReLu:
2936 {
James Ward58dec6b2020-09-11 17:32:44 +01002937 layerName += fmt::format("RELU6:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsc42c3842019-01-22 14:18:11 +00002938 activationDesc.m_A = 6.0f;
2939 activationDesc.m_B = 0.0f;
2940 break;
2941 }
2942 case ActivationFunction::Sigmoid:
2943 {
James Ward58dec6b2020-09-11 17:32:44 +01002944 layerName += fmt::format("SIGMOID:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsc42c3842019-01-22 14:18:11 +00002945 break;
2946 }
Nina Drozd99851762019-04-09 09:37:38 +01002947 case ActivationFunction::TanH:
2948 {
James Ward58dec6b2020-09-11 17:32:44 +01002949 layerName += fmt::format("TANH:{}:{}", subgraphIndex, operatorIndex);
Nina Drozd99851762019-04-09 09:37:38 +01002950 activationDesc.m_A = 1.0f;
2951 activationDesc.m_B = 1.0f;
2952 break;
2953 }
Sadik Armagan12239e72020-05-27 11:06:17 +01002954 case ActivationFunction::LeakyReLu:
2955 {
James Ward58dec6b2020-09-11 17:32:44 +01002956 layerName += fmt::format("LEAKYRELU:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00002957 const auto* options = operatorPtr->builtin_options.AsLeakyReluOptions();
Sadik Armagan12239e72020-05-27 11:06:17 +01002958 activationDesc.m_A = options->alpha;
2959 break;
2960 }
Matthew Sloyan7515d072020-12-16 12:50:01 +00002961 case ActivationFunction::Elu:
2962 {
2963 layerName += fmt::format("ELU:{}:{}", subgraphIndex, operatorIndex);
2964 activationDesc.m_A = 1.0f;
2965 break;
2966 }
Jan Eilers2f746b32020-07-28 14:00:06 +01002967 case ActivationFunction::HardSwish:
Matthew Sloyan7515d072020-12-16 12:50:01 +00002968 {
James Ward58dec6b2020-09-11 17:32:44 +01002969 layerName += fmt::format("HARDSWISH:{}:{}", subgraphIndex, operatorIndex);
Jan Eilers2f746b32020-07-28 14:00:06 +01002970 break;
Matthew Sloyan7515d072020-12-16 12:50:01 +00002971 }
Finn Williamsc42c3842019-01-22 14:18:11 +00002972 default:
2973 {
2974 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01002975 fmt::format("Unexpected ActivationFunction[{}] when creating layerName {} ",
2976 static_cast<int>(activationType), CHECK_LOCATION().AsString()));
Finn Williamsc42c3842019-01-22 14:18:11 +00002977 }
2978 }
2979
2980 IConnectableLayer* const layer = m_Network->AddActivationLayer(activationDesc, layerName.c_str());
Sadik Armagan58f39192018-09-17 14:14:39 +01002981
Mike Kelly377fb212023-01-10 15:55:28 +00002982 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Sadik Armagan58f39192018-09-17 14:14:39 +01002983 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2984
2985 // register the input connection slots for the layer, connections are made after all layers have been created
2986 // only the tensors for the inputs are relevant, exclude the const tensors
2987 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2988 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2989
2990 // register the output connection slots for the layer, connections are made after all layers have been created
2991 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2992 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2993}
Mike Kelly0d77ae12022-01-07 17:42:27 +00002994armnn::TensorInfo TfLiteParserImpl::OutputShapeOfReshape(const armnn::TensorInfo& inputTensorInfo,
2995 const std::vector<int32_t>& targetDimsIn)
Sadikb94967b2018-09-19 15:30:00 +01002996{
2997 std::vector<unsigned int> outputDims(targetDimsIn.begin(), targetDimsIn.end());
2998 const auto stretchDim = std::find(targetDimsIn.begin(), targetDimsIn.end(), -1);
2999
3000 if (stretchDim != targetDimsIn.end())
3001 {
3002 if (std::find(std::next(stretchDim), targetDimsIn.end(), -1) != targetDimsIn.end())
3003 {
3004 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003005 fmt::format("At most one component of shape can be -1 {}", CHECK_LOCATION().AsString()));
Sadikb94967b2018-09-19 15:30:00 +01003006 }
3007
3008 auto targetNumElements =
Matthew Sloyan589e3e82020-09-11 16:17:48 +01003009 armnn::numeric_cast<unsigned int>(
Sadikb94967b2018-09-19 15:30:00 +01003010 std::accumulate(targetDimsIn.begin(), targetDimsIn.end(), -1, std::multiplies<int32_t>()));
3011
3012 auto stretchIndex = static_cast<size_t>(std::distance(targetDimsIn.begin(), stretchDim));
3013 outputDims[stretchIndex] = inputTensorInfo.GetNumElements() / targetNumElements;
3014 }
3015
3016 TensorShape outputShape = TensorShape(static_cast<unsigned int>(outputDims.size()), outputDims.data());
3017
3018 TensorInfo reshapeInfo = inputTensorInfo;
3019 reshapeInfo.SetShape(outputShape);
3020
3021 return reshapeInfo;
3022}
3023
Kevin May7d96b162021-02-03 17:38:41 +00003024void TfLiteParserImpl::ParseReshape(size_t subgraphIndex, size_t operatorIndex)
Sadikb94967b2018-09-19 15:30:00 +01003025{
3026 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3027
3028 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Sadikb94967b2018-09-19 15:30:00 +01003029
3030 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3031 CHECK_VALID_SIZE(outputs.size(), 1);
3032
Mike Kelly0d77ae12022-01-07 17:42:27 +00003033 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3034 const auto* options = operatorPtr->builtin_options.AsReshapeOptions();
James Ward58dec6b2020-09-11 17:32:44 +01003035 auto layerName = fmt::format("Reshape:{}:{}", subgraphIndex, operatorIndex);
Sadikb94967b2018-09-19 15:30:00 +01003036
Mike Kelly377fb212023-01-10 15:55:28 +00003037 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
kevmay0171972a82018-12-17 14:28:03 +00003038 armnn::TensorInfo actualOutputTensorInfo = ToTensorInfo(outputs[0]);
James Conroy05102392020-06-24 15:39:55 +01003039 CheckMatchingQuantization(inputTensorInfo, actualOutputTensorInfo, layerName, "Input 0", "Output 0");
Derek Lambertic9e52792020-03-11 11:42:26 +00003040
Jan Eilersbac9b352020-07-13 13:40:24 +01003041 // Extracting new shape for the output
3042 // There are two ways it can be passed
3043 // * First is to define the target shape in the operator built-in options
3044 // * Second is to pass it as a second input tensor
Derek Lambertic9e52792020-03-11 11:42:26 +00003045 std::vector<int32_t> targetShape;
Jan Eilersbac9b352020-07-13 13:40:24 +01003046 bool targetShapeFound = false;
3047 // Check if built-in options were given
3048 if (options != nullptr)
Derek Lambertic9e52792020-03-11 11:42:26 +00003049 {
Jan Eilersbac9b352020-07-13 13:40:24 +01003050 // make sure the parameter is given
3051 if (options->new_shape.empty() == false)
Derek Lambertic9e52792020-03-11 11:42:26 +00003052 {
Jan Eilersbac9b352020-07-13 13:40:24 +01003053 targetShape = options->new_shape;
3054 targetShapeFound = true;
Derek Lambertif4a953f2020-03-17 14:25:57 +00003055 }
Derek Lambertic9e52792020-03-11 11:42:26 +00003056 }
Jan Eilersbac9b352020-07-13 13:40:24 +01003057
3058 // If there is no built-in option given or if the built-in new_shape parameter was empty
3059 if (!targetShapeFound)
Derek Lambertic9e52792020-03-11 11:42:26 +00003060 {
Teresa Charlin6a056a42021-12-01 10:25:43 +00003061 // Check for a second input tensor
3062 if (inputs.size() > 1 && inputs[1] != nullptr)
Jan Eilersbac9b352020-07-13 13:40:24 +01003063 {
3064 if (inputs[1]->is_variable)
3065 {
3066 ARMNN_THROW_PARSE_EXCEPTION( "Target shapes defined in non-const input tensors is not supported");
3067 }
3068
3069 if (inputs[1]->shape.size() != 1)
3070 {
3071 ARMNN_THROW_PARSE_EXCEPTION("Target 'shape' input is not a 1D tensor");
3072 }
3073
3074 if (inputs[1]->type != tflite::TensorType_INT32)
3075 {
3076 ARMNN_THROW_PARSE_EXCEPTION("Target 'shape' input is not an int32 type");
3077 }
3078
Teresa Charlin6a056a42021-12-01 10:25:43 +00003079 // Extract target shape from input
3080 auto bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
3081 auto values = reinterpret_cast<const int32_t*>(bufferPtr->data.data());
Cathal Corbettd2f73232021-12-10 13:38:52 +00003082 if (values)
Sadik Armagan19a1c032021-01-20 12:17:00 +00003083 {
Cathal Corbettd2f73232021-12-10 13:38:52 +00003084 for (int i = 0; i < inputs[1]->shape[0]; ++i)
3085 {
3086 targetShape.push_back(values[i]);
3087 }
Sadik Armagan19a1c032021-01-20 12:17:00 +00003088 }
Cathal Corbettd2f73232021-12-10 13:38:52 +00003089 else
Jan Eilersbac9b352020-07-13 13:40:24 +01003090 {
Cathal Corbettd2f73232021-12-10 13:38:52 +00003091 try
3092 {
3093 // We attempt to infer during Runtime.
Mike Kelly04d82292023-01-19 18:29:40 +00003094 TensorShape reshapeShapes = ToTensorInfo(inputs[1]).GetShape();
3095
3096 if (reshapeShapes[0] == actualOutputTensorInfo.GetNumDimensions())
3097 {
3098 for (unsigned int i = 0; i < actualOutputTensorInfo.GetShape().GetNumDimensions(); ++i)
3099 {
3100 targetShape.push_back(actualOutputTensorInfo.GetShape()[i]);
3101 }
3102 }
Cathal Corbettd2f73232021-12-10 13:38:52 +00003103 // The parser only supports shape (batch, -1) or (-1) for non-constant shape input.
Mike Kelly04d82292023-01-19 18:29:40 +00003104 else if (reshapeShapes[0] > 2)
Cathal Corbettd2f73232021-12-10 13:38:52 +00003105 {
3106 throw ParseException(fmt::format("Invalid input shape '{}' in Reshape layer '{}' {}. "
3107 "When inferring during runtime, the parser only supports "
3108 "shape (batch, -1) or (-1) for target shape input.",
3109 reshapeShapes[0],
3110 layerName,
3111 CHECK_LOCATION().AsString()));
3112 }
Mike Kelly04d82292023-01-19 18:29:40 +00003113 else
Cathal Corbettd2f73232021-12-10 13:38:52 +00003114 {
Mike Kelly04d82292023-01-19 18:29:40 +00003115 const int32_t numInputElements = inputTensorInfo.GetNumElements();
3116 const int32_t inputTensorShape = inputTensorInfo.GetShape()[0];
3117 if (reshapeShapes[0] == 1)
3118 {
3119 targetShape = {numInputElements};
3120 }
3121 else if (reshapeShapes[0] == 2)
3122 {
3123 targetShape = {inputTensorShape, numInputElements / inputTensorShape};
3124 }
Cathal Corbettd2f73232021-12-10 13:38:52 +00003125 }
3126 }
3127 catch (const std::exception& exc)
3128 {
3129 ARMNN_THROW_PARSE_EXCEPTION("Failed attempt to infer during runtime the target shape input for "
3130 "Reshape operation. Reshape operator target shape input buffer data "
3131 "is null. " << exc.what());
3132 }
Jan Eilersbac9b352020-07-13 13:40:24 +01003133 }
3134 }
3135 else
Derek Lambertic9e52792020-03-11 11:42:26 +00003136 {
3137 ARMNN_THROW_PARSE_EXCEPTION("Target shape not defined in reshape parameters or input tensor. "
3138 "At least one method required");
3139 }
Derek Lambertic9e52792020-03-11 11:42:26 +00003140 }
3141
kevmay0171972a82018-12-17 14:28:03 +00003142 armnn::TensorInfo reshapeOutputTensorInfo =
Kevin May7d96b162021-02-03 17:38:41 +00003143 TfLiteParserImpl::OutputShapeOfReshape(inputTensorInfo, targetShape);
Sadikb94967b2018-09-19 15:30:00 +01003144
kevmay0171972a82018-12-17 14:28:03 +00003145 // Check for valid input size and that reshape parameters equal output shape
Cathal Corbett2b922e22022-09-23 15:49:24 +01003146 // The output shape can be provided to us in 2 ways:
3147 // 1. through the normal 'shape' parameter given by outputs[indx]->shape
3148 // 2. through additional parameter 'shape_signature' given by outputs[indx]->buffer.
3149 // This parameter can sometimes contain -1 value not visible in the 'shape' parameter.
Aron Virginas-Tar70672f62019-01-23 14:00:00 +00003150 const armnn::TensorShape& reshapeOutputTensorShape = reshapeOutputTensorInfo.GetShape();
3151 if (inputs.size() > 1 && !CheckShape(reshapeOutputTensorShape, outputs[0]->shape))
kevmay0171972a82018-12-17 14:28:03 +00003152 {
Cathal Corbett2b922e22022-09-23 15:49:24 +01003153 // Attempt to extract output shape from secondary 'shape_signature'
3154 // parameter and try to CheckShape() with this param.
3155 std::vector<int32_t> secondaryOutputTargetShape = outputs[0]->shape_signature;
3156
3157 // if outputs[0]->shape_signature contain a -1 value, we need to compute its actual value
3158 // from reshape input in order to correctly verify reshape parameters equal output shape
3159 armnn::TensorInfo secondaryReshapeOutputTensorInfo =
3160 TfLiteParserImpl::OutputShapeOfReshape(inputTensorInfo, secondaryOutputTargetShape);
3161
3162 if (!CheckShape(reshapeOutputTensorShape, secondaryReshapeOutputTensorInfo.GetShape()))
3163 {
3164 std::stringstream ss;
3165 ss << "New shape defined in reshape parameters "
3166 << reshapeOutputTensorShape
3167 << " does not equal output shape "
3168 << actualOutputTensorInfo.GetShape()
3169 << ": "
3170 << CHECK_LOCATION().AsString();
3171 throw ParseException(ss.str());
3172 }
kevmay0171972a82018-12-17 14:28:03 +00003173 }
Mike Kelly377fb212023-01-10 15:55:28 +00003174 auto outputTensorIds = GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex);
kevmay0171972a82018-12-17 14:28:03 +00003175
Sadikb94967b2018-09-19 15:30:00 +01003176 ReshapeDescriptor reshapeDesc;
kevmay0171972a82018-12-17 14:28:03 +00003177 reshapeDesc.m_TargetShape = reshapeOutputTensorInfo.GetShape();
Mike Kelly377fb212023-01-10 15:55:28 +00003178 m_TensorInfos[outputTensorIds[0]] = reshapeOutputTensorInfo;
Sadikb94967b2018-09-19 15:30:00 +01003179
Sadikb94967b2018-09-19 15:30:00 +01003180 IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01003181 ARMNN_ASSERT(layer != nullptr);
kevmay0171972a82018-12-17 14:28:03 +00003182 layer->GetOutputSlot(0).SetTensorInfo(reshapeOutputTensorInfo);
Sadikb94967b2018-09-19 15:30:00 +01003183
3184 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3185 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3186
3187 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3188 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3189}
3190
Kevin May7d96b162021-02-03 17:38:41 +00003191void TfLiteParserImpl::ParseResizeBilinear(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003192{
Sadik Armagana3b31f02019-12-05 09:08:53 +00003193 ParseResize(subgraphIndex, operatorIndex, ResizeMethod::Bilinear);
3194}
3195
Kevin May7d96b162021-02-03 17:38:41 +00003196void TfLiteParserImpl::ParseResizeNearestNeighbor(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagana3b31f02019-12-05 09:08:53 +00003197{
3198 ParseResize(subgraphIndex, operatorIndex, ResizeMethod::NearestNeighbor);
3199}
3200
Kevin May7d96b162021-02-03 17:38:41 +00003201void TfLiteParserImpl::ParseResize(size_t subgraphIndex, size_t operatorIndex, ResizeMethod resizeMethod)
Sadik Armagana3b31f02019-12-05 09:08:53 +00003202{
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003203 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3204
3205 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3206 CHECK_VALID_SIZE(inputs.size(), 2);
3207
3208 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3209 CHECK_VALID_SIZE(outputs.size(), 1);
3210
Mike Kelly377fb212023-01-10 15:55:28 +00003211 armnn::TensorInfo sizeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003212
3213 // Data for the parsed tensor args (size) must be stored locally.
3214 std::vector<int32_t> sizeTensorData(sizeTensorInfo.GetNumElements());
3215
3216 BufferRawPtr sizeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
3217 ::memcpy(sizeTensorData.data(), sizeBufferPtr->data.data(), sizeTensorInfo.GetNumBytes());
3218
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01003219 ResizeDescriptor desc;
Sadik Armagana3b31f02019-12-05 09:08:53 +00003220 desc.m_Method = resizeMethod;
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003221 desc.m_TargetHeight = static_cast<uint32_t> (sizeTensorData[0]);
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01003222 desc.m_TargetWidth = static_cast<uint32_t> (sizeTensorData[1]);
3223 desc.m_DataLayout = armnn::DataLayout::NHWC;
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003224
James Ward58dec6b2020-09-11 17:32:44 +01003225 auto layerName = fmt::format("Resize:");
Sadik Armagana3b31f02019-12-05 09:08:53 +00003226
3227 switch (resizeMethod)
3228 {
3229 case ResizeMethod::Bilinear:
3230 {
James Ward58dec6b2020-09-11 17:32:44 +01003231 layerName += fmt::format("BILINEAR:{}:{}", subgraphIndex, operatorIndex);
Sang-Hoon Park820eb142020-01-08 10:25:24 +00003232
3233 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3234 const auto * options = operatorPtr->builtin_options.AsResizeBilinearOptions();
3235
David Monahan4a0c9b92020-05-30 09:48:39 +01003236 desc.m_AlignCorners = options->align_corners;
Sadik Armagana3b31f02019-12-05 09:08:53 +00003237 break;
3238 }
3239 case ResizeMethod::NearestNeighbor:
3240 {
James Ward58dec6b2020-09-11 17:32:44 +01003241 layerName += fmt::format("NEARESTNEIGHBOR:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagana3b31f02019-12-05 09:08:53 +00003242 break;
3243 }
3244 default:
3245 {
3246 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003247 fmt::format("Unexpected ResizeMethod[{}] when creating layerName {} ",
3248 static_cast<int>(resizeMethod), CHECK_LOCATION().AsString()));
Sadik Armagana3b31f02019-12-05 09:08:53 +00003249 }
3250 }
3251
Mike Kelly377fb212023-01-10 15:55:28 +00003252 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
James Conroy05102392020-06-24 15:39:55 +01003253
3254 IConnectableLayer* layer = m_Network->AddResizeLayer(desc, layerName.c_str());
3255 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00003256 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
3257 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003258 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3259
3260 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3261 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3262
3263 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3264 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
3265}
3266
Kevin May7d96b162021-02-03 17:38:41 +00003267void TfLiteParserImpl::ParseConcatenation(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan479045b2018-10-01 11:51:37 +01003268{
3269 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3270
Mike Kelly0d77ae12022-01-07 17:42:27 +00003271 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3272 const auto* options = operatorPtr->builtin_options.AsConcatenationOptions();
Sadik Armagan479045b2018-10-01 11:51:37 +01003273
3274 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
3275
3276 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3277 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Mike Kelly377fb212023-01-10 15:55:28 +00003278 auto inputTensorIds = GetInputTensorIds(m_Model, subgraphIndex, operatorIndex);
3279
Sadik Armagan479045b2018-10-01 11:51:37 +01003280 CHECK_VALID_SIZE(outputs.size(), 1);
3281
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003282 unsigned int numConcatView = static_cast<unsigned int>(inputs.size());
Mike Kelly377fb212023-01-10 15:55:28 +00003283 uint32_t inputRank = InputTensorInfo(subgraphIndex, operatorIndex, 0).GetNumDimensions();
Sadik Armagan479045b2018-10-01 11:51:37 +01003284
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003285 const unsigned int concatDimInput = static_cast<unsigned int>(
Mike Kelly377fb212023-01-10 15:55:28 +00003286 (static_cast<int>(inputRank) + options->axis) % static_cast<int>(inputRank));
Sadik Armagan479045b2018-10-01 11:51:37 +01003287
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003288 OriginsDescriptor concatDescriptor(static_cast<uint32_t>(numConcatView), inputRank);
3289 concatDescriptor.SetConcatAxis(concatDimInput);
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003290 unsigned int mergeDimOrigin = 0;
Sadik Armagan479045b2018-10-01 11:51:37 +01003291
3292 for (unsigned int viewIndex = 0; viewIndex < numConcatView; ++viewIndex)
3293 {
Mike Kelly377fb212023-01-10 15:55:28 +00003294 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, viewIndex);
Sadik Armagan479045b2018-10-01 11:51:37 +01003295
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003296 // This set up concatDescriptor view origin
3297 armnnUtils::ProcessConcatInputTensorInfo(
Mike Kelly377fb212023-01-10 15:55:28 +00003298 inputTensorInfo, concatDescriptor, concatDimInput, viewIndex, mergeDimOrigin);
Sadik Armagan479045b2018-10-01 11:51:37 +01003299 }
3300
James Ward58dec6b2020-09-11 17:32:44 +01003301 auto layerName = fmt::format("Concatenation:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01003302
Jim Flynn906f9462019-05-10 13:55:21 +01003303 IConnectableLayer* layer = m_Network->AddConcatLayer(concatDescriptor, layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01003304 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00003305 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {});
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003306 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
Sadik Armagan479045b2018-10-01 11:51:37 +01003307
James Conroy05102392020-06-24 15:39:55 +01003308 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003309 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes});
Sadik Armagan479045b2018-10-01 11:51:37 +01003310
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003311 // add fused activation layer
3312 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
Sadik Armagan479045b2018-10-01 11:51:37 +01003313
Sadik Armagan479045b2018-10-01 11:51:37 +01003314 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3315 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3316}
3317
Kevin May7d96b162021-02-03 17:38:41 +00003318void TfLiteParserImpl::ParseFullyConnected(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003319{
3320 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3321
Mike Kelly0d77ae12022-01-07 17:42:27 +00003322 const auto& operatorRfr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003323 const auto options = operatorRfr->builtin_options.AsFullyConnectedOptions();
3324
3325 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
3326
3327 FullyConnectedDescriptor desc;
3328 desc.m_BiasEnabled = false;
Nattapat Chaimanowongd8eee592018-10-26 10:24:14 +01003329 desc.m_TransposeWeightMatrix = true;
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003330
3331 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3332 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3333 CHECK_VALID_SIZE(outputs.size(), 1);
3334
Mike Kelly377fb212023-01-10 15:55:28 +00003335 armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003336
3337 // Fully Connected Layer accepts two dimensional weights input
3338 int32_t weightsDimension = static_cast<int32_t>(filterTensorInfo.GetNumDimensions());
3339 if (weightsDimension != 2)
3340 {
3341 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003342 fmt::format("Dimension {} for Fully Connected weights is not supported by Armnn. "
3343 "Node {}",
3344 weightsDimension,
3345 CHECK_LOCATION().AsString()));
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003346 }
3347
Matthew Jackson74bf7da2019-08-16 16:51:42 +01003348 armnn::IConnectableLayer* layer = nullptr;
James Ward58dec6b2020-09-11 17:32:44 +01003349 auto layerName = fmt::format("FullyConnected:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003350
Matthew Sloyan81beae32021-07-13 19:46:11 +01003351 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3352 // Add the first input tensor to the registration list
3353 std::vector<unsigned int> tensorIndexesToRegister = {inputTensorIndexes[0]};
Mike Kelly377fb212023-01-10 15:55:28 +00003354 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Finn Williamsd4fa5452021-03-01 12:31:41 +00003355
3356 desc.m_ConstantWeights = IsConstTensor(inputs[1]);
3357
Matthew Sloyan81beae32021-07-13 19:46:11 +01003358 // Add the weights input to the registration list, constant layers will be added by SetupConstantLayers if constant.
3359 tensorIndexesToRegister.emplace_back(inputTensorIndexes[1]);
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003360
Mike Kelly0506ef02023-01-03 16:29:44 +00003361 if (ShouldConstantTensorBeConverted(inputs[1], inputTensorInfo.GetDataType(), filterTensorInfo.GetDataType()))
Mike Kelly5880b912022-01-28 16:18:54 +00003362 {
3363 m_ConstantsToDequantize.emplace_back(inputs[1]->buffer);
3364 }
3365
Finn Williamsd4fa5452021-03-01 12:31:41 +00003366 if (inputs.size() == 3)
3367 {
3368 desc.m_BiasEnabled = true;
Mike Kelly377fb212023-01-10 15:55:28 +00003369 armnn::TensorInfo biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Matthew Sloyan81beae32021-07-13 19:46:11 +01003370
3371 // Add the biases input to the registration list, constant layer will be added by SetupConstantLayers.
3372 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
Mike Kelly5880b912022-01-28 16:18:54 +00003373
Mike Kelly0506ef02023-01-03 16:29:44 +00003374 if (ShouldConstantTensorBeConverted(inputs[2], inputTensorInfo.GetDataType(), biasTensorInfo.GetDataType()))
Mike Kelly5880b912022-01-28 16:18:54 +00003375 {
3376 m_ConstantsToDequantize.emplace_back(inputs[2]->buffer);
3377 }
Finn Williamsd4fa5452021-03-01 12:31:41 +00003378 }
3379
Matthew Sloyan81beae32021-07-13 19:46:11 +01003380 // Filters and biases are always passed to fully connected as inputs
3381 layer = m_Network->AddFullyConnectedLayer(desc, layerName.c_str());
Finn Williamsd4fa5452021-03-01 12:31:41 +00003382
3383 ARMNN_ASSERT(layer != nullptr);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003384
Finn Williamsd4fa5452021-03-01 12:31:41 +00003385 unsigned int startingSlotIndex = 0;
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003386 if (inputTensorInfo.GetNumDimensions() > 2)
3387 {
3388 // Add reshape to flatten to 2D [batch_size, input_size],
3389 // where "input_size" corresponds to the number of inputs to the layer,
3390 // matching the second dimension of weights,
3391 // and "batch_size" is calculated by dividing the number of elements by "input_size".
3392 std::vector<unsigned int> reshapedDimensions(2);
3393 reshapedDimensions[1] = filterTensorInfo.GetShape()[1];
3394 reshapedDimensions[0] = inputTensorInfo.GetNumElements() / reshapedDimensions[1];
3395
3396 if (inputTensorInfo.GetNumElements() % reshapedDimensions[1] != 0)
3397 {
3398 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003399 fmt::format("Failed to deduce input tensor shape from filter size {} {}",
3400 reshapedDimensions[1],
3401 CHECK_LOCATION().AsString()));
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003402 }
3403
Mike Kelly377fb212023-01-10 15:55:28 +00003404 armnn::TensorInfo reshapedTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003405 reshapedTensorInfo.SetShape(armnn::TensorShape{ 2, reshapedDimensions.data() });
Mike Kelly377fb212023-01-10 15:55:28 +00003406 inputTensorInfo = reshapedTensorInfo;
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003407
James Ward58dec6b2020-09-11 17:32:44 +01003408 std::string reshapeLayerName = fmt::format("Reshape_for:{}", layer->GetName());
Finn Williamsd4fa5452021-03-01 12:31:41 +00003409 armnn::ReshapeDescriptor reshapeDescriptor;
3410 reshapeDescriptor.m_TargetShape = reshapedTensorInfo.GetShape();
Mike Kelly04d82292023-01-19 18:29:40 +00003411 armnn::IConnectableLayer* reshapeLayer = m_Network->AddReshapeLayer(reshapeDescriptor,
3412 reshapeLayerName.c_str());
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003413
3414 reshapeLayer->GetOutputSlot(0).SetTensorInfo(reshapedTensorInfo);
3415 reshapeLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
3416
3417 RegisterInputSlots(subgraphIndex, operatorIndex, reshapeLayer, {inputTensorIndexes[0]});
Finn Williamsd4fa5452021-03-01 12:31:41 +00003418 // Fc layer connects to the reshape layer, so we skip the first input slot when registering fc's input slots
3419 tensorIndexesToRegister.erase(tensorIndexesToRegister.begin());
3420 startingSlotIndex = 1;
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003421 }
Finn Williamsd4fa5452021-03-01 12:31:41 +00003422
3423 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister, startingSlotIndex);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003424
Mike Kelly377fb212023-01-10 15:55:28 +00003425 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromShapes(subgraphIndex, operatorIndex, layer, 0,
3426 { inputTensorInfo.GetShape(),
3427 filterTensorInfo.GetShape() });
Mike Kelly04d82292023-01-19 18:29:40 +00003428
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003429 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3430
Mike Kelly04d82292023-01-19 18:29:40 +00003431 if (outputTensorInfo.GetNumDimensions() > 2)
3432 {
3433 // Calculate reshape to flatten to 2D [batch_size, input_size]
3434 std::vector<unsigned int> reshapedDimensions(2);
3435 reshapedDimensions[1] = filterTensorInfo.GetShape()[0];
3436 reshapedDimensions[0] = outputTensorInfo.GetNumElements() / reshapedDimensions[1];
3437 armnn::TensorInfo reshapedOutputTensorInfo = outputTensorInfo;
3438 if (outputTensorInfo.GetNumElements() % reshapedDimensions[1] != 0)
3439 {
3440 throw ParseException(
3441 fmt::format("Failed to deduce output tensor shape from filter size {} {}",
3442 reshapedDimensions[1],
3443 CHECK_LOCATION().AsString()));
3444 }
3445 reshapedOutputTensorInfo.SetShape(armnn::TensorShape{ 2, reshapedDimensions.data() });
3446 layer->GetOutputSlot(0).SetTensorInfo(reshapedOutputTensorInfo);
3447
3448 std::string reshapeLayerName = fmt::format("ExpandDims:{}:{}", subgraphIndex, operatorIndex);
3449 layer = AddReshapeLayer(layer, 0, reshapeLayerName, outputTensorInfo);
3450 }
3451
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003452 // we need to add the activation layer and fortunately we don't need to care about the data layout
3453 armnn::IConnectableLayer* fusedActivationLayer = AddFusedActivationLayer(layer, 0,
3454 options->fused_activation_function);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003455
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003456 // register the output connection slots for the layer, connections are made after all layers have been created
3457 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3458 RegisterOutputSlots(subgraphIndex, operatorIndex, fusedActivationLayer, {outputTensorIndexes[0]});
Mike Kelly04d82292023-01-19 18:29:40 +00003459
3460 m_TensorInfos[outputTensorIndexes[0]] = layer->GetOutputSlot(0).GetTensorInfo();
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003461}
3462
Kevin May7d96b162021-02-03 17:38:41 +00003463void TfLiteParserImpl::ParseDetectionPostProcess(size_t subgraphIndex, size_t operatorIndex)
keidav011b3e2ea2019-02-21 10:07:37 +00003464{
3465 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3466
Mike Kelly0d77ae12022-01-07 17:42:27 +00003467 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
keidav011b3e2ea2019-02-21 10:07:37 +00003468
3469 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3470 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3471 CHECK_VALID_SIZE(outputs.size(), 4);
3472
3473 // Obtain custom options from flexbuffers
3474 auto custom_options = operatorPtr->custom_options;
3475 const flexbuffers::Map& m = flexbuffers::GetRoot(custom_options.data(), custom_options.size()).AsMap();
3476
3477 // Obtain descriptor information from tf lite
3478 DetectionPostProcessDescriptor desc;
3479 desc.m_MaxDetections = m["max_detections"].AsUInt32();
3480 desc.m_MaxClassesPerDetection = m["max_classes_per_detection"].AsUInt32();
3481 desc.m_NmsScoreThreshold = m["nms_score_threshold"].AsFloat();
3482 desc.m_NmsIouThreshold = m["nms_iou_threshold"].AsFloat();
3483 desc.m_NumClasses = m["num_classes"].AsUInt32();
3484 desc.m_ScaleH = m["h_scale"].AsFloat();
3485 desc.m_ScaleW = m["w_scale"].AsFloat();
3486 desc.m_ScaleX = m["x_scale"].AsFloat();
3487 desc.m_ScaleY = m["y_scale"].AsFloat();
3488
keidav0107d58c72019-02-26 11:57:39 +00003489 if (!(m["use_regular_nms"].IsNull()))
keidav011b3e2ea2019-02-21 10:07:37 +00003490 {
keidav0107d58c72019-02-26 11:57:39 +00003491 desc.m_UseRegularNms = m["use_regular_nms"].AsBool();
keidav011b3e2ea2019-02-21 10:07:37 +00003492 }
3493 if (!(m["detections_per_class"].IsNull()))
3494 {
3495 desc.m_DetectionsPerClass = m["detections_per_class"].AsUInt32();
3496 }
3497
3498 if (desc.m_NmsIouThreshold <= 0.0f || desc.m_NmsIouThreshold > 1.0f)
3499 {
3500 throw InvalidArgumentException("DetectionPostProcessTFLiteParser: Intersection over union threshold "
3501 "must be positive and less than or equal to 1.");
3502 }
3503
Mike Kelly377fb212023-01-10 15:55:28 +00003504 armnn::TensorInfo anchorTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Finn Williamsd4fa5452021-03-01 12:31:41 +00003505 auto anchorTensorAndData = CreateConstTensorNonPermuted(inputs[2], anchorTensorInfo);
keidav011b3e2ea2019-02-21 10:07:37 +00003506
James Ward58dec6b2020-09-11 17:32:44 +01003507 auto layerName = fmt::format("DetectionPostProcess:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsd4fa5452021-03-01 12:31:41 +00003508 IConnectableLayer* layer = m_Network->AddDetectionPostProcessLayer(desc, anchorTensorAndData,
keidav011b3e2ea2019-02-21 10:07:37 +00003509 layerName.c_str());
3510
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01003511 ARMNN_ASSERT(layer != nullptr);
keidav011b3e2ea2019-02-21 10:07:37 +00003512
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00003513 // The model does not specify the output shapes.
3514 // The output shapes are calculated from the max_detection and max_classes_per_detection.
3515 unsigned int numDetectedBox = desc.m_MaxDetections * desc.m_MaxClassesPerDetection;
Mike Kelly377fb212023-01-10 15:55:28 +00003516 m_OverriddenOutputShapes.push_back({ 1, numDetectedBox, 4 });
3517 m_OverriddenOutputShapes.push_back({ 1, numDetectedBox });
3518 m_OverriddenOutputShapes.push_back({ 1, numDetectedBox });
3519 m_OverriddenOutputShapes.push_back({ 1 });
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00003520
keidav011b3e2ea2019-02-21 10:07:37 +00003521 for (unsigned int i = 0 ; i < outputs.size() ; ++i)
3522 {
Mike Kelly377fb212023-01-10 15:55:28 +00003523 armnn::TensorInfo detectionBoxOutputTensorInfo = ToTensorInfo(outputs[i], m_OverriddenOutputShapes[i]);
keidav011b3e2ea2019-02-21 10:07:37 +00003524 layer->GetOutputSlot(i).SetTensorInfo(detectionBoxOutputTensorInfo);
3525 }
3526
3527 // Register the input connection slots for the layer, connections are made after all layers have been created
3528 // only the tensors for the inputs are relevant, exclude the const tensors
3529 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3530 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
3531
3532 // Register the output connection slots for the layer, connections are made after all layers have been created
3533 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3534 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0],
3535 outputTensorIndexes[1],
3536 outputTensorIndexes[2],
3537 outputTensorIndexes[3]});
3538}
3539
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003540/// The TfLite Pack operator is equivalent to the ArmNN Stack operator
Kevin May7d96b162021-02-03 17:38:41 +00003541void TfLiteParserImpl::ParsePack(size_t subgraphIndex, size_t operatorIndex)
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003542{
3543 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3544
3545 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3546 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3547 CHECK_VALID_SIZE(outputs.size(), 1);
3548
3549 if (inputs.size() < 1)
3550 {
3551 throw ParseException("Pack must have at least one input.");
3552 }
3553
3554 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3555 const auto* options = operatorPtr->builtin_options.AsPackOptions();
3556
3557 StackDescriptor desc;
3558 desc.m_Axis = static_cast<uint32_t>(options->axis);
3559 desc.m_NumInputs = static_cast<uint32_t>(inputs.size());
3560
3561 // Use the tensor shape of the first input as the "correct" input shape in the descriptor
Mike Kelly377fb212023-01-10 15:55:28 +00003562 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003563 desc.m_InputShape = inputTensorInfo.GetShape();
3564
James Ward58dec6b2020-09-11 17:32:44 +01003565 auto layerName = fmt::format("Pack:{}:{}", subgraphIndex, operatorIndex);
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003566 IConnectableLayer* layer = m_Network->AddStackLayer(desc, layerName.c_str());
3567
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01003568 ARMNN_ASSERT(layer != nullptr);
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003569
Mike Kelly377fb212023-01-10 15:55:28 +00003570 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {});
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003571 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3572
3573 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3574 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes});
3575
3576 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3577 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3578}
3579
Mike Kelly5880b912022-01-28 16:18:54 +00003580void TfLiteParserImpl::ParseUnidirectionalSequenceLSTM(size_t subgraphIndex, size_t operatorIndex)
3581{
3582 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3583
3584 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3585 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3586
3587 if (inputs.size() < 2)
3588 {
3589 throw ParseException("UnidirectionalSequenceLSTM must have at least 2 input.");
3590 }
3591
3592 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3593 const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex];
3594 const auto nodeParams = operatorPtr->builtin_options.AsUnidirectionalSequenceLSTMOptions();
3595 CHECK_SUPPORTED_FUSED_ACTIVATION(nodeParams, subgraphIndex, operatorIndex);
Mike Kelly377fb212023-01-10 15:55:28 +00003596 auto inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Mike Kelly5880b912022-01-28 16:18:54 +00003597 auto outputTensorInfo = ToTensorInfo(outputs[0]);
3598
3599 // Set the params structure for the AddUnidirectionalSequenceLstmLayer call
3600 // Please refer to each operand at
3601 // https://www.tensorflow.org/mlir/tfl_ops#tflunidirectional_sequence_lstm_tflunidirectionalsequencelstmop
3602 armnn::LstmInputParams params;
3603
3604 if (IsOptionalOperandPresent(operatorPtr->inputs[1]))
3605 {
3606 params.m_InputToInputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[1]].get(),
3607 inputTensorInfo).first;
3608 }
3609
3610 params.m_InputToForgetWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[2]].get(),
3611 inputTensorInfo).first;
3612 params.m_InputToCellWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[3]].get(),
3613 inputTensorInfo).first;
3614 params.m_InputToOutputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[4]].get(),
3615 inputTensorInfo).first;
3616
3617 // Recurrent weight tensors of size {n_cell, n_output}
3618 if (IsOptionalOperandPresent(operatorPtr->inputs[5]))
3619 {
3620 params.m_RecurrentToInputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[5]].get(),
3621 inputTensorInfo).first;
3622 }
3623
3624 params.m_RecurrentToForgetWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[6]].get(),
3625 inputTensorInfo).first;
3626 params.m_RecurrentToCellWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[7]].get(),
3627 inputTensorInfo).first;
3628 params.m_RecurrentToOutputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[8]].get(),
3629 inputTensorInfo).first;
3630
3631 // Peephole weights tensors of size {n_cell}, representing a diagonal matrix.
3632 if (IsOptionalOperandPresent(operatorPtr->inputs[9]))
3633 {
3634 params.m_CellToInputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[9]].get(),
3635 inputTensorInfo).first;
3636 }
3637
3638 if (IsOptionalOperandPresent(operatorPtr->inputs[10]))
3639 {
3640 params.m_CellToForgetWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[10]].get(),
3641 inputTensorInfo).first;
3642 }
3643
3644 if (IsOptionalOperandPresent(operatorPtr->inputs[11]))
3645 {
3646 params.m_CellToOutputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[11]].get(),
3647 inputTensorInfo).first;
3648 }
3649
3650 // Gates bias tensors of size {n_cell}
3651 if (IsOptionalOperandPresent(operatorPtr->inputs[12]))
3652 {
3653 params.m_InputGateBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[12]].get(),
3654 inputTensorInfo).first;
3655 }
3656
3657 params.m_ForgetGateBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[13]].get(),
3658 inputTensorInfo).first;
3659 params.m_CellBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[14]].get(),
3660 inputTensorInfo).first;
3661 params.m_OutputGateBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[15]].get(),
3662 inputTensorInfo).first;
3663
3664 // Projection weight tensor of size {n_output, n_cell}
3665 if (IsOptionalOperandPresent(operatorPtr->inputs[16]))
3666 {
3667 params.m_ProjectionWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[16]].get(),
3668 inputTensorInfo).first;
3669 }
3670 // Projection bias tensor of size {n_output}
3671 if (IsOptionalOperandPresent(operatorPtr->inputs[17]))
3672 {
3673 params.m_ProjectionBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[17]].get(),
3674 inputTensorInfo).first;
3675 }
3676
3677 // These state tensors are defined as variable tensors, and will be modified by this op.
3678 armnn::TensorInfo outputStateInInfo = ToTensorInfo(subgraphPtr->tensors[operatorPtr->inputs[18]].get());
3679 m_ConstantsToBeCreated.push_back(operatorPtr->inputs[18]);
3680 armnn::TensorInfo cellStateInInfo = ToTensorInfo(subgraphPtr->tensors[operatorPtr->inputs[19]].get());
3681 m_ConstantsToBeCreated.push_back(operatorPtr->inputs[19]);
3682
3683 // Layer norm coefficient tensors of size {n_cell}, representing a diagonal matrix.
3684 if (inputs.size() >= 21 && IsOptionalOperandPresent(operatorPtr->inputs[20]))
3685 {
3686 params.m_InputLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[20]].get(),
3687 inputTensorInfo).first;
3688 }
3689
3690 if (inputs.size() >= 22 && IsOptionalOperandPresent(operatorPtr->inputs[21]))
3691 {
3692 params.m_ForgetLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[21]].get(),
3693 inputTensorInfo).first;
3694 }
3695
3696 if (inputs.size() >= 23 && IsOptionalOperandPresent(operatorPtr->inputs[22]))
3697 {
3698 params.m_CellLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[22]].get(),
3699 inputTensorInfo).first;
3700 }
3701
3702 if (inputs.size() >= 24 && IsOptionalOperandPresent(operatorPtr->inputs[23]))
3703 {
3704 params.m_OutputLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[23]].get(),
3705 inputTensorInfo).first;
3706 }
3707
3708 // set the layer descriptor
3709 armnn::UnidirectionalSequenceLstmDescriptor desc;
3710 desc.m_ActivationFunc = nodeParams->fused_activation_function;
3711 desc.m_ClippingThresCell = nodeParams->cell_clip;
3712 desc.m_ClippingThresProj = nodeParams->proj_clip;
3713 desc.m_CifgEnabled = (params.m_InputToInputWeights == nullptr
3714 || params.m_RecurrentToInputWeights == nullptr
3715 || params.m_InputGateBias == nullptr);
3716 desc.m_PeepholeEnabled = (params.m_CellToForgetWeights != nullptr || params.m_CellToOutputWeights != nullptr);
3717 desc.m_ProjectionEnabled = (params.m_ProjectionWeights != nullptr);
3718 desc.m_LayerNormEnabled = (params.m_InputLayerNormWeights != nullptr
3719 || params.m_ForgetLayerNormWeights != nullptr
3720 || params.m_CellLayerNormWeights != nullptr
3721 || params.m_OutputLayerNormWeights != nullptr);
3722 desc.m_TimeMajor = nodeParams->time_major;
3723
Mike Kellyc0800a32022-06-15 10:57:52 +01003724 if (operatorPtr->intermediates.size() > 3 && desc.m_LayerNormEnabled)
Mike Kelly5880b912022-01-28 16:18:54 +00003725 {
3726 auto inputIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[0]].get(),
3727 inputTensorInfo).first;
3728 auto inputIntermediateTensorInfo = inputIntermediate->GetInfo();
3729 desc.m_InputIntermediateScale = inputIntermediateTensorInfo.GetQuantizationScale();
3730
3731 auto forgetIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[1]].get(),
3732 inputTensorInfo).first;
3733 auto forgetIntermediateTensorInfo = forgetIntermediate->GetInfo();
3734 desc.m_ForgetIntermediateScale = forgetIntermediateTensorInfo.GetQuantizationScale();
3735
3736 auto cellIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[2]].get(),
3737 inputTensorInfo).first;
3738 auto cellIntermediateTensorInfo = cellIntermediate->GetInfo();
3739 desc.m_CellIntermediateScale = cellIntermediateTensorInfo.GetQuantizationScale();
3740
3741 auto outputIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[3]].get(),
3742 inputTensorInfo).first;
3743 auto outputIntermediateTensorInfo = outputIntermediate->GetInfo();
3744 desc.m_OutputIntermediateScale = outputIntermediateTensorInfo.GetQuantizationScale();
3745 }
3746 else
3747 {
3748 float defaultIntermediate = std::pow(2, -12);
3749 desc.m_InputIntermediateScale = defaultIntermediate;
3750 desc.m_ForgetIntermediateScale = defaultIntermediate;
3751 desc.m_CellIntermediateScale = defaultIntermediate;
3752 desc.m_OutputIntermediateScale = defaultIntermediate;
3753 }
3754
Mike Kellyc0800a32022-06-15 10:57:52 +01003755 if (operatorPtr->intermediates.size() > 4)
3756 {
3757 auto hiddentensor = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[4]].get(),
3758 inputTensorInfo).first;
Mike Kelly5880b912022-01-28 16:18:54 +00003759
Mike Kellyc0800a32022-06-15 10:57:52 +01003760 desc.m_HiddenStateScale = hiddentensor->GetInfo().GetQuantizationScale();
3761 desc.m_HiddenStateZeroPoint = hiddentensor->GetInfo().GetQuantizationOffset();
3762 }
Mike Kelly5880b912022-01-28 16:18:54 +00003763 unsigned int batchSize = inputTensorInfo.GetShape()[0];
3764 unsigned int outputSize = outputTensorInfo.GetShape()[2];
3765 unsigned int numUnits = cellStateInInfo.GetShape()[1];
3766
3767 armnn::DataType dataType = inputTensorInfo.GetDataType();
3768 float qScale = inputTensorInfo.GetQuantizationScale();
3769 float qOffset = inputTensorInfo.GetQuantizationOffset();
3770
3771 armnn::TensorInfo scratchBufferTensorInfo({batchSize, numUnits * 3}, dataType, qScale, qOffset);
3772 if (!desc.m_CifgEnabled)
3773 {
3774 scratchBufferTensorInfo = armnn::TensorInfo({batchSize, numUnits * 4}, dataType, qScale, qOffset);
3775 }
3776 armnn::TensorInfo cellStateOutTensorInfo({batchSize, numUnits},
3777 cellStateInInfo.GetDataType(),
3778 cellStateInInfo.GetQuantizationScale(),
3779 cellStateInInfo.GetQuantizationOffset());
3780 armnn::TensorInfo outputStateOutTensorInfo({batchSize, outputSize}, dataType, qScale, qOffset);
3781
3782 armnn::LstmInputParamsInfo paramsInfo;
3783 paramsInfo.m_InputToForgetWeights = &(params.m_InputToForgetWeights->GetInfo());
3784 paramsInfo.m_InputToCellWeights = &(params.m_InputToCellWeights->GetInfo());
3785 paramsInfo.m_InputToOutputWeights = &(params.m_InputToOutputWeights->GetInfo());
3786 paramsInfo.m_RecurrentToForgetWeights = &(params.m_RecurrentToForgetWeights->GetInfo());
3787 paramsInfo.m_RecurrentToCellWeights = &(params.m_RecurrentToCellWeights->GetInfo());
3788 paramsInfo.m_RecurrentToOutputWeights = &(params.m_RecurrentToOutputWeights->GetInfo());
3789 paramsInfo.m_ForgetGateBias = &(params.m_ForgetGateBias->GetInfo());
3790 paramsInfo.m_CellBias = &(params.m_CellBias->GetInfo());
3791 paramsInfo.m_OutputGateBias = &(params.m_OutputGateBias->GetInfo());
3792
3793 if (!desc.m_CifgEnabled)
3794 {
3795 paramsInfo.m_InputToInputWeights = &(params.m_InputToInputWeights->GetInfo());
3796 paramsInfo.m_RecurrentToInputWeights = &(params.m_RecurrentToInputWeights->GetInfo());
3797 if (params.m_CellToInputWeights != nullptr)
3798 {
3799 paramsInfo.m_CellToInputWeights = &(params.m_CellToInputWeights->GetInfo());
3800 }
3801 paramsInfo.m_InputGateBias = &(params.m_InputGateBias->GetInfo());
3802 }
3803
3804 if (desc.m_ProjectionEnabled)
3805 {
3806 paramsInfo.m_ProjectionWeights = &(params.m_ProjectionWeights->GetInfo());
3807 if (params.m_ProjectionBias != nullptr)
3808 {
3809 paramsInfo.m_ProjectionBias = &(params.m_ProjectionBias->GetInfo());
3810 }
3811 }
3812
3813 if (desc.m_PeepholeEnabled)
3814 {
3815 paramsInfo.m_CellToForgetWeights = &(params.m_CellToForgetWeights->GetInfo());
3816 paramsInfo.m_CellToOutputWeights = &(params.m_CellToOutputWeights->GetInfo());
3817 }
3818
3819 if (desc.m_LayerNormEnabled)
3820 {
3821 if(!desc.m_CifgEnabled)
3822 {
3823 paramsInfo.m_InputLayerNormWeights = &(params.m_InputLayerNormWeights->GetInfo());
3824 }
3825 paramsInfo.m_ForgetLayerNormWeights = &(params.m_ForgetLayerNormWeights->GetInfo());
3826 paramsInfo.m_CellLayerNormWeights = &(params.m_CellLayerNormWeights->GetInfo());
3827 paramsInfo.m_OutputLayerNormWeights = &(params.m_OutputLayerNormWeights->GetInfo());
3828 }
3829
3830 auto layerName = fmt::format("UnidirectionalSequenceLSTM:{}:{}", subgraphIndex, operatorIndex);
3831 armnn::IConnectableLayer* layer = m_Network->AddUnidirectionalSequenceLstmLayer(desc, params);
3832 ARMNN_ASSERT(layer != nullptr);
3833
3834 // register the input connection slots for the layer, connections are made after all layers have been created
3835 // only the tensors for the inputs are relevant, exclude the const tensors
3836 auto inputTensorIndexes = AsUnsignedVector({operatorPtr->inputs[0],
3837 operatorPtr->inputs[18],
3838 operatorPtr->inputs[19]});
3839 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0],
3840 inputTensorIndexes[1],
3841 inputTensorIndexes[2]});
3842
3843 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3844
3845 layer->GetOutputSlot(0).SetTensorInfo(outputStateOutTensorInfo);
3846 layer->GetOutputSlot(1).SetTensorInfo(cellStateOutTensorInfo);
3847 layer->GetOutputSlot(2).SetTensorInfo(outputTensorInfo);
3848
3849 unsigned int tensorIndex = outputTensorIndexes[0];
3850 armnn::IOutputSlot* slot = &(layer->GetOutputSlot(2));
3851 RegisterProducerOfTensor(subgraphIndex, tensorIndex, slot);
3852}
3853
Kevin May7d96b162021-02-03 17:38:41 +00003854void TfLiteParserImpl::ParseUnpack(size_t subgraphIndex, size_t operatorIndex)
Nina Drozd200e3802019-04-15 09:47:39 +01003855{
3856 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3857
Mike Kelly0d77ae12022-01-07 17:42:27 +00003858 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3859 const auto* options = operatorPtr->builtin_options.AsUnpackOptions();
Nina Drozd200e3802019-04-15 09:47:39 +01003860
3861 // This unpackAxis indicates the axis to unpack
3862 const unsigned int unpackAxis = CHECKED_NON_NEGATIVE(options->axis);
3863
3864 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3865 CHECK_VALID_SIZE(inputs.size(), 1);
3866
Mike Kelly377fb212023-01-10 15:55:28 +00003867 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003868
3869 if (unpackAxis >= inputTensorInfo.GetNumDimensions())
3870 {
3871 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003872 fmt::format("The unpack axis: {} cannot be greater than or equal to "
3873 "the number of input dimension {} {}",
3874 unpackAxis,
3875 inputTensorInfo.GetNumDimensions(),
3876 CHECK_LOCATION().AsString()));
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003877 }
3878
Nina Drozd200e3802019-04-15 09:47:39 +01003879 unsigned int unpackNum = CHECKED_NON_NEGATIVE(options->num);
3880 // If num is not defined, automatically infer from the length of the dimension axis.
3881 if(unpackNum == 0)
3882 {
3883 unpackNum = inputTensorInfo.GetShape()[unpackAxis];
3884 }
3885
3886 // If unpack number cannot be inferred and is still zero, throw ParseException.
3887 if(unpackNum == 0)
3888 {
3889 throw ParseException("Number to unpack must greater than zero.");
3890 }
3891
3892 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3893 CHECK_VALID_SIZE(outputs.size(), unpackNum);
3894
3895 auto inputDimSize = inputTensorInfo.GetNumDimensions();
3896 std::vector<unsigned int> unpackDimSizes(inputDimSize);
3897
3898 // Add current input shape to unpackDimSizes
3899 for (unsigned int i = 0; i < inputDimSize; ++i)
3900 {
3901 unpackDimSizes[i] = inputTensorInfo.GetShape()[i];
3902 }
3903
3904 if (unpackDimSizes[unpackAxis] != unpackNum)
3905 {
3906 throw ParseException("Number to unpack must be the same as length of the dimension to "
3907 "unpack along.");
3908 }
3909
3910 unpackDimSizes[unpackAxis] /= unpackNum;
3911
3912 SplitterDescriptor splitDesc(unpackNum, static_cast<unsigned int>(unpackDimSizes.size()));
3913 for (unsigned int j = 0; j < unpackNum; ++j)
3914 {
3915 // Set the size of the views.
3916 for (unsigned int dimIdx = 0; dimIdx < unpackDimSizes.size(); ++dimIdx)
3917 {
3918 splitDesc.SetViewSize(j, dimIdx, unpackDimSizes[dimIdx]);
3919 }
3920 splitDesc.SetViewOriginCoord(j, unpackAxis, unpackDimSizes[unpackAxis] * j);
3921 }
3922
James Ward58dec6b2020-09-11 17:32:44 +01003923 auto layerName = fmt::format("Unpack:{}:{}", subgraphIndex, operatorIndex);
Nina Drozd200e3802019-04-15 09:47:39 +01003924 IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01003925 ARMNN_ASSERT(layer != nullptr);
Nina Drozd200e3802019-04-15 09:47:39 +01003926
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003927 TensorShape splitOutShape = TensorShape(static_cast<unsigned int>(unpackDimSizes.size()),
3928 unpackDimSizes.data());
3929
Nina Drozd200e3802019-04-15 09:47:39 +01003930 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3931 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3932
Finn Williamsb49ed182021-06-29 15:50:08 +01003933 std::vector<unsigned int> reshapeDims;
3934 for (unsigned int axis = 0; axis < splitOutShape.GetNumDimensions(); ++axis)
3935 {
3936 if (axis != unpackAxis)
3937 {
3938 reshapeDims.push_back(splitOutShape[axis]);
3939 }
3940 }
3941
3942 TensorShape reshapeOutputShape(splitOutShape.GetNumDimensions() -1, reshapeDims.data());
3943
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003944 // Create reshape to remove the unpacked dimension for unpack operator of each output from Splitter.
3945 for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
3946 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01003947 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[k], true);
James Ward58dec6b2020-09-11 17:32:44 +01003948 std::string reshapeLayerName = fmt::format("Reshape_for:{}", layer->GetName());
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003949 armnn::ReshapeDescriptor desc;
Finn Williamsb49ed182021-06-29 15:50:08 +01003950 desc.m_TargetShape = reshapeOutputShape;
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003951 armnn::IConnectableLayer* reshapeLayer = m_Network->AddReshapeLayer(desc, layerName.c_str());
3952
Narumol Prangnawarat2c526462019-10-21 14:58:26 +01003953 layer->GetOutputSlot(k).SetTensorInfo(armnn::TensorInfo(splitOutShape,
3954 outputTensorInfo.GetDataType(),
3955 outputTensorInfo.GetQuantizationScale(),
3956 outputTensorInfo.GetQuantizationOffset()));
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003957 layer->GetOutputSlot(k).Connect(reshapeLayer->GetInputSlot(0));
3958
Narumol Prangnawarat2c526462019-10-21 14:58:26 +01003959 reshapeLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003960
3961 uint32_t reshapedOutputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[k]);
3962 armnn::IOutputSlot* slot = &(reshapeLayer->GetOutputSlot(0));
3963 RegisterProducerOfTensor(subgraphIndex, reshapedOutputId, slot);
3964 }
Nina Drozd200e3802019-04-15 09:47:39 +01003965}
3966
Kevin May7d96b162021-02-03 17:38:41 +00003967void TfLiteParserImpl::ParseSplit(size_t subgraphIndex, size_t operatorIndex)
Nina Drozd0324f482019-04-08 10:52:10 +01003968{
3969 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3970
Mike Kelly0d77ae12022-01-07 17:42:27 +00003971 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3972 const auto* options = operatorPtr->builtin_options.AsSplitOptions();
Nina Drozd0324f482019-04-08 10:52:10 +01003973
3974 const unsigned int numSplits = CHECKED_NON_NEGATIVE(options->num_splits);
3975
Nina Drozd200e3802019-04-15 09:47:39 +01003976 // If number of splits cannot be inferred and is zero, throw ParseException.
3977 if(numSplits == 0)
3978 {
3979 throw ParseException("Number to splits must greater than zero.");
3980 }
3981
Nina Drozd0324f482019-04-08 10:52:10 +01003982 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3983 CHECK_VALID_SIZE(inputs.size(), 2);
3984 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3985 CHECK_VALID_SIZE(outputs.size(), numSplits);
3986
Mike Kelly377fb212023-01-10 15:55:28 +00003987 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
3988 armnn::TensorInfo axisTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01003989 ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
Nina Drozd0324f482019-04-08 10:52:10 +01003990
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01003991 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[0]->buffer);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01003992 if (axisBufferPtr == nullptr)
3993 {
3994 throw ParseException(
3995 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
3996 CHECK_LOCATION().AsString()));
3997 }
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01003998
Matthew Sloyaned7fce42021-04-15 20:46:24 +01003999 std::vector<int32_t> axisData(axisTensorInfo.GetNumElements());
4000 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
4001 int32_t axis = axisData[0];
4002
4003 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
4004 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
4005 {
4006 // Square bracket denotes inclusive n while parenthesis denotes exclusive n
4007 // E.g. Rank 4 tensor can have axis in range [-4, 3)
4008 // -1 == 3, -2 == 2, -3 == 1, -4 == 0
4009 throw ParseException(
4010 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
4011 axis,
4012 CHECK_LOCATION().AsString()));
4013 }
4014
4015 const unsigned int splitDim = armnnUtils::GetUnsignedAxis(inputTensorInfo.GetNumDimensions(), axis);
Nina Drozd0324f482019-04-08 10:52:10 +01004016
Nina Drozd0324f482019-04-08 10:52:10 +01004017 auto inputDimSize = inputTensorInfo.GetNumDimensions();
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01004018 if (inputDimSize > MaxNumOfTensorDimensions)
Nina Drozd0324f482019-04-08 10:52:10 +01004019 {
4020 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01004021 fmt::format("The number of dimensions: {} for input tensors of the split op cannot be greater than {} {}",
4022 inputTensorInfo.GetNumDimensions(),
4023 MaxNumOfTensorDimensions,
4024 CHECK_LOCATION().AsString()));
Nina Drozd0324f482019-04-08 10:52:10 +01004025 }
4026
4027 std::vector<unsigned int> splitterDimSizes(inputDimSize);
4028
4029 // Add current input shape to splitterDimSizes
4030 for (unsigned int i = 0; i < inputDimSize; ++i)
4031 {
4032 splitterDimSizes[i] = inputTensorInfo.GetShape()[i];
4033 }
4034
4035 if (splitterDimSizes[splitDim] % numSplits != 0)
4036 {
4037 throw ParseException("Number of splits must evenly divide the dimension");
4038 }
4039 splitterDimSizes[splitDim] /= numSplits;
4040
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01004041 SplitterDescriptor splitDesc(numSplits, inputDimSize);
Nina Drozd0324f482019-04-08 10:52:10 +01004042 for (unsigned int j = 0; j < numSplits; ++j)
4043 {
4044 // Set the size of the views.
4045 for (unsigned int dimIdx = 0; dimIdx < splitterDimSizes.size(); ++dimIdx)
4046 {
4047 splitDesc.SetViewSize(j, dimIdx, splitterDimSizes[dimIdx]);
4048 }
4049 splitDesc.SetViewOriginCoord(j, splitDim, splitterDimSizes[splitDim] * j);
4050 }
4051
James Ward58dec6b2020-09-11 17:32:44 +01004052 auto layerName = fmt::format("Split:{}:{}", subgraphIndex, operatorIndex);
Nina Drozd0324f482019-04-08 10:52:10 +01004053 IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01004054 ARMNN_ASSERT(layer != nullptr);
Nina Drozd0324f482019-04-08 10:52:10 +01004055
4056 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01004057 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[1]});
Nina Drozd0324f482019-04-08 10:52:10 +01004058
Nina Drozd0324f482019-04-08 10:52:10 +01004059 for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
4060 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01004061 armnn::TensorInfo tensorInfo = ToTensorInfo(outputs[k], true);
Francis Murtagh98d6b3d2019-10-21 10:52:54 +01004062 layer->GetOutputSlot(k).SetTensorInfo(tensorInfo);
Nina Drozd0324f482019-04-08 10:52:10 +01004063 }
4064
4065 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4066 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4067}
4068
Derek Lambertif0176992020-04-28 13:37:49 +01004069unsigned int ComputeWrappedIndex(int idx, unsigned int numDimsIn)
4070{
4071 int numDims = armnn::numeric_cast<int>(numDimsIn);
4072 int v = idx < 0 ? numDims + idx : idx;
4073 ARMNN_ASSERT(v >= 0);
4074 ARMNN_ASSERT(v < numDims);
4075
4076 return static_cast<unsigned int>(v);
4077}
4078
Kevin May7d96b162021-02-03 17:38:41 +00004079void TfLiteParserImpl::ParseSplitV(size_t subgraphIndex, size_t operatorIndex)
Derek Lambertif0176992020-04-28 13:37:49 +01004080{
4081 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4082
Mike Kelly0d77ae12022-01-07 17:42:27 +00004083 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4084 const auto* options = operatorPtr->builtin_options.AsSplitVOptions();
Derek Lambertif0176992020-04-28 13:37:49 +01004085
4086 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4087 CHECK_VALID_SIZE(inputs.size(), 3);
4088
4089 auto& inputTensor = inputs[0];
4090 auto& splitsTensor = inputs[1];
4091 auto& axisTensor = inputs[2];
4092
4093 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputTensor);
4094 armnn::TensorInfo splitsInfo = ToTensorInfo(splitsTensor);
4095 armnn::TensorInfo axisTensorInfo = ToTensorInfo(axisTensor);
4096 ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
4097
4098 // Inputs
4099 auto inputDimSize = inputTensorInfo.GetNumDimensions();
4100 if (inputDimSize > MaxNumOfTensorDimensions)
4101 {
4102 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01004103 fmt::format("The number of dimensions: {} for input tensors of the "
4104 "SplitV op cannot be greater than {} {}",
4105 inputTensorInfo.GetNumDimensions(),
4106 MaxNumOfTensorDimensions,
4107 CHECK_LOCATION().AsString()));
Derek Lambertif0176992020-04-28 13:37:49 +01004108 }
4109
4110 // Get split axis
4111 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, axisTensor->buffer);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004112 if (axisBufferPtr == nullptr)
4113 {
4114 throw ParseException(
4115 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
4116 CHECK_LOCATION().AsString()));
4117 }
4118
Derek Lambertif0176992020-04-28 13:37:49 +01004119 std::vector<int> axisData(axisTensorInfo.GetNumElements());
4120 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004121 int32_t axis = axisData[0];
4122
4123 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
4124 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
4125 {
4126 // Square bracket denotes inclusive n while parenthesis denotes exclusive n
4127 // E.g. Rank 4 tensor can have axis in range [-4, 3)
4128 // -1 == 3, -2 == 2, -3 == 1, -4 == 0
4129 throw ParseException(
4130 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
4131 axis,
4132 CHECK_LOCATION().AsString()));
4133 }
4134 const unsigned int splitDim = ComputeWrappedIndex(axis, inputTensorInfo.GetNumDimensions());
Derek Lambertif0176992020-04-28 13:37:49 +01004135
Derek Lambertif0176992020-04-28 13:37:49 +01004136 // Set split sizes
Derek Lambertif0176992020-04-28 13:37:49 +01004137 CHECK_VALID_SIZE(splitsInfo.GetNumDimensions(), 1);
Ryan OShea86704732020-05-26 11:41:04 +01004138 unsigned int numSplits{0};
4139
4140 if(options)
Derek Lambertif0176992020-04-28 13:37:49 +01004141 {
4142 numSplits = CHECKED_NON_NEGATIVE(options->num_splits);
Derek Lambertif0176992020-04-28 13:37:49 +01004143 }
4144 else
4145 {
Ryan OShea86704732020-05-26 11:41:04 +01004146 numSplits = splitsInfo.GetNumElements();
Derek Lambertif0176992020-04-28 13:37:49 +01004147 }
4148
4149 if (numSplits <=0)
4150 {
4151 throw ParseException("SplitV has invalid number of splits");
4152 }
4153
Jan Eilersc0761e92020-06-29 16:48:44 +01004154 std::vector<int> splitsData(numSplits);
Ryan OShea86704732020-05-26 11:41:04 +01004155 BufferRawPtr splitsBufferPtr = GetBuffer(m_Model, splitsTensor->buffer);
Jan Eilersc0761e92020-06-29 16:48:44 +01004156 ::memcpy(splitsData.data(), splitsBufferPtr->data.data(), splitsInfo.GetNumBytes());
Ryan OShea86704732020-05-26 11:41:04 +01004157
Jan Eilersc0761e92020-06-29 16:48:44 +01004158 unsigned int idx = 0;
Ryan OShea86704732020-05-26 11:41:04 +01004159 int numInferred{0};
4160 unsigned int inferIdx{0};
4161 int splitSum{0};
4162 for (auto split : splitsData)
4163 {
4164 if (split < 0)
4165 {
4166 numInferred++;
4167 inferIdx = idx;
4168 }
4169 else
4170 {
4171 splitSum += split;
4172 }
4173 idx++;
4174 }
4175 // Check for inferred Axis
4176 if (numInferred == 0)
4177 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +01004178 if (splitSum != armnn::numeric_cast<int>(inputTensorInfo.GetShape()[splitDim]))
Ryan OShea86704732020-05-26 11:41:04 +01004179 {
4180 throw ParseException("SplitV split_sizes does not sum to the dimension of value along split_dim.");
4181 }
4182 }
4183 else if (numInferred == 1)
4184 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +01004185 splitsData[inferIdx] = armnn::numeric_cast<int>(inputTensorInfo.GetShape()[splitDim]) - splitSum;
Ryan OShea86704732020-05-26 11:41:04 +01004186 }
4187 else
4188 {
4189 throw ParseException("Cannot infer split size for more than one split");
4190 }
4191
Derek Lambertif0176992020-04-28 13:37:49 +01004192 //Ouput size validation
4193 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4194 CHECK_VALID_SIZE(outputs.size(), numSplits);
4195
4196 // Setup Armnn descriptor
4197 SplitterDescriptor splitDesc(numSplits, inputDimSize);
4198 unsigned int accumSplit = 0;
4199 for (unsigned int j = 0; j < numSplits; ++j)
4200 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +01004201 unsigned int splitSize = armnn::numeric_cast<unsigned int>(splitsData[j]);
Derek Lambertif0176992020-04-28 13:37:49 +01004202
4203 // Set the size of the views.
4204 for (unsigned int dimIdx = 0; dimIdx < inputTensorInfo.GetNumDimensions(); ++dimIdx)
4205 {
4206 unsigned int dimSize = inputTensorInfo.GetShape()[dimIdx];
4207 if (dimIdx == splitDim)
4208 {
4209 dimSize = splitSize;
4210 }
4211 splitDesc.SetViewSize(j, dimIdx, dimSize);
4212 }
4213
4214 splitDesc.SetViewOriginCoord(j, splitDim, accumSplit);
4215 accumSplit += splitSize;
4216 }
4217
James Ward58dec6b2020-09-11 17:32:44 +01004218 auto layerName = fmt::format("SplitV:{}:{}", subgraphIndex, operatorIndex);
Derek Lambertif0176992020-04-28 13:37:49 +01004219 IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01004220 ARMNN_ASSERT(layer != nullptr);
Derek Lambertif0176992020-04-28 13:37:49 +01004221
4222 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4223 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4224
4225 for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
4226 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01004227 armnn::TensorInfo tensorInfo = ToTensorInfo(outputs[k], true);
Derek Lambertif0176992020-04-28 13:37:49 +01004228 layer->GetOutputSlot(k).SetTensorInfo(tensorInfo);
4229 }
4230
4231 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4232 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4233}
4234
Matthew Sloyan28f177c2021-04-09 14:38:52 +01004235void TfLiteParserImpl::ParseArgMin(size_t subgraphIndex, size_t operatorIndex)
4236{
4237 ParseArgMinMax(subgraphIndex, operatorIndex, armnn::ArgMinMaxFunction::Min);
4238}
4239
Kevin May7d96b162021-02-03 17:38:41 +00004240void TfLiteParserImpl::ParseArgMax(size_t subgraphIndex, size_t operatorIndex)
Inki Daed4619e22020-09-10 15:33:54 +09004241{
Matthew Sloyan28f177c2021-04-09 14:38:52 +01004242 ParseArgMinMax(subgraphIndex, operatorIndex, armnn::ArgMinMaxFunction::Max);
4243}
4244
4245void TfLiteParserImpl::ParseArgMinMax(size_t subgraphIndex, size_t operatorIndex, ArgMinMaxFunction argMinMaxFunction)
4246{
Inki Daed4619e22020-09-10 15:33:54 +09004247 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4248 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4249 CHECK_VALID_SIZE(inputs.size(), 2);
4250
4251 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4252 CHECK_VALID_SIZE(outputs.size(), 1);
4253
Mike Kelly377fb212023-01-10 15:55:28 +00004254 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4255 armnn::TensorInfo axisTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Inki Daed4619e22020-09-10 15:33:54 +09004256 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004257 ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
Matthew Sloyan28f177c2021-04-09 14:38:52 +01004258
4259 // Check if output tensor type is Signed32 or Signed64
Mike Kelly1f140f72021-04-06 12:25:55 +01004260 if (outputTensorInfo.GetDataType() != armnn::DataType::Signed32 &&
4261 outputTensorInfo.GetDataType() != armnn::DataType::Signed64)
4262 {
4263 throw ParseException(
4264 fmt::format(
4265 "Output tensor data type is not supported. (Supported types: Signed32 & Signed64) {}",
4266 CHECK_LOCATION().AsString()));
4267 }
Matthew Sloyan28f177c2021-04-09 14:38:52 +01004268
4269 // Get const axis value from model and set it to descriptor.
4270 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
4271 if (axisBufferPtr == nullptr)
4272 {
4273 throw ParseException(
4274 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
4275 CHECK_LOCATION().AsString()));
4276 }
4277
4278 std::vector<int32_t> axisData(axisTensorInfo.GetNumElements());
4279 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
4280 int32_t axis = axisData.front();
4281
4282 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
4283 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
4284 {
4285 // Square bracket denotes inclusive n while parenthesis denotes exclusive n
4286 // E.g. Rank 4 tensor can have axis in range [-4, 3)
4287 // -1 == 3, -2 == 2, -3 == 1, -4 == 0
4288 throw ParseException(
4289 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
4290 axis,
4291 CHECK_LOCATION().AsString()));
4292 }
4293
4294 ArgMinMaxDescriptor desc;
4295 desc.m_Axis = axis;
4296 desc.m_Function = argMinMaxFunction;
4297
4298 // Register a ArgMin/ArgMax layer.
4299 auto layerName = argMinMaxFunction == ArgMinMaxFunction::Max ? "ArgMax:{}:{}" : "ArgMin:{}:{}";
4300 auto layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4301 IConnectableLayer *layer = m_Network->AddArgMinMaxLayer(desc, layerNameFormatted.c_str());
4302 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00004303 outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Inki Daed4619e22020-09-10 15:33:54 +09004304 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4305
4306 // Register input tensor to the layer.
4307 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4308 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4309
4310 // Register output tensor to the layer.
4311 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4312 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4313}
4314
Kevin May7d96b162021-02-03 17:38:41 +00004315void TfLiteParserImpl::ParseGather(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan26868492021-01-22 14:25:31 +00004316{
4317 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4318
Kevin May7d96b162021-02-03 17:38:41 +00004319 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00004320 CHECK_VALID_SIZE(inputs.size(), 2);
Kevin May7d96b162021-02-03 17:38:41 +00004321 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00004322 CHECK_VALID_SIZE(outputs.size(), 1);
4323
Mike Kelly377fb212023-01-10 15:55:28 +00004324 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4325 armnn::TensorInfo indicesTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
4326 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
Sadik Armagan26868492021-01-22 14:25:31 +00004327
4328 armnn::GatherDescriptor gatherDescriptor;
4329
Mike Kelly0d77ae12022-01-07 17:42:27 +00004330 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4331 const auto* options = operatorPtr->builtin_options.AsGatherOptions();
Sadik Armagan26868492021-01-22 14:25:31 +00004332 auto axis = options->axis;
4333
Mike Kelly377fb212023-01-10 15:55:28 +00004334 auto layerName = fmt::format("Gather:{}:{}", subgraphIndex, operatorIndex);
4335
Sadik Armagan26868492021-01-22 14:25:31 +00004336 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
4337 auto indicesDimensions = indicesTensorInfo.GetNumDimensions();
4338 auto outputDimensions = outputTensorInfo.GetNumDimensions();
4339 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
4340 {
4341 throw ParseException(
4342 fmt::format("Operation has invalid axis: {} It is out of bounds [ -{}, {} ) {}",
4343 axis,
4344 inputDimensions, inputDimensions,
4345 CHECK_LOCATION().AsString()));
4346 }
4347 if (outputDimensions != static_cast<unsigned int>(inputDimensions) + indicesDimensions - 1)
4348 {
4349 throw ParseException(
4350 fmt::format("Operation has invalid output dimensions: {} Output must be an ({} + {} - 1) -D tensor {}",
4351 outputDimensions,
4352 inputDimensions, indicesDimensions,
4353 CHECK_LOCATION().AsString()));
4354 }
4355
4356 gatherDescriptor.m_Axis = axis;
4357
Sadik Armagan26868492021-01-22 14:25:31 +00004358 IConnectableLayer* layer = m_Network->AddGatherLayer(gatherDescriptor, layerName.c_str());
4359 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00004360 outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Sadik Armagan26868492021-01-22 14:25:31 +00004361 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4362
4363 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4364 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4365
4366 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4367 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4368}
4369
Teresa Charlin91a53ea2022-04-25 15:47:29 +01004370void TfLiteParserImpl::ParseGatherNd(size_t subgraphIndex, size_t operatorIndex)
4371{
4372 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4373
4374 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4375 CHECK_VALID_SIZE(inputs.size(), 2);
4376 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4377 CHECK_VALID_SIZE(outputs.size(), 1);
4378
Mike Kelly377fb212023-01-10 15:55:28 +00004379 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4380 armnn::TensorInfo indicesTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Teresa Charlin91a53ea2022-04-25 15:47:29 +01004381
4382 auto layerName = fmt::format("GatherNd:{}:{}", subgraphIndex, operatorIndex);
4383 IConnectableLayer* layer = m_Network->AddGatherNdLayer(layerName.c_str());
4384 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00004385 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Teresa Charlin91a53ea2022-04-25 15:47:29 +01004386 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4387
4388 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4389 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4390
4391 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4392 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4393}
4394
Kevin May7d96b162021-02-03 17:38:41 +00004395void TfLiteParserImpl::ParseDepthToSpace(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan26868492021-01-22 14:25:31 +00004396{
4397 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4398
Kevin May7d96b162021-02-03 17:38:41 +00004399 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00004400 CHECK_VALID_SIZE(inputs.size(), 1);
Kevin May7d96b162021-02-03 17:38:41 +00004401 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00004402 CHECK_VALID_SIZE(outputs.size(), 1);
4403
4404 armnn::DepthToSpaceDescriptor descriptor;
4405
Mike Kelly0d77ae12022-01-07 17:42:27 +00004406 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4407 const auto* options = operatorPtr->builtin_options.AsDepthToSpaceOptions();
Sadik Armagan26868492021-01-22 14:25:31 +00004408 auto blockSize = options->block_size;
4409 if (blockSize < 2)
4410 {
4411 throw ParseException(
4412 fmt::format("Operation has invalid block size: {} Block size should be >= 2 {}",
4413 blockSize,
4414 CHECK_LOCATION().AsString()));
4415 }
4416 descriptor.m_BlockSize = armnn::numeric_cast<uint32_t>(blockSize);
4417
4418 auto layerName = fmt::format("DepthToSpace:{}:{}", subgraphIndex, operatorIndex);
4419 IConnectableLayer* layer = m_Network->AddDepthToSpaceLayer(descriptor, layerName.c_str());
4420 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00004421 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Sadik Armagan26868492021-01-22 14:25:31 +00004422 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4423
4424 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4425 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4426
4427 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4428 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4429}
4430
Kevin May7d96b162021-02-03 17:38:41 +00004431void TfLiteParserImpl::ParseSum(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004432{
Sadik Armagana2747482021-02-09 10:28:54 +00004433 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Sum);
4434}
4435
Teresa Charlin4e3e8312021-08-05 12:34:37 +01004436void TfLiteParserImpl::ParseReduceProd(size_t subgraphIndex, size_t operatorIndex)
4437{
4438 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Prod);
4439}
4440
Sadik Armagana2747482021-02-09 10:28:54 +00004441void TfLiteParserImpl::ParseReduceMax(size_t subgraphIndex, size_t operatorIndex)
4442{
4443 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Max);
4444}
4445
4446void TfLiteParserImpl::ParseReduceMin(size_t subgraphIndex, size_t operatorIndex)
4447{
4448 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Min);
4449}
4450
4451void TfLiteParserImpl::ParseReduce(size_t subgraphIndex, size_t operatorIndex, ReduceOperation reduceOperation)
4452{
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004453 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4454
Mike Kelly0d77ae12022-01-07 17:42:27 +00004455 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4456 const auto* options = operatorPtr->builtin_options.AsReducerOptions();
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004457
4458 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4459 CHECK_VALID_SIZE(inputs.size(), 2);
4460
4461 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4462 CHECK_VALID_SIZE(outputs.size(), 1);
4463
Sadik Armagana2747482021-02-09 10:28:54 +00004464 auto layerName = fmt::format("Reduce:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004465
Mike Kelly377fb212023-01-10 15:55:28 +00004466 armnn::TensorInfo inputTensorInfo0 = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4467 armnn::TensorInfo inputTensorInfo1 = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004468
4469 ReduceDescriptor desc;
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004470 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
4471 // Get const axis value from model and set it to descriptor.
4472 if (axisBufferPtr != nullptr)
4473 {
Sadik Armagan49bdb792021-02-11 13:57:07 +00004474 std::vector<int32_t> axisData(inputTensorInfo1.GetNumElements());
4475 ::memcpy(axisData.data(), axisBufferPtr->data.data(), inputTensorInfo1.GetNumBytes());
4476
4477 // Convert the axis to unsigned int and remove duplicates.
4478 auto rank = static_cast<int32_t>(inputTensorInfo0.GetNumDimensions());
4479 std::set<unsigned int> uniqueAxis;
4480 std::transform(axisData.begin(),
4481 axisData.end(),
4482 std::inserter(uniqueAxis, uniqueAxis.begin()),
4483 [rank](int i)->unsigned int{
4484 return static_cast<uint32_t>(((i + rank) % rank)); });
4485 desc.m_vAxis.assign(uniqueAxis.begin(), uniqueAxis.end());
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004486 }
Sadik Armagana2747482021-02-09 10:28:54 +00004487 else
4488 {
4489 for (uint32_t i = 0; i < inputTensorInfo0.GetNumDimensions(); ++i)
4490 {
4491 desc.m_vAxis.push_back(i);
4492 }
4493 }
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004494
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004495 desc.m_KeepDims = options->keep_dims;
Sadik Armagana2747482021-02-09 10:28:54 +00004496 desc.m_ReduceOperation = reduceOperation;
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004497
4498 // Register a new layer object, Sum.
Mike Kelly0d77ae12022-01-07 17:42:27 +00004499 IConnectableLayer* layer = m_Network->AddReduceLayer(desc, layerName.c_str());
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004500
Mike Kelly377fb212023-01-10 15:55:28 +00004501 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004502 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4503
4504 // Register input tensor to the layer.
4505 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4506 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4507
4508 // Register output tensor to the layer.
4509 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4510 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4511}
4512
Mike Kelly31dce2b2021-09-01 21:22:37 +01004513void TfLiteParserImpl::ParseLocalResponseNormalization(size_t subgraphIndex, size_t operatorIndex)
4514{
4515 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4516
4517 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4518 CHECK_VALID_SIZE(inputs.size(), 1);
4519
4520 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4521 CHECK_VALID_SIZE(outputs.size(), 1);
4522
4523 auto layerName = fmt::format("LRN:{}:{}", subgraphIndex, operatorIndex);
4524 std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4525
Mike Kelly377fb212023-01-10 15:55:28 +00004526 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Mike Kelly31dce2b2021-09-01 21:22:37 +01004527
4528 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4529 const auto* options = operatorPtr->builtin_options.AsLocalResponseNormalizationOptions();
4530
4531 armnn::NormalizationDescriptor descriptor;
4532 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
4533 descriptor.m_NormChannelType = armnn::NormalizationAlgorithmChannel::Across;
4534 descriptor.m_NormMethodType = armnn::NormalizationAlgorithmMethod::LocalBrightness;
4535 descriptor.m_NormSize = static_cast<uint32_t>(options->radius);
4536 descriptor.m_K = options->bias;
4537 descriptor.m_Alpha = options->alpha;
4538 descriptor.m_Beta = options->beta;
4539
4540 // ArmNN expects normSize to be the full size of the normalization
4541 // window rather than the radius as in TfLite.
4542 descriptor.m_NormSize = 1 + (2 * descriptor.m_NormSize);
4543
4544 IConnectableLayer* layer = m_Network->AddNormalizationLayer(descriptor, layerNameFormatted.c_str());
4545 ARMNN_ASSERT(layer != nullptr);
4546
Mike Kelly377fb212023-01-10 15:55:28 +00004547 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Mike Kelly31dce2b2021-09-01 21:22:37 +01004548 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4549
4550 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4551 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4552
4553 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4554 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4555}
4556
Teresa Charlin28aa6692022-07-12 11:18:44 +01004557void TfLiteParserImpl::ParseAbs(size_t subgraphIndex, size_t operatorIndex)
4558{
4559 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Abs);
4560}
4561
Teresa Charlin93f0ad02023-03-23 15:28:02 +00004562void TfLiteParserImpl::ParseCeil(size_t subgraphIndex, size_t operatorIndex)
4563{
4564 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Ceil);
4565}
4566
Teresa Charlin28aa6692022-07-12 11:18:44 +01004567void TfLiteParserImpl::ParseExp(size_t subgraphIndex, size_t operatorIndex)
4568{
4569 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Exp);
4570}
4571
4572void TfLiteParserImpl::ParseLog(size_t subgraphIndex, size_t operatorIndex)
4573{
4574 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Log);
4575}
4576
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004577void TfLiteParserImpl::ParseLogicalNot(size_t subgraphIndex, size_t operatorIndex)
4578{
4579 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::LogicalNot);
4580}
4581
4582void TfLiteParserImpl::ParseNeg(size_t subgraphIndex, size_t operatorIndex)
4583{
4584 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Neg);
4585}
4586
4587void TfLiteParserImpl::ParseRsqrt(size_t subgraphIndex, size_t operatorIndex)
4588{
4589 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Rsqrt);
4590}
4591
Teresa Charlin28aa6692022-07-12 11:18:44 +01004592void TfLiteParserImpl::ParseSin(size_t subgraphIndex, size_t operatorIndex)
4593{
4594 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Sin);
4595}
4596
Teresa Charlinf0fce5b2022-05-04 17:24:43 +01004597void TfLiteParserImpl::ParseSqrt(size_t subgraphIndex, size_t operatorIndex)
4598{
4599 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Sqrt);
4600}
4601
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004602void TfLiteParserImpl::ParseElementwiseUnary(size_t subgraphIndex, size_t operatorIndex, UnaryOperation unaryOperation)
4603{
4604 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4605
4606 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4607 CHECK_VALID_SIZE(inputs.size(), 1);
4608
4609 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4610 CHECK_VALID_SIZE(outputs.size(), 1);
4611
4612 std::string layerName = std::string(GetUnaryOperationAsCString(unaryOperation)) + ":{}:{}";
4613 std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4614
4615 ElementwiseUnaryDescriptor desc;
4616 desc.m_Operation = unaryOperation;
4617 IConnectableLayer* layer = m_Network->AddElementwiseUnaryLayer(desc, layerNameFormatted.c_str());
4618 ARMNN_ASSERT(layer != nullptr);
4619
Mike Kelly377fb212023-01-10 15:55:28 +00004620 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004621 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4622
4623 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4624 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4625
4626 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4627 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4628}
4629
Bruno Goncalves2d0eb862021-07-11 14:10:15 -03004630void TfLiteParserImpl::ParseEqual(size_t subgraphIndex, size_t operatorIndex)
4631{
4632 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::Equal);
4633}
4634
4635void TfLiteParserImpl::ParseNotEqual(size_t subgraphIndex, size_t operatorIndex)
4636{
4637 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::NotEqual);
4638}
4639
4640void TfLiteParserImpl::ParseGreater(size_t subgraphIndex, size_t operatorIndex)
4641{
4642 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::Greater);
4643}
4644
4645void TfLiteParserImpl::ParseGreaterOrEqual(size_t subgraphIndex, size_t operatorIndex)
4646{
4647 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::GreaterOrEqual);
4648}
4649
4650void TfLiteParserImpl::ParseLess(size_t subgraphIndex, size_t operatorIndex)
4651{
4652 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::Less);
4653}
4654
4655void TfLiteParserImpl::ParseLessOrEqual(size_t subgraphIndex, size_t operatorIndex)
4656{
4657 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::LessOrEqual);
4658}
4659
4660void TfLiteParserImpl::ParseComparison(size_t subgraphIndex, size_t operatorIndex,
4661 ComparisonOperation comparisonOperation)
4662{
4663 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4664
4665 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4666 CHECK_VALID_SIZE(inputs.size(), 2);
4667
4668 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4669 CHECK_VALID_SIZE(outputs.size(), 1);
4670
4671 auto layerName = std::string(GetComparisonOperationAsCString(comparisonOperation)) + ":{}:{}";
4672 std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4673
Mike Kelly377fb212023-01-10 15:55:28 +00004674 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4675 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves2d0eb862021-07-11 14:10:15 -03004676 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerNameFormatted, "Input 0", "Input 1");
4677
4678 ComparisonDescriptor desc;
4679 desc.m_Operation = comparisonOperation;
4680 IConnectableLayer* layer = m_Network->AddComparisonLayer(desc, layerNameFormatted.c_str());
4681 ARMNN_ASSERT(layer != nullptr);
4682
Mike Kelly377fb212023-01-10 15:55:28 +00004683 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Bruno Goncalves2d0eb862021-07-11 14:10:15 -03004684 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4685
4686 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4687 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4688
4689 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4690 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4691}
4692
Mike Kelly04d82292023-01-19 18:29:40 +00004693armnn::IConnectableLayer* TfLiteParserImpl::AddReshapeLayer(armnn::IConnectableLayer* layer,
4694 unsigned int outputSlot,
4695 std::string reshapeLayerName,
4696 armnn::TensorInfo outputShape)
4697{
4698 ReshapeDescriptor desc;
4699 desc.m_TargetShape = outputShape.GetShape();
4700
4701 IConnectableLayer* reshapeLayer =
4702 m_Network->AddReshapeLayer(desc, reshapeLayerName.c_str());
4703
4704 auto & prevOutputSlot = layer->GetOutputSlot(outputSlot);
4705 prevOutputSlot.Connect(reshapeLayer->GetInputSlot(0));
4706 reshapeLayer->GetOutputSlot(0).SetTensorInfo(outputShape);
4707 return reshapeLayer;
4708}
4709
Kevin May7d96b162021-02-03 17:38:41 +00004710armnn::IConnectableLayer* TfLiteParserImpl::AddFusedActivationLayer(armnn::IConnectableLayer* prevLayer,
4711 unsigned int outputSlot,
4712 tflite::ActivationFunctionType activationType)
telsoa01c577f2c2018-08-31 09:22:23 +01004713{
4714 ActivationDescriptor activationDesc;
4715 std::string layerName = prevLayer->GetName();
4716
4717 switch(activationType)
4718 {
4719 case tflite::ActivationFunctionType_NONE:
4720 {
4721 // this is a no-op: return previous layer
4722 return prevLayer;
4723 }
4724 case tflite::ActivationFunctionType_RELU:
4725 {
4726 activationDesc.m_Function = ActivationFunction::ReLu;
4727 layerName += ":RELU";
4728 break;
4729 }
4730 case tflite::ActivationFunctionType_RELU6:
4731 {
4732 activationDesc.m_Function = ActivationFunction::BoundedReLu;
4733 activationDesc.m_A = 6.0f;
4734 activationDesc.m_B = 0.0f;
4735 layerName += ":RELU6";
4736 break;
4737 }
4738 case tflite::ActivationFunctionType_TANH:
4739 {
4740 activationDesc.m_Function = ActivationFunction::TanH;
4741 activationDesc.m_A = 1.0f;
4742 activationDesc.m_B = 1.0f;
4743 layerName += ":TANH";
4744 break;
4745 }
4746
4747 // I only put these here as a reminder what others we could support
4748 case tflite::ActivationFunctionType_RELU_N1_TO_1:
4749 case tflite::ActivationFunctionType_SIGN_BIT:
4750 default:
4751 {
4752 throw ParseException(
Mike Kelly377fb212023-01-10 15:55:28 +00004753 fmt::format("TfLite parser doesn't support fused activation: "
James Ward58dec6b2020-09-11 17:32:44 +01004754 "{}/{} {} ",
4755 activationType,
4756 tflite::EnumNameActivationFunctionType(activationType),
4757 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01004758
4759 }
4760 }
4761
4762 IConnectableLayer* activationLayer =
4763 m_Network->AddActivationLayer(activationDesc, layerName.c_str());
4764
4765 auto & prevOutputSlot = prevLayer->GetOutputSlot(outputSlot);
4766 prevOutputSlot.Connect(activationLayer->GetInputSlot(0));
4767 activationLayer->GetOutputSlot(0).SetTensorInfo(prevOutputSlot.GetTensorInfo());
4768 return activationLayer;
4769}
4770
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004771armnn::IConnectableLayer* TfLiteParserImpl::AddFusedFloorLayer(armnn::IConnectableLayer* prevLayer,
4772 unsigned int outputSlot)
4773{
Teresa Charlin725728e2022-05-05 13:33:33 +01004774
4775 auto& prevOutputSlot = prevLayer->GetOutputSlot(outputSlot);
4776 DataType dataType = prevOutputSlot.GetTensorInfo().GetDataType();
4777
4778 if (dataType == DataType::Signed32)
4779 {
4780 return prevLayer;
4781 }
4782
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004783 std::string layerName = prevLayer->GetName();
4784 IConnectableLayer* floorLayer = m_Network->AddFloorLayer(layerName.c_str());
4785
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004786 prevOutputSlot.Connect(floorLayer->GetInputSlot(0));
4787 floorLayer->GetOutputSlot(0).SetTensorInfo(prevOutputSlot.GetTensorInfo());
Teresa Charlin725728e2022-05-05 13:33:33 +01004788
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004789 return floorLayer;
4790}
4791
Mike Kelly0d77ae12022-01-07 17:42:27 +00004792TfLiteParserImpl::ModelPtr TfLiteParserImpl::LoadModelFromFile(const char* fileName)
telsoa01c577f2c2018-08-31 09:22:23 +01004793{
4794 if (fileName == nullptr)
4795 {
James Ward58dec6b2020-09-11 17:32:44 +01004796 throw InvalidArgumentException(fmt::format("Invalid (null) file name {}",
telsoa01c577f2c2018-08-31 09:22:23 +01004797 CHECK_LOCATION().AsString()));
4798 }
Francis Murtagh532a29d2020-06-29 11:50:01 +01004799 std::error_code errorCode;
4800 fs::path pathToFile(fileName);
4801 if (!fs::exists(pathToFile, errorCode))
telsoa01c577f2c2018-08-31 09:22:23 +01004802 {
James Ward58dec6b2020-09-11 17:32:44 +01004803 //fmt::format() could not be used here (format error)
4804 std::stringstream msg;
4805 msg << "Cannot find the file (" << fileName << ") errorCode: " << errorCode
4806 << " " << CHECK_LOCATION().AsString();
4807
4808 throw FileNotFoundException(msg.str());
telsoa01c577f2c2018-08-31 09:22:23 +01004809 }
4810 std::ifstream file(fileName, std::ios::binary);
4811 std::string fileContent((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
4812 return LoadModelFromBinary(reinterpret_cast<const uint8_t *>(fileContent.c_str()),
4813 fileContent.size());
4814}
4815
Mike Kelly0d77ae12022-01-07 17:42:27 +00004816TfLiteParserImpl::ModelPtr TfLiteParserImpl::LoadModelFromBinary(const uint8_t* binaryContent, size_t len)
telsoa01c577f2c2018-08-31 09:22:23 +01004817{
4818 if (binaryContent == nullptr)
4819 {
James Ward58dec6b2020-09-11 17:32:44 +01004820 throw InvalidArgumentException(fmt::format("Invalid (null) binary content {}",
telsoa01c577f2c2018-08-31 09:22:23 +01004821 CHECK_LOCATION().AsString()));
4822 }
4823 flatbuffers::Verifier verifier(binaryContent, len);
4824 if (verifier.VerifyBuffer<tflite::Model>() == false)
4825 {
4826 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01004827 fmt::format("Buffer doesn't conform to the expected Tensorflow Lite "
4828 "flatbuffers format. size:{} {}",
4829 len,
4830 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01004831 }
4832 return tflite::UnPackModel(binaryContent);
4833}
4834
Mike Kelly0d77ae12022-01-07 17:42:27 +00004835TfLiteParserImpl::TensorRawPtrVector TfLiteParserImpl::GetInputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00004836 size_t subgraphIndex,
4837 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004838{
4839 CHECK_MODEL(model, subgraphIndex, operatorIndex);
4840
Mike Kelly0d77ae12022-01-07 17:42:27 +00004841 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
4842 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01004843
4844 size_t inputCount = operatorPtr->inputs.size();
mathad01c21025d2021-04-26 10:09:37 +01004845 TensorRawPtrVector result;
Mike Kelly0d77ae12022-01-07 17:42:27 +00004846 for (size_t i = 0; i < inputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01004847 {
mathad01c21025d2021-04-26 10:09:37 +01004848 // If the input location is -1 then assume input is turned off.
4849 if (operatorPtr->inputs[i] == -1)
4850 {
4851 continue;
4852 }
4853 else
4854 {
4855 uint32_t inputId = CHECKED_NON_NEGATIVE(operatorPtr->inputs[i]);
4856 result.push_back(subgraphPtr->tensors[inputId].get());
4857 }
telsoa01c577f2c2018-08-31 09:22:23 +01004858 }
4859 return result;
4860}
4861
Mike Kelly0d77ae12022-01-07 17:42:27 +00004862TfLiteParserImpl::TensorRawPtrVector TfLiteParserImpl::GetOutputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00004863 size_t subgraphIndex,
4864 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004865{
4866 CHECK_MODEL(model, subgraphIndex, operatorIndex);
4867
Mike Kelly0d77ae12022-01-07 17:42:27 +00004868 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
4869 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01004870
4871 size_t outputCount = operatorPtr->outputs.size();
4872 TensorRawPtrVector result(outputCount);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004873 for (size_t i = 0; i < outputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01004874 {
4875 uint32_t outputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[i]);
4876 CHECK_TENSOR(model, subgraphIndex, outputId);
Derek Lambertiff05cc52019-04-26 13:05:17 +01004877 result[i] = subgraphPtr->tensors[outputId].get();
telsoa01c577f2c2018-08-31 09:22:23 +01004878 }
4879 return result;
4880}
4881
Mike Kelly0d77ae12022-01-07 17:42:27 +00004882TfLiteParserImpl::TensorIdRawPtrVector TfLiteParserImpl::GetSubgraphInputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00004883 size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004884{
4885 CHECK_SUBGRAPH(model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004886 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01004887
Derek Lambertiff05cc52019-04-26 13:05:17 +01004888 size_t inputCount = subgraphPtr->inputs.size();
telsoa01c577f2c2018-08-31 09:22:23 +01004889 TensorIdRawPtrVector result(inputCount);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004890 for (size_t i = 0; i < inputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01004891 {
Derek Lambertiff05cc52019-04-26 13:05:17 +01004892 uint32_t inputId = CHECKED_NON_NEGATIVE(subgraphPtr->inputs[i]);
telsoa01c577f2c2018-08-31 09:22:23 +01004893 CHECK_TENSOR(model, subgraphIndex, inputId);
Derek Lambertiff05cc52019-04-26 13:05:17 +01004894 result[i] = std::make_pair(inputId, subgraphPtr->tensors[inputId].get());
telsoa01c577f2c2018-08-31 09:22:23 +01004895 }
4896 return result;
4897}
4898
Mike Kelly0d77ae12022-01-07 17:42:27 +00004899TfLiteParserImpl::TensorIdRawPtrVector TfLiteParserImpl::GetSubgraphOutputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00004900 size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004901{
4902 CHECK_SUBGRAPH(model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004903 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01004904
Derek Lambertiff05cc52019-04-26 13:05:17 +01004905 size_t outputCount = subgraphPtr->outputs.size();
telsoa01c577f2c2018-08-31 09:22:23 +01004906 TensorIdRawPtrVector result(outputCount);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004907 for (size_t i = 0; i < outputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01004908 {
Derek Lambertiff05cc52019-04-26 13:05:17 +01004909 uint32_t outputId = CHECKED_NON_NEGATIVE(subgraphPtr->outputs[i]);
4910 result[i] = std::make_pair(outputId, subgraphPtr->tensors[outputId].get());
telsoa01c577f2c2018-08-31 09:22:23 +01004911 }
4912 return result;
4913}
4914
Kevin May7d96b162021-02-03 17:38:41 +00004915std::vector<int32_t>& TfLiteParserImpl::GetInputTensorIds(const ModelPtr& model,
4916 size_t subgraphIndex,
4917 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004918{
4919 CHECK_MODEL(model, subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004920 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
4921 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01004922 return operatorPtr->inputs;
4923}
4924
Kevin May7d96b162021-02-03 17:38:41 +00004925std::vector<int32_t>& TfLiteParserImpl::GetOutputTensorIds(const ModelPtr& model,
4926 size_t subgraphIndex,
4927 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004928{
4929 CHECK_MODEL(model, subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004930 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
4931 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01004932 return operatorPtr->outputs;
4933}
4934
Kevin May7d96b162021-02-03 17:38:41 +00004935void TfLiteParserImpl::RegisterInputSlots(size_t subgraphIndex,
4936 size_t operatorIndex,
4937 IConnectableLayer* layer,
Finn Williamsd4fa5452021-03-01 12:31:41 +00004938 const std::vector<unsigned int>& tensorIndexes,
4939 unsigned int startingSlotIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004940{
4941 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01004942 ARMNN_ASSERT(layer != nullptr);
Matthew Sloyan81beae32021-07-13 19:46:11 +01004943
Finn Williamsd4fa5452021-03-01 12:31:41 +00004944 if (tensorIndexes.size() + startingSlotIndex != layer->GetNumInputSlots())
telsoa01c577f2c2018-08-31 09:22:23 +01004945 {
4946 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01004947 fmt::format("The number of tensor inputs ({}) does not match the number expected ({})"
4948 " for subgraph:{} operator index:{} {}",
4949 tensorIndexes.size(),
4950 layer->GetNumInputSlots(),
4951 subgraphIndex,
4952 operatorIndex,
4953 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01004954 }
4955
Finn Williamsd4fa5452021-03-01 12:31:41 +00004956 for (unsigned int index = 0; index < tensorIndexes.size() ; ++index)
telsoa01c577f2c2018-08-31 09:22:23 +01004957 {
Finn Williamsd4fa5452021-03-01 12:31:41 +00004958 unsigned int tensorIndex = tensorIndexes[index];
4959 armnn::IInputSlot* slot = &(layer->GetInputSlot(startingSlotIndex + index));
telsoa01c577f2c2018-08-31 09:22:23 +01004960 RegisterConsumerOfTensor(subgraphIndex, tensorIndex, slot);
4961 }
4962}
4963
Kevin May7d96b162021-02-03 17:38:41 +00004964void TfLiteParserImpl::RegisterOutputSlots(size_t subgraphIndex,
4965 size_t operatorIndex,
4966 IConnectableLayer* layer,
4967 const std::vector<unsigned int>& tensorIndexes)
telsoa01c577f2c2018-08-31 09:22:23 +01004968{
4969 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01004970 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01004971 if (tensorIndexes.size() != layer->GetNumOutputSlots())
4972 {
4973 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01004974 fmt::format("The number of tensor outputs ({}) does not match the number expected ({})"
4975 " for subgraph:{} operator index:{} {}",
4976 tensorIndexes.size(),
4977 layer->GetNumOutputSlots(),
4978 subgraphIndex,
4979 operatorIndex,
4980 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01004981 }
4982
4983 for (unsigned int slotIndex = 0; slotIndex < layer->GetNumOutputSlots(); ++slotIndex)
4984 {
4985 unsigned int tensorIndex = tensorIndexes[slotIndex];
4986 armnn::IOutputSlot* slot = &(layer->GetOutputSlot(slotIndex));
4987 RegisterProducerOfTensor(subgraphIndex, tensorIndex, slot);
4988 }
4989}
4990
Mike Kelly377fb212023-01-10 15:55:28 +00004991void TfLiteParserImpl::SetupInputLayerTensorInfos(size_t subgraphIndex)
4992{
4993 CHECK_SUBGRAPH(m_Model, subgraphIndex);
4994
4995 auto inputs = GetSubgraphInputs(m_Model, subgraphIndex);
4996 for (auto const& tensorIdAndPtr : inputs)
4997 {
4998 auto tensorInfo = ToTensorInfo(tensorIdAndPtr.second);
4999 m_TensorInfos.insert({tensorIdAndPtr.first, tensorInfo});
5000 }
5001}
5002
Kevin May7d96b162021-02-03 17:38:41 +00005003void TfLiteParserImpl::SetupInputLayers(size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005004{
5005 CHECK_SUBGRAPH(m_Model, subgraphIndex);
5006
5007 auto inputs = GetSubgraphInputs(m_Model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005008 for (auto const& tensorIdAndPtr : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005009 {
5010 auto bindingId = GenerateLayerBindingId(subgraphIndex, tensorIdAndPtr.first);
5011 IConnectableLayer* layer =
5012 m_Network->AddInputLayer(bindingId, tensorIdAndPtr.second->name.c_str());
5013
5014 auto tensorInfo = ToTensorInfo(tensorIdAndPtr.second);
5015 layer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
5016
5017 RegisterOutputSlots(subgraphIndex,
5018 VIRTUAL_OPERATOR_ID,
5019 layer,
5020 { static_cast<uint32_t>(tensorIdAndPtr.first) });
5021 }
5022}
5023
Kevin May7d96b162021-02-03 17:38:41 +00005024void TfLiteParserImpl::SetupOutputLayers(size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005025{
5026 CHECK_SUBGRAPH(m_Model, subgraphIndex);
5027
5028 auto outputs = GetSubgraphOutputs(m_Model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005029 for (auto const& tensorIdAndPtr : outputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005030 {
5031 auto bindingId = GenerateLayerBindingId(subgraphIndex, tensorIdAndPtr.first);
5032 IConnectableLayer* layer =
5033 m_Network->AddOutputLayer(bindingId, tensorIdAndPtr.second->name.c_str());
5034
5035 RegisterInputSlots(subgraphIndex,
5036 VIRTUAL_OPERATOR_ID,
5037 layer,
5038 { static_cast<uint32_t>(tensorIdAndPtr.first) });
5039 }
5040}
5041
Mike Kelly377fb212023-01-10 15:55:28 +00005042void TfLiteParserImpl::SetupConstantLayerTensorInfos(size_t subgraph)
5043{
5044 CHECK_SUBGRAPH(m_Model, subgraph);
5045
5046 const auto & subgraphPtr = m_Model->subgraphs[subgraph];
5047 for (unsigned int subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex)
5048 {
5049 for (unsigned int tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex)
5050 {
5051 if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot == nullptr &&
5052 m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size() > 0)
5053 {
5054 TensorRawPtr tensorPtr = subgraphPtr->tensors[tensorIndex].get();
5055
5056 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
5057
5058 m_TensorInfos.insert({tensorIndex, tensorInfo});
5059 }
5060 }
5061 }
5062}
5063
Mike Kelly5880b912022-01-28 16:18:54 +00005064void TfLiteParserImpl::SetupConstantLayers(size_t subgraph)
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005065{
Mike Kelly5880b912022-01-28 16:18:54 +00005066 CHECK_SUBGRAPH(m_Model, subgraph);
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005067
Mike Kelly5880b912022-01-28 16:18:54 +00005068 const auto & subgraphPtr = m_Model->subgraphs[subgraph];
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005069 for (unsigned int subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex)
5070 {
5071 for (unsigned int tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex)
5072 {
5073 if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot == nullptr &&
5074 m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size() > 0)
5075 {
Derek Lambertiff05cc52019-04-26 13:05:17 +01005076 TensorRawPtr tensorPtr = subgraphPtr->tensors[tensorIndex].get();
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005077
Mike Kelly5880b912022-01-28 16:18:54 +00005078 if (IsConstTensor(tensorPtr))
Matthew Sloyan81beae32021-07-13 19:46:11 +01005079 {
5080 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
Mike Kelly5880b912022-01-28 16:18:54 +00005081 armnn::DataType dataType = tensorInfo.GetDataType();
5082
5083 if (std::find(m_ConstantsToDequantize.begin(), m_ConstantsToDequantize.end(), tensorPtr->buffer)
5084 != m_ConstantsToDequantize.end())
5085 {
5086 dataType = DataType::Float32;
5087 }
5088 auto tensorAndData = CreateConstTensorNonPermuted(tensorPtr, tensorInfo, dataType);
5089
5090 std::string layerName = fmt::format("Constant:{}", tensorPtr->name);
5091 IConnectableLayer *layer = m_Network->AddConstantLayer(tensorAndData.first, layerName.c_str());
5092
5093 layer->GetOutputSlot(0).SetTensorInfo(tensorAndData.first.GetInfo());
5094 RegisterOutputSlots(subgraphIndex,
5095 VIRTUAL_OPERATOR_ID,
5096 layer,
5097 { tensorIndex });
5098 }
5099 else if (ShouldConstantTensorBeCreated(tensorIndex))
5100 {
5101 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
5102 armnn::DataType dataType = tensorInfo.GetDataType();
5103
5104 if (std::find(m_ConstantsToDequantize.begin(), m_ConstantsToDequantize.end(), tensorPtr->buffer)
5105 != m_ConstantsToDequantize.end())
5106 {
5107 dataType = DataType::Float32;
5108 }
5109 // Make sure isConstant flag is set.
5110 tensorInfo.SetConstant();
5111 tensorInfo.SetDataType(dataType);
5112
5113 auto tensorAndData = ConstTensor(tensorInfo, std::vector<uint8_t>(tensorInfo.GetNumBytes()));
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005114
Matthew Sloyan81beae32021-07-13 19:46:11 +01005115 std::string layerName = fmt::format("Constant:{}", tensorPtr->name);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005116 IConnectableLayer* layer = m_Network->AddConstantLayer(tensorAndData, layerName.c_str());
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005117
Matthew Sloyan81beae32021-07-13 19:46:11 +01005118 layer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
5119 RegisterOutputSlots(subgraphIndex,
5120 VIRTUAL_OPERATOR_ID,
5121 layer,
Mike Kelly5880b912022-01-28 16:18:54 +00005122 {tensorIndex});
Matthew Sloyan81beae32021-07-13 19:46:11 +01005123 }
5124 else
5125 {
5126 throw ParseException(
5127 fmt::format("Invalid Tensor: Tensor should be constant. {}",
5128 CHECK_LOCATION().AsString()));
5129 }
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005130 }
5131 }
5132 }
5133}
5134
telsoa01c577f2c2018-08-31 09:22:23 +01005135// example usage: BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[0]->buffer);
Kevin May7d96b162021-02-03 17:38:41 +00005136TfLiteParserImpl::BufferRawPtr TfLiteParserImpl::GetBuffer(const ModelPtr& model, size_t bufferIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005137{
5138 CHECK_BUFFER(model, bufferIndex);
5139 return model->buffers[bufferIndex].get();
5140}
5141
Matteo Martincigh747ef822018-12-18 09:26:39 +00005142template<typename T>
Kevin May7d96b162021-02-03 17:38:41 +00005143std::pair<armnn::ConstTensor, TfLiteParserImpl::SupportedDataStorage>
5144TfLiteParserImpl::CreateConstTensorAndStoreData(TfLiteParserImpl::BufferRawPtr bufferPtr,
5145 TfLiteParserImpl::TensorRawPtr tensorPtr,
Matteo Martincigh747ef822018-12-18 09:26:39 +00005146 armnn::TensorInfo& tensorInfo,
5147 armnn::Optional<armnn::PermutationVector&> permutationVector)
5148{
Matthew Sloyan81beae32021-07-13 19:46:11 +01005149 // Make sure isConstant flag is set.
5150 tensorInfo.SetConstant();
5151
Matteo Martincigh747ef822018-12-18 09:26:39 +00005152 auto constData = CreateConstTensorImpl<T>(bufferPtr,
5153 tensorPtr,
5154 tensorInfo,
5155 permutationVector);
Kevin May7d96b162021-02-03 17:38:41 +00005156 TfLiteParserImpl::SupportedDataStorage storage(std::move(constData.second));
Matteo Martincigh747ef822018-12-18 09:26:39 +00005157 return std::make_pair(constData.first, std::move(storage));
5158}
5159
Mike Kelly5880b912022-01-28 16:18:54 +00005160bool TfLiteParserImpl::ShouldConstantTensorBeCreated(unsigned int tensorIndex)
5161{
5162 // If the TensorIndex appears in the list of ConstantsToBeCreated then return true
5163 return (std::find(m_ConstantsToBeCreated.begin(), m_ConstantsToBeCreated.end(), tensorIndex)
5164 != m_ConstantsToBeCreated.end());
5165}
5166
Finn Williamsd4fa5452021-03-01 12:31:41 +00005167bool TfLiteParserImpl::IsConstTensor(TensorRawPtr tensorPtr)
5168{
5169 CHECK_TENSOR_PTR(tensorPtr);
mathad01bf7edb62021-04-20 16:12:45 +01005170 bool isConst = true;
5171
5172 auto buffer = GetBuffer(m_Model, tensorPtr->buffer);
5173 if (buffer->data.size() == 0)
5174 {
5175 isConst = false;
5176 }
5177
5178 return isConst;
Finn Williamsd4fa5452021-03-01 12:31:41 +00005179}
5180
Kevin May7d96b162021-02-03 17:38:41 +00005181std::pair<armnn::ConstTensor, TfLiteParserImpl::SupportedDataStorage>
Finn Williamsd4fa5452021-03-01 12:31:41 +00005182TfLiteParserImpl::CreateConstTensorPermuted(TensorRawPtr tensorPtr,
5183 armnn::TensorInfo& tensorInfo,
5184 armnn::Optional<armnn::PermutationVector&> permutationVector)
telsoa01c577f2c2018-08-31 09:22:23 +01005185{
5186 CHECK_TENSOR_PTR(tensorPtr);
5187 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5188 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5189
Matthew Sloyan81beae32021-07-13 19:46:11 +01005190 // Make sure isConstant flag is set.
5191 tensorInfo.SetConstant();
5192
telsoa01c577f2c2018-08-31 09:22:23 +01005193 switch (tensorInfo.GetDataType())
5194 {
5195 case armnn::DataType::Float32:
Matteo Martincigh747ef822018-12-18 09:26:39 +00005196 return CreateConstTensorAndStoreData<float>(bufferPtr,
5197 tensorPtr,
5198 tensorInfo,
5199 permutationVector);
Derek Lambertif90c56d2020-01-10 17:14:08 +00005200 case armnn::DataType::QAsymmU8:
Matteo Martincigh747ef822018-12-18 09:26:39 +00005201 return CreateConstTensorAndStoreData<uint8_t>(bufferPtr,
5202 tensorPtr,
5203 tensorInfo,
5204 permutationVector);
Keith Davisd305e1a2020-01-22 11:57:54 +00005205 case armnn::DataType::QSymmS8:
5206 return CreateConstTensorAndStoreData<int8_t>(bufferPtr,
5207 tensorPtr,
5208 tensorInfo,
5209 permutationVector);
Keith Davis67e6c542020-02-19 10:08:33 +00005210 case armnn::DataType::QAsymmS8:
5211 return CreateConstTensorAndStoreData<int8_t>(bufferPtr,
5212 tensorPtr,
5213 tensorInfo,
5214 permutationVector);
telsoa01c577f2c2018-08-31 09:22:23 +01005215 case armnn::DataType::Signed32:
Matteo Martincigh747ef822018-12-18 09:26:39 +00005216 return CreateConstTensorAndStoreData<int32_t>(bufferPtr,
5217 tensorPtr,
5218 tensorInfo,
5219 permutationVector);
telsoa01c577f2c2018-08-31 09:22:23 +01005220 default:
5221 {
5222 std::stringstream errString;
5223 errString << "Unexpected datatype when creating const tensor: "
5224 << armnn::GetDataTypeName(tensorInfo.GetDataType())
5225 << " shape:" << tensorInfo.GetShape()
5226 << CHECK_LOCATION().AsString();
5227 throw ParseException(errString.str());
5228 }
5229 }
5230}
5231
Finn Williamsd4fa5452021-03-01 12:31:41 +00005232armnn::ConstTensor TfLiteParserImpl::CreateConstTensorNonPermuted(TensorRawPtr tensorPtr,
5233 armnn::TensorInfo& tensorInfo)
5234{
5235 CHECK_TENSOR_PTR(tensorPtr);
5236 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5237 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5238
Matthew Sloyan81beae32021-07-13 19:46:11 +01005239 // Make sure isConstant flag is set.
5240 tensorInfo.SetConstant();
5241
Finn Williamsd4fa5452021-03-01 12:31:41 +00005242 return ConstTensor(tensorInfo, bufferPtr->data.data());
5243}
5244
Mike Kelly5880b912022-01-28 16:18:54 +00005245std::pair<armnn::ConstTensor, std::unique_ptr<float[]>>
5246TfLiteParserImpl::CreateConstTensorNonPermuted(TensorRawPtr tensorPtr,
5247 armnn::TensorInfo& tensorInfo,
5248 armnn::DataType inputDataType)
5249{
5250 CHECK_TENSOR_PTR(tensorPtr);
5251 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5252 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5253
5254 // Make sure isConstant flag is set.
5255 tensorInfo.SetConstant();
5256
Mike Kelly0506ef02023-01-03 16:29:44 +00005257 if (inputDataType == DataType::Float32 && tensorInfo.GetDataType() != DataType::Float32)
Mike Kelly5880b912022-01-28 16:18:54 +00005258 {
Mike Kelly0506ef02023-01-03 16:29:44 +00005259 try
5260 {
5261 TensorInfo constTensorInfo(tensorInfo.GetShape(), DataType::Float32, 0.0f, 0, true);
5262 std::unique_ptr<float[]> data = armnnUtils::ToFloatArray(bufferPtr->data, tensorInfo);
5263 return std::make_pair(ConstTensor(constTensorInfo, data.get()), std::move(data));
5264 }
Cathal Corbett9c843c32023-01-09 17:51:37 +00005265 catch (InvalidArgumentException&)
Mike Kelly0506ef02023-01-03 16:29:44 +00005266 {
5267 throw ParseException(
5268 fmt::format("Unsupported input/weights combination: Input {} not supported with Weights {}",
5269 GetDataTypeName(DataType::Float32),
5270 GetDataTypeName(tensorInfo.GetDataType()),
5271 CHECK_LOCATION().AsString()));
5272 }
Mike Kelly5880b912022-01-28 16:18:54 +00005273 }
5274 else
5275 {
5276 return std::make_pair(ConstTensor(tensorInfo, bufferPtr->data.data()), std::unique_ptr<float[]>());
5277 }
5278}
5279
5280std::pair<armnn::ConstTensor*, std::unique_ptr<float[]>>
5281TfLiteParserImpl::CreateConstTensorPtr(TensorRawPtr tensorPtr, armnn::TensorInfo& inputTensorInfo)
5282{
5283 CHECK_TENSOR_PTR(tensorPtr);
5284 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
5285 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5286 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5287
5288 // Make sure isConstant flag is set.
5289 tensorInfo.SetConstant();
5290
5291 if (inputTensorInfo.GetDataType() == DataType::Float32 && tensorInfo.GetDataType() != DataType::Float32)
5292 {
Mike Kelly0506ef02023-01-03 16:29:44 +00005293 try
5294 {
5295 TensorInfo constTensorInfo(tensorInfo.GetShape(), DataType::Float32, 0.0f, 0, true);
5296 std::unique_ptr<float[]> data = armnnUtils::ToFloatArray(bufferPtr->data, tensorInfo);
5297 return std::make_pair(new ConstTensor(constTensorInfo, data.get()), std::move(data));
5298 }
Cathal Corbett9c843c32023-01-09 17:51:37 +00005299 catch (InvalidArgumentException&)
Mike Kelly0506ef02023-01-03 16:29:44 +00005300 {
5301 throw ParseException(
5302 fmt::format("Unsupported input/weights combination: Input {} not supported with Weights {}",
5303 GetDataTypeName(DataType::Float32),
5304 GetDataTypeName(tensorInfo.GetDataType()),
5305 CHECK_LOCATION().AsString()));
5306 }
Mike Kelly5880b912022-01-28 16:18:54 +00005307 }
5308 else
5309 {
5310 return std::make_pair(new ConstTensor(tensorInfo, bufferPtr->data.data()), std::unique_ptr<float[]>());
5311 }
5312}
5313
Kevin May7d96b162021-02-03 17:38:41 +00005314BindingPointInfo TfLiteParserImpl::GetNetworkInputBindingInfo(size_t subgraphId,
5315 const std::string& name) const
telsoa01c577f2c2018-08-31 09:22:23 +01005316{
5317 CHECK_SUBGRAPH(m_Model, subgraphId);
5318 auto inputs = GetSubgraphInputs(m_Model, subgraphId);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005319 for (auto const& input : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005320 {
5321 if (input.second->name == name)
5322 {
5323 auto bindingId = GenerateLayerBindingId(subgraphId, input.first);
Colm Donelan4bc993b2021-11-09 20:39:10 +00005324 auto inputTensorInfo = ToTensorInfo(input.second);
5325 // Input tensors are always treated as constant tensors during network execution.
5326 inputTensorInfo.SetConstant(true);
5327 return std::make_pair(bindingId, inputTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +01005328 }
5329 }
5330
5331 std::stringstream bindings;
Mike Kelly0d77ae12022-01-07 17:42:27 +00005332 for (auto const& input : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005333 {
5334 bindings << "'" << input.second->name << "' ";
5335 }
5336
5337 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01005338 fmt::format("No input binding found for subgraph:{} and name:{}. "
5339 "Possible inputs are: [{}] {}",
5340 subgraphId,
5341 name,
5342 bindings.str(),
5343 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01005344}
5345
Kevin May7d96b162021-02-03 17:38:41 +00005346BindingPointInfo TfLiteParserImpl::GetNetworkOutputBindingInfo(size_t subgraphId,
5347 const std::string& name) const
telsoa01c577f2c2018-08-31 09:22:23 +01005348{
5349 CHECK_SUBGRAPH(m_Model, subgraphId);
5350 auto outputs = GetSubgraphOutputs(m_Model, subgraphId);
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00005351 for (unsigned int i = 0; i < outputs.size(); ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01005352 {
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00005353 auto const output = outputs[i];
telsoa01c577f2c2018-08-31 09:22:23 +01005354 if (output.second->name == name)
5355 {
5356 auto bindingId = GenerateLayerBindingId(subgraphId, output.first);
Mike Kelly377fb212023-01-10 15:55:28 +00005357 std::vector<unsigned int> shape = m_OverriddenOutputShapes.size() > 0 ?
5358 m_OverriddenOutputShapes[i] : AsUnsignedVector(output.second->shape);
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00005359 return std::make_pair(bindingId, ToTensorInfo(output.second, shape));
telsoa01c577f2c2018-08-31 09:22:23 +01005360 }
5361 }
5362
5363 std::stringstream bindings;
Mike Kelly0d77ae12022-01-07 17:42:27 +00005364 for (auto const& output : outputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005365 {
5366 bindings << "'" << output.second->name << "' ";
5367 }
5368
5369 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01005370 fmt::format("No output binding found for subgraph:{} and name:{}. "
5371 "Possible outputs are: [{}] {}",
5372 subgraphId,
5373 name,
5374 bindings.str(),
5375 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01005376}
5377
Kevin May7d96b162021-02-03 17:38:41 +00005378size_t TfLiteParserImpl::GetSubgraphCount() const
telsoa01c577f2c2018-08-31 09:22:23 +01005379{
5380 return m_Model->subgraphs.size();
5381}
5382
Kevin May7d96b162021-02-03 17:38:41 +00005383std::vector<std::string> TfLiteParserImpl::GetSubgraphInputTensorNames(size_t subgraphId) const
telsoa01c577f2c2018-08-31 09:22:23 +01005384{
5385 CHECK_SUBGRAPH(m_Model, subgraphId);
5386 auto inputs = GetSubgraphInputs(m_Model, subgraphId);
5387 std::vector<std::string> result;
5388 result.reserve(inputs.size());
Mike Kelly0d77ae12022-01-07 17:42:27 +00005389 for (auto const& input : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005390 {
5391 result.push_back(input.second->name);
5392 }
5393 return result;
5394}
5395
Kevin May7d96b162021-02-03 17:38:41 +00005396std::vector<std::string> TfLiteParserImpl::GetSubgraphOutputTensorNames(size_t subgraphId) const
telsoa01c577f2c2018-08-31 09:22:23 +01005397{
5398 CHECK_SUBGRAPH(m_Model, subgraphId);
5399 auto outputs = GetSubgraphOutputs(m_Model, subgraphId);
5400 std::vector<std::string> result;
5401 result.reserve(outputs.size());
Mike Kelly0d77ae12022-01-07 17:42:27 +00005402 for (auto const& output : outputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005403 {
5404 result.push_back(output.second->name);
5405 }
5406 return result;
5407}
5408
Matthew Sloyanac001ee2021-02-03 10:43:04 +00005409const std::string TfLiteParserImpl::GetVersion()
5410{
5411 return TFLITE_PARSER_VERSION;
5412}
5413
Mike Kelly0d77ae12022-01-07 17:42:27 +00005414TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<float[]>&& data)
telsoa01c577f2c2018-08-31 09:22:23 +01005415: m_FloatData(std::move(data))
5416, m_Uint8Data(nullptr)
Keith Davisd305e1a2020-01-22 11:57:54 +00005417, m_Int8Data(nullptr)
telsoa01c577f2c2018-08-31 09:22:23 +01005418, m_Int32Data(nullptr)
5419{
5420}
5421
Mike Kelly0d77ae12022-01-07 17:42:27 +00005422TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<uint8_t[]>&& data)
telsoa01c577f2c2018-08-31 09:22:23 +01005423: m_FloatData(nullptr)
5424, m_Uint8Data(std::move(data))
Keith Davisd305e1a2020-01-22 11:57:54 +00005425, m_Int8Data(nullptr)
5426, m_Int32Data(nullptr)
5427{
5428}
5429
Mike Kelly0d77ae12022-01-07 17:42:27 +00005430TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<int8_t[]>&& data)
Keith Davisd305e1a2020-01-22 11:57:54 +00005431: m_FloatData(nullptr)
5432, m_Uint8Data(nullptr)
5433, m_Int8Data(std::move(data))
telsoa01c577f2c2018-08-31 09:22:23 +01005434, m_Int32Data(nullptr)
5435{
5436}
5437
Mike Kelly0d77ae12022-01-07 17:42:27 +00005438TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<int32_t[]>&& data)
telsoa01c577f2c2018-08-31 09:22:23 +01005439: m_FloatData(nullptr)
5440, m_Uint8Data(nullptr)
Keith Davisd305e1a2020-01-22 11:57:54 +00005441, m_Int8Data(nullptr)
telsoa01c577f2c2018-08-31 09:22:23 +01005442, m_Int32Data(std::move(data))
5443{
5444}
5445
5446} // armnnTfLiteParser