blob: 77ce5659597bc54fd1629f6a5397189c67e904ce [file] [log] [blame]
telsoa01c577f2c2018-08-31 09:22:23 +01001//
Mike Kelly04d82292023-01-19 18:29:40 +00002// Copyright © 2017-2023 Arm Ltd and Contributors. All rights reserved.
David Beckecb56cd2018-09-05 12:52:57 +01003// SPDX-License-Identifier: MIT
telsoa01c577f2c2018-08-31 09:22:23 +01004//
Matteo Martincighe011d202019-11-28 11:35:47 +00005
telsoa01c577f2c2018-08-31 09:22:23 +01006#include "TfLiteParser.hpp"
7
Matthew Sloyanac001ee2021-02-03 10:43:04 +00008#include "armnnTfLiteParser/Version.hpp"
Mike Kelly5880b912022-01-28 16:18:54 +00009#include "armnn/LstmParams.hpp"
Matthew Sloyanac001ee2021-02-03 10:43:04 +000010
Sadik Armagand109a4d2020-07-28 10:42:13 +010011#include <armnn/BackendOptions.hpp>
Matthew Bentham39ef3e52020-01-20 10:09:09 +000012#include <armnn/Descriptors.hpp>
telsoa01c577f2c2018-08-31 09:22:23 +010013#include <armnn/Exceptions.hpp>
Derek Lamberti08446972019-11-26 16:38:31 +000014#include <armnn/Logging.hpp>
James Conroy05102392020-06-24 15:39:55 +010015#include <armnn/Tensor.hpp>
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +000016#include <armnnUtils/TensorUtils.hpp>
telsoa01c577f2c2018-08-31 09:22:23 +010017#include <armnn/TypesUtils.hpp>
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +010018#include <armnn/utility/Assert.hpp>
Jan Eilers8eb25602020-03-09 12:13:48 +000019#include <armnn/utility/IgnoreUnused.hpp>
Derek Lambertif0176992020-04-28 13:37:49 +010020#include <armnn/utility/NumericCast.hpp>
Mike Kelly377fb212023-01-10 15:55:28 +000021#include <armnn/LayerSupport.hpp>
telsoa01c577f2c2018-08-31 09:22:23 +010022
23// armnnUtils:
Matteo Martincighe011d202019-11-28 11:35:47 +000024#include <armnnUtils/Permute.hpp>
Rob Hughes9542f902021-07-14 09:48:54 +010025#include <armnnUtils/Filesystem.hpp>
Matteo Martincighe011d202019-11-28 11:35:47 +000026
Sadik Armagan479045b2018-10-01 11:51:37 +010027#include <ParserHelper.hpp>
telsoa01c577f2c2018-08-31 09:22:23 +010028#include <VerificationHelpers.hpp>
29
30// The generated code based on the Tf Lite schema:
31#include <schema_generated.h>
32
Matteo Martincighe011d202019-11-28 11:35:47 +000033#include <flatbuffers/flexbuffers.h>
34
James Ward58dec6b2020-09-11 17:32:44 +010035#include <fmt/format.h>
telsoa01c577f2c2018-08-31 09:22:23 +010036
telsoa01c577f2c2018-08-31 09:22:23 +010037#include <algorithm>
Matthew Sloyanac001ee2021-02-03 10:43:04 +000038#include <iostream>
telsoa01c577f2c2018-08-31 09:22:23 +010039#include <limits>
Sadikb94967b2018-09-19 15:30:00 +010040#include <numeric>
Derek Lambertic9e52792020-03-11 11:42:26 +000041
42#define ARMNN_THROW_PARSE_EXCEPTION(msg) \
43 { \
44 throw armnn::ParseException( static_cast<const std::stringstream&>( std::stringstream() << msg \
45 << ": " \
46 << CHECK_LOCATION().AsString()).str()); \
47 }
telsoa01c577f2c2018-08-31 09:22:23 +010048
49using namespace armnn;
50using armnn::CheckLocation;
51namespace armnnTfLiteParser
52{
Kevin May7d96b162021-02-03 17:38:41 +000053
54ITfLiteParser::ITfLiteParser(const armnn::Optional<TfLiteParserOptions>& options) :
55 pTfLiteParserImpl(new TfLiteParserImpl(options)) {}
56
57ITfLiteParser::~ITfLiteParser() = default;
58
59ITfLiteParser* ITfLiteParser::CreateRaw(const armnn::Optional<TfLiteParserOptions>& options)
60{
61 return new ITfLiteParser(options);
62}
63
64ITfLiteParserPtr ITfLiteParser::Create(const armnn::Optional<TfLiteParserOptions>& options)
65{
66 return ITfLiteParserPtr(CreateRaw(options), &ITfLiteParser::Destroy);
67}
68
69void ITfLiteParser::Destroy(ITfLiteParser* parser)
70{
71 delete parser;
72}
73
74armnn::INetworkPtr ITfLiteParser::CreateNetworkFromBinaryFile(const char* graphFile)
75{
76 return pTfLiteParserImpl->CreateNetworkFromBinaryFile(graphFile);
77}
78
Mike Kelly0d77ae12022-01-07 17:42:27 +000079armnn::INetworkPtr ITfLiteParser::CreateNetworkFromBinary(const std::vector<uint8_t>& binaryContent)
Kevin May7d96b162021-02-03 17:38:41 +000080{
81 return pTfLiteParserImpl->CreateNetworkFromBinary(binaryContent);
82}
83
84BindingPointInfo ITfLiteParser::GetNetworkInputBindingInfo(size_t subgraphId,
85 const std::string& name) const
86{
87 return pTfLiteParserImpl->GetNetworkInputBindingInfo(subgraphId, name);
88}
89
90BindingPointInfo ITfLiteParser::GetNetworkOutputBindingInfo(size_t subgraphId,
91 const std::string& name) const
92{
93 return pTfLiteParserImpl->GetNetworkOutputBindingInfo(subgraphId, name);
94}
95
96size_t ITfLiteParser::GetSubgraphCount() const
97{
98 return pTfLiteParserImpl->GetSubgraphCount();
99}
100
101std::vector<std::string> ITfLiteParser::GetSubgraphInputTensorNames(size_t subgraphId) const
102{
103 return pTfLiteParserImpl->GetSubgraphInputTensorNames(subgraphId);
104}
105
106std::vector<std::string> ITfLiteParser::GetSubgraphOutputTensorNames(size_t subgraphId) const
107{
108 return pTfLiteParserImpl->GetSubgraphOutputTensorNames(subgraphId);
109}
110
telsoa01c577f2c2018-08-31 09:22:23 +0100111namespace
112{
jimfly01c25411c2018-11-14 17:47:22 +0000113
telsoa01c577f2c2018-08-31 09:22:23 +0100114const uint32_t VIRTUAL_OPERATOR_ID = std::numeric_limits<uint32_t>::max();
115
Mike Kelly0d77ae12022-01-07 17:42:27 +0000116void CheckSubgraph(const TfLiteParserImpl::ModelPtr& model,
telsoa01c577f2c2018-08-31 09:22:23 +0100117 size_t subgraphIndex,
Mike Kelly0d77ae12022-01-07 17:42:27 +0000118 const CheckLocation& location)
telsoa01c577f2c2018-08-31 09:22:23 +0100119{
120 if (model.get() == nullptr)
121 {
122 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100123 fmt::format("{} was called with invalid (null) model. "
124 "Possible reason is that the model is not yet loaded and Unpack(ed). "
125 "subgraph:{} at {}",
126 location.m_Function,
127 subgraphIndex,
128 location.FileLine()));
telsoa01c577f2c2018-08-31 09:22:23 +0100129 }
130 else if (subgraphIndex >= model->subgraphs.size())
131 {
132 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100133 fmt::format("{} was called with an invalid subgraph index. "
134 "subgraph:{} at {}",
135 location.m_Function,
136 subgraphIndex,
137 location.FileLine()));
telsoa01c577f2c2018-08-31 09:22:23 +0100138 }
139}
140
141#define CHECK_SUBGRAPH(MODEL, SUBGRAPH_INDEX) \
142 CheckSubgraph(MODEL, SUBGRAPH_INDEX, CHECK_LOCATION())
143
Mike Kelly0d77ae12022-01-07 17:42:27 +0000144void CheckModel(const TfLiteParserImpl::ModelPtr& model,
telsoa01c577f2c2018-08-31 09:22:23 +0100145 size_t subgraphIndex,
146 size_t operatorIndex,
Mike Kelly0d77ae12022-01-07 17:42:27 +0000147 const CheckLocation& location)
telsoa01c577f2c2018-08-31 09:22:23 +0100148{
149 if (model.get() == nullptr)
150 {
151 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100152 fmt::format("{} was called with invalid (null) model. "
153 "Possible reason is that the model is not yet loaded and Unpack(ed). "
154 "subgraph:{} operator:{} at {}",
155 location.m_Function,
156 subgraphIndex,
157 operatorIndex,
158 location.FileLine()));
telsoa01c577f2c2018-08-31 09:22:23 +0100159 }
160 else if (subgraphIndex >= model->subgraphs.size())
161 {
162 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100163 fmt::format("{} was called with an invalid subgraph index. "
164 "subgraph:{} operator:{} at {}",
165 location.m_Function,
166 subgraphIndex,
167 operatorIndex,
168 location.FileLine()));
telsoa01c577f2c2018-08-31 09:22:23 +0100169 }
170 else if (operatorIndex >= model->subgraphs[subgraphIndex]->operators.size() &&
171 operatorIndex != VIRTUAL_OPERATOR_ID)
172 {
173 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100174 fmt::format("{} was called with an invalid operator index. "
175 "subgraph:{} operator:{} at {}",
176 location.m_Function,
177 subgraphIndex,
178 operatorIndex,
179 location.FileLine()));
telsoa01c577f2c2018-08-31 09:22:23 +0100180 }
181}
182
183#define CHECK_MODEL(MODEL, SUBGRAPH_INDEX, OPERATOR_INDEX) \
184 CheckModel(MODEL, SUBGRAPH_INDEX, OPERATOR_INDEX, CHECK_LOCATION())
185
Mike Kelly0d77ae12022-01-07 17:42:27 +0000186void CheckTensor(const TfLiteParserImpl::ModelPtr& model,
telsoa01c577f2c2018-08-31 09:22:23 +0100187 size_t subgraphIndex,
188 size_t tensorIndex,
Mike Kelly0d77ae12022-01-07 17:42:27 +0000189 const CheckLocation& location)
telsoa01c577f2c2018-08-31 09:22:23 +0100190{
191 // not checking model, because I assume CHECK_MODEL already run
192 // and checked that. An assert would do.
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100193 ARMNN_ASSERT_MSG(model.get() != nullptr, "Expecting a valid model in this function");
telsoa01c577f2c2018-08-31 09:22:23 +0100194
195 // also subgraph index should be checked by CHECK_MODEL so
196 // I only add an assert here
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100197 ARMNN_ASSERT_MSG(subgraphIndex < model->subgraphs.size(), "Expecting a valid subgraph index");
telsoa01c577f2c2018-08-31 09:22:23 +0100198
199 // the tensor index is the only one to check here
200 if (tensorIndex >= model->subgraphs[subgraphIndex]->tensors.size())
201 {
202 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100203 fmt::format("{} was called with an invalid tensor index. "
204 "subgraph:{} tensor:{} at {}",
205 location.m_Function,
206 subgraphIndex,
207 tensorIndex,
208 location.FileLine()));
telsoa01c577f2c2018-08-31 09:22:23 +0100209 }
210}
211
212#define CHECK_TENSOR(MODEL, SUBGRAPH_INDEX, TENSOR_INDEX) \
213 CheckTensor(MODEL, SUBGRAPH_INDEX, TENSOR_INDEX, CHECK_LOCATION())
214
Kevin May7d96b162021-02-03 17:38:41 +0000215void CheckTensorPtr(TfLiteParserImpl::TensorRawPtr rawPtr,
Mike Kelly0d77ae12022-01-07 17:42:27 +0000216 const CheckLocation& location)
telsoa01c577f2c2018-08-31 09:22:23 +0100217{
218 if (rawPtr == nullptr)
219 {
220 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100221 fmt::format("{} was called with a null tensor pointer at {}", location.m_Function, location.FileLine()));
telsoa01c577f2c2018-08-31 09:22:23 +0100222 }
223}
224
225#define CHECK_TENSOR_PTR(TENSOR_PTR) \
226 CheckTensorPtr(TENSOR_PTR, CHECK_LOCATION())
227
Mike Kelly0d77ae12022-01-07 17:42:27 +0000228void CheckBuffer(const TfLiteParserImpl::ModelPtr& model,
telsoa01c577f2c2018-08-31 09:22:23 +0100229 size_t bufferIndex,
Mike Kelly0d77ae12022-01-07 17:42:27 +0000230 const CheckLocation& location)
telsoa01c577f2c2018-08-31 09:22:23 +0100231{
232 if (model.get() == nullptr)
233 {
234 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100235 fmt::format("{} was called with invalid (null) model. "
236 "Possible reason is that the model is not yet loaded and Unpack(ed). "
237 "buffer:{} at {}",
238 location.m_Function,
239 bufferIndex,
240 location.FileLine()));
telsoa01c577f2c2018-08-31 09:22:23 +0100241 }
242 else if (bufferIndex >= model->buffers.size())
243 {
244 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100245 fmt::format("{} was called with an invalid buffer index. "
246 "buffer index:{} at {}",
247 location.m_Function,
248 bufferIndex,
249 location.FileLine()));
telsoa01c577f2c2018-08-31 09:22:23 +0100250 }
251 else if (model->buffers[bufferIndex].get() == nullptr)
252 {
253 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100254 fmt::format("The buffer #{} is null. {}",
255 bufferIndex,
256 location.AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +0100257 }
258}
259
260#define CHECK_BUFFER(MODEL, BUFFER_INDEX) \
261 CheckBuffer(MODEL, BUFFER_INDEX, CHECK_LOCATION())
262
Kevin May7d96b162021-02-03 17:38:41 +0000263void CheckBufferSize(TfLiteParserImpl::BufferRawPtr bufferPtr,
Mike Kelly0d77ae12022-01-07 17:42:27 +0000264 const armnn::TensorInfo& tensorInfo,
telsoa01c577f2c2018-08-31 09:22:23 +0100265 uint32_t bufferId,
Mike Kelly0d77ae12022-01-07 17:42:27 +0000266 const CheckLocation& location)
telsoa01c577f2c2018-08-31 09:22:23 +0100267{
268 if (bufferPtr == nullptr)
269 {
270 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100271 fmt::format("BufferPtr is null for buffer:{}. {}",
272 bufferId,
273 location.AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +0100274 }
275 else if(tensorInfo.GetNumElements() > bufferPtr->data.size() ||
276 tensorInfo.GetNumBytes() > bufferPtr->data.size())
277 {
278 std::stringstream ss;
279 ss << "Buffer #" << bufferId << " has " << bufferPtr->data.size() << " bytes. "
280 << "For tensor: " << tensorInfo.GetShape()
281 << " expecting: " << tensorInfo.GetNumBytes() << " bytes and "
282 << tensorInfo.GetNumElements() << " elements. " << location.AsString();
283 throw ParseException(ss.str());
284 }
285}
286
Mike Kelly0d77ae12022-01-07 17:42:27 +0000287
288tflite::BuiltinOperator GetOpCode(const TfLiteParserImpl::ModelPtr& model, size_t subgraphIndex, size_t operatorIndex)
289{
290 const auto& operatorPtr = model->subgraphs[subgraphIndex]->operators[operatorIndex];
291 auto opcodeIndex = operatorPtr->opcode_index;
292
293// work around the introduction of the deprecated_builtin_code introduced in 2.4 in a backwards compatible manner
294#if defined(ARMNN_POST_TFLITE_2_3)
295 auto opcode = std::max(model->operator_codes[opcodeIndex]->builtin_code,
296 static_cast<tflite::BuiltinOperator>(model->operator_codes[opcodeIndex]->deprecated_builtin_code));
297#else
298 auto opcode = model->operator_codes[opcodeIndex]->builtin_code;
299#endif
300 return opcode;
301}
302
303std::vector<unsigned int> GetUIntBuffer(armnn::TensorInfo info,
304 const TfLiteParserImpl::ModelPtr& model,
305 size_t bufferIndex)
306{
307 TfLiteParserImpl::BufferRawPtr bufferPtr = TfLiteParserImpl::GetBuffer(model, bufferIndex);
308 std::vector<unsigned int> buffer(info.GetNumElements());
309
310 if (info.GetDataType() == DataType::Signed32)
311 {
312 ::memcpy(buffer.data(), bufferPtr->data.data(), bufferPtr->data.size());
313 }
314 else if (info.GetDataType() == DataType::Signed64)
315 {
316 std::vector<uint64_t> uint64Buffer(info.GetNumElements());
317 ::memcpy(uint64Buffer.data(), bufferPtr->data.data(), bufferPtr->data.size());
318 buffer.assign(std::begin(uint64Buffer), std::end(uint64Buffer));
319 }
Mike Kelly0506ef02023-01-03 16:29:44 +0000320 else
321 {
322 CheckLocation location = CHECK_LOCATION();
323 throw ParseException(
324 fmt::format("Unsupported data type for uint buffer {}, only Signed 32 or Signed 64 are supported. {}",
325 GetDataTypeName(info.GetDataType()),
326 location.AsString()));
327 }
Mike Kelly0d77ae12022-01-07 17:42:27 +0000328 return buffer;
329}
330
telsoa01c577f2c2018-08-31 09:22:23 +0100331#define CHECK_BUFFER_SIZE(BUFFER_PTR, TENSOR_INFO, BUFFER_ID) \
332 CheckBufferSize(BUFFER_PTR, TENSOR_INFO, BUFFER_ID, CHECK_LOCATION())
333
334bool IsActivationSupported(tflite::ActivationFunctionType activationType)
335{
336 switch(activationType)
337 {
338 case tflite::ActivationFunctionType_NONE:
339 case tflite::ActivationFunctionType_RELU:
340 case tflite::ActivationFunctionType_RELU6:
341 case tflite::ActivationFunctionType_TANH:
342 {
343 return true;
344 }
345 default:
346 {
347 return false;
348 }
349 }
350}
351
352#define CHECK_SUPPORTED_FUSED_ACTIVATION(OPTION, SUBGRAPH_INDEX, OPERATOR_INDEX) \
353 do { \
354 if (IsActivationSupported(OPTION->fused_activation_function) == false) \
355 { \
356 throw ParseException( \
Mike Kelly377fb212023-01-10 15:55:28 +0000357 fmt::format("TfLite parser doesn't support fused activation: " \
James Ward58dec6b2020-09-11 17:32:44 +0100358 "{}/{} in {} subgraph:{} operator:{} at {}", \
359 OPTION->fused_activation_function, \
360 tflite::EnumNameActivationFunctionType(\
361 OPTION->fused_activation_function), \
362 __func__, \
363 SUBGRAPH_INDEX, \
364 OPERATOR_INDEX, \
365 CHECK_LOCATION().FileLine())); \
telsoa01c577f2c2018-08-31 09:22:23 +0100366 } \
367 } while(false)
368
369
Mike Kelly0d77ae12022-01-07 17:42:27 +0000370std::vector<unsigned int> AsUnsignedVector(const std::vector<int32_t>& in)
telsoa01c577f2c2018-08-31 09:22:23 +0100371{
372 std::vector<unsigned int> result;
373 result.reserve(in.size());
Mike Kelly0d77ae12022-01-07 17:42:27 +0000374 for (auto& i : in)
telsoa01c577f2c2018-08-31 09:22:23 +0100375 {
mathad01c21025d2021-04-26 10:09:37 +0100376 // If the location of the input data is -1 then the input should be ignored.
377 if (i == -1)
378 {
379 continue;
380 }
telsoa01c577f2c2018-08-31 09:22:23 +0100381 result.push_back(CHECKED_NON_NEGATIVE(i));
382 }
383 return result;
384}
385
Mike Kelly5880b912022-01-28 16:18:54 +0000386bool IsOptionalOperandPresent(int input)
387{
388 return (input >= 0);
389}
390
telsoa01c577f2c2018-08-31 09:22:23 +0100391void CalcPadding(uint32_t inputSize,
392 uint32_t filterSize,
393 uint32_t stride,
Pablo Tellof0bd6832019-04-26 17:58:13 +0100394 uint32_t dilation,
telsoa01c577f2c2018-08-31 09:22:23 +0100395 uint32_t& paddingFront,
396 uint32_t& paddingBack,
397 tflite::Padding padding)
398{
399 paddingFront = 0;
400 paddingBack = 0;
401 if (padding == tflite::Padding_SAME)
402 {
403 uint32_t outputSize = (inputSize + stride - 1) / stride;
Pablo Tellof0bd6832019-04-26 17:58:13 +0100404 uint32_t dilatedSize = filterSize + (dilation - 1) * (filterSize - 1);
405 uint32_t temp = (outputSize - 1) * stride + dilatedSize;
telsoa01c577f2c2018-08-31 09:22:23 +0100406 if (temp > inputSize)
407 {
408 paddingFront = (temp - inputSize) / 2;
409 paddingBack = (temp - inputSize) - paddingFront;
410 }
411 }
412}
413
Teresa Charlin024ef0b2023-04-26 11:19:03 +0100414// Function that calculates explicit padding when the output shape is known.
415// At the moment the output is only given as an input parameter in Transpose Convolution,
416// not in Convolution and Depthwise Convolution
417void CalcPadding(uint32_t inputSize,
418 uint32_t filterSize,
419 uint32_t stride,
420 uint32_t dilation,
421 uint32_t& paddingFront,
422 uint32_t& paddingBack,
423 tflite::Padding padding,
424 uint32_t outputSize)
425{
426 IgnoreUnused(dilation);
427 paddingFront = 0;
428 paddingBack = 0;
429 if (padding == tflite::Padding_SAME)
430 {
431 uint32_t totalPadding = (inputSize - 1) * stride + filterSize - outputSize;
432 paddingFront = totalPadding / 2;
433 paddingBack = totalPadding - paddingFront;
434 }
435}
436
Kevin May7d96b162021-02-03 17:38:41 +0000437armnn::TensorInfo ToTensorInfo(TfLiteParserImpl::TensorRawPtr tensorPtr,
Finn Williamsb49ed182021-06-29 15:50:08 +0100438 const std::vector<unsigned int>& shape,
Sadik Armagand109a4d2020-07-28 10:42:13 +0100439 const bool outputTensor = false)
telsoa01c577f2c2018-08-31 09:22:23 +0100440{
441 armnn::DataType type;
442 CHECK_TENSOR_PTR(tensorPtr);
443
444 switch (tensorPtr->type)
445 {
446 case tflite::TensorType_UINT8:
Derek Lambertif90c56d2020-01-10 17:14:08 +0000447 type = armnn::DataType::QAsymmU8;
telsoa01c577f2c2018-08-31 09:22:23 +0100448 break;
449 case tflite::TensorType_FLOAT32:
450 type = armnn::DataType::Float32;
451 break;
Keith Davisb4dd5cc2022-04-07 11:32:00 +0100452 case tflite::TensorType_FLOAT16:
453 type = armnn::DataType::Float16;
454 break;
Finn Williamsed66d142019-12-06 09:55:55 +0000455 case tflite::TensorType_INT8:
Keith Davis67e6c542020-02-19 10:08:33 +0000456 if (tensorPtr->quantization->zero_point.size() == 1)
Ryan OShea03181ff2020-02-07 17:22:22 +0000457 {
Keith Davis0c2eeac2020-02-11 16:51:50 +0000458 // Per-tensor
Ryan OShea03181ff2020-02-07 17:22:22 +0000459 type = armnn::DataType::QAsymmS8;
460 }
461 else
462 {
Keith Davis0c2eeac2020-02-11 16:51:50 +0000463 // Per-channel
Ryan OShea03181ff2020-02-07 17:22:22 +0000464 type = armnn::DataType::QSymmS8;
465 }
Finn Williamsed66d142019-12-06 09:55:55 +0000466 break;
467 case tflite::TensorType_INT16:
Derek Lambertif90c56d2020-01-10 17:14:08 +0000468 type = armnn::DataType::QSymmS16;
Finn Williamsed66d142019-12-06 09:55:55 +0000469 break;
telsoa01c577f2c2018-08-31 09:22:23 +0100470 case tflite::TensorType_INT32:
471 type = armnn::DataType::Signed32;
472 break;
Inki Daed4619e22020-09-10 15:33:54 +0900473 case tflite::TensorType_INT64:
474 type = armnn::DataType::Signed64;
475 break;
Matthew Sloyaned7fce42021-04-15 20:46:24 +0100476 case tflite::TensorType_BOOL:
477 type = armnn::DataType::Boolean;
478 break;
telsoa01c577f2c2018-08-31 09:22:23 +0100479 default:
480 {
481 CheckLocation location = CHECK_LOCATION();
482 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100483 fmt::format("Unsupported data type {} = {} for tensor: {}. {}",
484 tensorPtr->type,
485 tflite::EnumNameTensorType(tensorPtr->type),
486 tensorPtr->name,
487 location.AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +0100488 }
489 }
Finn Williamsb49ed182021-06-29 15:50:08 +0100490 TensorShape tensorShape;
491
492 std::vector<unsigned int> safeShape = shape;
493 if (shape.size() == 0)
Narumol Prangnawarat4818d462019-04-17 11:22:38 +0100494 {
495 safeShape.push_back(1);
Finn Williamsb49ed182021-06-29 15:50:08 +0100496 }
497
498 if (!outputTensor)
499 {
500 tensorShape = TensorShape(armnn::numeric_cast<unsigned int>(safeShape.size()), safeShape.data());
501 }
502 else
503 {
Rob Hughesd812a312021-08-06 13:10:53 +0100504 size_t shapeSignatureSize = tensorPtr->shape_signature.size();
Finn Williamsb49ed182021-06-29 15:50:08 +0100505
506 // If a shape signature exists we will use that to infer dynamic tensors
507 if (shapeSignatureSize != 0)
Sadik Armagand109a4d2020-07-28 10:42:13 +0100508 {
Finn Williamsb49ed182021-06-29 15:50:08 +0100509 // If the shape is incompatible with the shape signature override the shape
510 if (shapeSignatureSize != shape.size())
511 {
512 safeShape = {};
513
514 for (unsigned int i = 0; i < shapeSignatureSize; ++i)
515 {
516 unsigned int dim = tensorPtr->shape_signature[i] > -1 ?
517 static_cast<unsigned int>(tensorPtr->shape_signature[i]) : 0;
518 safeShape.push_back(dim);
519 }
520 }
521
Rob Hughesd812a312021-08-06 13:10:53 +0100522 std::unique_ptr<bool[]> dimMask = std::make_unique<bool[]>(tensorPtr->shape_signature.size());
Mike Kelly04d82292023-01-19 18:29:40 +0000523 bool batchOnly = true;
Finn Williamsb49ed182021-06-29 15:50:08 +0100524 for (unsigned int i = 0; i < tensorPtr->shape_signature.size(); ++i)
525 {
Mike Kelly04d82292023-01-19 18:29:40 +0000526 dimMask[i] = tensorPtr->shape_signature[i] != -1;
527
528 if (i > 0 && !dimMask[i])
529 {
530 batchOnly = false;
531 }
532 }
533 if (batchOnly)
534 {
535 dimMask[0] = true;
Finn Williamsb49ed182021-06-29 15:50:08 +0100536 }
Rob Hughesd812a312021-08-06 13:10:53 +0100537 tensorShape = TensorShape(static_cast<unsigned int>(safeShape.size()), safeShape.data(), dimMask.get());
Finn Williamsb49ed182021-06-29 15:50:08 +0100538 }
539 // If there is no shape signature treat the tensor as dynamic if the shape has a size of zero
540 else if (shape.size() == 0)
541 {
542 tensorShape = TensorShape(1, false);
543 }
544 else
545 {
546 tensorShape = TensorShape(armnn::numeric_cast<unsigned int>(shape.size()), shape.data());
Sadik Armagand109a4d2020-07-28 10:42:13 +0100547 }
Narumol Prangnawarat4818d462019-04-17 11:22:38 +0100548 }
549
Teresa Charlinacb3ec52023-04-03 19:57:00 +0100550 float quantizationScale = 1.0f;
Keith Davisd305e1a2020-01-22 11:57:54 +0000551 int32_t quantizationOffset = 0;
552
553 if (tensorPtr->quantization.get())
554 {
555 if (tensorPtr->quantization->scale.size() <= 1)
556 {
557 CHECK_VALID_SIZE(tensorPtr->quantization->zero_point.size(), 0, 1);
558 CHECK_VALID_SIZE(tensorPtr->quantization->zero_point.size(), 0, 1);
559
560 if (tensorPtr->quantization->scale.size() == 1)
561 {
562 quantizationScale = tensorPtr->quantization->scale[0];
563 }
564 if (tensorPtr->quantization->zero_point.size() == 1)
565 {
566 // NOTE: we lose precision here when converting from 64 bit to 32
Ryan OShea03181ff2020-02-07 17:22:22 +0000567 // but this is what we support at the moment in ArmNN
Matthew Sloyan589e3e82020-09-11 16:17:48 +0100568 quantizationOffset = armnn::numeric_cast<int32_t>(tensorPtr->quantization->zero_point[0]);
Keith Davisd305e1a2020-01-22 11:57:54 +0000569 }
570
Sadik Armagand109a4d2020-07-28 10:42:13 +0100571 armnn::TensorInfo result(tensorShape,
572 type,
573 quantizationScale,
574 quantizationOffset);
Keith Davisd305e1a2020-01-22 11:57:54 +0000575 return result;
576 }
577 else
578 {
579 std::vector<float> quantizationScales;
580 std::vector<int32_t> quantizationOffsets;
581
582 // Scale
583 std::copy(tensorPtr->quantization->scale.begin(),
584 tensorPtr->quantization->scale.end(),
585 std::back_inserter(quantizationScales));
586
Keith Davis0c2eeac2020-02-11 16:51:50 +0000587 // QSymmS8 Per-axis
Sadik Armagand109a4d2020-07-28 10:42:13 +0100588 armnn::TensorInfo result(tensorShape,
589 type,
590 quantizationScales,
Jan Eilers7612bd62021-04-06 17:29:03 +0100591 armnn::numeric_cast<unsigned int>(tensorPtr->quantization->quantized_dimension));
Keith Davisd305e1a2020-01-22 11:57:54 +0000592 return result;
593 }
594 }
595 else
596 {
Sadik Armagand109a4d2020-07-28 10:42:13 +0100597 armnn::TensorInfo result(tensorShape,
Keith Davisd305e1a2020-01-22 11:57:54 +0000598 type,
599 quantizationScale,
600 quantizationOffset);
601 return result;
602 }
telsoa01c577f2c2018-08-31 09:22:23 +0100603}
604
Kevin May7d96b162021-02-03 17:38:41 +0000605armnn::TensorInfo ToTensorInfo(TfLiteParserImpl::TensorRawPtr tensorPtr,
Mike Kelly377fb212023-01-10 15:55:28 +0000606 const bool outputTensor = false)
Sadik Armagand109a4d2020-07-28 10:42:13 +0100607{
Mike Kelly0d77ae12022-01-07 17:42:27 +0000608 auto const& dimensions = AsUnsignedVector(tensorPtr->shape);
Jan Eilers7612bd62021-04-06 17:29:03 +0100609 return ToTensorInfo(tensorPtr, dimensions, outputTensor);
Sadik Armagand109a4d2020-07-28 10:42:13 +0100610}
611
telsoa01c577f2c2018-08-31 09:22:23 +0100612template<typename T>
613std::pair<armnn::ConstTensor, std::unique_ptr<T[]>>
Kevin May7d96b162021-02-03 17:38:41 +0000614CreateConstTensorImpl(TfLiteParserImpl::BufferRawPtr bufferPtr,
615 TfLiteParserImpl::TensorRawPtr tensorPtr,
Matteo Martincigh747ef822018-12-18 09:26:39 +0000616 armnn::TensorInfo& tensorInfo,
617 armnn::Optional<armnn::PermutationVector&> permutationVector)
telsoa01c577f2c2018-08-31 09:22:23 +0100618{
Jan Eilers8eb25602020-03-09 12:13:48 +0000619 IgnoreUnused(tensorPtr);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100620 ARMNN_ASSERT_MSG(tensorPtr != nullptr, "tensorPtr is null");
621 ARMNN_ASSERT_MSG(bufferPtr != nullptr,
James Ward58dec6b2020-09-11 17:32:44 +0100622 fmt::format("Buffer for buffer:{} is null", tensorPtr->buffer).c_str());
telsoa01c577f2c2018-08-31 09:22:23 +0100623
624 std::unique_ptr<T[]> data(new T[tensorInfo.GetNumElements()]);
Matteo Martincigh747ef822018-12-18 09:26:39 +0000625
626 if (permutationVector.has_value() && permutationVector.value().GetSize() > 0)
627 {
628 tensorInfo = armnnUtils::Permuted(tensorInfo, permutationVector.value());
Matteo Martincighd5b9e642019-01-04 18:01:21 +0000629 armnnUtils::Permute(tensorInfo.GetShape(), permutationVector.value(),
630 reinterpret_cast<const T*>(bufferPtr->data.data()), data.get(), sizeof(T));
Matteo Martincigh747ef822018-12-18 09:26:39 +0000631 }
632 else
633 {
634 ::memcpy(data.get(), bufferPtr->data.data(), tensorInfo.GetNumBytes());
635 }
636
Matthew Sloyan81beae32021-07-13 19:46:11 +0100637 // Make sure isConstant flag is set.
638 tensorInfo.SetConstant();
639
telsoa01c577f2c2018-08-31 09:22:23 +0100640 return std::make_pair(ConstTensor(tensorInfo, data.get()), std::move(data));
641}
642
telsoa01c577f2c2018-08-31 09:22:23 +0100643armnn::LayerBindingId GenerateLayerBindingId(size_t subgraphIndex, size_t tensorIndex)
644{
645 // generate the binding id by shifting the tensor id by 8 bit
646 // and add the subgraph id, which allows 256 subgraphs
647 return static_cast<armnn::LayerBindingId>((tensorIndex<<8)+subgraphIndex);
648}
649
Aron Virginas-Tar70672f62019-01-23 14:00:00 +0000650bool CheckShape(const armnn::TensorShape& actual, const std::vector<int32_t>& expected)
651{
652 const unsigned int actualSize = actual.GetNumDimensions();
653 if (actualSize != expected.size())
654 {
655 return false;
656 }
657
658 for (unsigned int i = 0u; i < actualSize; i++)
659 {
660 if (expected[i] < 0 ||
661 actual[i] != static_cast<unsigned int>(expected[i]))
662 {
663 return false;
664 }
665 }
666
667 return true;
668}
669
Cathal Corbett2b922e22022-09-23 15:49:24 +0100670bool CheckShape(const armnn::TensorShape& actual, const armnn::TensorShape& expected)
671{
672 std::vector<int32_t> expectedVec;
673 for (uint32_t i = 0; i < expected.GetNumDimensions(); i++)
674 {
675 expectedVec.push_back(expected[i]);
676 }
677 return CheckShape(actual, expectedVec);
678}
679
James Conroy05102392020-06-24 15:39:55 +0100680void CheckMatchingQuantization(const TensorInfo& first,
681 const TensorInfo& second,
682 const std::string& descName,
683 std::string const& firstName,
684 std::string const& secondName)
685{
686 if (!first.IsQuantized() ||
687 !second.IsQuantized())
688 {
689 // Not a quantized type, ignore the validation
690 return;
691 }
692
693 DataType firstDataType = first.GetDataType();
694 DataType secondDataType = second.GetDataType();
695
696 if (firstDataType != secondDataType)
697 {
698 throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
699 " must be of the same quantized type, " +
700 firstName + " is " + GetDataTypeName(firstDataType) + ", " +
701 secondName + " is " + GetDataTypeName(secondDataType));
702 }
703
704 if (!first.IsTypeSpaceMatch(second))
705 {
706 throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
707 " must have the same quantization space, " +
708 firstName + " has offset " + std::to_string(first.GetQuantizationOffset()) +
709 " and scale " + std::to_string(first.GetQuantizationScale()) + ", " +
710 secondName + " has offset " + std::to_string(second.GetQuantizationOffset()) +
711 " and scale " + std::to_string(second.GetQuantizationScale()));
712 }
713}
714
Mike Kelly377fb212023-01-10 15:55:28 +0000715bool IsDynamic(TfLiteParserImpl::TensorRawPtr tensorPtr)
716{
717 auto shape = tensorPtr->shape;
718
719 if (shape.empty())
720 {
721 return true;
722 }
723 auto shapeSig = tensorPtr->shape_signature;
724
725 if (shapeSig.empty())
726 {
727 return false;
728 }
729
730 for (unsigned int i = 0; i < shapeSig.size() ; ++i)
731 {
732 if (shapeSig[i] == -1)
733 {
734 return true;
735 }
736 }
737 return false;
738}
739
telsoa01c577f2c2018-08-31 09:22:23 +0100740} // <anonymous>
741
Kevin May7d96b162021-02-03 17:38:41 +0000742TfLiteParserImpl::TfLiteParserImpl(const Optional<ITfLiteParser::TfLiteParserOptions>& options)
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100743: m_Options(options)
744, m_Network(nullptr, nullptr)
Kevin May7d96b162021-02-03 17:38:41 +0000745, m_ParserFunctions(tflite::BuiltinOperator_MAX+1, &TfLiteParserImpl::ParseUnsupportedOperator)
telsoa01c577f2c2018-08-31 09:22:23 +0100746{
747 // register supported operators
Matthew Sloyaned7fce42021-04-15 20:46:24 +0100748 m_ParserFunctions[tflite::BuiltinOperator_ABS] = &TfLiteParserImpl::ParseAbs;
Kevin May7d96b162021-02-03 17:38:41 +0000749 m_ParserFunctions[tflite::BuiltinOperator_ADD] = &TfLiteParserImpl::ParseAdd;
Matthew Sloyan28f177c2021-04-09 14:38:52 +0100750 m_ParserFunctions[tflite::BuiltinOperator_ARG_MIN] = &TfLiteParserImpl::ParseArgMin;
751 m_ParserFunctions[tflite::BuiltinOperator_ARG_MAX] = &TfLiteParserImpl::ParseArgMax;
Kevin May7d96b162021-02-03 17:38:41 +0000752 m_ParserFunctions[tflite::BuiltinOperator_AVERAGE_POOL_2D] = &TfLiteParserImpl::ParseAveragePool2D;
753 m_ParserFunctions[tflite::BuiltinOperator_BATCH_TO_SPACE_ND] = &TfLiteParserImpl::ParseBatchToSpaceND;
Samuel Yapfd3ba5a2022-08-24 17:04:34 +0100754 m_ParserFunctions[tflite::BuiltinOperator_BATCH_MATMUL] = &TfLiteParserImpl::ParseBatchMatMul;
Teresa Charlin93f0ad02023-03-23 15:28:02 +0000755 m_ParserFunctions[tflite::BuiltinOperator_CEIL] = &TfLiteParserImpl::ParseCeil;
mathad01b392e982021-04-07 12:07:30 +0100756 m_ParserFunctions[tflite::BuiltinOperator_CAST] = &TfLiteParserImpl::ParseCast;
Kevin May7d96b162021-02-03 17:38:41 +0000757 m_ParserFunctions[tflite::BuiltinOperator_CONCATENATION] = &TfLiteParserImpl::ParseConcatenation;
758 m_ParserFunctions[tflite::BuiltinOperator_CONV_2D] = &TfLiteParserImpl::ParseConv2D;
Matthew Sloyan4d217c02021-10-07 11:48:58 +0100759 // Conv3D support was added in TF 2.5, so for backwards compatibility a hash define is needed.
Cathal Corbett80b4ef02022-05-25 11:21:11 +0100760 #if defined(ARMNN_POST_TFLITE_2_4)
Matthew Sloyaneb5f8102021-10-05 17:31:42 +0100761 m_ParserFunctions[tflite::BuiltinOperator_CONV_3D] = &TfLiteParserImpl::ParseConv3D;
Matthew Sloyan4d217c02021-10-07 11:48:58 +0100762 #endif
Kevin May7d96b162021-02-03 17:38:41 +0000763 m_ParserFunctions[tflite::BuiltinOperator_CUSTOM] = &TfLiteParserImpl::ParseCustomOperator;
764 m_ParserFunctions[tflite::BuiltinOperator_DEPTH_TO_SPACE] = &TfLiteParserImpl::ParseDepthToSpace;
765 m_ParserFunctions[tflite::BuiltinOperator_DEPTHWISE_CONV_2D] = &TfLiteParserImpl::ParseDepthwiseConv2D;
766 m_ParserFunctions[tflite::BuiltinOperator_DEQUANTIZE] = &TfLiteParserImpl::ParseDequantize;
Matthew Sloyan28f177c2021-04-09 14:38:52 +0100767 m_ParserFunctions[tflite::BuiltinOperator_DIV] = &TfLiteParserImpl::ParseDiv;
Kevin May7d96b162021-02-03 17:38:41 +0000768 m_ParserFunctions[tflite::BuiltinOperator_ELU] = &TfLiteParserImpl::ParseElu;
Bruno Goncalves2d0eb862021-07-11 14:10:15 -0300769 m_ParserFunctions[tflite::BuiltinOperator_EQUAL] = &TfLiteParserImpl::ParseEqual;
Kevin May7d96b162021-02-03 17:38:41 +0000770 m_ParserFunctions[tflite::BuiltinOperator_EXP] = &TfLiteParserImpl::ParseExp;
Teresa Charlin3ab85482021-06-08 16:59:29 +0100771 m_ParserFunctions[tflite::BuiltinOperator_EXPAND_DIMS] = &TfLiteParserImpl::ParseExpandDims;
Teresa Charlincdbd40b2022-02-25 13:21:55 +0000772 m_ParserFunctions[tflite::BuiltinOperator_FLOOR_DIV] = &TfLiteParserImpl::ParseFloorDiv;
Kevin May7d96b162021-02-03 17:38:41 +0000773 m_ParserFunctions[tflite::BuiltinOperator_FULLY_CONNECTED] = &TfLiteParserImpl::ParseFullyConnected;
774 m_ParserFunctions[tflite::BuiltinOperator_GATHER] = &TfLiteParserImpl::ParseGather;
Teresa Charlin91a53ea2022-04-25 15:47:29 +0100775 m_ParserFunctions[tflite::BuiltinOperator_GATHER_ND] = &TfLiteParserImpl::ParseGatherNd;
Bruno Goncalves2d0eb862021-07-11 14:10:15 -0300776 m_ParserFunctions[tflite::BuiltinOperator_GREATER] = &TfLiteParserImpl::ParseGreater;
777 m_ParserFunctions[tflite::BuiltinOperator_GREATER_EQUAL] = &TfLiteParserImpl::ParseGreaterOrEqual;
Kevin May7d96b162021-02-03 17:38:41 +0000778 m_ParserFunctions[tflite::BuiltinOperator_HARD_SWISH] = &TfLiteParserImpl::ParseHardSwish;
779 m_ParserFunctions[tflite::BuiltinOperator_LEAKY_RELU] = &TfLiteParserImpl::ParseLeakyRelu;
Bruno Goncalves2d0eb862021-07-11 14:10:15 -0300780 m_ParserFunctions[tflite::BuiltinOperator_LESS] = &TfLiteParserImpl::ParseLess;
781 m_ParserFunctions[tflite::BuiltinOperator_LESS_EQUAL] = &TfLiteParserImpl::ParseLessOrEqual;
Mike Kelly31dce2b2021-09-01 21:22:37 +0100782 m_ParserFunctions[tflite::BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION]
783 = &TfLiteParserImpl::ParseLocalResponseNormalization;
Teresa Charlin28aa6692022-07-12 11:18:44 +0100784 m_ParserFunctions[tflite::BuiltinOperator_LOG] = &TfLiteParserImpl::ParseLog;
Matthew Sloyaned7fce42021-04-15 20:46:24 +0100785 m_ParserFunctions[tflite::BuiltinOperator_LOGICAL_NOT] = &TfLiteParserImpl::ParseLogicalNot;
Kevin May7d96b162021-02-03 17:38:41 +0000786 m_ParserFunctions[tflite::BuiltinOperator_LOGISTIC] = &TfLiteParserImpl::ParseLogistic;
Teresa Charlinfd33a692022-06-29 15:35:57 +0100787 m_ParserFunctions[tflite::BuiltinOperator_LOG_SOFTMAX] = &TfLiteParserImpl::ParseLogSoftmax;
Kevin May7d96b162021-02-03 17:38:41 +0000788 m_ParserFunctions[tflite::BuiltinOperator_L2_NORMALIZATION] = &TfLiteParserImpl::ParseL2Normalization;
789 m_ParserFunctions[tflite::BuiltinOperator_MAX_POOL_2D] = &TfLiteParserImpl::ParseMaxPool2D;
790 m_ParserFunctions[tflite::BuiltinOperator_MAXIMUM] = &TfLiteParserImpl::ParseMaximum;
791 m_ParserFunctions[tflite::BuiltinOperator_MEAN] = &TfLiteParserImpl::ParseMean;
792 m_ParserFunctions[tflite::BuiltinOperator_MINIMUM] = &TfLiteParserImpl::ParseMinimum;
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +0100793 m_ParserFunctions[tflite::BuiltinOperator_MIRROR_PAD] = &TfLiteParserImpl::ParseMirrorPad;
Kevin May7d96b162021-02-03 17:38:41 +0000794 m_ParserFunctions[tflite::BuiltinOperator_MUL] = &TfLiteParserImpl::ParseMul;
795 m_ParserFunctions[tflite::BuiltinOperator_NEG] = &TfLiteParserImpl::ParseNeg;
Bruno Goncalves2d0eb862021-07-11 14:10:15 -0300796 m_ParserFunctions[tflite::BuiltinOperator_NOT_EQUAL] = &TfLiteParserImpl::ParseNotEqual;
Kevin May7d96b162021-02-03 17:38:41 +0000797 m_ParserFunctions[tflite::BuiltinOperator_PACK] = &TfLiteParserImpl::ParsePack;
798 m_ParserFunctions[tflite::BuiltinOperator_PAD] = &TfLiteParserImpl::ParsePad;
Mike Kelly0d77ae12022-01-07 17:42:27 +0000799 m_ParserFunctions[tflite::BuiltinOperator_PADV2] = &TfLiteParserImpl::ParsePad;
John Mcloughlin0ec00872023-05-15 17:03:49 +0100800 m_ParserFunctions[tflite::BuiltinOperator_POW] = &TfLiteParserImpl::ParsePower;
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +0100801 m_ParserFunctions[tflite::BuiltinOperator_PRELU] = &TfLiteParserImpl::ParsePrelu;
Kevin May7d96b162021-02-03 17:38:41 +0000802 m_ParserFunctions[tflite::BuiltinOperator_QUANTIZE] = &TfLiteParserImpl::ParseQuantize;
803 m_ParserFunctions[tflite::BuiltinOperator_RELU] = &TfLiteParserImpl::ParseRelu;
804 m_ParserFunctions[tflite::BuiltinOperator_RELU6] = &TfLiteParserImpl::ParseRelu6;
Sadik Armagana2747482021-02-09 10:28:54 +0000805 m_ParserFunctions[tflite::BuiltinOperator_REDUCE_MAX] = &TfLiteParserImpl::ParseReduceMax;
806 m_ParserFunctions[tflite::BuiltinOperator_REDUCE_MIN] = &TfLiteParserImpl::ParseReduceMin;
Teresa Charlin4e3e8312021-08-05 12:34:37 +0100807 m_ParserFunctions[tflite::BuiltinOperator_REDUCE_PROD] = &TfLiteParserImpl::ParseReduceProd;
Kevin May7d96b162021-02-03 17:38:41 +0000808 m_ParserFunctions[tflite::BuiltinOperator_RESHAPE] = &TfLiteParserImpl::ParseReshape;
809 m_ParserFunctions[tflite::BuiltinOperator_RESIZE_BILINEAR] = &TfLiteParserImpl::ParseResizeBilinear;
810 m_ParserFunctions[tflite::BuiltinOperator_RESIZE_NEAREST_NEIGHBOR] = &TfLiteParserImpl::ParseResizeNearestNeighbor;
Tianle Chenge5a30ff2023-07-03 11:24:12 +0100811 m_ParserFunctions[tflite::BuiltinOperator_REVERSE_V2] = &TfLiteParserImpl::ParseReverseV2;
Matthew Sloyaned7fce42021-04-15 20:46:24 +0100812 m_ParserFunctions[tflite::BuiltinOperator_RSQRT] = &TfLiteParserImpl::ParseRsqrt;
Teresa Charlinf0fce5b2022-05-04 17:24:43 +0100813 m_ParserFunctions[tflite::BuiltinOperator_SQRT] = &TfLiteParserImpl::ParseSqrt;
Keith Davis0176fd82021-06-01 17:36:32 +0100814 m_ParserFunctions[tflite::BuiltinOperator_SHAPE] = &TfLiteParserImpl::ParseShape;
Teresa Charlin28aa6692022-07-12 11:18:44 +0100815 m_ParserFunctions[tflite::BuiltinOperator_SIN] = &TfLiteParserImpl::ParseSin;
Kevin May7d96b162021-02-03 17:38:41 +0000816 m_ParserFunctions[tflite::BuiltinOperator_SLICE] = &TfLiteParserImpl::ParseSlice;
817 m_ParserFunctions[tflite::BuiltinOperator_SOFTMAX] = &TfLiteParserImpl::ParseSoftmax;
818 m_ParserFunctions[tflite::BuiltinOperator_SPACE_TO_BATCH_ND] = &TfLiteParserImpl::ParseSpaceToBatchND;
Teresa Charlin2a764ad2023-02-24 18:17:31 +0000819 m_ParserFunctions[tflite::BuiltinOperator_SPACE_TO_DEPTH] = &TfLiteParserImpl::ParseSpaceToDepth;
Kevin May7d96b162021-02-03 17:38:41 +0000820 m_ParserFunctions[tflite::BuiltinOperator_SPLIT] = &TfLiteParserImpl::ParseSplit;
821 m_ParserFunctions[tflite::BuiltinOperator_SPLIT_V] = &TfLiteParserImpl::ParseSplitV;
822 m_ParserFunctions[tflite::BuiltinOperator_SQUEEZE] = &TfLiteParserImpl::ParseSqueeze;
Teresa Charlin6963b332023-07-11 11:35:41 +0100823 m_ParserFunctions[tflite::BuiltinOperator_SQUARE] = &TfLiteParserImpl::ParseSquare;
John Mcloughlin0ec00872023-05-15 17:03:49 +0100824 m_ParserFunctions[tflite::BuiltinOperator_SQUARED_DIFFERENCE] = &TfLiteParserImpl::ParseSquaredDifference;
Kevin May7d96b162021-02-03 17:38:41 +0000825 m_ParserFunctions[tflite::BuiltinOperator_STRIDED_SLICE] = &TfLiteParserImpl::ParseStridedSlice;
826 m_ParserFunctions[tflite::BuiltinOperator_SUB] = &TfLiteParserImpl::ParseSub;
827 m_ParserFunctions[tflite::BuiltinOperator_SUM] = &TfLiteParserImpl::ParseSum;
828 m_ParserFunctions[tflite::BuiltinOperator_TANH] = &TfLiteParserImpl::ParseTanH;
829 m_ParserFunctions[tflite::BuiltinOperator_TRANSPOSE] = &TfLiteParserImpl::ParseTranspose;
830 m_ParserFunctions[tflite::BuiltinOperator_TRANSPOSE_CONV] = &TfLiteParserImpl::ParseTransposeConv;
Mike Kelly5880b912022-01-28 16:18:54 +0000831 m_ParserFunctions[tflite::BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM]
832 = &TfLiteParserImpl::ParseUnidirectionalSequenceLSTM;
Kevin May7d96b162021-02-03 17:38:41 +0000833 m_ParserFunctions[tflite::BuiltinOperator_UNPACK] = &TfLiteParserImpl::ParseUnpack;
Matthew Sloyan28f177c2021-04-09 14:38:52 +0100834
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100835 // register supported custom operators
Kevin May7d96b162021-02-03 17:38:41 +0000836 m_CustomParserFunctions["TFLite_Detection_PostProcess"] = &TfLiteParserImpl::ParseDetectionPostProcess;
telsoa01c577f2c2018-08-31 09:22:23 +0100837}
838
Mike Kelly377fb212023-01-10 15:55:28 +0000839armnn::TensorInfo TfLiteParserImpl::InputTensorInfo(size_t subgraphIndex,
840 size_t operatorIndex,
841 int input)
842{
843 const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex];
844 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
845
846 uint32_t inputId = CHECKED_NON_NEGATIVE(operatorPtr->inputs[input]);
847 auto search = armnnTfLiteParser::TfLiteParserImpl::m_TensorInfos.find(inputId);
848
849 if (search != m_TensorInfos.end())
850 {
851 return m_TensorInfos[inputId];
852 }
853 else
854 {
855 auto tensorInfo = ::armnnTfLiteParser::ToTensorInfo(subgraphPtr->tensors[inputId].get());
856 m_TensorInfos.insert({ inputId, tensorInfo });
857 return tensorInfo;
858 }
859}
860
861armnn::TensorInfo TfLiteParserImpl::OutputTensorInfoFromInputs(size_t subgraphIndex,
862 size_t operatorIndex,
863 armnn::IConnectableLayer* layer,
864 int output,
865 std::vector<int> inputs)
866{
867 const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex];
868 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
869
870 uint32_t outputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[output]);
871
872 auto outputSearch = armnnTfLiteParser::TfLiteParserImpl::m_TensorInfos.find(outputId);
873
874 if (outputSearch != m_TensorInfos.end())
875 {
876 return m_TensorInfos[outputId];
877 }
878
879 const auto& outputTensorPtr = subgraphPtr->tensors[outputId].get();
880 TensorInfo tensor = ::armnnTfLiteParser::ToTensorInfo(outputTensorPtr, true);
881
882 if (IsDynamic(outputTensorPtr))
883 {
884 if (inputs.empty())
885 {
886 for (unsigned int i = 0; i < layer->GetNumInputSlots(); ++i)
887 {
888 inputs.emplace_back(i);
889 }
890 }
891 auto inputTensorIds = GetInputTensorIds(m_Model, subgraphIndex, operatorIndex);
892 std::vector<armnn::TensorShape> inputShapes;
893
894 for (unsigned int i = 0; i < inputs.size(); ++i)
895 {
896 uint32_t inputId = CHECKED_NON_NEGATIVE(operatorPtr->inputs[inputs[i]]);
897 auto search = armnnTfLiteParser::TfLiteParserImpl::m_TensorInfos.find(inputId);
898
899 if (search != m_TensorInfos.end())
900 {
901 auto &inputTensorInfo = m_TensorInfos[inputId];
902 inputShapes.push_back(inputTensorInfo.GetShape());
903 }
904 else
905 {
Mike Kelly377fb212023-01-10 15:55:28 +0000906 auto inputTensorInfo = ::armnnTfLiteParser::ToTensorInfo(subgraphPtr->tensors[inputId].get());
907 m_TensorInfos.insert({ inputId, inputTensorInfo});
908 inputShapes.push_back(inputTensorInfo.GetShape());
909 }
910 }
911 const auto outputShape = layer->InferOutputShapes(inputShapes)[output];
912 tensor.SetShape(outputShape);
913 }
914 m_TensorInfos.insert({ outputId, tensor});
915 return tensor;
916}
917
918armnn::TensorInfo TfLiteParserImpl::OutputTensorInfoFromShapes(size_t subgraphIndex,
919 size_t operatorIndex,
920 armnn::IConnectableLayer* layer,
921 int output,
922 std::vector<armnn::TensorShape> inputShapes)
923{
924 const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex];
925 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
926
927 uint32_t outputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[output]);
928 const auto& outputTensorPtr = subgraphPtr->tensors[outputId].get();
929 TensorInfo tensor = ::armnnTfLiteParser::ToTensorInfo(outputTensorPtr, true);
930
931 if (IsDynamic(outputTensorPtr))
932 {
933 const auto outputShape = layer->InferOutputShapes(inputShapes)[output];
934 tensor.SetShape(outputShape);
935 }
936 m_TensorInfos.insert({ outputId, tensor});
937 return tensor;
938}
939
Kevin May7d96b162021-02-03 17:38:41 +0000940void TfLiteParserImpl::ResetParser()
telsoa01c577f2c2018-08-31 09:22:23 +0100941{
942 m_Network = armnn::INetworkPtr(nullptr, nullptr);
943 m_Model = nullptr;
944 m_SubgraphConnections.clear();
Mike Kelly377fb212023-01-10 15:55:28 +0000945 m_OverriddenOutputShapes.clear();
Mike Kelly5880b912022-01-28 16:18:54 +0000946 m_ConstantsToDequantize.clear();
947 m_ConstantsToBeCreated.clear();
Mike Kelly377fb212023-01-10 15:55:28 +0000948 m_TensorInfos.clear();
telsoa01c577f2c2018-08-31 09:22:23 +0100949}
950
Kevin May7d96b162021-02-03 17:38:41 +0000951INetworkPtr TfLiteParserImpl::CreateNetworkFromBinaryFile(const char* graphFile)
telsoa01c577f2c2018-08-31 09:22:23 +0100952{
953 ResetParser();
954 m_Model = LoadModelFromFile(graphFile);
955 return CreateNetworkFromModel();
956}
957
Mike Kelly0d77ae12022-01-07 17:42:27 +0000958INetworkPtr TfLiteParserImpl::CreateNetworkFromBinary(const std::vector<uint8_t>& binaryContent)
telsoa01c577f2c2018-08-31 09:22:23 +0100959{
960 ResetParser();
961 m_Model = LoadModelFromBinary(binaryContent.data(), binaryContent.size());
962 return CreateNetworkFromModel();
963}
964
Finn Williamsb49ed182021-06-29 15:50:08 +0100965
966armnn::INetworkPtr TfLiteParserImpl::LoadModel(std::unique_ptr<tflite::ModelT> model)
967{
968 ResetParser();
969 m_Model = std::move(model);
970
971 return CreateNetworkFromModel();
972}
973
Kevin May7d96b162021-02-03 17:38:41 +0000974INetworkPtr TfLiteParserImpl::CreateNetworkFromModel()
telsoa01c577f2c2018-08-31 09:22:23 +0100975{
Sadik Armagand109a4d2020-07-28 10:42:13 +0100976
977 using NetworkOptions = std::vector<BackendOptions>;
978 NetworkOptions networkOptions = {};
Mike Kelly80512b02022-05-16 23:10:42 +0100979 if (m_Options)
Sadik Armagand109a4d2020-07-28 10:42:13 +0100980 {
Mike Kelly80512b02022-05-16 23:10:42 +0100981 if (m_Options.value().m_InferAndValidate)
982 {
983 BackendOptions shapeInferenceMethodOption("ShapeInferenceMethod",
984 {
985 { "InferAndValidate", true }
986 });
Sadik Armagand109a4d2020-07-28 10:42:13 +0100987
Mike Kelly80512b02022-05-16 23:10:42 +0100988 networkOptions.push_back(shapeInferenceMethodOption);
989 }
990 if (m_Options.value().m_AllowExpandedDims)
991 {
992 BackendOptions shapeInferenceMethodOption("AllowExpandedDims",
993 {
994 { "AllowExpandedDims", true }
995 });
996
997 networkOptions.push_back(shapeInferenceMethodOption);
998 }
Sadik Armagand109a4d2020-07-28 10:42:13 +0100999 }
Sadik Armagand109a4d2020-07-28 10:42:13 +01001000 m_Network = INetwork::Create(networkOptions);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001001 ARMNN_ASSERT(m_Model.get() != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01001002
telsoa01c577f2c2018-08-31 09:22:23 +01001003 if (m_Model->subgraphs.size() != 1)
1004 {
1005 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01001006 fmt::format("Current TfLite parser only supports 1 subgraph. Current one has: {} {}",
1007 m_Model->subgraphs.size(),
1008 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01001009 }
1010
1011 size_t subgraphIndex = 0;
Colm Donelan6350d272020-06-09 16:56:25 +01001012 size_t operatorIndex = 0;
1013 try
telsoa01c577f2c2018-08-31 09:22:23 +01001014 {
Colm Donelan6350d272020-06-09 16:56:25 +01001015 for (SubgraphPtr const& subgraph : m_Model->subgraphs)
telsoa01c577f2c2018-08-31 09:22:23 +01001016 {
Mike Kelly377fb212023-01-10 15:55:28 +00001017 SetupInputLayerTensorInfos(subgraphIndex);
1018 SetupConstantLayerTensorInfos(subgraphIndex);
1019
Colm Donelan6350d272020-06-09 16:56:25 +01001020 m_SubgraphConnections.emplace_back(subgraph->tensors.size());
1021 for (OperatorPtr const& op : subgraph->operators)
telsoa01c577f2c2018-08-31 09:22:23 +01001022 {
Colm Donelan6350d272020-06-09 16:56:25 +01001023 auto const& opCodePtr = m_Model->operator_codes[op->opcode_index];
Jim Flynnfca233e2021-09-23 12:16:53 +01001024
1025// 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 +01001026#if defined(ARMNN_POST_TFLITE_2_3)
Jim Flynnfca233e2021-09-23 12:16:53 +01001027 auto builtinCode = std::max(opCodePtr->builtin_code,
1028 static_cast<tflite::BuiltinOperator>(opCodePtr->deprecated_builtin_code));
1029#else
telsoa01c577f2c2018-08-31 09:22:23 +01001030 auto builtinCode = opCodePtr->builtin_code;
Jim Flynnfca233e2021-09-23 12:16:53 +01001031#endif
telsoa01c577f2c2018-08-31 09:22:23 +01001032
1033 if (builtinCode > tflite::BuiltinOperator_MAX)
1034 {
James Ward58dec6b2020-09-11 17:32:44 +01001035 throw ParseException(fmt::format("Operator code {} is out of range 0-{}. "
1036 "subgraph:{} operator idx:{}. {}",
1037 builtinCode, tflite::BuiltinOperator_MAX, subgraphIndex,
1038 operatorIndex, CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01001039 }
1040
1041 // lookup and call the parser function
Colm Donelan6350d272020-06-09 16:56:25 +01001042 auto& parserFunction = m_ParserFunctions[builtinCode];
telsoa01c577f2c2018-08-31 09:22:23 +01001043 (this->*parserFunction)(subgraphIndex, operatorIndex);
Colm Donelan6350d272020-06-09 16:56:25 +01001044 ++operatorIndex;
telsoa01c577f2c2018-08-31 09:22:23 +01001045 }
telsoa01c577f2c2018-08-31 09:22:23 +01001046
Colm Donelan6350d272020-06-09 16:56:25 +01001047 SetupInputLayers(subgraphIndex);
1048 SetupOutputLayers(subgraphIndex);
1049 SetupConstantLayers(subgraphIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001050
Colm Donelan6350d272020-06-09 16:56:25 +01001051 ++subgraphIndex;
1052 operatorIndex = 0;
telsoa01c577f2c2018-08-31 09:22:23 +01001053 }
telsoa01c577f2c2018-08-31 09:22:23 +01001054 }
Colm Donelan6350d272020-06-09 16:56:25 +01001055 catch (const ParseException& e)
telsoa01c577f2c2018-08-31 09:22:23 +01001056 {
Colm Donelan6350d272020-06-09 16:56:25 +01001057 std::stringstream errorString;
1058 errorString << "Failed to parse operator #" << operatorIndex << " within subgraph #"
1059 << subgraphIndex << " error: " << e.what();
1060 ARMNN_LOG(error) << errorString.str();
1061 std::stringstream errors;
1062 errors << errorString.str() << "\n";
telsoa01c577f2c2018-08-31 09:22:23 +01001063 throw ParseException(errors.str());
1064 }
1065
1066 // establish the connections from the layer outputs to the inputs of the subsequent layers
Colm Donelan6350d272020-06-09 16:56:25 +01001067 for (subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001068 {
1069 for (size_t tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex)
1070 {
1071 if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot != nullptr)
1072 {
1073 for (size_t inputSlotIdx = 0;
1074 inputSlotIdx < m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size();
1075 ++inputSlotIdx)
1076 {
1077 m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot->Connect(
1078 *(m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots[inputSlotIdx]));
1079 }
1080 }
1081 }
1082 }
telsoa01c577f2c2018-08-31 09:22:23 +01001083 return std::move(m_Network);
1084}
1085
Mike Kelly0506ef02023-01-03 16:29:44 +00001086bool TfLiteParserImpl::ShouldConstantTensorBeConverted(TfLiteParserImpl::TensorRawPtr tensorPtr,
1087 armnn::DataType inputDataType,
1088 armnn::DataType tensorDataType)
Mike Kelly5880b912022-01-28 16:18:54 +00001089{
Mike Kelly0506ef02023-01-03 16:29:44 +00001090 return (TfLiteParserImpl::IsConstTensor(tensorPtr) && inputDataType == DataType::Float32 &&
1091 (tensorDataType == DataType::QAsymmU8 ||
1092 tensorDataType == DataType::QAsymmS8 ||
1093 tensorDataType == DataType::QSymmS8 ||
1094 tensorDataType == DataType::Signed32 ||
1095 tensorDataType == DataType::Signed64));
Mike Kelly5880b912022-01-28 16:18:54 +00001096}
1097
Kevin May7d96b162021-02-03 17:38:41 +00001098void TfLiteParserImpl::RegisterProducerOfTensor(size_t subgraphIndex,
1099 size_t tensorIndex,
1100 armnn::IOutputSlot* slot)
telsoa01c577f2c2018-08-31 09:22:23 +01001101{
1102 CHECK_TENSOR(m_Model, subgraphIndex, tensorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001103 ARMNN_ASSERT(m_SubgraphConnections.size() > subgraphIndex);
1104 ARMNN_ASSERT(m_SubgraphConnections[subgraphIndex].size() > tensorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001105
1106 TensorSlots & tensorSlots = m_SubgraphConnections[subgraphIndex][tensorIndex];
1107
Nikhil Rajd4d1c312022-08-03 18:20:59 +01001108 if (slot->GetOwningIConnectableLayer().GetType() != LayerType::Constant)
telsoa01c577f2c2018-08-31 09:22:23 +01001109 {
telsoa01c577f2c2018-08-31 09:22:23 +01001110
Nikhil Rajd4d1c312022-08-03 18:20:59 +01001111 // assuming there is only one producer for that tensor
1112 if (tensorSlots.outputSlot != nullptr)
1113 {
1114 throw ParseException(fmt::format("Another layer has already registered itself as the producer of "
1115 "subgraph:{} tensor:{} {}",
1116 subgraphIndex,
1117 tensorIndex,
1118 CHECK_LOCATION().AsString()));
1119 }
1120 }
telsoa01c577f2c2018-08-31 09:22:23 +01001121 tensorSlots.outputSlot = slot;
1122}
1123
Kevin May7d96b162021-02-03 17:38:41 +00001124void TfLiteParserImpl::RegisterConsumerOfTensor(size_t subgraphIndex,
1125 size_t tensorIndex,
1126 armnn::IInputSlot* slot)
telsoa01c577f2c2018-08-31 09:22:23 +01001127{
1128 CHECK_TENSOR(m_Model, subgraphIndex, tensorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001129 ARMNN_ASSERT(m_SubgraphConnections.size() > subgraphIndex);
1130 ARMNN_ASSERT(m_SubgraphConnections[subgraphIndex].size() > tensorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001131
Finn Williamsd4fa5452021-03-01 12:31:41 +00001132 TensorSlots& tensorSlots = m_SubgraphConnections[subgraphIndex][tensorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01001133 tensorSlots.inputSlots.push_back(slot);
1134}
1135
Kevin May7d96b162021-02-03 17:38:41 +00001136void TfLiteParserImpl::ParseCustomOperator(size_t subgraphIndex, size_t operatorIndex)
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001137{
1138 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1139
1140 // NOTE: By default we presume the custom operator is not supported
Kevin May7d96b162021-02-03 17:38:41 +00001141 auto customParserFunction = &TfLiteParserImpl::ParseUnsupportedOperator;
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001142
1143 // Identify custom code defined for custom operator
1144 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1145 const auto& customCode = m_Model->operator_codes[operatorPtr->opcode_index]->custom_code;
1146
Mike Kelly377fb212023-01-10 15:55:28 +00001147 // Find parser function that corresponds to custom code (if any)
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001148 auto iterator = m_CustomParserFunctions.find(customCode);
1149 if (iterator != m_CustomParserFunctions.end())
1150 {
1151 customParserFunction = iterator->second;
1152 }
1153
1154 // Run parser function
1155 (this->*customParserFunction)(subgraphIndex, operatorIndex);
1156}
1157
Kevin May7d96b162021-02-03 17:38:41 +00001158void TfLiteParserImpl::ParseUnsupportedOperator(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001159{
1160 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001161
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001162 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1163
1164 auto opcodeIndex = operatorPtr->opcode_index;
Jim Flynnfca233e2021-09-23 12:16:53 +01001165
1166// 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 +01001167#if defined(ARMNN_POST_TFLITE_2_3)
Jim Flynnfca233e2021-09-23 12:16:53 +01001168 auto opcode = std::max(m_Model->operator_codes[opcodeIndex]->builtin_code,
1169 static_cast<tflite::BuiltinOperator>(m_Model->operator_codes[opcodeIndex]->deprecated_builtin_code));
1170#else
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001171 auto opcode = m_Model->operator_codes[opcodeIndex]->builtin_code;
Jim Flynnfca233e2021-09-23 12:16:53 +01001172#endif
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001173
1174 if (!m_Options || !m_Options.value().m_StandInLayerForUnsupported)
1175 {
1176 // Do not add StandInLayer, throw ParseException instead
1177 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01001178 fmt::format("Operator not supported. "
1179 "subgraph:{} operator:{} "
1180 "opcode_index:{} opcode:{} / {} {}",
1181 subgraphIndex,
1182 operatorIndex,
1183 opcodeIndex,
1184 opcode,
1185 tflite::EnumNameBuiltinOperator(opcode),
1186 CHECK_LOCATION().AsString()));
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001187 }
1188
1189 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1190 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1191
Matthew Sloyan589e3e82020-09-11 16:17:48 +01001192 const unsigned int numInputs = armnn::numeric_cast<unsigned int>(inputs.size());
1193 const unsigned int numOutputs = armnn::numeric_cast<unsigned int>(outputs.size());
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001194
1195 StandInDescriptor descriptor(numInputs, numOutputs);
James Ward58dec6b2020-09-11 17:32:44 +01001196 auto layerName = fmt::format("StandIn:{}:{}:{}", subgraphIndex, operatorIndex, opcode);
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001197
1198 // Add a non-executable StandInLayer as a placeholder for any unsupported operator
1199 IConnectableLayer* layer = m_Network->AddStandInLayer(descriptor, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01001200 ARMNN_ASSERT(layer != nullptr);
1201
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001202 for (unsigned int i = 0u; i < numOutputs; ++i)
1203 {
Mike Kelly04d82292023-01-19 18:29:40 +00001204 layer->GetOutputSlot(i).SetTensorInfo(ToTensorInfo(outputs[0], true));
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001205 }
1206
1207 auto inputTensorIds = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1208 auto outputTensorIds = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1209
1210 RegisterInputSlots(subgraphIndex, operatorIndex, layer, inputTensorIds);
1211 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIds);
telsoa01c577f2c2018-08-31 09:22:23 +01001212}
1213
mathad01b392e982021-04-07 12:07:30 +01001214void TfLiteParserImpl::ParseCast(size_t subgraphIndex, size_t operatorIndex)
1215{
1216 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1217
1218 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1219 CHECK_VALID_SIZE(inputs.size(), 1);
1220 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1221 CHECK_VALID_SIZE(outputs.size(), 1);
1222
1223 auto layerName = fmt::format("Cast:{}:{}", subgraphIndex, operatorIndex);
1224
1225 IConnectableLayer* layer = m_Network->AddCastLayer(layerName.c_str());
1226 ARMNN_ASSERT(layer != nullptr);
1227
Mike Kelly377fb212023-01-10 15:55:28 +00001228 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
mathad01b392e982021-04-07 12:07:30 +01001229 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1230
1231 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1232 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1233
1234 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1235 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
1236}
1237
Kevin May7d96b162021-02-03 17:38:41 +00001238void TfLiteParserImpl::ParseConv2D(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001239{
1240 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1241
Mike Kelly0d77ae12022-01-07 17:42:27 +00001242 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1243 const auto* options = operatorPtr->builtin_options.AsConv2DOptions();
telsoa01c577f2c2018-08-31 09:22:23 +01001244
1245 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1246
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001247 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1248 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1249 CHECK_VALID_SIZE(outputs.size(), 1);
1250
telsoa01c577f2c2018-08-31 09:22:23 +01001251 Convolution2dDescriptor desc;
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001252 inputs.size() == 3 ?
1253 desc.m_BiasEnabled = true : desc.m_BiasEnabled = false;
telsoa01c577f2c2018-08-31 09:22:23 +01001254 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1255 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
jimfly01c25411c2018-11-14 17:47:22 +00001256 desc.m_DataLayout = armnn::DataLayout::NHWC;
Pablo Tellof0bd6832019-04-26 17:58:13 +01001257 desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
1258 desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
Kevin May83add212019-03-26 11:39:19 +00001259
Mike Kelly377fb212023-01-10 15:55:28 +00001260 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1261 armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
telsoa01c577f2c2018-08-31 09:22:23 +01001262
1263 // assuming input is NHWC
1264 unsigned int inputHeight = inputTensorInfo.GetShape()[1];
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001265 unsigned int inputWidth = inputTensorInfo.GetShape()[2];
telsoa01c577f2c2018-08-31 09:22:23 +01001266
1267 // assuming the filter is OHWI : Output, H, W, Input
1268 // which is essentially the same as NHWC
1269 unsigned int filterHeight = filterTensorInfo.GetShape()[1];
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001270 unsigned int filterWidth = filterTensorInfo.GetShape()[2];
telsoa01c577f2c2018-08-31 09:22:23 +01001271
Pablo Tellof0bd6832019-04-26 17:58:13 +01001272 CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
1273 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
1274 CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
1275 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
telsoa01c577f2c2018-08-31 09:22:23 +01001276
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001277 // Add the first input and weights tensor to the registration list.
1278 // The constant weights will be added by SetupConstantLayers.
1279 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1280 std::vector<unsigned int> tensorIndexesToRegister = { inputTensorIndexes[0], inputTensorIndexes[1] };
telsoa01c577f2c2018-08-31 09:22:23 +01001281
James Ward58dec6b2020-09-11 17:32:44 +01001282 auto layerName = fmt::format("Conv2D:{}:{}", subgraphIndex, operatorIndex);
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001283 armnn::IConnectableLayer* layer = m_Network->AddConvolution2dLayer(desc, layerName.c_str());
telsoa01c577f2c2018-08-31 09:22:23 +01001284
Mike Kelly0506ef02023-01-03 16:29:44 +00001285 if (ShouldConstantTensorBeConverted(inputs[1], inputTensorInfo.GetDataType(), filterTensorInfo.GetDataType()))
telsoa01c577f2c2018-08-31 09:22:23 +01001286 {
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001287 m_ConstantsToDequantize.emplace_back(inputs[1]->buffer);
telsoa01c577f2c2018-08-31 09:22:23 +01001288 }
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001289
1290 if (desc.m_BiasEnabled)
telsoa01c577f2c2018-08-31 09:22:23 +01001291 {
Mike Kelly377fb212023-01-10 15:55:28 +00001292 armnn::TensorInfo biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001293
1294 // Add the biases input to the registration list, a constant layer will be added by SetupConstantLayers.
1295 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
1296
Mike Kelly0506ef02023-01-03 16:29:44 +00001297 if (ShouldConstantTensorBeConverted(inputs[2], inputTensorInfo.GetDataType(), biasTensorInfo.GetDataType()))
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001298 {
1299 m_ConstantsToDequantize.emplace_back(inputs[2]->buffer);
1300 }
telsoa01c577f2c2018-08-31 09:22:23 +01001301 }
1302
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001303 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01001304
Mike Kelly377fb212023-01-10 15:55:28 +00001305 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
jimfly01c25411c2018-11-14 17:47:22 +00001306 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +01001307
1308 // register the input connection slots for the layer, connections are made after all layers have been created
1309 // only the tensors for the inputs are relevant, exclude the const tensors
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001310 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister);
telsoa01c577f2c2018-08-31 09:22:23 +01001311
jimfly01c25411c2018-11-14 17:47:22 +00001312 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
telsoa01c577f2c2018-08-31 09:22:23 +01001313 // register the output connection slots for the layer, connections are made after all layers have been created
1314 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001315 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, { outputTensorIndexes[0] });
telsoa01c577f2c2018-08-31 09:22:23 +01001316}
1317
Matthew Sloyan4d217c02021-10-07 11:48:58 +01001318// Conv3D support was added in TF 2.5, so for backwards compatibility a hash define is needed.
Cathal Corbett80b4ef02022-05-25 11:21:11 +01001319#if defined(ARMNN_POST_TFLITE_2_4)
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001320void TfLiteParserImpl::ParseConv3D(size_t subgraphIndex, size_t operatorIndex)
1321{
1322 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1323
1324 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1325 const auto* options = operatorPtr->builtin_options.AsConv3DOptions();
1326
1327 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1328
1329 Convolution3dDescriptor desc;
1330 desc.m_BiasEnabled = false;
1331 desc.m_DataLayout = armnn::DataLayout::NDHWC;
1332 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1333 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1334 desc.m_StrideZ = CHECKED_NON_NEGATIVE(options->stride_d);
1335 desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
1336 desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
1337 desc.m_DilationZ = CHECKED_NON_NEGATIVE(options->dilation_d_factor);
1338
1339 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1340 CHECK_VALID_SIZE(inputs.size(), 2, 3);
1341
1342 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1343 CHECK_VALID_SIZE(outputs.size(), 1);
1344
Mike Kelly377fb212023-01-10 15:55:28 +00001345 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1346 armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001347
1348 // Assuming input is NDHWC
1349 unsigned int inputDepth = inputTensorInfo.GetShape()[1];
1350 unsigned int inputHeight = inputTensorInfo.GetShape()[2];
1351 unsigned int inputWidth = inputTensorInfo.GetShape()[3];
1352
1353 // Assuming the filter is DHWIO : Depth, Height, Width, OutputChannels, InputChannels
1354 unsigned int filterDepth = filterTensorInfo.GetShape()[0];
1355 unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1356 unsigned int filterWidth = filterTensorInfo.GetShape()[2];
1357
1358 CalcPadding(inputDepth, filterDepth, desc.m_StrideZ,
Teresa Charlin502ab942022-03-23 17:23:07 +00001359 desc.m_DilationZ, desc.m_PadFront, desc.m_PadBack, options->padding);
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001360 CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
1361 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
1362 CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
1363 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
1364
Mike Kelly5880b912022-01-28 16:18:54 +00001365 auto filterTensorAndData = CreateConstTensorNonPermuted(inputs[1], filterTensorInfo, inputTensorInfo.GetDataType());
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001366
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001367 auto layerName = fmt::format("Conv3D:{}:{}", subgraphIndex, operatorIndex);
1368
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001369 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1370 // Add the first input and weights tensor to the registration list.
1371 // The constant weights will be added by SetupConstantLayers.
1372 std::vector<unsigned int> tensorIndexesToRegister = {inputTensorIndexes[0], inputTensorIndexes[1]};
1373
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001374 if (inputs.size() == 3)
1375 {
1376 desc.m_BiasEnabled = true;
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001377
1378 // Add the biases input to the registration list, a constant layer will be added by SetupConstantLayers.
1379 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001380 }
1381
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001382 armnn::IConnectableLayer* layer = m_Network->AddConvolution3dLayer(desc, layerName.c_str());
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001383 ARMNN_ASSERT(layer != nullptr);
1384
Mike Kelly377fb212023-01-10 15:55:28 +00001385 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001386 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1387
1388 // Register the input connection slots for the layer, connections are made after all layers have been created
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001389 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister);
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001390
1391 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
1392 // Register the output connection slots for the layer, connections are made after all layers have been created
1393 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1394 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1395}
Matthew Sloyan4d217c02021-10-07 11:48:58 +01001396#endif
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001397
Kevin May7d96b162021-02-03 17:38:41 +00001398void TfLiteParserImpl::ParseDepthwiseConv2D(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001399{
1400 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1401
Mike Kelly0d77ae12022-01-07 17:42:27 +00001402 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1403 const auto* options = operatorPtr->builtin_options.AsDepthwiseConv2DOptions();
telsoa01c577f2c2018-08-31 09:22:23 +01001404
1405 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1406
1407 DepthwiseConvolution2dDescriptor desc;
telsoa01c577f2c2018-08-31 09:22:23 +01001408 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1409 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
jimfly01c25411c2018-11-14 17:47:22 +00001410 desc.m_DataLayout = armnn::DataLayout::NHWC;
Matthew Jacksond6a9dee2019-07-22 13:53:24 +01001411 CHECKED_NON_NEGATIVE(options->depth_multiplier);
telsoa01c577f2c2018-08-31 09:22:23 +01001412
1413 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1414 CHECK_VALID_SIZE(inputs.size(), 2, 3);
Cathal Corbett06902652022-04-14 17:55:11 +01001415 if (inputs.size() == 3)
1416 {
1417 desc.m_BiasEnabled = true;
1418 }
1419
telsoa01c577f2c2018-08-31 09:22:23 +01001420 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1421 CHECK_VALID_SIZE(outputs.size(), 1);
Pablo Tellof0bd6832019-04-26 17:58:13 +01001422 desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
1423 desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
Kevin May83add212019-03-26 11:39:19 +00001424
Mike Kelly377fb212023-01-10 15:55:28 +00001425 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1426 armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
telsoa01c577f2c2018-08-31 09:22:23 +01001427
Matteo Martincigh747ef822018-12-18 09:26:39 +00001428 // Assuming input is NHWC
telsoa01c577f2c2018-08-31 09:22:23 +01001429 unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1430 unsigned int inputWidth = inputTensorInfo.GetShape()[2];
Matteo Martincigh747ef822018-12-18 09:26:39 +00001431
1432 // TensorflowLite weights come in the format [1, H, W, I * M]
telsoa01c577f2c2018-08-31 09:22:23 +01001433 unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1434 unsigned int filterWidth = filterTensorInfo.GetShape()[2];
1435
Pablo Tellof0bd6832019-04-26 17:58:13 +01001436 CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
1437 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
1438 CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
1439 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
telsoa01c577f2c2018-08-31 09:22:23 +01001440
Jan Eilers53ef7952021-06-02 12:01:25 +01001441 // 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 +01001442 auto layerName = fmt::format("DepthwiseConv2D:{}:{}", subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001443
Cathal Corbett06902652022-04-14 17:55:11 +01001444 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1445 // Add the first input and weights tensor to the registration list.
1446 // The constant weights will be added by SetupConstantLayers.
1447 std::vector<unsigned int> tensorIndexesToRegister = {inputTensorIndexes[0], inputTensorIndexes[1]};
1448
1449 armnn::IConnectableLayer* layer = m_Network->AddDepthwiseConvolution2dLayer(desc, layerName.c_str());
1450
1451 if (desc.m_BiasEnabled)
telsoa01c577f2c2018-08-31 09:22:23 +01001452 {
1453 desc.m_BiasEnabled = true;
Mike Kelly377fb212023-01-10 15:55:28 +00001454 TensorInfo biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Cathal Corbett06902652022-04-14 17:55:11 +01001455
1456 // Add the biases input to the registration list, a constant layer will be added by SetupConstantLayers.
1457 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
telsoa01c577f2c2018-08-31 09:22:23 +01001458 }
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001459 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01001460
Mike Kelly377fb212023-01-10 15:55:28 +00001461 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
jimfly01c25411c2018-11-14 17:47:22 +00001462 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +01001463
1464 // register the input connection slots for the layer, connections are made after all layers have been created
1465 // only the tensors for the inputs are relevant, exclude the const tensors
Cathal Corbett06902652022-04-14 17:55:11 +01001466 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister);
telsoa01c577f2c2018-08-31 09:22:23 +01001467
jimfly01c25411c2018-11-14 17:47:22 +00001468 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
telsoa01c577f2c2018-08-31 09:22:23 +01001469 // register the output connection slots for the layer, connections are made after all layers have been created
1470 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1471 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1472}
1473
Kevin May7d96b162021-02-03 17:38:41 +00001474void TfLiteParserImpl::ParseDequantize(size_t subgraphIndex, size_t operatorIndex)
Finn Williamsed66d142019-12-06 09:55:55 +00001475{
1476 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1477
1478 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1479 CHECK_VALID_SIZE(inputs.size(), 1);
1480
1481 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1482 CHECK_VALID_SIZE(outputs.size(), 1);
1483
James Ward58dec6b2020-09-11 17:32:44 +01001484 auto layerName = fmt::format("Dequantize:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsed66d142019-12-06 09:55:55 +00001485
1486 IConnectableLayer* layer = m_Network->AddDequantizeLayer(layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001487 ARMNN_ASSERT(layer != nullptr);
Finn Williamsed66d142019-12-06 09:55:55 +00001488
Mike Kelly377fb212023-01-10 15:55:28 +00001489 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Finn Williamsed66d142019-12-06 09:55:55 +00001490 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1491
1492 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1493 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1494
1495 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1496 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
1497}
1498
Teresa Charlin3ab85482021-06-08 16:59:29 +01001499void TfLiteParserImpl::ParseExpandDims(size_t subgraphIndex, size_t operatorIndex)
1500{
1501 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1502
1503 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1504 CHECK_VALID_SIZE(inputs.size(), 2);
1505
1506 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1507 CHECK_VALID_SIZE(outputs.size(), 1);
1508
1509 auto layerName = fmt::format("ExpandDims:{}:{}", subgraphIndex, operatorIndex);
1510
Mike Kelly377fb212023-01-10 15:55:28 +00001511 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Teresa Charlin3ab85482021-06-08 16:59:29 +01001512 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Teresa Charlin3ab85482021-06-08 16:59:29 +01001513 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1514
Teresa Charlina7a605a2023-06-14 14:51:17 +01001515 armnn::TensorInfo axisTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
1516
1517 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1518 if (axisBufferPtr == nullptr)
1519 {
1520 throw ParseException(fmt::format("{}: Operation has invalid inputs. Failed to read axis.",
1521 CHECK_LOCATION().AsString()));
1522 }
1523
1524 std::vector<int32_t> axisData(axisTensorInfo.GetNumElements());
1525 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
1526 int32_t axis = axisData[0];
1527
1528 auto inputRank = static_cast<int32_t>(inputTensorInfo.GetShape().GetNumDimensions());
1529 auto outputRank = inputRank + 1;
1530 if((axis < -1 * outputRank) || (outputRank <= axis))
1531 {
1532 throw ParseException(fmt::format("{}: Axis {} is not within [-{}, {}) range.",
1533 CHECK_LOCATION().AsString(), axis, outputRank, outputRank));
1534 }
1535
1536 axis = axis < 0 ? (axis + outputRank) : axis;
1537
1538 std::vector<unsigned int> shape(static_cast<unsigned int>(outputRank));
1539 unsigned int inputShapeIndex = 0;
1540 for (unsigned int i = 0; i < static_cast<unsigned int>(outputRank); ++i)
1541 {
1542 if (i == static_cast<unsigned int>(axis))
1543 {
1544 shape[i] = 1;
1545 }
1546 else
1547 {
1548 shape[i] = inputTensorInfo.GetShape()[inputShapeIndex];
1549 ++inputShapeIndex;
1550 }
1551 }
1552
Teresa Charlin3ab85482021-06-08 16:59:29 +01001553 ReshapeDescriptor reshapeDesc;
Teresa Charlina7a605a2023-06-14 14:51:17 +01001554 reshapeDesc.m_TargetShape = TensorShape(static_cast<unsigned int>(outputRank), shape.data());
1555 outputTensorInfo.SetShape(reshapeDesc.m_TargetShape);
Teresa Charlin3ab85482021-06-08 16:59:29 +01001556
1557 IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
1558 ARMNN_ASSERT(layer != nullptr);
1559 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1560
Teresa Charlina7a605a2023-06-14 14:51:17 +01001561 auto outputTensorIds = GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex);
1562 m_TensorInfos[outputTensorIds[0]] = outputTensorInfo;
1563
Teresa Charlin3ab85482021-06-08 16:59:29 +01001564 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1565 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1566
1567 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1568 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1569}
1570
Kevin May7d96b162021-02-03 17:38:41 +00001571void TfLiteParserImpl::ParseTranspose(size_t subgraphIndex, size_t operatorIndex)
Keith Davis4cd29a02019-09-09 14:49:20 +01001572{
1573 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1574
1575 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Kevin May85d92602019-09-27 17:21:06 +01001576 CHECK_VALID_SIZE(inputs.size(), 1, 2);
Keith Davis4cd29a02019-09-09 14:49:20 +01001577
1578 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1579 CHECK_VALID_SIZE(outputs.size(), 1);
1580
James Ward58dec6b2020-09-11 17:32:44 +01001581 auto layerName = fmt::format("Transpose:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly08759e22020-03-02 11:41:31 +00001582 TransposeDescriptor desc;
Keith Davis4cd29a02019-09-09 14:49:20 +01001583
josh minorba424d22019-11-13 10:55:17 -06001584 if (inputs.size() == 2)
Kevin May85d92602019-09-27 17:21:06 +01001585 {
Mike Kelly377fb212023-01-10 15:55:28 +00001586 armnn::TensorInfo permuteTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Kevin May85d92602019-09-27 17:21:06 +01001587 BufferRawPtr permuteBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
josh minorba424d22019-11-13 10:55:17 -06001588 auto numPermVecElements = permuteTensorInfo.GetNumElements();
1589 std::vector<unsigned int> permuteShape(numPermVecElements);
Kevin May85d92602019-09-27 17:21:06 +01001590 ::memcpy(permuteShape.data(), permuteBufferPtr->data.data(), permuteTensorInfo.GetNumBytes());
Mike Kelly08759e22020-03-02 11:41:31 +00001591 PermutationVector permutationVector(permuteShape.data(), permuteTensorInfo.GetNumElements());
Kevin May85d92602019-09-27 17:21:06 +01001592
Mike Kelly08759e22020-03-02 11:41:31 +00001593 desc = TransposeDescriptor(permutationVector);
Kevin May85d92602019-09-27 17:21:06 +01001594 }
Mike Kelly377fb212023-01-10 15:55:28 +00001595 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Keith Davis4cd29a02019-09-09 14:49:20 +01001596
James Conroy05102392020-06-24 15:39:55 +01001597 IConnectableLayer* layer = m_Network->AddTransposeLayer(desc, layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001598 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00001599
1600 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
1601 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Keith Davis4cd29a02019-09-09 14:49:20 +01001602 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1603
1604 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1605 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1606
1607 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1608 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1609}
1610
Kevin May7d96b162021-02-03 17:38:41 +00001611void TfLiteParserImpl::ParseTransposeConv(size_t subgraphIndex, size_t operatorIndex)
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001612{
1613 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1614
Mike Kelly0d77ae12022-01-07 17:42:27 +00001615 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1616 const auto* options = operatorPtr->builtin_options.AsTransposeConvOptions();
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001617
1618 TransposeConvolution2dDescriptor desc;
1619 desc.m_BiasEnabled = false;
1620 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1621 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1622 desc.m_DataLayout = armnn::DataLayout::NHWC;
1623
1624 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
David Monahan61683802021-01-12 09:11:07 +00001625 if (inputs.size() == 4)
1626 {
1627 desc.m_BiasEnabled = true;
1628 }
1629 else
1630 {
1631 CHECK_VALID_SIZE(inputs.size(), 3);
1632 }
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001633
1634 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1635 CHECK_VALID_SIZE(outputs.size(), 1);
1636
Teresa Charlin024ef0b2023-04-26 11:19:03 +01001637
1638 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
1639 armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
1640
1641 // TfLite uses NHWC tensors
1642 const unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1643 const unsigned int inputWidth = inputTensorInfo.GetShape()[2];
1644
1645 const unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1646 const unsigned int filterWidth = filterTensorInfo.GetShape()[2];
1647
Ryan OSheaf0a35b82023-02-21 18:32:30 +00001648 // This block determines the output shape of the transpose convolution. If the output shape tensor ptr is not null
1649 // And the tensor is a constant, we can access the data at load time and set the output shape of the
1650 // layer. If this is not constant, We do not have access to the shape data, so we have to use
1651 // infer output shape and skip this code block.
1652 if (inputs[0] && IsConstTensor(inputs[0]))
Colm Donelan0ad3ef12020-07-03 15:54:28 +01001653 {
Mike Kelly377fb212023-01-10 15:55:28 +00001654 armnn::TensorInfo tensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Colm Donelan0ad3ef12020-07-03 15:54:28 +01001655 std::vector<int> output_shape(tensorInfo.GetNumElements());
Mike Kelly377fb212023-01-10 15:55:28 +00001656
Colm Donelan0ad3ef12020-07-03 15:54:28 +01001657 if (tensorInfo.GetDataType() == DataType::Signed32)
1658 {
1659 ::memcpy(output_shape.data(), GetBuffer(m_Model, inputs[0]->buffer)->data.data(), tensorInfo.GetNumBytes());
1660 }
1661 if (tensorInfo.GetDataType() == DataType::QAsymmU8)
1662 {
1663 for(unsigned int i=0; i < tensorInfo.GetNumElements(); i++)
1664 {
1665 output_shape[i] = GetBuffer(m_Model, inputs[0]->buffer)->data.data()[i];
1666 }
1667 }
1668 // Change from signed to unsigned int to store in TransposeConvolution2dDescriptor.
1669 for (int dimension : output_shape)
1670 {
1671 desc.m_OutputShape.push_back(static_cast<unsigned int>(dimension));
1672 }
1673 desc.m_OutputShapeEnabled = true;
Teresa Charlin024ef0b2023-04-26 11:19:03 +01001674
1675 // TfLite uses NHWC tensors
1676 const unsigned int outputHeight = desc.m_OutputShape[1];
1677 const unsigned int outputWidth = desc.m_OutputShape[2];
1678
1679 CalcPadding(inputHeight,
1680 filterHeight,
1681 desc.m_StrideY,
1682 1, // DilationY
1683 desc.m_PadTop,
1684 desc.m_PadBottom,
1685 options->padding,
1686 outputHeight);
1687
1688 CalcPadding(inputWidth,
1689 filterWidth,
1690 desc.m_StrideX,
1691 1, // DilationX
1692 desc.m_PadLeft,
1693 desc.m_PadRight,
1694 options->padding,
1695 outputWidth);
Colm Donelan0ad3ef12020-07-03 15:54:28 +01001696 }
Teresa Charlin024ef0b2023-04-26 11:19:03 +01001697 else
1698 {
1699 CalcPadding(inputHeight,
1700 filterHeight,
1701 desc.m_StrideY,
1702 1, // DilationY
1703 desc.m_PadTop,
1704 desc.m_PadBottom,
1705 options->padding);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001706
Teresa Charlin024ef0b2023-04-26 11:19:03 +01001707 CalcPadding(inputWidth,
1708 filterWidth,
1709 desc.m_StrideX,
1710 1, // DilationX
1711 desc.m_PadLeft,
1712 desc.m_PadRight,
1713 options->padding);
1714 }
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001715
Mike Kelly5880b912022-01-28 16:18:54 +00001716 auto filterTensorAndData = CreateConstTensorNonPermuted(inputs[1], filterTensorInfo, inputTensorInfo.GetDataType());
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001717
1718 armnn::IConnectableLayer* layer = nullptr;
James Ward58dec6b2020-09-11 17:32:44 +01001719 auto layerName = fmt::format("TransposeConv:{}:{}", subgraphIndex, operatorIndex);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001720
David Monahan61683802021-01-12 09:11:07 +00001721 if (desc.m_BiasEnabled)
1722 {
Mike Kelly377fb212023-01-10 15:55:28 +00001723 auto biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 3);
Mike Kelly5880b912022-01-28 16:18:54 +00001724 auto biasConstTensor = CreateConstTensorNonPermuted(inputs[3], biasTensorInfo, inputTensorInfo.GetDataType());
David Monahan61683802021-01-12 09:11:07 +00001725 layer = m_Network->AddTransposeConvolution2dLayer(desc,
Mike Kelly5880b912022-01-28 16:18:54 +00001726 filterTensorAndData.first,
1727 biasConstTensor.first,
David Monahan61683802021-01-12 09:11:07 +00001728 layerName.c_str());
1729 }
1730 else
1731 {
1732 layer = m_Network->AddTransposeConvolution2dLayer(desc,
Mike Kelly5880b912022-01-28 16:18:54 +00001733 filterTensorAndData.first,
David Monahan61683802021-01-12 09:11:07 +00001734 EmptyOptional(),
1735 layerName.c_str());
1736 }
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001737
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001738 ARMNN_ASSERT(layer != nullptr);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001739
Mike Kelly377fb212023-01-10 15:55:28 +00001740 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0 , { 2, 1 });
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001741 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1742
1743 // only the tensors for the inputs are relevant, exclude the const (filter) tensor
1744 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Matthew Jacksonccb25ea2019-08-20 17:18:33 +01001745 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[2]});
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001746
1747 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1748 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1749}
1750
Kevin May7d96b162021-02-03 17:38:41 +00001751void TfLiteParserImpl::ParseAveragePool2D(size_t subgraphIndex, size_t operatorIndex)
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001752{
1753 ParsePool(subgraphIndex, operatorIndex, PoolingAlgorithm::Average);
1754}
1755
Samuel Yapfd3ba5a2022-08-24 17:04:34 +01001756void TfLiteParserImpl::ParseBatchMatMul(size_t subgraphIndex, size_t operatorIndex)
1757{
1758 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1759
1760 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1761 CHECK_VALID_SIZE(inputs.size(), 2);
1762
1763 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1764 CHECK_VALID_SIZE(outputs.size(), 1);
1765
1766 auto layerName = fmt::format("BatchMatMul:{}:{}", subgraphIndex, operatorIndex);
1767
Mike Kelly377fb212023-01-10 15:55:28 +00001768 TensorInfo inputXTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1769 TensorInfo inputYTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Samuel Yapfd3ba5a2022-08-24 17:04:34 +01001770
1771 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1772 const auto* options = operatorPtr->builtin_options.AsBatchMatMulOptions();
1773
Teresa Charlinbc37a6b2022-09-22 10:12:58 +01001774 // Adjoint in tensorflow lite performs transpose operation
1775 BatchMatMulDescriptor descriptor(options->adj_x,
1776 options->adj_y,
Samuel Yapfd3ba5a2022-08-24 17:04:34 +01001777 false,
Teresa Charlinbc37a6b2022-09-22 10:12:58 +01001778 false);
Samuel Yapfd3ba5a2022-08-24 17:04:34 +01001779 // Arbitrary DataLayout
1780
1781 IConnectableLayer* layer = m_Network->AddBatchMatMulLayer(descriptor, layerName.c_str());
1782 ARMNN_ASSERT(layer != nullptr);
1783
Mike Kelly377fb212023-01-10 15:55:28 +00001784 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Samuel Yapfd3ba5a2022-08-24 17:04:34 +01001785 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1786
1787 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1788 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
1789
1790 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1791 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1792}
1793
Kevin May7d96b162021-02-03 17:38:41 +00001794void TfLiteParserImpl::ParseBatchToSpaceND(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001795{
1796 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1797
1798 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1799 CHECK_VALID_SIZE(inputs.size(), 3);
1800
1801 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1802 CHECK_VALID_SIZE(outputs.size(), 1);
1803
Mike Kelly377fb212023-01-10 15:55:28 +00001804 armnn::TensorInfo blockShapeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001805 BufferRawPtr blockShapeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1806
Mike Kelly377fb212023-01-10 15:55:28 +00001807 armnn::TensorInfo cropsTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001808 BufferRawPtr cropsBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
1809
1810 std::vector<unsigned int> blockShape(blockShapeTensorInfo.GetNumElements());
1811 ::memcpy(blockShape.data(), blockShapeBufferPtr->data.data(), blockShapeTensorInfo.GetNumBytes());
1812
1813 std::vector<unsigned int> cropsVector(cropsTensorInfo.GetNumElements());
1814 ::memcpy(cropsVector.data(), cropsBufferPtr->data.data(), cropsTensorInfo.GetNumBytes());
1815
1816 size_t step = 2;
1817 std::vector<std::pair<unsigned int, unsigned int>> crops;
1818 for (unsigned int i = 0; i < cropsTensorInfo.GetNumElements() / step; ++i)
1819 {
1820 crops.emplace_back(cropsVector[i * step], cropsVector[i * step + 1]);
1821 }
1822
1823 armnn::BatchToSpaceNdDescriptor desc;
1824 desc.m_BlockShape = blockShape;
1825 desc.m_Crops = crops;
1826 desc.m_DataLayout = armnn::DataLayout::NHWC;
1827
James Ward58dec6b2020-09-11 17:32:44 +01001828 auto layerName = fmt::format("BatchToSpaceND:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001829
Mike Kelly377fb212023-01-10 15:55:28 +00001830 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
James Conroy05102392020-06-24 15:39:55 +01001831
1832 IConnectableLayer* layer = m_Network->AddBatchToSpaceNdLayer(desc, layerName.c_str());
1833 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00001834
1835 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
1836 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001837 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1838
1839 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1840 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1841
1842 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1843 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1844}
1845
Kevin May7d96b162021-02-03 17:38:41 +00001846void TfLiteParserImpl::ParseL2Normalization(size_t subgraphIndex, size_t operatorIndex)
Matthew Jackson28c94572019-07-18 10:47:03 +01001847{
1848 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1849
1850 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1851 CHECK_VALID_SIZE(inputs.size(), 1);
1852
1853 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1854 CHECK_VALID_SIZE(outputs.size(), 1);
1855
1856 L2NormalizationDescriptor desc;
1857 desc.m_DataLayout = armnn::DataLayout::NHWC;
James Ward58dec6b2020-09-11 17:32:44 +01001858 auto layerName = fmt::format("L2Normalization:{}:{}", subgraphIndex, operatorIndex);
Matthew Jackson28c94572019-07-18 10:47:03 +01001859 IConnectableLayer* layer = m_Network->AddL2NormalizationLayer(desc, layerName.c_str());
1860
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001861 ARMNN_ASSERT(layer != nullptr);
Matthew Jackson28c94572019-07-18 10:47:03 +01001862
Mike Kelly377fb212023-01-10 15:55:28 +00001863 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Matthew Jackson28c94572019-07-18 10:47:03 +01001864 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1865
1866 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1867 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1868
1869 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1870 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1871}
1872
Kevin May7d96b162021-02-03 17:38:41 +00001873void TfLiteParserImpl::ParseMaxPool2D(size_t subgraphIndex, size_t operatorIndex)
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001874{
1875 ParsePool(subgraphIndex, operatorIndex, PoolingAlgorithm::Max);
1876}
1877
Kevin May7d96b162021-02-03 17:38:41 +00001878void TfLiteParserImpl::ParseMaximum(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001879{
1880 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1881
1882 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1883 CHECK_VALID_SIZE(inputs.size(), 2);
1884
1885 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1886 CHECK_VALID_SIZE(outputs.size(), 1);
1887
James Ward58dec6b2020-09-11 17:32:44 +01001888 auto layerName = fmt::format("Maximum:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01001889
Mike Kelly377fb212023-01-10 15:55:28 +00001890 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1891 TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
James Conroy05102392020-06-24 15:39:55 +01001892 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001893
Mike Kelly3ec30772023-03-08 13:47:17 +00001894 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Maximum, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01001895 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00001896
1897 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
1898 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001899 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1900
1901 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01001902 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001903
1904 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1905 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1906}
1907
Kevin May7d96b162021-02-03 17:38:41 +00001908void TfLiteParserImpl::ParseMinimum(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001909{
1910 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1911
1912 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1913 CHECK_VALID_SIZE(inputs.size(), 2);
1914
1915 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1916 CHECK_VALID_SIZE(outputs.size(), 1);
1917
James Ward58dec6b2020-09-11 17:32:44 +01001918 auto layerName = fmt::format("Minimum:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01001919
Mike Kelly377fb212023-01-10 15:55:28 +00001920 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1921 TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
James Conroy05102392020-06-24 15:39:55 +01001922 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001923
Mike Kelly3ec30772023-03-08 13:47:17 +00001924 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Minimum, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01001925 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00001926
1927 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
1928 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001929 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1930
1931 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01001932 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001933
1934 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1935 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1936}
1937
Kevin May7d96b162021-02-03 17:38:41 +00001938void TfLiteParserImpl::ParsePool(size_t subgraphIndex,
1939 size_t operatorIndex,
1940 PoolingAlgorithm algorithm)
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001941{
1942 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1943
Mike Kelly0d77ae12022-01-07 17:42:27 +00001944 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1945 const auto* options = operatorPtr->builtin_options.AsPool2DOptions();
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001946
1947 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1948
1949 std::string layerName;
1950
1951 switch (algorithm)
1952 {
1953 case PoolingAlgorithm::Average:
1954 layerName =
James Ward58dec6b2020-09-11 17:32:44 +01001955 fmt::format("AveragePool2D:{}:{}", subgraphIndex, operatorIndex);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001956 break;
1957 case PoolingAlgorithm::Max:
1958 layerName =
James Ward58dec6b2020-09-11 17:32:44 +01001959 fmt::format("MaxPool2D:{}:{}", subgraphIndex, operatorIndex);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001960 break;
1961 default:
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001962 ARMNN_ASSERT_MSG(false, "Unsupported Pooling Algorithm");
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001963 }
1964
1965 Pooling2dDescriptor desc;
1966
1967 desc.m_PoolType = algorithm;
1968 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1969 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1970 desc.m_PoolWidth = CHECKED_NON_NEGATIVE(options->filter_width);
1971 desc.m_PoolHeight = CHECKED_NON_NEGATIVE(options->filter_height);
1972 desc.m_PaddingMethod = PaddingMethod::Exclude;
1973 desc.m_OutputShapeRounding = OutputShapeRounding::Floor;
jimfly01c25411c2018-11-14 17:47:22 +00001974 desc.m_DataLayout = armnn::DataLayout::NHWC;
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001975
1976 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1977 CHECK_VALID_SIZE(inputs.size(), 1);
Mike Kelly377fb212023-01-10 15:55:28 +00001978 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001979
1980 // assuming input is NHWC
1981 unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1982 unsigned int inputWidth = inputTensorInfo.GetShape()[2];
1983
Pablo Tellof0bd6832019-04-26 17:58:13 +01001984 CalcPadding(inputHeight, desc.m_PoolHeight, desc.m_StrideY, 1u,
1985 desc.m_PadTop, desc.m_PadBottom, options->padding);
1986 CalcPadding(inputWidth, desc.m_PoolWidth, desc.m_StrideX, 1u,
1987 desc.m_PadLeft, desc.m_PadRight, options->padding);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001988
1989 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1990 CHECK_VALID_SIZE(outputs.size(), 1);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001991
James Conroy05102392020-06-24 15:39:55 +01001992 IConnectableLayer* layer = m_Network->AddPooling2dLayer(desc, layerName.c_str());
1993 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00001994
1995 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
1996 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
jimfly01c25411c2018-11-14 17:47:22 +00001997 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001998
1999 // register the input connection slots for the layer, connections are made after all layers have been created
2000 // only the tensors for the inputs are relevant, exclude the const tensors
2001 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
jimfly01c25411c2018-11-14 17:47:22 +00002002 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01002003
jimfly01c25411c2018-11-14 17:47:22 +00002004 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01002005 // register the output connection slots for the layer, connections are made after all layers have been created
2006 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2007 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2008}
2009
Kevin May7d96b162021-02-03 17:38:41 +00002010void TfLiteParserImpl::ParseSlice(size_t subgraphIndex, size_t operatorIndex)
josh minorba424d22019-11-13 10:55:17 -06002011{
2012 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2013
2014 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2015 CHECK_VALID_SIZE(inputs.size(), 3);
2016 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2017 CHECK_VALID_SIZE(outputs.size(), 1);
2018
2019 SliceDescriptor desc;
2020
2021 // set begin tensor info for slice descriptor
Mike Kelly377fb212023-01-10 15:55:28 +00002022 armnn::TensorInfo beginTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
josh minorba424d22019-11-13 10:55:17 -06002023 BufferRawPtr beginBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2024
2025 std::vector<unsigned int> begin(beginTensorInfo.GetNumElements());
2026 ::memcpy(begin.data(), beginBufferPtr->data.data(), beginTensorInfo.GetNumBytes());
2027
2028 // set size tensor info for slice descriptor
Mike Kelly377fb212023-01-10 15:55:28 +00002029 armnn::TensorInfo sizeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
josh minorba424d22019-11-13 10:55:17 -06002030 BufferRawPtr sizeBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
2031
Cathal Corbettde33dda2022-09-20 16:40:09 +01002032 std::vector<int> signedSize(sizeTensorInfo.GetNumElements(), 1);
2033
2034 // if size buffer data is not specified, all contents of size vector remain as values of 1
2035 if (sizeBufferPtr->data.data())
2036 {
2037 ::memcpy(signedSize.data(), sizeBufferPtr->data.data(), sizeTensorInfo.GetNumBytes());
2038 }
2039
josh minorba424d22019-11-13 10:55:17 -06002040 std::vector<unsigned int> size(sizeTensorInfo.GetNumElements());
Mike Kelly377fb212023-01-10 15:55:28 +00002041 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Mike Kelly7ba84d62021-09-10 15:27:19 +01002042
2043 for (unsigned int i = 0; i < signedSize.size(); ++i)
2044 {
2045 int signedValue = signedSize[i];
Jim Flynnfca233e2021-09-23 12:16:53 +01002046
Mike Kelly7ba84d62021-09-10 15:27:19 +01002047 if (signedValue < -1 || signedValue > static_cast<int>(inputTensorInfo.GetShape()[i] - begin[i]))
2048 {
2049 throw ParseException(fmt::format("Invalid value for size {} size must be in range "
2050 "[-1, inputDimSize - begin] [-1, {}] inclusive {}",
2051 signedValue,
2052 inputTensorInfo.GetShape()[i] - begin[i],
2053 CHECK_LOCATION().AsString()));
2054 }
2055
2056 if (signedValue == -1)
2057 {
2058 size[i] = inputTensorInfo.GetShape()[i] - begin[i];
2059 }
2060 else
2061 {
2062 size[i] = static_cast<unsigned int>(signedValue);
2063 }
2064 }
2065
josh minorba424d22019-11-13 10:55:17 -06002066 desc = SliceDescriptor(begin, size);
2067
James Ward58dec6b2020-09-11 17:32:44 +01002068 auto layerName = fmt::format("Slice:{}:{}", subgraphIndex, operatorIndex);
josh minorba424d22019-11-13 10:55:17 -06002069
James Conroy05102392020-06-24 15:39:55 +01002070 IConnectableLayer* const layer = m_Network->AddSliceLayer(desc, layerName.c_str());
Mike Kelly377fb212023-01-10 15:55:28 +00002071
2072 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
2073 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
josh minorba424d22019-11-13 10:55:17 -06002074 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2075
2076 // register the input connection slots for the layer, connections are made after all layers have been created
2077 // only the tensors for the inputs are relevant, exclude the const tensors
2078 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2079 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2080
2081 // register the output connection slots for the layer, connections are made after all layers have been created
2082 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2083 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2084}
2085
Kevin May7d96b162021-02-03 17:38:41 +00002086void TfLiteParserImpl::ParseSoftmax(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01002087{
2088 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00002089 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2090 const auto* options = operatorPtr->builtin_options.AsSoftmaxOptions();
telsoa01c577f2c2018-08-31 09:22:23 +01002091
2092 SoftmaxDescriptor desc;
2093 desc.m_Beta = options->beta;
2094
2095 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2096 CHECK_VALID_SIZE(inputs.size(), 1);
2097 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2098 CHECK_VALID_SIZE(outputs.size(), 1);
2099
James Ward58dec6b2020-09-11 17:32:44 +01002100 auto layerName = fmt::format("Softmax:{}:{}", subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01002101 IConnectableLayer* const layer = m_Network->AddSoftmaxLayer(desc, layerName.c_str());
2102
Mike Kelly377fb212023-01-10 15:55:28 +00002103 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
telsoa01c577f2c2018-08-31 09:22:23 +01002104 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2105
2106 // register the input connection slots for the layer, connections are made after all layers have been created
2107 // only the tensors for the inputs are relevant, exclude the const tensors
2108 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2109 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2110
2111 // register the output connection slots for the layer, connections are made after all layers have been created
2112 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2113 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2114}
2115
Teresa Charlinfd33a692022-06-29 15:35:57 +01002116void TfLiteParserImpl::ParseLogSoftmax(size_t subgraphIndex, size_t operatorIndex)
2117{
2118 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2119
2120 LogSoftmaxDescriptor desc;
2121
2122 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2123 CHECK_VALID_SIZE(inputs.size(), 1);
2124 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2125 CHECK_VALID_SIZE(outputs.size(), 1);
2126
2127 auto layerName = fmt::format("LogSoftmax:{}:{}", subgraphIndex, operatorIndex);
2128 IConnectableLayer* const layer = m_Network->AddLogSoftmaxLayer(desc, layerName.c_str());
2129
Mike Kelly377fb212023-01-10 15:55:28 +00002130 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Teresa Charlinfd33a692022-06-29 15:35:57 +01002131 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2132
2133 // register the input connection slots for the layer, connections are made after all layers have been created
2134 // only the tensors for the inputs are relevant, exclude the const tensors
2135 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2136 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2137
2138 // register the output connection slots for the layer, connections are made after all layers have been created
2139 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2140 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2141}
2142
Kevin May7d96b162021-02-03 17:38:41 +00002143void TfLiteParserImpl::ParseSpaceToBatchND(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesbaded142019-02-08 19:02:48 -02002144{
2145 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2146
2147 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2148 CHECK_VALID_SIZE(inputs.size(), 3);
2149
2150 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2151 CHECK_VALID_SIZE(outputs.size(), 1);
2152
Mike Kelly377fb212023-01-10 15:55:28 +00002153 armnn::TensorInfo blockShapeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalvesbaded142019-02-08 19:02:48 -02002154 BufferRawPtr blockShapeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2155
Mike Kelly377fb212023-01-10 15:55:28 +00002156 armnn::TensorInfo padListTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Bruno Goncalvesbaded142019-02-08 19:02:48 -02002157 BufferRawPtr padListBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
2158
2159 std::vector<unsigned int> blockShape(blockShapeTensorInfo.GetNumElements());
2160 ::memcpy(blockShape.data(), blockShapeBufferPtr->data.data(), blockShapeTensorInfo.GetNumBytes());
2161
2162 std::vector<unsigned int> padListVector(padListTensorInfo.GetNumElements());
2163 ::memcpy(padListVector.data(), padListBufferPtr->data.data(), padListTensorInfo.GetNumBytes());
2164
2165 size_t step = 2;
2166 std::vector<std::pair<unsigned int, unsigned int>> padList;
2167 for (unsigned int i = 0; i < padListTensorInfo.GetNumElements() / step; ++i)
2168 {
2169 padList.emplace_back(padListVector[i * step], padListVector[i * step + 1]);
2170 }
2171
2172 armnn::SpaceToBatchNdDescriptor desc;
2173 desc.m_BlockShape = blockShape;
2174 desc.m_PadList = padList;
2175 desc.m_DataLayout = armnn::DataLayout::NHWC;
2176
James Ward58dec6b2020-09-11 17:32:44 +01002177 auto layerName = fmt::format("SpaceToBatchND:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesbaded142019-02-08 19:02:48 -02002178
Mike Kelly377fb212023-01-10 15:55:28 +00002179 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
James Conroy05102392020-06-24 15:39:55 +01002180
2181 IConnectableLayer* layer = m_Network->AddSpaceToBatchNdLayer(desc, layerName.c_str());
2182 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00002183
2184 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
2185 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Bruno Goncalvesbaded142019-02-08 19:02:48 -02002186 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2187
2188 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2189 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2190
2191 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2192 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2193}
2194
Teresa Charlin2a764ad2023-02-24 18:17:31 +00002195void TfLiteParserImpl::ParseSpaceToDepth(size_t subgraphIndex, size_t operatorIndex)
2196{
2197 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2198
2199 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2200 CHECK_VALID_SIZE(inputs.size(), 1);
2201 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2202 CHECK_VALID_SIZE(outputs.size(), 1);
2203
2204 armnn::SpaceToDepthDescriptor descriptor;
2205
2206 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2207 const auto* options = operatorPtr->builtin_options.AsSpaceToDepthOptions();
2208 auto blockSize = options->block_size;
2209 if (blockSize < 2)
2210 {
2211 throw ParseException(
2212 fmt::format("Operation has invalid block size: {} Block size should be >= 2 {}",
2213 blockSize,
2214 CHECK_LOCATION().AsString()));
2215 }
2216 descriptor.m_BlockSize = armnn::numeric_cast<uint32_t>(blockSize);
2217
2218 auto layerName = fmt::format("SpaceToDepth:{}:{}", subgraphIndex, operatorIndex);
2219 IConnectableLayer* layer = m_Network->AddSpaceToDepthLayer(descriptor, layerName.c_str());
2220 ARMNN_ASSERT(layer != nullptr);
2221 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
2222 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2223
2224 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2225 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2226
2227 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2228 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2229}
2230
Teresa Charlin3ab85482021-06-08 16:59:29 +01002231armnn::TensorInfo TfLiteParserImpl::OutputShapeOfSqueeze(std::vector<uint32_t> squeezeDims,
Mike Kelly0d77ae12022-01-07 17:42:27 +00002232 const armnn::TensorInfo& inputTensorInfo)
telsoa01c577f2c2018-08-31 09:22:23 +01002233{
Teresa Charlin3ab85482021-06-08 16:59:29 +01002234 CHECK_VALID_SIZE(squeezeDims.size(), 0, 1, 2, 3, 4);
telsoa01c577f2c2018-08-31 09:22:23 +01002235 static const uint32_t dimensionSequence[] = { 0, 1, 2, 3 };
2236
2237 if (inputTensorInfo.GetNumDimensions() > 4)
2238 {
2239 std::stringstream ss;
2240 ss << "Input tensor has unexpected number of dimensions:" << inputTensorInfo.GetNumDimensions()
2241 << " shape:" << inputTensorInfo.GetShape() << " "
2242 << CHECK_LOCATION().AsString();
2243 throw ParseException(ss.str());
2244 }
2245
2246 if (squeezeDims.empty())
2247 {
2248 squeezeDims.assign(dimensionSequence,
2249 dimensionSequence+inputTensorInfo.GetNumDimensions());
2250 }
2251
2252 std::vector<uint32_t> outputDims;
2253 for(unsigned int i = 0; i < inputTensorInfo.GetNumDimensions(); i++)
2254 {
2255 bool skipSqueeze = (std::find(squeezeDims.begin(), squeezeDims.end(), i) == squeezeDims.end());
2256 auto currentDimension = inputTensorInfo.GetShape()[i];
2257 if (skipSqueeze || currentDimension != 1)
2258 {
2259 outputDims.push_back(currentDimension);
2260 }
2261 }
2262
2263 if (outputDims.size() > 4)
2264 {
2265 std::stringstream ss;
2266 ss << "Output tensor has unexpected number of dimensions:" << inputTensorInfo.GetNumDimensions()
2267 << " shape:" << inputTensorInfo.GetShape() << " "
2268 << CHECK_LOCATION().AsString();
2269 throw ParseException(ss.str());
2270 }
2271
2272 TensorShape outShape = TensorShape(static_cast<unsigned int>(outputDims.size()),
2273 outputDims.data());
2274
2275 // we need to preserve the tensor type and the quantization data as well
2276 TensorInfo outTensorInfo = inputTensorInfo;
2277 outTensorInfo.SetShape(outShape);
2278
2279 return outTensorInfo;
2280}
2281
Keith Davis0176fd82021-06-01 17:36:32 +01002282void TfLiteParserImpl::ParseShape(size_t subgraphIndex, size_t operatorIndex)
2283{
2284 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2285
2286 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2287 CHECK_VALID_SIZE(inputs.size(), 1);
2288 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2289 CHECK_VALID_SIZE(outputs.size(), 1);
2290
2291 auto layerName = fmt::format("Shape:{}:{}", subgraphIndex, operatorIndex);
2292
2293 IConnectableLayer* layer = m_Network->AddShapeLayer(layerName.c_str());
2294 ARMNN_ASSERT(layer != nullptr);
2295
Mike Kelly377fb212023-01-10 15:55:28 +00002296 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Keith Davis0176fd82021-06-01 17:36:32 +01002297 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2298
2299 // Check if output tensor type is Signed32 or Signed64
2300 if (outputTensorInfo.GetDataType() != armnn::DataType::Signed32 &&
2301 outputTensorInfo.GetDataType() != armnn::DataType::Signed64)
2302 {
2303 throw ParseException(
2304 fmt::format(
2305 "Output tensor data type is not supported. (Supported types: Signed32 & Signed64) {}",
2306 CHECK_LOCATION().AsString()));
2307 }
2308
2309 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2310 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2311
2312 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2313 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2314}
2315
Kevin May7d96b162021-02-03 17:38:41 +00002316void TfLiteParserImpl::ParseSqueeze(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01002317{
2318 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2319
2320 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2321 CHECK_VALID_SIZE(inputs.size(), 1);
2322
2323 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2324 CHECK_VALID_SIZE(outputs.size(), 1);
2325
2326 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2327 const auto * options = operatorPtr->builtin_options.AsSqueezeOptions();
James Ward58dec6b2020-09-11 17:32:44 +01002328 auto layerName = fmt::format("Squeeze:{}:{}", subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01002329
Mike Kelly377fb212023-01-10 15:55:28 +00002330 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Teresa Charlin3ab85482021-06-08 16:59:29 +01002331
2332 std::vector<uint32_t> squeezeDim;
2333 // A single negative dim index is interpreted as a negative index in python
2334 // Meaning the index will be the shape size plus the negative index value
2335 if (options->squeeze_dims.size() == 1 && options->squeeze_dims[0] < 0)
2336 {
2337 int32_t dim = static_cast<int32_t>(inputTensorInfo.GetShape().GetNumDimensions()) + options->squeeze_dims[0];
2338 squeezeDim.push_back(static_cast<uint32_t>(dim));
2339 }
2340 else
2341 {
2342 squeezeDim = AsUnsignedVector(options->squeeze_dims);
2343 }
2344
2345 armnn::TensorInfo outputTensorInfo = TfLiteParserImpl::OutputShapeOfSqueeze(squeezeDim, inputTensorInfo);
2346
James Conroy05102392020-06-24 15:39:55 +01002347 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
telsoa01c577f2c2018-08-31 09:22:23 +01002348
2349 ReshapeDescriptor reshapeDesc;
2350 reshapeDesc.m_TargetShape = outputTensorInfo.GetShape();
2351
Mike Kellyb2293702023-02-14 17:16:12 +00002352 auto outputTensorIds = GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex);
2353 m_TensorInfos[outputTensorIds[0]] = outputTensorInfo;
2354
telsoa01c577f2c2018-08-31 09:22:23 +01002355 IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002356 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01002357 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2358
2359 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2360 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2361
2362 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2363 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2364}
2365
Kevin May7d96b162021-02-03 17:38:41 +00002366void TfLiteParserImpl::ParseStridedSlice(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002367{
2368 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2369
2370 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2371 CHECK_VALID_SIZE(inputs.size(), 4);
2372
2373 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2374 CHECK_VALID_SIZE(outputs.size(), 1);
2375
Mike Kelly0d77ae12022-01-07 17:42:27 +00002376 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2377 const auto* options = operatorPtr->builtin_options.AsStridedSliceOptions();
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002378
2379 StridedSliceDescriptor desc;
2380 desc.m_BeginMask = options->begin_mask;
2381 desc.m_EllipsisMask = options->ellipsis_mask;
2382 desc.m_EndMask = options->end_mask;
2383 desc.m_NewAxisMask = options->new_axis_mask;
2384 desc.m_ShrinkAxisMask = options->shrink_axis_mask;
2385 desc.m_DataLayout = armnn::DataLayout::NHWC;
2386
Mike Kelly377fb212023-01-10 15:55:28 +00002387 armnn::TensorInfo beginTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002388 BufferRawPtr beginBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2389
2390 std::vector<int> begin(beginTensorInfo.GetNumElements());
2391 ::memcpy(begin.data(), beginBufferPtr->data.data(), beginTensorInfo.GetNumBytes());
2392
Mike Kelly377fb212023-01-10 15:55:28 +00002393 armnn::TensorInfo endTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002394 BufferRawPtr endBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
2395
2396 std::vector<int> end(endTensorInfo.GetNumElements());
2397 ::memcpy(end.data(), endBufferPtr->data.data(), endTensorInfo.GetNumBytes());
2398
Mike Kelly377fb212023-01-10 15:55:28 +00002399 armnn::TensorInfo strideTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 3);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002400 BufferRawPtr strideBufferPtr = GetBuffer(m_Model, inputs[3]->buffer);
2401
2402 std::vector<int> stride(strideTensorInfo.GetNumElements());
2403 ::memcpy(stride.data(), strideBufferPtr->data.data(), strideTensorInfo.GetNumBytes());
2404
2405 desc.m_Begin = begin;
2406 desc.m_End = end;
2407 desc.m_Stride = stride;
2408
James Ward58dec6b2020-09-11 17:32:44 +01002409 auto layerName = fmt::format("StridedSlice:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002410 IConnectableLayer* layer = m_Network->AddStridedSliceLayer(desc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002411 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002412
Mike Kelly377fb212023-01-10 15:55:28 +00002413 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002414 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2415
2416 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2417 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2418
2419 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2420 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2421}
2422
Kevin May7d96b162021-02-03 17:38:41 +00002423void TfLiteParserImpl::ParseSub(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002424{
2425 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2426
Mike Kelly0d77ae12022-01-07 17:42:27 +00002427 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2428 const auto* options = operatorPtr->builtin_options.AsSubOptions();
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002429
2430 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2431 CHECK_VALID_SIZE(inputs.size(), 2);
2432
2433 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2434 CHECK_VALID_SIZE(outputs.size(), 1);
2435
Mike Kelly377fb212023-01-10 15:55:28 +00002436 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2437 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002438
James Ward58dec6b2020-09-11 17:32:44 +01002439 auto layerName = fmt::format("Sub:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +00002440 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Sub, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002441 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002442
Mike Kelly377fb212023-01-10 15:55:28 +00002443 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002444 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2445
2446 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002447 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Teresa Charlind04873f2023-05-23 14:16:28 +01002448 if (options)
2449 {
2450 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2451 }
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002452
2453 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2454 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2455}
2456
Kevin May7d96b162021-02-03 17:38:41 +00002457void TfLiteParserImpl::ParseDiv(size_t subgraphIndex, size_t operatorIndex)
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302458{
2459 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2460
Mike Kelly0d77ae12022-01-07 17:42:27 +00002461 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2462 const auto* options = operatorPtr->builtin_options.AsDivOptions();
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302463
2464 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2465 CHECK_VALID_SIZE(inputs.size(), 2);
2466
2467 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2468 CHECK_VALID_SIZE(outputs.size(), 1);
2469
Mike Kelly377fb212023-01-10 15:55:28 +00002470 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2471 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302472
James Ward58dec6b2020-09-11 17:32:44 +01002473 auto layerName = fmt::format("Div:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +00002474 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Div, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002475 ARMNN_ASSERT(layer != nullptr);
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302476
Mike Kelly377fb212023-01-10 15:55:28 +00002477 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302478 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2479
2480 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002481 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Teresa Charlind04873f2023-05-23 14:16:28 +01002482 if (options)
2483 {
2484 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2485 }
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302486
2487 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2488 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2489}
2490
Teresa Charlincdbd40b2022-02-25 13:21:55 +00002491void TfLiteParserImpl::ParseFloorDiv(size_t subgraphIndex, size_t operatorIndex)
2492{
2493 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2494
2495 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2496 CHECK_VALID_SIZE(inputs.size(), 2);
2497
2498 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2499 CHECK_VALID_SIZE(outputs.size(), 1);
2500
Mike Kelly377fb212023-01-10 15:55:28 +00002501 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2502 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Teresa Charlincdbd40b2022-02-25 13:21:55 +00002503
2504 auto layerName = fmt::format("Div:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +00002505 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Div, layerName.c_str());
Teresa Charlincdbd40b2022-02-25 13:21:55 +00002506 ARMNN_ASSERT(layer != nullptr);
2507
Mike Kelly377fb212023-01-10 15:55:28 +00002508 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Teresa Charlincdbd40b2022-02-25 13:21:55 +00002509 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2510
2511 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2512 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
2513 layer = AddFusedFloorLayer(layer, 0);
2514
2515 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2516 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2517}
2518
Kevin May7d96b162021-02-03 17:38:41 +00002519void TfLiteParserImpl::ParseAdd(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002520{
2521 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2522
Mike Kelly0d77ae12022-01-07 17:42:27 +00002523 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2524 const auto* options = operatorPtr->builtin_options.AsAddOptions();
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002525
2526 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2527 CHECK_VALID_SIZE(inputs.size(), 2);
2528
2529 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2530 CHECK_VALID_SIZE(outputs.size(), 1);
2531
Mike Kelly377fb212023-01-10 15:55:28 +00002532 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2533 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves9c761a62018-12-27 14:20:35 -02002534
James Ward58dec6b2020-09-11 17:32:44 +01002535 auto layerName = fmt::format("Add:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +00002536 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Add, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002537 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002538
Mike Kelly377fb212023-01-10 15:55:28 +00002539 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002540 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2541
2542 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002543 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Teresa Charlind04873f2023-05-23 14:16:28 +01002544 if (options)
2545 {
2546 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2547 }
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002548
2549 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2550 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2551}
2552
Kevin May7d96b162021-02-03 17:38:41 +00002553void TfLiteParserImpl::ParseMul(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002554{
2555 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2556
Mike Kelly0d77ae12022-01-07 17:42:27 +00002557 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2558 const auto* options = operatorPtr->builtin_options.AsMulOptions();
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002559
2560 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2561 CHECK_VALID_SIZE(inputs.size(), 2);
2562
2563 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2564 CHECK_VALID_SIZE(outputs.size(), 1);
2565
Mike Kelly377fb212023-01-10 15:55:28 +00002566 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2567 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves9c761a62018-12-27 14:20:35 -02002568
James Ward58dec6b2020-09-11 17:32:44 +01002569 auto layerName = fmt::format("Mul:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +00002570 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Mul, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002571 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002572
Mike Kelly377fb212023-01-10 15:55:28 +00002573 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002574 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2575
2576 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002577 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Teresa Charlind04873f2023-05-23 14:16:28 +01002578 if (options)
2579 {
2580 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2581 }
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002582
2583 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2584 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2585}
2586
Kevin May7d96b162021-02-03 17:38:41 +00002587void TfLiteParserImpl::ParseMean(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002588{
2589 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2590
2591 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2592
2593 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2594 CHECK_VALID_SIZE(outputs.size(), 1);
2595
Teresa Charlin046e2cb2023-03-28 17:20:19 +01002596 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2597 TensorInfo dimTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002598
2599 armnn::MeanDescriptor desc;
Teresa Charlin046e2cb2023-03-28 17:20:19 +01002600 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2601 // Get const axis value from model and set it to descriptor.
2602 if (axisBufferPtr != nullptr)
2603 {
2604 std::vector<int32_t> axisData(dimTensorInfo.GetNumElements());
2605 ::memcpy(axisData.data(), axisBufferPtr->data.data(), dimTensorInfo.GetNumBytes());
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002606
Teresa Charlin046e2cb2023-03-28 17:20:19 +01002607 // Convert the axis to unsigned int and remove duplicates.
2608 auto rank = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
2609 std::set<unsigned int> uniqueAxis;
2610 std::transform(axisData.begin(),
2611 axisData.end(),
2612 std::inserter(uniqueAxis, uniqueAxis.begin()),
2613 [rank](int i)->unsigned int{
2614 return static_cast<uint32_t>(((i + rank) % rank)); });
2615 desc.m_Axis.assign(uniqueAxis.begin(), uniqueAxis.end());
2616 }
2617 else
2618 {
2619 for (uint32_t i = 0; i < inputTensorInfo.GetNumDimensions(); ++i)
2620 {
2621 desc.m_Axis.push_back(i);
2622 }
2623 }
2624
Sadik Armagand109a4d2020-07-28 10:42:13 +01002625 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002626
Teresa Charlin046e2cb2023-03-28 17:20:19 +01002627 desc.m_KeepDims = inputTensorInfo.GetNumDimensions() == outputTensorInfo.GetNumDimensions() ? true : false;
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002628
James Ward58dec6b2020-09-11 17:32:44 +01002629 auto layerName = fmt::format("Mean:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002630 IConnectableLayer* layer = m_Network->AddMeanLayer(desc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002631 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002632
Mike Kelly377fb212023-01-10 15:55:28 +00002633 outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002634 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2635
2636 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2637 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2638
2639 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2640 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2641}
2642
Kevin May7d96b162021-02-03 17:38:41 +00002643void TfLiteParserImpl::ParsePad(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002644{
2645 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2646
Kevin May7d96b162021-02-03 17:38:41 +00002647 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002648
Kevin May7d96b162021-02-03 17:38:41 +00002649 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002650 CHECK_VALID_SIZE(outputs.size(), 1);
2651
Mike Kelly377fb212023-01-10 15:55:28 +00002652 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2653 armnn::TensorInfo padTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002654
Mike Kelly0d77ae12022-01-07 17:42:27 +00002655 std::vector<unsigned int> padBuffer = GetUIntBuffer(padTensorInfo, m_Model, inputs[1]->buffer);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002656
2657 size_t step = 2;
2658 armnn::PadDescriptor desc;
Mike Kelly0d77ae12022-01-07 17:42:27 +00002659 auto opcode = GetOpCode(m_Model, subgraphIndex, operatorIndex);
2660
2661 if (opcode == tflite::BuiltinOperator_PAD)
Narumol Prangnawarat8719d222020-11-27 16:57:56 +00002662 {
Mike Kelly0d77ae12022-01-07 17:42:27 +00002663 CHECK_VALID_SIZE(inputs.size(), 2);
2664
2665 if (inputTensorInfo.IsQuantized())
2666 {
2667 desc.m_PadValue = static_cast<float>(inputTensorInfo.GetQuantizationOffset());
2668 }
Narumol Prangnawarat8719d222020-11-27 16:57:56 +00002669 }
Mike Kelly0d77ae12022-01-07 17:42:27 +00002670 else if (opcode == tflite::BuiltinOperator_PADV2)
2671 {
2672 CHECK_VALID_SIZE(inputs.size(), 3);
2673
Mike Kelly377fb212023-01-10 15:55:28 +00002674 armnn::TensorInfo padValueTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Mike Kelly0d77ae12022-01-07 17:42:27 +00002675
2676 if (padValueTensorInfo.GetNumElements() != 1)
2677 {
2678 ARMNN_THROW_PARSE_EXCEPTION("Multiple padding values are not supported in PADV2");
2679 }
2680 BufferRawPtr padValueBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
2681
2682 // Get the pad value from the input tensor
2683 if (padValueBufferPtr->data.size() > 0)
2684 {
2685 switch (padValueTensorInfo.GetDataType())
2686 {
2687 case armnn::DataType::Float32:
2688 {
2689 std::vector<float> padValueBuffer(padValueTensorInfo.GetNumElements());
2690 ::memcpy(padValueBuffer.data(), padValueBufferPtr->data.data(), padValueBufferPtr->data.size());
2691 desc.m_PadValue = padValueBuffer[0];
2692 break;
2693 }
2694 case armnn::DataType::QAsymmU8:
2695 {
2696 std::vector<uint8_t> padValueBuffer(padValueTensorInfo.GetNumElements());
2697 ::memcpy(padValueBuffer.data(), padValueBufferPtr->data.data(), padValueBufferPtr->data.size());
2698 desc.m_PadValue = armnn::Dequantize<uint8_t>(padValueBuffer[0],
2699 padValueTensorInfo.GetQuantizationScale(),
2700 padValueTensorInfo.GetQuantizationOffset());
2701 break;
2702 }
2703 case armnn::DataType::QAsymmS8:
2704 case armnn::DataType::QSymmS8:
2705 {
2706 std::vector<int8_t> padValueBuffer(padValueTensorInfo.GetNumElements());
2707 ::memcpy(padValueBuffer.data(), padValueBufferPtr->data.data(), padValueBufferPtr->data.size());
2708 desc.m_PadValue = armnn::Dequantize<int8_t>(padValueBuffer[0],
2709 padValueTensorInfo.GetQuantizationScale(),
2710 padValueTensorInfo.GetQuantizationOffset());
2711 break;
2712 }
2713 default: ARMNN_THROW_PARSE_EXCEPTION("Unsupported DataType");
2714 }
2715 }
2716 else if (inputTensorInfo.IsQuantized())
2717 {
2718 desc.m_PadValue = static_cast<float>(inputTensorInfo.GetQuantizationOffset());
2719 }
2720 }
2721
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002722 for (unsigned int i = 0; i < padTensorInfo.GetNumElements() / step; ++i)
2723 {
2724 desc.m_PadList.emplace_back(padBuffer[i * step], padBuffer[i * step + 1]);
2725 }
2726
Mike Kelly0d77ae12022-01-07 17:42:27 +00002727 auto layerName = (opcode == tflite::BuiltinOperator_PAD) ? fmt::format("Pad:{}:{}", subgraphIndex, operatorIndex)
2728 : fmt::format("PadV2:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01002729
2730 IConnectableLayer* layer = m_Network->AddPadLayer(desc, layerName.c_str());
2731 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00002732 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002733 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2734
2735 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2736 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2737
2738 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2739 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2740}
2741
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002742void TfLiteParserImpl::ParseMirrorPad(size_t subgraphIndex, size_t operatorIndex)
2743{
2744 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2745
2746 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2747 CHECK_VALID_SIZE(inputs.size(), 2);
2748
2749 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2750 CHECK_VALID_SIZE(outputs.size(), 1);
2751
Mike Kelly377fb212023-01-10 15:55:28 +00002752 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002753
Mike Kelly377fb212023-01-10 15:55:28 +00002754 armnn::TensorInfo padTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002755 BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2756
2757 std::vector<unsigned int> padBuffer(padTensorInfo.GetNumElements());
2758 ::memcpy(padBuffer.data(), bufferPtr->data.data(), padTensorInfo.GetNumBytes());
2759
2760 size_t step = 2;
2761 armnn::PadDescriptor desc;
2762 for (unsigned int i = 0; i < padTensorInfo.GetNumElements() / step; ++i)
2763 {
2764 desc.m_PadList.emplace_back(padBuffer[i * step], padBuffer[i * step + 1]);
2765 }
2766
2767 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2768 const auto* options = operatorPtr->builtin_options.AsMirrorPadOptions();
2769
2770 if (options->mode == tflite::MirrorPadMode_REFLECT)
2771 {
2772 desc.m_PaddingMode = PaddingMode::Reflect;
2773 }
2774 else if (options->mode == tflite::MirrorPadMode_SYMMETRIC)
2775 {
2776 desc.m_PaddingMode = PaddingMode::Symmetric;
2777 }
2778 else
2779 {
2780 ARMNN_THROW_PARSE_EXCEPTION("PaddingMode must be either REFLECT or SYMMETRIC");
2781 }
2782
2783 // If padding mode is Reflect then both paddings must be no greater than inputShape(i) - 1.
2784 // If padding mode is Symmetric then both paddings must be no greater than inputShape(i).
2785 auto inputShape = inputTensorInfo.GetShape();
2786 auto padList = desc.m_PadList;
2787
2788 const unsigned int isReflect = static_cast<unsigned int>(desc.m_PaddingMode == PaddingMode::Reflect);
2789 for(unsigned int i = 0; i < padList.size(); ++i)
2790 {
2791 if(padList.at(i).first > (inputShape[i] - isReflect) ||
2792 padList.at(i).second > (inputShape[i] - isReflect))
2793 {
2794 ARMNN_THROW_PARSE_EXCEPTION("Padding values must be less (Reflect) or "
2795 "equal (Symmetric) to the dimension size.");
2796 }
2797 }
2798
2799 auto layerName = fmt::format("MirrorPad:{}:{}", subgraphIndex, operatorIndex);
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002800
2801 IConnectableLayer* layer = m_Network->AddPadLayer(desc, layerName.c_str());
2802 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00002803 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002804 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2805
2806 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2807 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2808
2809 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2810 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2811}
2812
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002813void TfLiteParserImpl::ParsePrelu(size_t subgraphIndex, size_t operatorIndex)
2814{
2815 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2816
2817 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2818 CHECK_VALID_SIZE(inputs.size(), 2);
2819
2820 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2821 CHECK_VALID_SIZE(outputs.size(), 1);
2822
2823 auto layerName = fmt::format("Prelu:{}:{}", subgraphIndex, operatorIndex);
2824
Mike Kelly377fb212023-01-10 15:55:28 +00002825 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2826 armnn::TensorInfo alphaTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002827
2828 IConnectableLayer* layer = m_Network->AddPreluLayer(layerName.c_str());
2829 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00002830
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002831
2832 if (IsConstTensor(inputs[1]))
2833 {
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002834 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawaratbf99b5f2021-05-27 09:55:43 +01002835 armnn::IInputSlot* slot = &(layer->GetInputSlot(0));
2836 RegisterConsumerOfTensor(subgraphIndex, inputTensorIndexes[0], slot);
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002837
Mike Kelly5880b912022-01-28 16:18:54 +00002838 auto alphaTensorAndData = CreateConstTensorNonPermuted(inputs[1], alphaTensorInfo,
2839 inputTensorInfo.GetDataType());
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002840 std::string constLayerName = fmt::format("Constant:{}", inputs[1]->name);
2841 IConnectableLayer* constLayer =
Mike Kelly5880b912022-01-28 16:18:54 +00002842 m_Network->AddConstantLayer(alphaTensorAndData.first, constLayerName.c_str());
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002843 ARMNN_ASSERT(constLayer != nullptr);
2844
2845 constLayer->GetOutputSlot(0).SetTensorInfo(alphaTensorInfo);
2846 constLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1));
2847 RegisterOutputSlots(subgraphIndex,
2848 VIRTUAL_OPERATOR_ID,
2849 constLayer,
2850 { inputTensorIndexes[1] });
2851 }
2852 else
2853 {
2854 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2855 RegisterInputSlots(subgraphIndex, operatorIndex, layer, inputTensorIndexes);
2856 }
2857
Mike Kelly377fb212023-01-10 15:55:28 +00002858 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
2859 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
2860 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2861
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002862 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2863 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2864}
2865
Kevin May7d96b162021-02-03 17:38:41 +00002866void TfLiteParserImpl::ParseQuantize(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan66dedc72019-12-10 16:32:07 +00002867{
2868 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2869
2870 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2871 CHECK_VALID_SIZE(inputs.size(), 1);
2872
2873 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2874 CHECK_VALID_SIZE(outputs.size(), 1);
2875
James Ward58dec6b2020-09-11 17:32:44 +01002876 auto layerName = fmt::format("Quantize:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan66dedc72019-12-10 16:32:07 +00002877
2878 IConnectableLayer* layer = m_Network->AddQuantizeLayer(layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01002879 ARMNN_ASSERT(layer != nullptr);
Sadik Armagan66dedc72019-12-10 16:32:07 +00002880
Mike Kelly377fb212023-01-10 15:55:28 +00002881 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Sadik Armagan66dedc72019-12-10 16:32:07 +00002882 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2883
2884 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2885 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2886
2887 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2888 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2889}
Finn Williamsc42c3842019-01-22 14:18:11 +00002890
Kevin May7d96b162021-02-03 17:38:41 +00002891void TfLiteParserImpl::ParseRelu(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan58f39192018-09-17 14:14:39 +01002892{
Finn Williamsc42c3842019-01-22 14:18:11 +00002893 ParseActivation(subgraphIndex,operatorIndex, ActivationFunction::ReLu);
Sadik Armagan58f39192018-09-17 14:14:39 +01002894}
2895
Kevin May7d96b162021-02-03 17:38:41 +00002896void TfLiteParserImpl::ParseRelu6(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan58f39192018-09-17 14:14:39 +01002897{
Finn Williamsc42c3842019-01-22 14:18:11 +00002898 ParseActivation(subgraphIndex,operatorIndex, ActivationFunction::BoundedReLu);
2899}
Sadik Armagan58f39192018-09-17 14:14:39 +01002900
Kevin May7d96b162021-02-03 17:38:41 +00002901void TfLiteParserImpl::ParseLeakyRelu(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan12239e72020-05-27 11:06:17 +01002902{
Jan Eilers2f746b32020-07-28 14:00:06 +01002903 ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::LeakyReLu);
Sadik Armagan12239e72020-05-27 11:06:17 +01002904}
2905
Kevin May7d96b162021-02-03 17:38:41 +00002906void TfLiteParserImpl::ParseLogistic(size_t subgraphIndex, size_t operatorIndex)
Finn Williamsc42c3842019-01-22 14:18:11 +00002907{
2908 ParseActivation(subgraphIndex,operatorIndex,ActivationFunction::Sigmoid);
2909}
2910
Kevin May7d96b162021-02-03 17:38:41 +00002911void TfLiteParserImpl::ParseTanH(size_t subgraphIndex, size_t operatorIndex)
Nina Drozd99851762019-04-09 09:37:38 +01002912{
2913 ParseActivation(subgraphIndex,operatorIndex,ActivationFunction::TanH);
2914}
2915
Kevin May7d96b162021-02-03 17:38:41 +00002916void TfLiteParserImpl::ParseElu(size_t subgraphIndex, size_t operatorIndex)
Matthew Sloyan7515d072020-12-16 12:50:01 +00002917{
2918 ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::Elu);
2919}
2920
Kevin May7d96b162021-02-03 17:38:41 +00002921void TfLiteParserImpl::ParseHardSwish(size_t subgraphIndex, size_t operatorIndex)
Jan Eilers2f746b32020-07-28 14:00:06 +01002922{
2923 ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::HardSwish);
2924}
Finn Williamsc42c3842019-01-22 14:18:11 +00002925
Kevin May7d96b162021-02-03 17:38:41 +00002926void TfLiteParserImpl::ParseActivation(size_t subgraphIndex, size_t operatorIndex, ActivationFunction activationType)
Finn Williamsc42c3842019-01-22 14:18:11 +00002927{
2928 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00002929 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
Jan Eilers8eb25602020-03-09 12:13:48 +00002930 IgnoreUnused(operatorPtr);
Sadik Armagan58f39192018-09-17 14:14:39 +01002931
2932 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2933 CHECK_VALID_SIZE(inputs.size(), 1);
2934
2935 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2936 CHECK_VALID_SIZE(outputs.size(), 1);
2937
James Ward58dec6b2020-09-11 17:32:44 +01002938 auto layerName = fmt::format("Activation:");
Sadik Armagan58f39192018-09-17 14:14:39 +01002939 ActivationDescriptor activationDesc;
Finn Williamsc42c3842019-01-22 14:18:11 +00002940 activationDesc.m_Function = activationType;
2941
2942 switch (activationType)
2943 {
2944 case ActivationFunction::ReLu:
2945 {
James Ward58dec6b2020-09-11 17:32:44 +01002946 layerName += fmt::format("RELU:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsc42c3842019-01-22 14:18:11 +00002947 break;
2948 }
2949 case ActivationFunction::BoundedReLu:
2950 {
James Ward58dec6b2020-09-11 17:32:44 +01002951 layerName += fmt::format("RELU6:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsc42c3842019-01-22 14:18:11 +00002952 activationDesc.m_A = 6.0f;
2953 activationDesc.m_B = 0.0f;
2954 break;
2955 }
2956 case ActivationFunction::Sigmoid:
2957 {
James Ward58dec6b2020-09-11 17:32:44 +01002958 layerName += fmt::format("SIGMOID:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsc42c3842019-01-22 14:18:11 +00002959 break;
2960 }
Nina Drozd99851762019-04-09 09:37:38 +01002961 case ActivationFunction::TanH:
2962 {
James Ward58dec6b2020-09-11 17:32:44 +01002963 layerName += fmt::format("TANH:{}:{}", subgraphIndex, operatorIndex);
Nina Drozd99851762019-04-09 09:37:38 +01002964 activationDesc.m_A = 1.0f;
2965 activationDesc.m_B = 1.0f;
2966 break;
2967 }
Sadik Armagan12239e72020-05-27 11:06:17 +01002968 case ActivationFunction::LeakyReLu:
2969 {
James Ward58dec6b2020-09-11 17:32:44 +01002970 layerName += fmt::format("LEAKYRELU:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00002971 const auto* options = operatorPtr->builtin_options.AsLeakyReluOptions();
Sadik Armagan12239e72020-05-27 11:06:17 +01002972 activationDesc.m_A = options->alpha;
2973 break;
2974 }
Matthew Sloyan7515d072020-12-16 12:50:01 +00002975 case ActivationFunction::Elu:
2976 {
2977 layerName += fmt::format("ELU:{}:{}", subgraphIndex, operatorIndex);
2978 activationDesc.m_A = 1.0f;
2979 break;
2980 }
Jan Eilers2f746b32020-07-28 14:00:06 +01002981 case ActivationFunction::HardSwish:
Matthew Sloyan7515d072020-12-16 12:50:01 +00002982 {
James Ward58dec6b2020-09-11 17:32:44 +01002983 layerName += fmt::format("HARDSWISH:{}:{}", subgraphIndex, operatorIndex);
Jan Eilers2f746b32020-07-28 14:00:06 +01002984 break;
Matthew Sloyan7515d072020-12-16 12:50:01 +00002985 }
Finn Williamsc42c3842019-01-22 14:18:11 +00002986 default:
2987 {
2988 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01002989 fmt::format("Unexpected ActivationFunction[{}] when creating layerName {} ",
2990 static_cast<int>(activationType), CHECK_LOCATION().AsString()));
Finn Williamsc42c3842019-01-22 14:18:11 +00002991 }
2992 }
2993
2994 IConnectableLayer* const layer = m_Network->AddActivationLayer(activationDesc, layerName.c_str());
Sadik Armagan58f39192018-09-17 14:14:39 +01002995
Mike Kelly377fb212023-01-10 15:55:28 +00002996 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Sadik Armagan58f39192018-09-17 14:14:39 +01002997 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2998
2999 // register the input connection slots for the layer, connections are made after all layers have been created
3000 // only the tensors for the inputs are relevant, exclude the const tensors
3001 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3002 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3003
3004 // register the output connection slots for the layer, connections are made after all layers have been created
3005 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3006 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3007}
Mike Kelly0d77ae12022-01-07 17:42:27 +00003008armnn::TensorInfo TfLiteParserImpl::OutputShapeOfReshape(const armnn::TensorInfo& inputTensorInfo,
3009 const std::vector<int32_t>& targetDimsIn)
Sadikb94967b2018-09-19 15:30:00 +01003010{
3011 std::vector<unsigned int> outputDims(targetDimsIn.begin(), targetDimsIn.end());
3012 const auto stretchDim = std::find(targetDimsIn.begin(), targetDimsIn.end(), -1);
3013
3014 if (stretchDim != targetDimsIn.end())
3015 {
3016 if (std::find(std::next(stretchDim), targetDimsIn.end(), -1) != targetDimsIn.end())
3017 {
3018 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003019 fmt::format("At most one component of shape can be -1 {}", CHECK_LOCATION().AsString()));
Sadikb94967b2018-09-19 15:30:00 +01003020 }
3021
3022 auto targetNumElements =
Matthew Sloyan589e3e82020-09-11 16:17:48 +01003023 armnn::numeric_cast<unsigned int>(
Sadikb94967b2018-09-19 15:30:00 +01003024 std::accumulate(targetDimsIn.begin(), targetDimsIn.end(), -1, std::multiplies<int32_t>()));
3025
3026 auto stretchIndex = static_cast<size_t>(std::distance(targetDimsIn.begin(), stretchDim));
3027 outputDims[stretchIndex] = inputTensorInfo.GetNumElements() / targetNumElements;
3028 }
3029
3030 TensorShape outputShape = TensorShape(static_cast<unsigned int>(outputDims.size()), outputDims.data());
3031
3032 TensorInfo reshapeInfo = inputTensorInfo;
3033 reshapeInfo.SetShape(outputShape);
3034
3035 return reshapeInfo;
3036}
3037
Kevin May7d96b162021-02-03 17:38:41 +00003038void TfLiteParserImpl::ParseReshape(size_t subgraphIndex, size_t operatorIndex)
Sadikb94967b2018-09-19 15:30:00 +01003039{
3040 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3041
3042 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Sadikb94967b2018-09-19 15:30:00 +01003043
3044 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3045 CHECK_VALID_SIZE(outputs.size(), 1);
3046
Mike Kelly0d77ae12022-01-07 17:42:27 +00003047 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3048 const auto* options = operatorPtr->builtin_options.AsReshapeOptions();
James Ward58dec6b2020-09-11 17:32:44 +01003049 auto layerName = fmt::format("Reshape:{}:{}", subgraphIndex, operatorIndex);
Sadikb94967b2018-09-19 15:30:00 +01003050
Mike Kelly377fb212023-01-10 15:55:28 +00003051 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
kevmay0171972a82018-12-17 14:28:03 +00003052 armnn::TensorInfo actualOutputTensorInfo = ToTensorInfo(outputs[0]);
James Conroy05102392020-06-24 15:39:55 +01003053 CheckMatchingQuantization(inputTensorInfo, actualOutputTensorInfo, layerName, "Input 0", "Output 0");
Derek Lambertic9e52792020-03-11 11:42:26 +00003054
Jan Eilersbac9b352020-07-13 13:40:24 +01003055 // Extracting new shape for the output
3056 // There are two ways it can be passed
3057 // * First is to define the target shape in the operator built-in options
3058 // * Second is to pass it as a second input tensor
Derek Lambertic9e52792020-03-11 11:42:26 +00003059 std::vector<int32_t> targetShape;
Jan Eilersbac9b352020-07-13 13:40:24 +01003060 bool targetShapeFound = false;
3061 // Check if built-in options were given
3062 if (options != nullptr)
Derek Lambertic9e52792020-03-11 11:42:26 +00003063 {
Jan Eilersbac9b352020-07-13 13:40:24 +01003064 // make sure the parameter is given
3065 if (options->new_shape.empty() == false)
Derek Lambertic9e52792020-03-11 11:42:26 +00003066 {
Jan Eilersbac9b352020-07-13 13:40:24 +01003067 targetShape = options->new_shape;
3068 targetShapeFound = true;
Derek Lambertif4a953f2020-03-17 14:25:57 +00003069 }
Derek Lambertic9e52792020-03-11 11:42:26 +00003070 }
Jan Eilersbac9b352020-07-13 13:40:24 +01003071
3072 // If there is no built-in option given or if the built-in new_shape parameter was empty
3073 if (!targetShapeFound)
Derek Lambertic9e52792020-03-11 11:42:26 +00003074 {
Teresa Charlin6a056a42021-12-01 10:25:43 +00003075 // Check for a second input tensor
3076 if (inputs.size() > 1 && inputs[1] != nullptr)
Jan Eilersbac9b352020-07-13 13:40:24 +01003077 {
3078 if (inputs[1]->is_variable)
3079 {
3080 ARMNN_THROW_PARSE_EXCEPTION( "Target shapes defined in non-const input tensors is not supported");
3081 }
3082
3083 if (inputs[1]->shape.size() != 1)
3084 {
3085 ARMNN_THROW_PARSE_EXCEPTION("Target 'shape' input is not a 1D tensor");
3086 }
3087
3088 if (inputs[1]->type != tflite::TensorType_INT32)
3089 {
3090 ARMNN_THROW_PARSE_EXCEPTION("Target 'shape' input is not an int32 type");
3091 }
3092
Teresa Charlin6a056a42021-12-01 10:25:43 +00003093 // Extract target shape from input
3094 auto bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
3095 auto values = reinterpret_cast<const int32_t*>(bufferPtr->data.data());
Cathal Corbettd2f73232021-12-10 13:38:52 +00003096 if (values)
Sadik Armagan19a1c032021-01-20 12:17:00 +00003097 {
Cathal Corbettd2f73232021-12-10 13:38:52 +00003098 for (int i = 0; i < inputs[1]->shape[0]; ++i)
3099 {
3100 targetShape.push_back(values[i]);
3101 }
Sadik Armagan19a1c032021-01-20 12:17:00 +00003102 }
Cathal Corbettd2f73232021-12-10 13:38:52 +00003103 else
Jan Eilersbac9b352020-07-13 13:40:24 +01003104 {
Cathal Corbettd2f73232021-12-10 13:38:52 +00003105 try
3106 {
3107 // We attempt to infer during Runtime.
Mike Kelly04d82292023-01-19 18:29:40 +00003108 TensorShape reshapeShapes = ToTensorInfo(inputs[1]).GetShape();
3109
3110 if (reshapeShapes[0] == actualOutputTensorInfo.GetNumDimensions())
3111 {
3112 for (unsigned int i = 0; i < actualOutputTensorInfo.GetShape().GetNumDimensions(); ++i)
3113 {
3114 targetShape.push_back(actualOutputTensorInfo.GetShape()[i]);
3115 }
3116 }
Cathal Corbettd2f73232021-12-10 13:38:52 +00003117 // The parser only supports shape (batch, -1) or (-1) for non-constant shape input.
Mike Kelly04d82292023-01-19 18:29:40 +00003118 else if (reshapeShapes[0] > 2)
Cathal Corbettd2f73232021-12-10 13:38:52 +00003119 {
3120 throw ParseException(fmt::format("Invalid input shape '{}' in Reshape layer '{}' {}. "
3121 "When inferring during runtime, the parser only supports "
3122 "shape (batch, -1) or (-1) for target shape input.",
3123 reshapeShapes[0],
3124 layerName,
3125 CHECK_LOCATION().AsString()));
3126 }
Mike Kelly04d82292023-01-19 18:29:40 +00003127 else
Cathal Corbettd2f73232021-12-10 13:38:52 +00003128 {
Mike Kelly04d82292023-01-19 18:29:40 +00003129 const int32_t numInputElements = inputTensorInfo.GetNumElements();
3130 const int32_t inputTensorShape = inputTensorInfo.GetShape()[0];
3131 if (reshapeShapes[0] == 1)
3132 {
3133 targetShape = {numInputElements};
3134 }
3135 else if (reshapeShapes[0] == 2)
3136 {
3137 targetShape = {inputTensorShape, numInputElements / inputTensorShape};
3138 }
Cathal Corbettd2f73232021-12-10 13:38:52 +00003139 }
3140 }
3141 catch (const std::exception& exc)
3142 {
3143 ARMNN_THROW_PARSE_EXCEPTION("Failed attempt to infer during runtime the target shape input for "
3144 "Reshape operation. Reshape operator target shape input buffer data "
3145 "is null. " << exc.what());
3146 }
Jan Eilersbac9b352020-07-13 13:40:24 +01003147 }
3148 }
3149 else
Derek Lambertic9e52792020-03-11 11:42:26 +00003150 {
3151 ARMNN_THROW_PARSE_EXCEPTION("Target shape not defined in reshape parameters or input tensor. "
3152 "At least one method required");
3153 }
Derek Lambertic9e52792020-03-11 11:42:26 +00003154 }
3155
kevmay0171972a82018-12-17 14:28:03 +00003156 armnn::TensorInfo reshapeOutputTensorInfo =
Kevin May7d96b162021-02-03 17:38:41 +00003157 TfLiteParserImpl::OutputShapeOfReshape(inputTensorInfo, targetShape);
Sadikb94967b2018-09-19 15:30:00 +01003158
kevmay0171972a82018-12-17 14:28:03 +00003159 // Check for valid input size and that reshape parameters equal output shape
Cathal Corbett2b922e22022-09-23 15:49:24 +01003160 // The output shape can be provided to us in 2 ways:
3161 // 1. through the normal 'shape' parameter given by outputs[indx]->shape
3162 // 2. through additional parameter 'shape_signature' given by outputs[indx]->buffer.
3163 // This parameter can sometimes contain -1 value not visible in the 'shape' parameter.
Aron Virginas-Tar70672f62019-01-23 14:00:00 +00003164 const armnn::TensorShape& reshapeOutputTensorShape = reshapeOutputTensorInfo.GetShape();
3165 if (inputs.size() > 1 && !CheckShape(reshapeOutputTensorShape, outputs[0]->shape))
kevmay0171972a82018-12-17 14:28:03 +00003166 {
Cathal Corbett2b922e22022-09-23 15:49:24 +01003167 // Attempt to extract output shape from secondary 'shape_signature'
3168 // parameter and try to CheckShape() with this param.
3169 std::vector<int32_t> secondaryOutputTargetShape = outputs[0]->shape_signature;
3170
3171 // if outputs[0]->shape_signature contain a -1 value, we need to compute its actual value
3172 // from reshape input in order to correctly verify reshape parameters equal output shape
3173 armnn::TensorInfo secondaryReshapeOutputTensorInfo =
3174 TfLiteParserImpl::OutputShapeOfReshape(inputTensorInfo, secondaryOutputTargetShape);
3175
3176 if (!CheckShape(reshapeOutputTensorShape, secondaryReshapeOutputTensorInfo.GetShape()))
3177 {
3178 std::stringstream ss;
3179 ss << "New shape defined in reshape parameters "
3180 << reshapeOutputTensorShape
3181 << " does not equal output shape "
3182 << actualOutputTensorInfo.GetShape()
3183 << ": "
3184 << CHECK_LOCATION().AsString();
3185 throw ParseException(ss.str());
3186 }
kevmay0171972a82018-12-17 14:28:03 +00003187 }
Mike Kelly377fb212023-01-10 15:55:28 +00003188 auto outputTensorIds = GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex);
kevmay0171972a82018-12-17 14:28:03 +00003189
Sadikb94967b2018-09-19 15:30:00 +01003190 ReshapeDescriptor reshapeDesc;
kevmay0171972a82018-12-17 14:28:03 +00003191 reshapeDesc.m_TargetShape = reshapeOutputTensorInfo.GetShape();
Mike Kelly377fb212023-01-10 15:55:28 +00003192 m_TensorInfos[outputTensorIds[0]] = reshapeOutputTensorInfo;
Sadikb94967b2018-09-19 15:30:00 +01003193
Sadikb94967b2018-09-19 15:30:00 +01003194 IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01003195 ARMNN_ASSERT(layer != nullptr);
kevmay0171972a82018-12-17 14:28:03 +00003196 layer->GetOutputSlot(0).SetTensorInfo(reshapeOutputTensorInfo);
Sadikb94967b2018-09-19 15:30:00 +01003197
3198 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3199 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3200
3201 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3202 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3203}
3204
Kevin May7d96b162021-02-03 17:38:41 +00003205void TfLiteParserImpl::ParseResizeBilinear(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003206{
Sadik Armagana3b31f02019-12-05 09:08:53 +00003207 ParseResize(subgraphIndex, operatorIndex, ResizeMethod::Bilinear);
3208}
3209
Kevin May7d96b162021-02-03 17:38:41 +00003210void TfLiteParserImpl::ParseResizeNearestNeighbor(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagana3b31f02019-12-05 09:08:53 +00003211{
3212 ParseResize(subgraphIndex, operatorIndex, ResizeMethod::NearestNeighbor);
3213}
3214
Kevin May7d96b162021-02-03 17:38:41 +00003215void TfLiteParserImpl::ParseResize(size_t subgraphIndex, size_t operatorIndex, ResizeMethod resizeMethod)
Sadik Armagana3b31f02019-12-05 09:08:53 +00003216{
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003217 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3218
3219 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3220 CHECK_VALID_SIZE(inputs.size(), 2);
3221
3222 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3223 CHECK_VALID_SIZE(outputs.size(), 1);
3224
Mike Kelly377fb212023-01-10 15:55:28 +00003225 armnn::TensorInfo sizeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003226
3227 // Data for the parsed tensor args (size) must be stored locally.
3228 std::vector<int32_t> sizeTensorData(sizeTensorInfo.GetNumElements());
3229
3230 BufferRawPtr sizeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
3231 ::memcpy(sizeTensorData.data(), sizeBufferPtr->data.data(), sizeTensorInfo.GetNumBytes());
3232
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01003233 ResizeDescriptor desc;
Sadik Armagana3b31f02019-12-05 09:08:53 +00003234 desc.m_Method = resizeMethod;
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003235 desc.m_TargetHeight = static_cast<uint32_t> (sizeTensorData[0]);
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01003236 desc.m_TargetWidth = static_cast<uint32_t> (sizeTensorData[1]);
3237 desc.m_DataLayout = armnn::DataLayout::NHWC;
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003238
James Ward58dec6b2020-09-11 17:32:44 +01003239 auto layerName = fmt::format("Resize:");
Sadik Armagana3b31f02019-12-05 09:08:53 +00003240
3241 switch (resizeMethod)
3242 {
3243 case ResizeMethod::Bilinear:
3244 {
James Ward58dec6b2020-09-11 17:32:44 +01003245 layerName += fmt::format("BILINEAR:{}:{}", subgraphIndex, operatorIndex);
Sang-Hoon Park820eb142020-01-08 10:25:24 +00003246
3247 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3248 const auto * options = operatorPtr->builtin_options.AsResizeBilinearOptions();
3249
David Monahan4a0c9b92020-05-30 09:48:39 +01003250 desc.m_AlignCorners = options->align_corners;
Sadik Armagana3b31f02019-12-05 09:08:53 +00003251 break;
3252 }
3253 case ResizeMethod::NearestNeighbor:
3254 {
James Ward58dec6b2020-09-11 17:32:44 +01003255 layerName += fmt::format("NEARESTNEIGHBOR:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagana3b31f02019-12-05 09:08:53 +00003256 break;
3257 }
3258 default:
3259 {
3260 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003261 fmt::format("Unexpected ResizeMethod[{}] when creating layerName {} ",
3262 static_cast<int>(resizeMethod), CHECK_LOCATION().AsString()));
Sadik Armagana3b31f02019-12-05 09:08:53 +00003263 }
3264 }
3265
Mike Kelly377fb212023-01-10 15:55:28 +00003266 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
James Conroy05102392020-06-24 15:39:55 +01003267
3268 IConnectableLayer* layer = m_Network->AddResizeLayer(desc, layerName.c_str());
3269 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00003270 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
3271 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003272 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3273
3274 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3275 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3276
3277 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3278 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
3279}
3280
Tianle Chenge5a30ff2023-07-03 11:24:12 +01003281void TfLiteParserImpl::ParseReverseV2(size_t subgraphIndex, size_t operatorIndex)
3282{
3283 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3284
3285 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3286 CHECK_VALID_SIZE(inputs.size(), 2);
3287
3288 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3289 CHECK_VALID_SIZE(outputs.size(), 1);
3290
3291 auto layerName = fmt::format("ReverseV2:{}:{}", subgraphIndex, operatorIndex);
3292
3293 TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
3294 TensorInfo axisTensorInfo = ToTensorInfo(inputs[1]);
3295 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
3296
Tracy Narinebb8d7592023-07-13 16:50:54 +01003297 IConnectableLayer* layer = m_Network->AddReverseV2Layer(layerName.c_str());
Tianle Chenge5a30ff2023-07-03 11:24:12 +01003298 ARMNN_ASSERT(layer != nullptr);
3299
3300 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3301
3302 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Tracy Narinebb8d7592023-07-13 16:50:54 +01003303 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Tianle Chenge5a30ff2023-07-03 11:24:12 +01003304
3305 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3306 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3307}
3308
Kevin May7d96b162021-02-03 17:38:41 +00003309void TfLiteParserImpl::ParseConcatenation(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan479045b2018-10-01 11:51:37 +01003310{
3311 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3312
Mike Kelly0d77ae12022-01-07 17:42:27 +00003313 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3314 const auto* options = operatorPtr->builtin_options.AsConcatenationOptions();
Sadik Armagan479045b2018-10-01 11:51:37 +01003315
3316 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
3317
3318 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3319 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Mike Kelly377fb212023-01-10 15:55:28 +00003320 auto inputTensorIds = GetInputTensorIds(m_Model, subgraphIndex, operatorIndex);
3321
Sadik Armagan479045b2018-10-01 11:51:37 +01003322 CHECK_VALID_SIZE(outputs.size(), 1);
3323
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003324 unsigned int numConcatView = static_cast<unsigned int>(inputs.size());
Mike Kelly377fb212023-01-10 15:55:28 +00003325 uint32_t inputRank = InputTensorInfo(subgraphIndex, operatorIndex, 0).GetNumDimensions();
Sadik Armagan479045b2018-10-01 11:51:37 +01003326
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003327 const unsigned int concatDimInput = static_cast<unsigned int>(
Mike Kelly377fb212023-01-10 15:55:28 +00003328 (static_cast<int>(inputRank) + options->axis) % static_cast<int>(inputRank));
Sadik Armagan479045b2018-10-01 11:51:37 +01003329
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003330 OriginsDescriptor concatDescriptor(static_cast<uint32_t>(numConcatView), inputRank);
3331 concatDescriptor.SetConcatAxis(concatDimInput);
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003332 unsigned int mergeDimOrigin = 0;
Sadik Armagan479045b2018-10-01 11:51:37 +01003333
3334 for (unsigned int viewIndex = 0; viewIndex < numConcatView; ++viewIndex)
3335 {
Mike Kelly377fb212023-01-10 15:55:28 +00003336 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, viewIndex);
Sadik Armagan479045b2018-10-01 11:51:37 +01003337
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003338 // This set up concatDescriptor view origin
3339 armnnUtils::ProcessConcatInputTensorInfo(
Mike Kelly377fb212023-01-10 15:55:28 +00003340 inputTensorInfo, concatDescriptor, concatDimInput, viewIndex, mergeDimOrigin);
Sadik Armagan479045b2018-10-01 11:51:37 +01003341 }
3342
James Ward58dec6b2020-09-11 17:32:44 +01003343 auto layerName = fmt::format("Concatenation:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01003344
Jim Flynn906f9462019-05-10 13:55:21 +01003345 IConnectableLayer* layer = m_Network->AddConcatLayer(concatDescriptor, layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01003346 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00003347 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {});
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003348 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
Sadik Armagan479045b2018-10-01 11:51:37 +01003349
James Conroy05102392020-06-24 15:39:55 +01003350 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003351 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes});
Sadik Armagan479045b2018-10-01 11:51:37 +01003352
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003353 // add fused activation layer
3354 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
Sadik Armagan479045b2018-10-01 11:51:37 +01003355
Sadik Armagan479045b2018-10-01 11:51:37 +01003356 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3357 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3358}
3359
Kevin May7d96b162021-02-03 17:38:41 +00003360void TfLiteParserImpl::ParseFullyConnected(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003361{
3362 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3363
Mike Kelly0d77ae12022-01-07 17:42:27 +00003364 const auto& operatorRfr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003365 const auto options = operatorRfr->builtin_options.AsFullyConnectedOptions();
3366
3367 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
3368
3369 FullyConnectedDescriptor desc;
3370 desc.m_BiasEnabled = false;
Nattapat Chaimanowongd8eee592018-10-26 10:24:14 +01003371 desc.m_TransposeWeightMatrix = true;
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003372
3373 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3374 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3375 CHECK_VALID_SIZE(outputs.size(), 1);
3376
Mike Kelly377fb212023-01-10 15:55:28 +00003377 armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003378
3379 // Fully Connected Layer accepts two dimensional weights input
3380 int32_t weightsDimension = static_cast<int32_t>(filterTensorInfo.GetNumDimensions());
3381 if (weightsDimension != 2)
3382 {
3383 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003384 fmt::format("Dimension {} for Fully Connected weights is not supported by Armnn. "
3385 "Node {}",
3386 weightsDimension,
3387 CHECK_LOCATION().AsString()));
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003388 }
3389
Matthew Jackson74bf7da2019-08-16 16:51:42 +01003390 armnn::IConnectableLayer* layer = nullptr;
James Ward58dec6b2020-09-11 17:32:44 +01003391 auto layerName = fmt::format("FullyConnected:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003392
Matthew Sloyan81beae32021-07-13 19:46:11 +01003393 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3394 // Add the first input tensor to the registration list
3395 std::vector<unsigned int> tensorIndexesToRegister = {inputTensorIndexes[0]};
Mike Kelly377fb212023-01-10 15:55:28 +00003396 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Finn Williamsd4fa5452021-03-01 12:31:41 +00003397
3398 desc.m_ConstantWeights = IsConstTensor(inputs[1]);
3399
Matthew Sloyan81beae32021-07-13 19:46:11 +01003400 // Add the weights input to the registration list, constant layers will be added by SetupConstantLayers if constant.
3401 tensorIndexesToRegister.emplace_back(inputTensorIndexes[1]);
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003402
Mike Kelly0506ef02023-01-03 16:29:44 +00003403 if (ShouldConstantTensorBeConverted(inputs[1], inputTensorInfo.GetDataType(), filterTensorInfo.GetDataType()))
Mike Kelly5880b912022-01-28 16:18:54 +00003404 {
3405 m_ConstantsToDequantize.emplace_back(inputs[1]->buffer);
3406 }
3407
Finn Williamsd4fa5452021-03-01 12:31:41 +00003408 if (inputs.size() == 3)
3409 {
3410 desc.m_BiasEnabled = true;
Mike Kelly377fb212023-01-10 15:55:28 +00003411 armnn::TensorInfo biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Matthew Sloyan81beae32021-07-13 19:46:11 +01003412
3413 // Add the biases input to the registration list, constant layer will be added by SetupConstantLayers.
3414 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
Mike Kelly5880b912022-01-28 16:18:54 +00003415
Mike Kelly0506ef02023-01-03 16:29:44 +00003416 if (ShouldConstantTensorBeConverted(inputs[2], inputTensorInfo.GetDataType(), biasTensorInfo.GetDataType()))
Mike Kelly5880b912022-01-28 16:18:54 +00003417 {
3418 m_ConstantsToDequantize.emplace_back(inputs[2]->buffer);
3419 }
Finn Williamsd4fa5452021-03-01 12:31:41 +00003420 }
3421
Matthew Sloyan81beae32021-07-13 19:46:11 +01003422 // Filters and biases are always passed to fully connected as inputs
3423 layer = m_Network->AddFullyConnectedLayer(desc, layerName.c_str());
Finn Williamsd4fa5452021-03-01 12:31:41 +00003424
3425 ARMNN_ASSERT(layer != nullptr);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003426
Finn Williamsd4fa5452021-03-01 12:31:41 +00003427 unsigned int startingSlotIndex = 0;
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003428 if (inputTensorInfo.GetNumDimensions() > 2)
3429 {
3430 // Add reshape to flatten to 2D [batch_size, input_size],
3431 // where "input_size" corresponds to the number of inputs to the layer,
3432 // matching the second dimension of weights,
3433 // and "batch_size" is calculated by dividing the number of elements by "input_size".
3434 std::vector<unsigned int> reshapedDimensions(2);
3435 reshapedDimensions[1] = filterTensorInfo.GetShape()[1];
3436 reshapedDimensions[0] = inputTensorInfo.GetNumElements() / reshapedDimensions[1];
3437
3438 if (inputTensorInfo.GetNumElements() % reshapedDimensions[1] != 0)
3439 {
3440 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003441 fmt::format("Failed to deduce input tensor shape from filter size {} {}",
3442 reshapedDimensions[1],
3443 CHECK_LOCATION().AsString()));
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003444 }
3445
Mike Kelly377fb212023-01-10 15:55:28 +00003446 armnn::TensorInfo reshapedTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003447 reshapedTensorInfo.SetShape(armnn::TensorShape{ 2, reshapedDimensions.data() });
Mike Kelly377fb212023-01-10 15:55:28 +00003448 inputTensorInfo = reshapedTensorInfo;
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003449
James Ward58dec6b2020-09-11 17:32:44 +01003450 std::string reshapeLayerName = fmt::format("Reshape_for:{}", layer->GetName());
Finn Williamsd4fa5452021-03-01 12:31:41 +00003451 armnn::ReshapeDescriptor reshapeDescriptor;
3452 reshapeDescriptor.m_TargetShape = reshapedTensorInfo.GetShape();
Mike Kelly04d82292023-01-19 18:29:40 +00003453 armnn::IConnectableLayer* reshapeLayer = m_Network->AddReshapeLayer(reshapeDescriptor,
3454 reshapeLayerName.c_str());
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003455
3456 reshapeLayer->GetOutputSlot(0).SetTensorInfo(reshapedTensorInfo);
3457 reshapeLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
3458
3459 RegisterInputSlots(subgraphIndex, operatorIndex, reshapeLayer, {inputTensorIndexes[0]});
Finn Williamsd4fa5452021-03-01 12:31:41 +00003460 // Fc layer connects to the reshape layer, so we skip the first input slot when registering fc's input slots
3461 tensorIndexesToRegister.erase(tensorIndexesToRegister.begin());
3462 startingSlotIndex = 1;
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003463 }
Finn Williamsd4fa5452021-03-01 12:31:41 +00003464
3465 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister, startingSlotIndex);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003466
Mike Kelly377fb212023-01-10 15:55:28 +00003467 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromShapes(subgraphIndex, operatorIndex, layer, 0,
3468 { inputTensorInfo.GetShape(),
3469 filterTensorInfo.GetShape() });
Mike Kelly04d82292023-01-19 18:29:40 +00003470
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003471 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3472
Mike Kelly04d82292023-01-19 18:29:40 +00003473 if (outputTensorInfo.GetNumDimensions() > 2)
3474 {
3475 // Calculate reshape to flatten to 2D [batch_size, input_size]
3476 std::vector<unsigned int> reshapedDimensions(2);
3477 reshapedDimensions[1] = filterTensorInfo.GetShape()[0];
3478 reshapedDimensions[0] = outputTensorInfo.GetNumElements() / reshapedDimensions[1];
3479 armnn::TensorInfo reshapedOutputTensorInfo = outputTensorInfo;
3480 if (outputTensorInfo.GetNumElements() % reshapedDimensions[1] != 0)
3481 {
3482 throw ParseException(
3483 fmt::format("Failed to deduce output tensor shape from filter size {} {}",
3484 reshapedDimensions[1],
3485 CHECK_LOCATION().AsString()));
3486 }
3487 reshapedOutputTensorInfo.SetShape(armnn::TensorShape{ 2, reshapedDimensions.data() });
3488 layer->GetOutputSlot(0).SetTensorInfo(reshapedOutputTensorInfo);
3489
3490 std::string reshapeLayerName = fmt::format("ExpandDims:{}:{}", subgraphIndex, operatorIndex);
3491 layer = AddReshapeLayer(layer, 0, reshapeLayerName, outputTensorInfo);
3492 }
3493
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003494 // we need to add the activation layer and fortunately we don't need to care about the data layout
3495 armnn::IConnectableLayer* fusedActivationLayer = AddFusedActivationLayer(layer, 0,
3496 options->fused_activation_function);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003497
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003498 // register the output connection slots for the layer, connections are made after all layers have been created
3499 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3500 RegisterOutputSlots(subgraphIndex, operatorIndex, fusedActivationLayer, {outputTensorIndexes[0]});
Mike Kelly04d82292023-01-19 18:29:40 +00003501
3502 m_TensorInfos[outputTensorIndexes[0]] = layer->GetOutputSlot(0).GetTensorInfo();
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003503}
3504
Kevin May7d96b162021-02-03 17:38:41 +00003505void TfLiteParserImpl::ParseDetectionPostProcess(size_t subgraphIndex, size_t operatorIndex)
keidav011b3e2ea2019-02-21 10:07:37 +00003506{
3507 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3508
Mike Kelly0d77ae12022-01-07 17:42:27 +00003509 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
keidav011b3e2ea2019-02-21 10:07:37 +00003510
3511 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3512 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3513 CHECK_VALID_SIZE(outputs.size(), 4);
3514
3515 // Obtain custom options from flexbuffers
3516 auto custom_options = operatorPtr->custom_options;
3517 const flexbuffers::Map& m = flexbuffers::GetRoot(custom_options.data(), custom_options.size()).AsMap();
3518
3519 // Obtain descriptor information from tf lite
3520 DetectionPostProcessDescriptor desc;
3521 desc.m_MaxDetections = m["max_detections"].AsUInt32();
3522 desc.m_MaxClassesPerDetection = m["max_classes_per_detection"].AsUInt32();
3523 desc.m_NmsScoreThreshold = m["nms_score_threshold"].AsFloat();
3524 desc.m_NmsIouThreshold = m["nms_iou_threshold"].AsFloat();
3525 desc.m_NumClasses = m["num_classes"].AsUInt32();
3526 desc.m_ScaleH = m["h_scale"].AsFloat();
3527 desc.m_ScaleW = m["w_scale"].AsFloat();
3528 desc.m_ScaleX = m["x_scale"].AsFloat();
3529 desc.m_ScaleY = m["y_scale"].AsFloat();
3530
keidav0107d58c72019-02-26 11:57:39 +00003531 if (!(m["use_regular_nms"].IsNull()))
keidav011b3e2ea2019-02-21 10:07:37 +00003532 {
keidav0107d58c72019-02-26 11:57:39 +00003533 desc.m_UseRegularNms = m["use_regular_nms"].AsBool();
keidav011b3e2ea2019-02-21 10:07:37 +00003534 }
3535 if (!(m["detections_per_class"].IsNull()))
3536 {
3537 desc.m_DetectionsPerClass = m["detections_per_class"].AsUInt32();
3538 }
3539
3540 if (desc.m_NmsIouThreshold <= 0.0f || desc.m_NmsIouThreshold > 1.0f)
3541 {
3542 throw InvalidArgumentException("DetectionPostProcessTFLiteParser: Intersection over union threshold "
3543 "must be positive and less than or equal to 1.");
3544 }
3545
Mike Kelly377fb212023-01-10 15:55:28 +00003546 armnn::TensorInfo anchorTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Finn Williamsd4fa5452021-03-01 12:31:41 +00003547 auto anchorTensorAndData = CreateConstTensorNonPermuted(inputs[2], anchorTensorInfo);
keidav011b3e2ea2019-02-21 10:07:37 +00003548
James Ward58dec6b2020-09-11 17:32:44 +01003549 auto layerName = fmt::format("DetectionPostProcess:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsd4fa5452021-03-01 12:31:41 +00003550 IConnectableLayer* layer = m_Network->AddDetectionPostProcessLayer(desc, anchorTensorAndData,
keidav011b3e2ea2019-02-21 10:07:37 +00003551 layerName.c_str());
3552
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01003553 ARMNN_ASSERT(layer != nullptr);
keidav011b3e2ea2019-02-21 10:07:37 +00003554
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00003555 // The model does not specify the output shapes.
3556 // The output shapes are calculated from the max_detection and max_classes_per_detection.
3557 unsigned int numDetectedBox = desc.m_MaxDetections * desc.m_MaxClassesPerDetection;
Mike Kelly377fb212023-01-10 15:55:28 +00003558 m_OverriddenOutputShapes.push_back({ 1, numDetectedBox, 4 });
3559 m_OverriddenOutputShapes.push_back({ 1, numDetectedBox });
3560 m_OverriddenOutputShapes.push_back({ 1, numDetectedBox });
3561 m_OverriddenOutputShapes.push_back({ 1 });
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00003562
keidav011b3e2ea2019-02-21 10:07:37 +00003563 for (unsigned int i = 0 ; i < outputs.size() ; ++i)
3564 {
Mike Kelly377fb212023-01-10 15:55:28 +00003565 armnn::TensorInfo detectionBoxOutputTensorInfo = ToTensorInfo(outputs[i], m_OverriddenOutputShapes[i]);
keidav011b3e2ea2019-02-21 10:07:37 +00003566 layer->GetOutputSlot(i).SetTensorInfo(detectionBoxOutputTensorInfo);
3567 }
3568
3569 // Register the input connection slots for the layer, connections are made after all layers have been created
3570 // only the tensors for the inputs are relevant, exclude the const tensors
3571 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3572 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
3573
3574 // Register the output connection slots for the layer, connections are made after all layers have been created
3575 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3576 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0],
3577 outputTensorIndexes[1],
3578 outputTensorIndexes[2],
3579 outputTensorIndexes[3]});
3580}
3581
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003582/// The TfLite Pack operator is equivalent to the ArmNN Stack operator
Kevin May7d96b162021-02-03 17:38:41 +00003583void TfLiteParserImpl::ParsePack(size_t subgraphIndex, size_t operatorIndex)
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003584{
3585 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3586
3587 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3588 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3589 CHECK_VALID_SIZE(outputs.size(), 1);
3590
3591 if (inputs.size() < 1)
3592 {
3593 throw ParseException("Pack must have at least one input.");
3594 }
3595
3596 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3597 const auto* options = operatorPtr->builtin_options.AsPackOptions();
3598
3599 StackDescriptor desc;
3600 desc.m_Axis = static_cast<uint32_t>(options->axis);
3601 desc.m_NumInputs = static_cast<uint32_t>(inputs.size());
3602
3603 // Use the tensor shape of the first input as the "correct" input shape in the descriptor
Mike Kelly377fb212023-01-10 15:55:28 +00003604 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003605 desc.m_InputShape = inputTensorInfo.GetShape();
3606
James Ward58dec6b2020-09-11 17:32:44 +01003607 auto layerName = fmt::format("Pack:{}:{}", subgraphIndex, operatorIndex);
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003608 IConnectableLayer* layer = m_Network->AddStackLayer(desc, layerName.c_str());
3609
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01003610 ARMNN_ASSERT(layer != nullptr);
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003611
Mike Kelly377fb212023-01-10 15:55:28 +00003612 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {});
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003613 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3614
3615 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3616 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes});
3617
3618 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3619 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3620}
3621
Mike Kelly5880b912022-01-28 16:18:54 +00003622void TfLiteParserImpl::ParseUnidirectionalSequenceLSTM(size_t subgraphIndex, size_t operatorIndex)
3623{
3624 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3625
3626 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3627 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3628
3629 if (inputs.size() < 2)
3630 {
3631 throw ParseException("UnidirectionalSequenceLSTM must have at least 2 input.");
3632 }
3633
3634 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3635 const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex];
3636 const auto nodeParams = operatorPtr->builtin_options.AsUnidirectionalSequenceLSTMOptions();
3637 CHECK_SUPPORTED_FUSED_ACTIVATION(nodeParams, subgraphIndex, operatorIndex);
Mike Kelly377fb212023-01-10 15:55:28 +00003638 auto inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Mike Kelly5880b912022-01-28 16:18:54 +00003639 auto outputTensorInfo = ToTensorInfo(outputs[0]);
3640
3641 // Set the params structure for the AddUnidirectionalSequenceLstmLayer call
3642 // Please refer to each operand at
3643 // https://www.tensorflow.org/mlir/tfl_ops#tflunidirectional_sequence_lstm_tflunidirectionalsequencelstmop
3644 armnn::LstmInputParams params;
3645
3646 if (IsOptionalOperandPresent(operatorPtr->inputs[1]))
3647 {
3648 params.m_InputToInputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[1]].get(),
3649 inputTensorInfo).first;
3650 }
3651
3652 params.m_InputToForgetWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[2]].get(),
3653 inputTensorInfo).first;
3654 params.m_InputToCellWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[3]].get(),
3655 inputTensorInfo).first;
3656 params.m_InputToOutputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[4]].get(),
3657 inputTensorInfo).first;
3658
3659 // Recurrent weight tensors of size {n_cell, n_output}
3660 if (IsOptionalOperandPresent(operatorPtr->inputs[5]))
3661 {
3662 params.m_RecurrentToInputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[5]].get(),
3663 inputTensorInfo).first;
3664 }
3665
3666 params.m_RecurrentToForgetWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[6]].get(),
3667 inputTensorInfo).first;
3668 params.m_RecurrentToCellWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[7]].get(),
3669 inputTensorInfo).first;
3670 params.m_RecurrentToOutputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[8]].get(),
3671 inputTensorInfo).first;
3672
3673 // Peephole weights tensors of size {n_cell}, representing a diagonal matrix.
3674 if (IsOptionalOperandPresent(operatorPtr->inputs[9]))
3675 {
3676 params.m_CellToInputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[9]].get(),
3677 inputTensorInfo).first;
3678 }
3679
3680 if (IsOptionalOperandPresent(operatorPtr->inputs[10]))
3681 {
3682 params.m_CellToForgetWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[10]].get(),
3683 inputTensorInfo).first;
3684 }
3685
3686 if (IsOptionalOperandPresent(operatorPtr->inputs[11]))
3687 {
3688 params.m_CellToOutputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[11]].get(),
3689 inputTensorInfo).first;
3690 }
3691
3692 // Gates bias tensors of size {n_cell}
3693 if (IsOptionalOperandPresent(operatorPtr->inputs[12]))
3694 {
3695 params.m_InputGateBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[12]].get(),
3696 inputTensorInfo).first;
3697 }
3698
3699 params.m_ForgetGateBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[13]].get(),
3700 inputTensorInfo).first;
3701 params.m_CellBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[14]].get(),
3702 inputTensorInfo).first;
3703 params.m_OutputGateBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[15]].get(),
3704 inputTensorInfo).first;
3705
3706 // Projection weight tensor of size {n_output, n_cell}
3707 if (IsOptionalOperandPresent(operatorPtr->inputs[16]))
3708 {
3709 params.m_ProjectionWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[16]].get(),
3710 inputTensorInfo).first;
3711 }
3712 // Projection bias tensor of size {n_output}
3713 if (IsOptionalOperandPresent(operatorPtr->inputs[17]))
3714 {
3715 params.m_ProjectionBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[17]].get(),
3716 inputTensorInfo).first;
3717 }
3718
3719 // These state tensors are defined as variable tensors, and will be modified by this op.
3720 armnn::TensorInfo outputStateInInfo = ToTensorInfo(subgraphPtr->tensors[operatorPtr->inputs[18]].get());
3721 m_ConstantsToBeCreated.push_back(operatorPtr->inputs[18]);
3722 armnn::TensorInfo cellStateInInfo = ToTensorInfo(subgraphPtr->tensors[operatorPtr->inputs[19]].get());
3723 m_ConstantsToBeCreated.push_back(operatorPtr->inputs[19]);
3724
3725 // Layer norm coefficient tensors of size {n_cell}, representing a diagonal matrix.
3726 if (inputs.size() >= 21 && IsOptionalOperandPresent(operatorPtr->inputs[20]))
3727 {
3728 params.m_InputLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[20]].get(),
3729 inputTensorInfo).first;
3730 }
3731
3732 if (inputs.size() >= 22 && IsOptionalOperandPresent(operatorPtr->inputs[21]))
3733 {
3734 params.m_ForgetLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[21]].get(),
3735 inputTensorInfo).first;
3736 }
3737
3738 if (inputs.size() >= 23 && IsOptionalOperandPresent(operatorPtr->inputs[22]))
3739 {
3740 params.m_CellLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[22]].get(),
3741 inputTensorInfo).first;
3742 }
3743
3744 if (inputs.size() >= 24 && IsOptionalOperandPresent(operatorPtr->inputs[23]))
3745 {
3746 params.m_OutputLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[23]].get(),
3747 inputTensorInfo).first;
3748 }
3749
3750 // set the layer descriptor
3751 armnn::UnidirectionalSequenceLstmDescriptor desc;
3752 desc.m_ActivationFunc = nodeParams->fused_activation_function;
3753 desc.m_ClippingThresCell = nodeParams->cell_clip;
3754 desc.m_ClippingThresProj = nodeParams->proj_clip;
3755 desc.m_CifgEnabled = (params.m_InputToInputWeights == nullptr
3756 || params.m_RecurrentToInputWeights == nullptr
3757 || params.m_InputGateBias == nullptr);
3758 desc.m_PeepholeEnabled = (params.m_CellToForgetWeights != nullptr || params.m_CellToOutputWeights != nullptr);
3759 desc.m_ProjectionEnabled = (params.m_ProjectionWeights != nullptr);
3760 desc.m_LayerNormEnabled = (params.m_InputLayerNormWeights != nullptr
3761 || params.m_ForgetLayerNormWeights != nullptr
3762 || params.m_CellLayerNormWeights != nullptr
3763 || params.m_OutputLayerNormWeights != nullptr);
3764 desc.m_TimeMajor = nodeParams->time_major;
3765
Mike Kellyc0800a32022-06-15 10:57:52 +01003766 if (operatorPtr->intermediates.size() > 3 && desc.m_LayerNormEnabled)
Mike Kelly5880b912022-01-28 16:18:54 +00003767 {
3768 auto inputIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[0]].get(),
3769 inputTensorInfo).first;
3770 auto inputIntermediateTensorInfo = inputIntermediate->GetInfo();
3771 desc.m_InputIntermediateScale = inputIntermediateTensorInfo.GetQuantizationScale();
3772
3773 auto forgetIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[1]].get(),
3774 inputTensorInfo).first;
3775 auto forgetIntermediateTensorInfo = forgetIntermediate->GetInfo();
3776 desc.m_ForgetIntermediateScale = forgetIntermediateTensorInfo.GetQuantizationScale();
3777
3778 auto cellIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[2]].get(),
3779 inputTensorInfo).first;
3780 auto cellIntermediateTensorInfo = cellIntermediate->GetInfo();
3781 desc.m_CellIntermediateScale = cellIntermediateTensorInfo.GetQuantizationScale();
3782
3783 auto outputIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[3]].get(),
3784 inputTensorInfo).first;
3785 auto outputIntermediateTensorInfo = outputIntermediate->GetInfo();
3786 desc.m_OutputIntermediateScale = outputIntermediateTensorInfo.GetQuantizationScale();
3787 }
3788 else
3789 {
3790 float defaultIntermediate = std::pow(2, -12);
3791 desc.m_InputIntermediateScale = defaultIntermediate;
3792 desc.m_ForgetIntermediateScale = defaultIntermediate;
3793 desc.m_CellIntermediateScale = defaultIntermediate;
3794 desc.m_OutputIntermediateScale = defaultIntermediate;
3795 }
3796
Mike Kellyc0800a32022-06-15 10:57:52 +01003797 if (operatorPtr->intermediates.size() > 4)
3798 {
3799 auto hiddentensor = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[4]].get(),
3800 inputTensorInfo).first;
Mike Kelly5880b912022-01-28 16:18:54 +00003801
Mike Kellyc0800a32022-06-15 10:57:52 +01003802 desc.m_HiddenStateScale = hiddentensor->GetInfo().GetQuantizationScale();
3803 desc.m_HiddenStateZeroPoint = hiddentensor->GetInfo().GetQuantizationOffset();
3804 }
Mike Kelly5880b912022-01-28 16:18:54 +00003805 unsigned int batchSize = inputTensorInfo.GetShape()[0];
3806 unsigned int outputSize = outputTensorInfo.GetShape()[2];
3807 unsigned int numUnits = cellStateInInfo.GetShape()[1];
3808
3809 armnn::DataType dataType = inputTensorInfo.GetDataType();
3810 float qScale = inputTensorInfo.GetQuantizationScale();
3811 float qOffset = inputTensorInfo.GetQuantizationOffset();
3812
3813 armnn::TensorInfo scratchBufferTensorInfo({batchSize, numUnits * 3}, dataType, qScale, qOffset);
3814 if (!desc.m_CifgEnabled)
3815 {
3816 scratchBufferTensorInfo = armnn::TensorInfo({batchSize, numUnits * 4}, dataType, qScale, qOffset);
3817 }
3818 armnn::TensorInfo cellStateOutTensorInfo({batchSize, numUnits},
3819 cellStateInInfo.GetDataType(),
3820 cellStateInInfo.GetQuantizationScale(),
3821 cellStateInInfo.GetQuantizationOffset());
3822 armnn::TensorInfo outputStateOutTensorInfo({batchSize, outputSize}, dataType, qScale, qOffset);
3823
3824 armnn::LstmInputParamsInfo paramsInfo;
3825 paramsInfo.m_InputToForgetWeights = &(params.m_InputToForgetWeights->GetInfo());
3826 paramsInfo.m_InputToCellWeights = &(params.m_InputToCellWeights->GetInfo());
3827 paramsInfo.m_InputToOutputWeights = &(params.m_InputToOutputWeights->GetInfo());
3828 paramsInfo.m_RecurrentToForgetWeights = &(params.m_RecurrentToForgetWeights->GetInfo());
3829 paramsInfo.m_RecurrentToCellWeights = &(params.m_RecurrentToCellWeights->GetInfo());
3830 paramsInfo.m_RecurrentToOutputWeights = &(params.m_RecurrentToOutputWeights->GetInfo());
3831 paramsInfo.m_ForgetGateBias = &(params.m_ForgetGateBias->GetInfo());
3832 paramsInfo.m_CellBias = &(params.m_CellBias->GetInfo());
3833 paramsInfo.m_OutputGateBias = &(params.m_OutputGateBias->GetInfo());
3834
3835 if (!desc.m_CifgEnabled)
3836 {
3837 paramsInfo.m_InputToInputWeights = &(params.m_InputToInputWeights->GetInfo());
3838 paramsInfo.m_RecurrentToInputWeights = &(params.m_RecurrentToInputWeights->GetInfo());
3839 if (params.m_CellToInputWeights != nullptr)
3840 {
3841 paramsInfo.m_CellToInputWeights = &(params.m_CellToInputWeights->GetInfo());
3842 }
3843 paramsInfo.m_InputGateBias = &(params.m_InputGateBias->GetInfo());
3844 }
3845
3846 if (desc.m_ProjectionEnabled)
3847 {
3848 paramsInfo.m_ProjectionWeights = &(params.m_ProjectionWeights->GetInfo());
3849 if (params.m_ProjectionBias != nullptr)
3850 {
3851 paramsInfo.m_ProjectionBias = &(params.m_ProjectionBias->GetInfo());
3852 }
3853 }
3854
3855 if (desc.m_PeepholeEnabled)
3856 {
3857 paramsInfo.m_CellToForgetWeights = &(params.m_CellToForgetWeights->GetInfo());
3858 paramsInfo.m_CellToOutputWeights = &(params.m_CellToOutputWeights->GetInfo());
3859 }
3860
3861 if (desc.m_LayerNormEnabled)
3862 {
3863 if(!desc.m_CifgEnabled)
3864 {
3865 paramsInfo.m_InputLayerNormWeights = &(params.m_InputLayerNormWeights->GetInfo());
3866 }
3867 paramsInfo.m_ForgetLayerNormWeights = &(params.m_ForgetLayerNormWeights->GetInfo());
3868 paramsInfo.m_CellLayerNormWeights = &(params.m_CellLayerNormWeights->GetInfo());
3869 paramsInfo.m_OutputLayerNormWeights = &(params.m_OutputLayerNormWeights->GetInfo());
3870 }
3871
3872 auto layerName = fmt::format("UnidirectionalSequenceLSTM:{}:{}", subgraphIndex, operatorIndex);
3873 armnn::IConnectableLayer* layer = m_Network->AddUnidirectionalSequenceLstmLayer(desc, params);
3874 ARMNN_ASSERT(layer != nullptr);
3875
3876 // register the input connection slots for the layer, connections are made after all layers have been created
3877 // only the tensors for the inputs are relevant, exclude the const tensors
3878 auto inputTensorIndexes = AsUnsignedVector({operatorPtr->inputs[0],
3879 operatorPtr->inputs[18],
3880 operatorPtr->inputs[19]});
3881 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0],
3882 inputTensorIndexes[1],
3883 inputTensorIndexes[2]});
3884
3885 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3886
3887 layer->GetOutputSlot(0).SetTensorInfo(outputStateOutTensorInfo);
3888 layer->GetOutputSlot(1).SetTensorInfo(cellStateOutTensorInfo);
3889 layer->GetOutputSlot(2).SetTensorInfo(outputTensorInfo);
3890
3891 unsigned int tensorIndex = outputTensorIndexes[0];
3892 armnn::IOutputSlot* slot = &(layer->GetOutputSlot(2));
3893 RegisterProducerOfTensor(subgraphIndex, tensorIndex, slot);
3894}
3895
Kevin May7d96b162021-02-03 17:38:41 +00003896void TfLiteParserImpl::ParseUnpack(size_t subgraphIndex, size_t operatorIndex)
Nina Drozd200e3802019-04-15 09:47:39 +01003897{
3898 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3899
Mike Kelly0d77ae12022-01-07 17:42:27 +00003900 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3901 const auto* options = operatorPtr->builtin_options.AsUnpackOptions();
Nina Drozd200e3802019-04-15 09:47:39 +01003902
3903 // This unpackAxis indicates the axis to unpack
3904 const unsigned int unpackAxis = CHECKED_NON_NEGATIVE(options->axis);
3905
3906 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3907 CHECK_VALID_SIZE(inputs.size(), 1);
3908
Mike Kelly377fb212023-01-10 15:55:28 +00003909 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003910
3911 if (unpackAxis >= inputTensorInfo.GetNumDimensions())
3912 {
3913 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003914 fmt::format("The unpack axis: {} cannot be greater than or equal to "
3915 "the number of input dimension {} {}",
3916 unpackAxis,
3917 inputTensorInfo.GetNumDimensions(),
3918 CHECK_LOCATION().AsString()));
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003919 }
3920
Nina Drozd200e3802019-04-15 09:47:39 +01003921 unsigned int unpackNum = CHECKED_NON_NEGATIVE(options->num);
3922 // If num is not defined, automatically infer from the length of the dimension axis.
3923 if(unpackNum == 0)
3924 {
3925 unpackNum = inputTensorInfo.GetShape()[unpackAxis];
3926 }
3927
3928 // If unpack number cannot be inferred and is still zero, throw ParseException.
3929 if(unpackNum == 0)
3930 {
3931 throw ParseException("Number to unpack must greater than zero.");
3932 }
3933
3934 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3935 CHECK_VALID_SIZE(outputs.size(), unpackNum);
3936
3937 auto inputDimSize = inputTensorInfo.GetNumDimensions();
3938 std::vector<unsigned int> unpackDimSizes(inputDimSize);
3939
3940 // Add current input shape to unpackDimSizes
3941 for (unsigned int i = 0; i < inputDimSize; ++i)
3942 {
3943 unpackDimSizes[i] = inputTensorInfo.GetShape()[i];
3944 }
3945
3946 if (unpackDimSizes[unpackAxis] != unpackNum)
3947 {
3948 throw ParseException("Number to unpack must be the same as length of the dimension to "
3949 "unpack along.");
3950 }
3951
3952 unpackDimSizes[unpackAxis] /= unpackNum;
3953
3954 SplitterDescriptor splitDesc(unpackNum, static_cast<unsigned int>(unpackDimSizes.size()));
3955 for (unsigned int j = 0; j < unpackNum; ++j)
3956 {
3957 // Set the size of the views.
3958 for (unsigned int dimIdx = 0; dimIdx < unpackDimSizes.size(); ++dimIdx)
3959 {
3960 splitDesc.SetViewSize(j, dimIdx, unpackDimSizes[dimIdx]);
3961 }
3962 splitDesc.SetViewOriginCoord(j, unpackAxis, unpackDimSizes[unpackAxis] * j);
3963 }
3964
James Ward58dec6b2020-09-11 17:32:44 +01003965 auto layerName = fmt::format("Unpack:{}:{}", subgraphIndex, operatorIndex);
Nina Drozd200e3802019-04-15 09:47:39 +01003966 IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01003967 ARMNN_ASSERT(layer != nullptr);
Nina Drozd200e3802019-04-15 09:47:39 +01003968
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003969 TensorShape splitOutShape = TensorShape(static_cast<unsigned int>(unpackDimSizes.size()),
3970 unpackDimSizes.data());
3971
Nina Drozd200e3802019-04-15 09:47:39 +01003972 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3973 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3974
Finn Williamsb49ed182021-06-29 15:50:08 +01003975 std::vector<unsigned int> reshapeDims;
3976 for (unsigned int axis = 0; axis < splitOutShape.GetNumDimensions(); ++axis)
3977 {
3978 if (axis != unpackAxis)
3979 {
3980 reshapeDims.push_back(splitOutShape[axis]);
3981 }
3982 }
3983
3984 TensorShape reshapeOutputShape(splitOutShape.GetNumDimensions() -1, reshapeDims.data());
3985
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003986 // Create reshape to remove the unpacked dimension for unpack operator of each output from Splitter.
3987 for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
3988 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01003989 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[k], true);
James Ward58dec6b2020-09-11 17:32:44 +01003990 std::string reshapeLayerName = fmt::format("Reshape_for:{}", layer->GetName());
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003991 armnn::ReshapeDescriptor desc;
Finn Williamsb49ed182021-06-29 15:50:08 +01003992 desc.m_TargetShape = reshapeOutputShape;
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003993 armnn::IConnectableLayer* reshapeLayer = m_Network->AddReshapeLayer(desc, layerName.c_str());
3994
Narumol Prangnawarat2c526462019-10-21 14:58:26 +01003995 layer->GetOutputSlot(k).SetTensorInfo(armnn::TensorInfo(splitOutShape,
3996 outputTensorInfo.GetDataType(),
3997 outputTensorInfo.GetQuantizationScale(),
3998 outputTensorInfo.GetQuantizationOffset()));
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003999 layer->GetOutputSlot(k).Connect(reshapeLayer->GetInputSlot(0));
4000
Narumol Prangnawarat2c526462019-10-21 14:58:26 +01004001 reshapeLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
Narumol Prangnawarat672de572019-04-23 15:28:06 +01004002
4003 uint32_t reshapedOutputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[k]);
4004 armnn::IOutputSlot* slot = &(reshapeLayer->GetOutputSlot(0));
4005 RegisterProducerOfTensor(subgraphIndex, reshapedOutputId, slot);
4006 }
Nina Drozd200e3802019-04-15 09:47:39 +01004007}
4008
Kevin May7d96b162021-02-03 17:38:41 +00004009void TfLiteParserImpl::ParseSplit(size_t subgraphIndex, size_t operatorIndex)
Nina Drozd0324f482019-04-08 10:52:10 +01004010{
4011 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4012
Mike Kelly0d77ae12022-01-07 17:42:27 +00004013 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4014 const auto* options = operatorPtr->builtin_options.AsSplitOptions();
Nina Drozd0324f482019-04-08 10:52:10 +01004015
4016 const unsigned int numSplits = CHECKED_NON_NEGATIVE(options->num_splits);
4017
Nina Drozd200e3802019-04-15 09:47:39 +01004018 // If number of splits cannot be inferred and is zero, throw ParseException.
4019 if(numSplits == 0)
4020 {
4021 throw ParseException("Number to splits must greater than zero.");
4022 }
4023
Nina Drozd0324f482019-04-08 10:52:10 +01004024 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4025 CHECK_VALID_SIZE(inputs.size(), 2);
4026 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4027 CHECK_VALID_SIZE(outputs.size(), numSplits);
4028
Mike Kelly377fb212023-01-10 15:55:28 +00004029 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
4030 armnn::TensorInfo axisTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004031 ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
Nina Drozd0324f482019-04-08 10:52:10 +01004032
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01004033 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[0]->buffer);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004034 if (axisBufferPtr == nullptr)
4035 {
4036 throw ParseException(
4037 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
4038 CHECK_LOCATION().AsString()));
4039 }
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01004040
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004041 std::vector<int32_t> axisData(axisTensorInfo.GetNumElements());
4042 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
4043 int32_t axis = axisData[0];
4044
4045 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
4046 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
4047 {
4048 // Square bracket denotes inclusive n while parenthesis denotes exclusive n
4049 // E.g. Rank 4 tensor can have axis in range [-4, 3)
4050 // -1 == 3, -2 == 2, -3 == 1, -4 == 0
4051 throw ParseException(
4052 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
4053 axis,
4054 CHECK_LOCATION().AsString()));
4055 }
4056
4057 const unsigned int splitDim = armnnUtils::GetUnsignedAxis(inputTensorInfo.GetNumDimensions(), axis);
Nina Drozd0324f482019-04-08 10:52:10 +01004058
Nina Drozd0324f482019-04-08 10:52:10 +01004059 auto inputDimSize = inputTensorInfo.GetNumDimensions();
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01004060 if (inputDimSize > MaxNumOfTensorDimensions)
Nina Drozd0324f482019-04-08 10:52:10 +01004061 {
4062 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01004063 fmt::format("The number of dimensions: {} for input tensors of the split op cannot be greater than {} {}",
4064 inputTensorInfo.GetNumDimensions(),
4065 MaxNumOfTensorDimensions,
4066 CHECK_LOCATION().AsString()));
Nina Drozd0324f482019-04-08 10:52:10 +01004067 }
4068
4069 std::vector<unsigned int> splitterDimSizes(inputDimSize);
4070
4071 // Add current input shape to splitterDimSizes
4072 for (unsigned int i = 0; i < inputDimSize; ++i)
4073 {
4074 splitterDimSizes[i] = inputTensorInfo.GetShape()[i];
4075 }
4076
4077 if (splitterDimSizes[splitDim] % numSplits != 0)
4078 {
4079 throw ParseException("Number of splits must evenly divide the dimension");
4080 }
4081 splitterDimSizes[splitDim] /= numSplits;
4082
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01004083 SplitterDescriptor splitDesc(numSplits, inputDimSize);
Nina Drozd0324f482019-04-08 10:52:10 +01004084 for (unsigned int j = 0; j < numSplits; ++j)
4085 {
4086 // Set the size of the views.
4087 for (unsigned int dimIdx = 0; dimIdx < splitterDimSizes.size(); ++dimIdx)
4088 {
4089 splitDesc.SetViewSize(j, dimIdx, splitterDimSizes[dimIdx]);
4090 }
4091 splitDesc.SetViewOriginCoord(j, splitDim, splitterDimSizes[splitDim] * j);
4092 }
4093
James Ward58dec6b2020-09-11 17:32:44 +01004094 auto layerName = fmt::format("Split:{}:{}", subgraphIndex, operatorIndex);
Nina Drozd0324f482019-04-08 10:52:10 +01004095 IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01004096 ARMNN_ASSERT(layer != nullptr);
Nina Drozd0324f482019-04-08 10:52:10 +01004097
4098 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01004099 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[1]});
Nina Drozd0324f482019-04-08 10:52:10 +01004100
Nina Drozd0324f482019-04-08 10:52:10 +01004101 for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
4102 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01004103 armnn::TensorInfo tensorInfo = ToTensorInfo(outputs[k], true);
Francis Murtagh98d6b3d2019-10-21 10:52:54 +01004104 layer->GetOutputSlot(k).SetTensorInfo(tensorInfo);
Nina Drozd0324f482019-04-08 10:52:10 +01004105 }
4106
4107 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4108 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4109}
4110
Derek Lambertif0176992020-04-28 13:37:49 +01004111unsigned int ComputeWrappedIndex(int idx, unsigned int numDimsIn)
4112{
4113 int numDims = armnn::numeric_cast<int>(numDimsIn);
4114 int v = idx < 0 ? numDims + idx : idx;
4115 ARMNN_ASSERT(v >= 0);
4116 ARMNN_ASSERT(v < numDims);
4117
4118 return static_cast<unsigned int>(v);
4119}
4120
Kevin May7d96b162021-02-03 17:38:41 +00004121void TfLiteParserImpl::ParseSplitV(size_t subgraphIndex, size_t operatorIndex)
Derek Lambertif0176992020-04-28 13:37:49 +01004122{
4123 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4124
Mike Kelly0d77ae12022-01-07 17:42:27 +00004125 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4126 const auto* options = operatorPtr->builtin_options.AsSplitVOptions();
Derek Lambertif0176992020-04-28 13:37:49 +01004127
4128 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4129 CHECK_VALID_SIZE(inputs.size(), 3);
4130
4131 auto& inputTensor = inputs[0];
4132 auto& splitsTensor = inputs[1];
4133 auto& axisTensor = inputs[2];
4134
4135 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputTensor);
4136 armnn::TensorInfo splitsInfo = ToTensorInfo(splitsTensor);
4137 armnn::TensorInfo axisTensorInfo = ToTensorInfo(axisTensor);
4138 ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
4139
4140 // Inputs
4141 auto inputDimSize = inputTensorInfo.GetNumDimensions();
4142 if (inputDimSize > MaxNumOfTensorDimensions)
4143 {
4144 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01004145 fmt::format("The number of dimensions: {} for input tensors of the "
4146 "SplitV op cannot be greater than {} {}",
4147 inputTensorInfo.GetNumDimensions(),
4148 MaxNumOfTensorDimensions,
4149 CHECK_LOCATION().AsString()));
Derek Lambertif0176992020-04-28 13:37:49 +01004150 }
4151
4152 // Get split axis
4153 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, axisTensor->buffer);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004154 if (axisBufferPtr == nullptr)
4155 {
4156 throw ParseException(
4157 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
4158 CHECK_LOCATION().AsString()));
4159 }
4160
Derek Lambertif0176992020-04-28 13:37:49 +01004161 std::vector<int> axisData(axisTensorInfo.GetNumElements());
4162 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004163 int32_t axis = axisData[0];
4164
4165 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
4166 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
4167 {
4168 // Square bracket denotes inclusive n while parenthesis denotes exclusive n
4169 // E.g. Rank 4 tensor can have axis in range [-4, 3)
4170 // -1 == 3, -2 == 2, -3 == 1, -4 == 0
4171 throw ParseException(
4172 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
4173 axis,
4174 CHECK_LOCATION().AsString()));
4175 }
4176 const unsigned int splitDim = ComputeWrappedIndex(axis, inputTensorInfo.GetNumDimensions());
Derek Lambertif0176992020-04-28 13:37:49 +01004177
Derek Lambertif0176992020-04-28 13:37:49 +01004178 // Set split sizes
Derek Lambertif0176992020-04-28 13:37:49 +01004179 CHECK_VALID_SIZE(splitsInfo.GetNumDimensions(), 1);
Ryan OShea86704732020-05-26 11:41:04 +01004180 unsigned int numSplits{0};
4181
4182 if(options)
Derek Lambertif0176992020-04-28 13:37:49 +01004183 {
4184 numSplits = CHECKED_NON_NEGATIVE(options->num_splits);
Derek Lambertif0176992020-04-28 13:37:49 +01004185 }
4186 else
4187 {
Ryan OShea86704732020-05-26 11:41:04 +01004188 numSplits = splitsInfo.GetNumElements();
Derek Lambertif0176992020-04-28 13:37:49 +01004189 }
4190
4191 if (numSplits <=0)
4192 {
4193 throw ParseException("SplitV has invalid number of splits");
4194 }
4195
Jan Eilersc0761e92020-06-29 16:48:44 +01004196 std::vector<int> splitsData(numSplits);
Ryan OShea86704732020-05-26 11:41:04 +01004197 BufferRawPtr splitsBufferPtr = GetBuffer(m_Model, splitsTensor->buffer);
Jan Eilersc0761e92020-06-29 16:48:44 +01004198 ::memcpy(splitsData.data(), splitsBufferPtr->data.data(), splitsInfo.GetNumBytes());
Ryan OShea86704732020-05-26 11:41:04 +01004199
Jan Eilersc0761e92020-06-29 16:48:44 +01004200 unsigned int idx = 0;
Ryan OShea86704732020-05-26 11:41:04 +01004201 int numInferred{0};
4202 unsigned int inferIdx{0};
4203 int splitSum{0};
4204 for (auto split : splitsData)
4205 {
4206 if (split < 0)
4207 {
4208 numInferred++;
4209 inferIdx = idx;
4210 }
4211 else
4212 {
4213 splitSum += split;
4214 }
4215 idx++;
4216 }
4217 // Check for inferred Axis
4218 if (numInferred == 0)
4219 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +01004220 if (splitSum != armnn::numeric_cast<int>(inputTensorInfo.GetShape()[splitDim]))
Ryan OShea86704732020-05-26 11:41:04 +01004221 {
4222 throw ParseException("SplitV split_sizes does not sum to the dimension of value along split_dim.");
4223 }
4224 }
4225 else if (numInferred == 1)
4226 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +01004227 splitsData[inferIdx] = armnn::numeric_cast<int>(inputTensorInfo.GetShape()[splitDim]) - splitSum;
Ryan OShea86704732020-05-26 11:41:04 +01004228 }
4229 else
4230 {
4231 throw ParseException("Cannot infer split size for more than one split");
4232 }
4233
Derek Lambertif0176992020-04-28 13:37:49 +01004234 //Ouput size validation
4235 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4236 CHECK_VALID_SIZE(outputs.size(), numSplits);
4237
4238 // Setup Armnn descriptor
4239 SplitterDescriptor splitDesc(numSplits, inputDimSize);
4240 unsigned int accumSplit = 0;
4241 for (unsigned int j = 0; j < numSplits; ++j)
4242 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +01004243 unsigned int splitSize = armnn::numeric_cast<unsigned int>(splitsData[j]);
Derek Lambertif0176992020-04-28 13:37:49 +01004244
4245 // Set the size of the views.
4246 for (unsigned int dimIdx = 0; dimIdx < inputTensorInfo.GetNumDimensions(); ++dimIdx)
4247 {
4248 unsigned int dimSize = inputTensorInfo.GetShape()[dimIdx];
4249 if (dimIdx == splitDim)
4250 {
4251 dimSize = splitSize;
4252 }
4253 splitDesc.SetViewSize(j, dimIdx, dimSize);
4254 }
4255
4256 splitDesc.SetViewOriginCoord(j, splitDim, accumSplit);
4257 accumSplit += splitSize;
4258 }
4259
James Ward58dec6b2020-09-11 17:32:44 +01004260 auto layerName = fmt::format("SplitV:{}:{}", subgraphIndex, operatorIndex);
Derek Lambertif0176992020-04-28 13:37:49 +01004261 IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01004262 ARMNN_ASSERT(layer != nullptr);
Derek Lambertif0176992020-04-28 13:37:49 +01004263
4264 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4265 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4266
4267 for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
4268 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01004269 armnn::TensorInfo tensorInfo = ToTensorInfo(outputs[k], true);
Derek Lambertif0176992020-04-28 13:37:49 +01004270 layer->GetOutputSlot(k).SetTensorInfo(tensorInfo);
4271 }
4272
4273 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4274 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4275}
4276
Matthew Sloyan28f177c2021-04-09 14:38:52 +01004277void TfLiteParserImpl::ParseArgMin(size_t subgraphIndex, size_t operatorIndex)
4278{
4279 ParseArgMinMax(subgraphIndex, operatorIndex, armnn::ArgMinMaxFunction::Min);
4280}
4281
Kevin May7d96b162021-02-03 17:38:41 +00004282void TfLiteParserImpl::ParseArgMax(size_t subgraphIndex, size_t operatorIndex)
Inki Daed4619e22020-09-10 15:33:54 +09004283{
Matthew Sloyan28f177c2021-04-09 14:38:52 +01004284 ParseArgMinMax(subgraphIndex, operatorIndex, armnn::ArgMinMaxFunction::Max);
4285}
4286
4287void TfLiteParserImpl::ParseArgMinMax(size_t subgraphIndex, size_t operatorIndex, ArgMinMaxFunction argMinMaxFunction)
4288{
Inki Daed4619e22020-09-10 15:33:54 +09004289 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4290 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4291 CHECK_VALID_SIZE(inputs.size(), 2);
4292
4293 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4294 CHECK_VALID_SIZE(outputs.size(), 1);
4295
Mike Kelly377fb212023-01-10 15:55:28 +00004296 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4297 armnn::TensorInfo axisTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Inki Daed4619e22020-09-10 15:33:54 +09004298 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004299 ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
Matthew Sloyan28f177c2021-04-09 14:38:52 +01004300
4301 // Check if output tensor type is Signed32 or Signed64
Mike Kelly1f140f72021-04-06 12:25:55 +01004302 if (outputTensorInfo.GetDataType() != armnn::DataType::Signed32 &&
4303 outputTensorInfo.GetDataType() != armnn::DataType::Signed64)
4304 {
4305 throw ParseException(
4306 fmt::format(
4307 "Output tensor data type is not supported. (Supported types: Signed32 & Signed64) {}",
4308 CHECK_LOCATION().AsString()));
4309 }
Matthew Sloyan28f177c2021-04-09 14:38:52 +01004310
4311 // Get const axis value from model and set it to descriptor.
4312 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
4313 if (axisBufferPtr == nullptr)
4314 {
4315 throw ParseException(
4316 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
4317 CHECK_LOCATION().AsString()));
4318 }
4319
4320 std::vector<int32_t> axisData(axisTensorInfo.GetNumElements());
4321 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
4322 int32_t axis = axisData.front();
4323
4324 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
4325 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
4326 {
4327 // Square bracket denotes inclusive n while parenthesis denotes exclusive n
4328 // E.g. Rank 4 tensor can have axis in range [-4, 3)
4329 // -1 == 3, -2 == 2, -3 == 1, -4 == 0
4330 throw ParseException(
4331 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
4332 axis,
4333 CHECK_LOCATION().AsString()));
4334 }
4335
4336 ArgMinMaxDescriptor desc;
4337 desc.m_Axis = axis;
4338 desc.m_Function = argMinMaxFunction;
4339
4340 // Register a ArgMin/ArgMax layer.
4341 auto layerName = argMinMaxFunction == ArgMinMaxFunction::Max ? "ArgMax:{}:{}" : "ArgMin:{}:{}";
4342 auto layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4343 IConnectableLayer *layer = m_Network->AddArgMinMaxLayer(desc, layerNameFormatted.c_str());
4344 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00004345 outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Inki Daed4619e22020-09-10 15:33:54 +09004346 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4347
4348 // Register input tensor to the layer.
4349 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4350 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4351
4352 // Register output tensor to the layer.
4353 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4354 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4355}
4356
Kevin May7d96b162021-02-03 17:38:41 +00004357void TfLiteParserImpl::ParseGather(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan26868492021-01-22 14:25:31 +00004358{
4359 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4360
Kevin May7d96b162021-02-03 17:38:41 +00004361 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00004362 CHECK_VALID_SIZE(inputs.size(), 2);
Kevin May7d96b162021-02-03 17:38:41 +00004363 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00004364 CHECK_VALID_SIZE(outputs.size(), 1);
4365
Mike Kelly377fb212023-01-10 15:55:28 +00004366 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4367 armnn::TensorInfo indicesTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
4368 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
Sadik Armagan26868492021-01-22 14:25:31 +00004369
4370 armnn::GatherDescriptor gatherDescriptor;
4371
Mike Kelly0d77ae12022-01-07 17:42:27 +00004372 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4373 const auto* options = operatorPtr->builtin_options.AsGatherOptions();
Sadik Armagan26868492021-01-22 14:25:31 +00004374 auto axis = options->axis;
4375
Mike Kelly377fb212023-01-10 15:55:28 +00004376 auto layerName = fmt::format("Gather:{}:{}", subgraphIndex, operatorIndex);
4377
Sadik Armagan26868492021-01-22 14:25:31 +00004378 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
4379 auto indicesDimensions = indicesTensorInfo.GetNumDimensions();
4380 auto outputDimensions = outputTensorInfo.GetNumDimensions();
4381 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
4382 {
4383 throw ParseException(
4384 fmt::format("Operation has invalid axis: {} It is out of bounds [ -{}, {} ) {}",
4385 axis,
4386 inputDimensions, inputDimensions,
4387 CHECK_LOCATION().AsString()));
4388 }
4389 if (outputDimensions != static_cast<unsigned int>(inputDimensions) + indicesDimensions - 1)
4390 {
4391 throw ParseException(
4392 fmt::format("Operation has invalid output dimensions: {} Output must be an ({} + {} - 1) -D tensor {}",
4393 outputDimensions,
4394 inputDimensions, indicesDimensions,
4395 CHECK_LOCATION().AsString()));
4396 }
4397
4398 gatherDescriptor.m_Axis = axis;
4399
Sadik Armagan26868492021-01-22 14:25:31 +00004400 IConnectableLayer* layer = m_Network->AddGatherLayer(gatherDescriptor, layerName.c_str());
4401 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00004402 outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Sadik Armagan26868492021-01-22 14:25:31 +00004403 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4404
4405 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4406 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4407
4408 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4409 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4410}
4411
Teresa Charlin91a53ea2022-04-25 15:47:29 +01004412void TfLiteParserImpl::ParseGatherNd(size_t subgraphIndex, size_t operatorIndex)
4413{
4414 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4415
4416 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4417 CHECK_VALID_SIZE(inputs.size(), 2);
4418 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4419 CHECK_VALID_SIZE(outputs.size(), 1);
4420
Mike Kelly377fb212023-01-10 15:55:28 +00004421 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4422 armnn::TensorInfo indicesTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Teresa Charlin91a53ea2022-04-25 15:47:29 +01004423
4424 auto layerName = fmt::format("GatherNd:{}:{}", subgraphIndex, operatorIndex);
4425 IConnectableLayer* layer = m_Network->AddGatherNdLayer(layerName.c_str());
4426 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00004427 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Teresa Charlin91a53ea2022-04-25 15:47:29 +01004428 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4429
4430 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4431 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4432
4433 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4434 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4435}
4436
Kevin May7d96b162021-02-03 17:38:41 +00004437void TfLiteParserImpl::ParseDepthToSpace(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan26868492021-01-22 14:25:31 +00004438{
4439 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4440
Kevin May7d96b162021-02-03 17:38:41 +00004441 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00004442 CHECK_VALID_SIZE(inputs.size(), 1);
Kevin May7d96b162021-02-03 17:38:41 +00004443 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00004444 CHECK_VALID_SIZE(outputs.size(), 1);
4445
4446 armnn::DepthToSpaceDescriptor descriptor;
4447
Mike Kelly0d77ae12022-01-07 17:42:27 +00004448 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4449 const auto* options = operatorPtr->builtin_options.AsDepthToSpaceOptions();
Sadik Armagan26868492021-01-22 14:25:31 +00004450 auto blockSize = options->block_size;
4451 if (blockSize < 2)
4452 {
4453 throw ParseException(
4454 fmt::format("Operation has invalid block size: {} Block size should be >= 2 {}",
4455 blockSize,
4456 CHECK_LOCATION().AsString()));
4457 }
4458 descriptor.m_BlockSize = armnn::numeric_cast<uint32_t>(blockSize);
4459
4460 auto layerName = fmt::format("DepthToSpace:{}:{}", subgraphIndex, operatorIndex);
4461 IConnectableLayer* layer = m_Network->AddDepthToSpaceLayer(descriptor, layerName.c_str());
4462 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00004463 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Sadik Armagan26868492021-01-22 14:25:31 +00004464 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4465
4466 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4467 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4468
4469 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4470 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4471}
4472
Kevin May7d96b162021-02-03 17:38:41 +00004473void TfLiteParserImpl::ParseSum(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004474{
Sadik Armagana2747482021-02-09 10:28:54 +00004475 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Sum);
4476}
4477
Teresa Charlin4e3e8312021-08-05 12:34:37 +01004478void TfLiteParserImpl::ParseReduceProd(size_t subgraphIndex, size_t operatorIndex)
4479{
4480 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Prod);
4481}
4482
Sadik Armagana2747482021-02-09 10:28:54 +00004483void TfLiteParserImpl::ParseReduceMax(size_t subgraphIndex, size_t operatorIndex)
4484{
4485 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Max);
4486}
4487
4488void TfLiteParserImpl::ParseReduceMin(size_t subgraphIndex, size_t operatorIndex)
4489{
4490 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Min);
4491}
4492
4493void TfLiteParserImpl::ParseReduce(size_t subgraphIndex, size_t operatorIndex, ReduceOperation reduceOperation)
4494{
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004495 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4496
Mike Kelly0d77ae12022-01-07 17:42:27 +00004497 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4498 const auto* options = operatorPtr->builtin_options.AsReducerOptions();
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004499
4500 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4501 CHECK_VALID_SIZE(inputs.size(), 2);
4502
4503 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4504 CHECK_VALID_SIZE(outputs.size(), 1);
4505
Sadik Armagana2747482021-02-09 10:28:54 +00004506 auto layerName = fmt::format("Reduce:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004507
Mike Kelly377fb212023-01-10 15:55:28 +00004508 armnn::TensorInfo inputTensorInfo0 = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4509 armnn::TensorInfo inputTensorInfo1 = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004510
4511 ReduceDescriptor desc;
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004512 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
4513 // Get const axis value from model and set it to descriptor.
4514 if (axisBufferPtr != nullptr)
4515 {
Sadik Armagan49bdb792021-02-11 13:57:07 +00004516 std::vector<int32_t> axisData(inputTensorInfo1.GetNumElements());
4517 ::memcpy(axisData.data(), axisBufferPtr->data.data(), inputTensorInfo1.GetNumBytes());
4518
4519 // Convert the axis to unsigned int and remove duplicates.
4520 auto rank = static_cast<int32_t>(inputTensorInfo0.GetNumDimensions());
4521 std::set<unsigned int> uniqueAxis;
4522 std::transform(axisData.begin(),
4523 axisData.end(),
4524 std::inserter(uniqueAxis, uniqueAxis.begin()),
4525 [rank](int i)->unsigned int{
4526 return static_cast<uint32_t>(((i + rank) % rank)); });
4527 desc.m_vAxis.assign(uniqueAxis.begin(), uniqueAxis.end());
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004528 }
Sadik Armagana2747482021-02-09 10:28:54 +00004529 else
4530 {
4531 for (uint32_t i = 0; i < inputTensorInfo0.GetNumDimensions(); ++i)
4532 {
4533 desc.m_vAxis.push_back(i);
4534 }
4535 }
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004536
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004537 desc.m_KeepDims = options->keep_dims;
Sadik Armagana2747482021-02-09 10:28:54 +00004538 desc.m_ReduceOperation = reduceOperation;
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004539
4540 // Register a new layer object, Sum.
Mike Kelly0d77ae12022-01-07 17:42:27 +00004541 IConnectableLayer* layer = m_Network->AddReduceLayer(desc, layerName.c_str());
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004542
Mike Kelly377fb212023-01-10 15:55:28 +00004543 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004544 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4545
4546 // Register input tensor to the layer.
4547 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4548 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4549
4550 // Register output tensor to the layer.
4551 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4552 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4553}
4554
Mike Kelly31dce2b2021-09-01 21:22:37 +01004555void TfLiteParserImpl::ParseLocalResponseNormalization(size_t subgraphIndex, size_t operatorIndex)
4556{
4557 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4558
4559 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4560 CHECK_VALID_SIZE(inputs.size(), 1);
4561
4562 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4563 CHECK_VALID_SIZE(outputs.size(), 1);
4564
4565 auto layerName = fmt::format("LRN:{}:{}", subgraphIndex, operatorIndex);
4566 std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4567
Mike Kelly377fb212023-01-10 15:55:28 +00004568 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Mike Kelly31dce2b2021-09-01 21:22:37 +01004569
4570 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4571 const auto* options = operatorPtr->builtin_options.AsLocalResponseNormalizationOptions();
4572
4573 armnn::NormalizationDescriptor descriptor;
4574 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
4575 descriptor.m_NormChannelType = armnn::NormalizationAlgorithmChannel::Across;
4576 descriptor.m_NormMethodType = armnn::NormalizationAlgorithmMethod::LocalBrightness;
4577 descriptor.m_NormSize = static_cast<uint32_t>(options->radius);
4578 descriptor.m_K = options->bias;
4579 descriptor.m_Alpha = options->alpha;
4580 descriptor.m_Beta = options->beta;
4581
4582 // ArmNN expects normSize to be the full size of the normalization
4583 // window rather than the radius as in TfLite.
4584 descriptor.m_NormSize = 1 + (2 * descriptor.m_NormSize);
4585
4586 IConnectableLayer* layer = m_Network->AddNormalizationLayer(descriptor, layerNameFormatted.c_str());
4587 ARMNN_ASSERT(layer != nullptr);
4588
Mike Kelly377fb212023-01-10 15:55:28 +00004589 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Mike Kelly31dce2b2021-09-01 21:22:37 +01004590 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4591
4592 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4593 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4594
4595 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4596 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4597}
4598
Teresa Charlin28aa6692022-07-12 11:18:44 +01004599void TfLiteParserImpl::ParseAbs(size_t subgraphIndex, size_t operatorIndex)
4600{
4601 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Abs);
4602}
4603
Teresa Charlin93f0ad02023-03-23 15:28:02 +00004604void TfLiteParserImpl::ParseCeil(size_t subgraphIndex, size_t operatorIndex)
4605{
4606 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Ceil);
4607}
4608
Teresa Charlin28aa6692022-07-12 11:18:44 +01004609void TfLiteParserImpl::ParseExp(size_t subgraphIndex, size_t operatorIndex)
4610{
4611 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Exp);
4612}
4613
4614void TfLiteParserImpl::ParseLog(size_t subgraphIndex, size_t operatorIndex)
4615{
4616 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Log);
4617}
4618
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004619void TfLiteParserImpl::ParseLogicalNot(size_t subgraphIndex, size_t operatorIndex)
4620{
4621 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::LogicalNot);
4622}
4623
4624void TfLiteParserImpl::ParseNeg(size_t subgraphIndex, size_t operatorIndex)
4625{
4626 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Neg);
4627}
4628
John Mcloughlin0ec00872023-05-15 17:03:49 +01004629void TfLiteParserImpl::ParsePower(size_t subgraphIndex, size_t operatorIndex)
4630{
4631 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4632
4633 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4634 CHECK_VALID_SIZE(inputs.size(), 2);
4635
4636 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4637 CHECK_VALID_SIZE(outputs.size(), 1);
4638
4639 auto layerName = fmt::format("Power:{}:{}", subgraphIndex, operatorIndex);
4640
4641 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4642 TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
4643 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
4644
4645 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Power, layerName.c_str());
4646 ARMNN_ASSERT(layer != nullptr);
4647
4648 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
4649 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
4650 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4651
4652 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4653 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4654
4655 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4656 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4657}
4658
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004659void TfLiteParserImpl::ParseRsqrt(size_t subgraphIndex, size_t operatorIndex)
4660{
4661 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Rsqrt);
4662}
4663
Teresa Charlin28aa6692022-07-12 11:18:44 +01004664void TfLiteParserImpl::ParseSin(size_t subgraphIndex, size_t operatorIndex)
4665{
4666 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Sin);
4667}
4668
Teresa Charlinf0fce5b2022-05-04 17:24:43 +01004669void TfLiteParserImpl::ParseSqrt(size_t subgraphIndex, size_t operatorIndex)
4670{
4671 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Sqrt);
4672}
4673
Teresa Charlin6963b332023-07-11 11:35:41 +01004674void TfLiteParserImpl::ParseSquare(size_t subgraphIndex, size_t operatorIndex)
4675{
4676 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4677
4678 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4679 CHECK_VALID_SIZE(inputs.size(), 1);
4680
4681 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4682 CHECK_VALID_SIZE(outputs.size(), 1);
4683
4684 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4685
4686 auto layerName = fmt::format("Square:{}:{}", subgraphIndex, operatorIndex);
4687 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Mul, layerName.c_str());
4688 ARMNN_ASSERT(layer != nullptr);
4689
4690 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 0});
4691 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
4692 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4693
4694 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4695 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[0]});
4696
4697 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4698 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4699}
4700
John Mcloughlin0ec00872023-05-15 17:03:49 +01004701void TfLiteParserImpl::ParseSquaredDifference(size_t subgraphIndex, size_t operatorIndex)
4702{
4703 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4704
4705 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4706 CHECK_VALID_SIZE(inputs.size(), 2);
4707
4708 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4709 CHECK_VALID_SIZE(outputs.size(), 1);
4710
4711 auto layerName = fmt::format("SquaredDifference:{}:{}", subgraphIndex, operatorIndex);
4712
4713 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4714 TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
4715 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
4716
4717 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::SqDiff, layerName.c_str());
4718 ARMNN_ASSERT(layer != nullptr);
4719
4720 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
4721 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
4722 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4723
4724 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4725 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4726
4727 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4728 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4729}
4730
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004731void TfLiteParserImpl::ParseElementwiseUnary(size_t subgraphIndex, size_t operatorIndex, UnaryOperation unaryOperation)
4732{
4733 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4734
4735 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4736 CHECK_VALID_SIZE(inputs.size(), 1);
4737
4738 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4739 CHECK_VALID_SIZE(outputs.size(), 1);
4740
4741 std::string layerName = std::string(GetUnaryOperationAsCString(unaryOperation)) + ":{}:{}";
4742 std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4743
4744 ElementwiseUnaryDescriptor desc;
4745 desc.m_Operation = unaryOperation;
4746 IConnectableLayer* layer = m_Network->AddElementwiseUnaryLayer(desc, layerNameFormatted.c_str());
4747 ARMNN_ASSERT(layer != nullptr);
4748
Mike Kelly377fb212023-01-10 15:55:28 +00004749 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004750 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4751
4752 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4753 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4754
4755 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4756 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4757}
4758
Bruno Goncalves2d0eb862021-07-11 14:10:15 -03004759void TfLiteParserImpl::ParseEqual(size_t subgraphIndex, size_t operatorIndex)
4760{
4761 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::Equal);
4762}
4763
4764void TfLiteParserImpl::ParseNotEqual(size_t subgraphIndex, size_t operatorIndex)
4765{
4766 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::NotEqual);
4767}
4768
4769void TfLiteParserImpl::ParseGreater(size_t subgraphIndex, size_t operatorIndex)
4770{
4771 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::Greater);
4772}
4773
4774void TfLiteParserImpl::ParseGreaterOrEqual(size_t subgraphIndex, size_t operatorIndex)
4775{
4776 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::GreaterOrEqual);
4777}
4778
4779void TfLiteParserImpl::ParseLess(size_t subgraphIndex, size_t operatorIndex)
4780{
4781 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::Less);
4782}
4783
4784void TfLiteParserImpl::ParseLessOrEqual(size_t subgraphIndex, size_t operatorIndex)
4785{
4786 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::LessOrEqual);
4787}
4788
4789void TfLiteParserImpl::ParseComparison(size_t subgraphIndex, size_t operatorIndex,
4790 ComparisonOperation comparisonOperation)
4791{
4792 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4793
4794 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4795 CHECK_VALID_SIZE(inputs.size(), 2);
4796
4797 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4798 CHECK_VALID_SIZE(outputs.size(), 1);
4799
4800 auto layerName = std::string(GetComparisonOperationAsCString(comparisonOperation)) + ":{}:{}";
4801 std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4802
Mike Kelly377fb212023-01-10 15:55:28 +00004803 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4804 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves2d0eb862021-07-11 14:10:15 -03004805 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerNameFormatted, "Input 0", "Input 1");
4806
4807 ComparisonDescriptor desc;
4808 desc.m_Operation = comparisonOperation;
4809 IConnectableLayer* layer = m_Network->AddComparisonLayer(desc, layerNameFormatted.c_str());
4810 ARMNN_ASSERT(layer != nullptr);
4811
Mike Kelly377fb212023-01-10 15:55:28 +00004812 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Bruno Goncalves2d0eb862021-07-11 14:10:15 -03004813 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4814
4815 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4816 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4817
4818 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4819 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4820}
4821
Mike Kelly04d82292023-01-19 18:29:40 +00004822armnn::IConnectableLayer* TfLiteParserImpl::AddReshapeLayer(armnn::IConnectableLayer* layer,
4823 unsigned int outputSlot,
4824 std::string reshapeLayerName,
4825 armnn::TensorInfo outputShape)
4826{
4827 ReshapeDescriptor desc;
4828 desc.m_TargetShape = outputShape.GetShape();
4829
4830 IConnectableLayer* reshapeLayer =
4831 m_Network->AddReshapeLayer(desc, reshapeLayerName.c_str());
4832
4833 auto & prevOutputSlot = layer->GetOutputSlot(outputSlot);
4834 prevOutputSlot.Connect(reshapeLayer->GetInputSlot(0));
4835 reshapeLayer->GetOutputSlot(0).SetTensorInfo(outputShape);
4836 return reshapeLayer;
4837}
4838
Kevin May7d96b162021-02-03 17:38:41 +00004839armnn::IConnectableLayer* TfLiteParserImpl::AddFusedActivationLayer(armnn::IConnectableLayer* prevLayer,
4840 unsigned int outputSlot,
4841 tflite::ActivationFunctionType activationType)
telsoa01c577f2c2018-08-31 09:22:23 +01004842{
4843 ActivationDescriptor activationDesc;
4844 std::string layerName = prevLayer->GetName();
4845
4846 switch(activationType)
4847 {
4848 case tflite::ActivationFunctionType_NONE:
4849 {
4850 // this is a no-op: return previous layer
4851 return prevLayer;
4852 }
4853 case tflite::ActivationFunctionType_RELU:
4854 {
4855 activationDesc.m_Function = ActivationFunction::ReLu;
4856 layerName += ":RELU";
4857 break;
4858 }
4859 case tflite::ActivationFunctionType_RELU6:
4860 {
4861 activationDesc.m_Function = ActivationFunction::BoundedReLu;
4862 activationDesc.m_A = 6.0f;
4863 activationDesc.m_B = 0.0f;
4864 layerName += ":RELU6";
4865 break;
4866 }
4867 case tflite::ActivationFunctionType_TANH:
4868 {
4869 activationDesc.m_Function = ActivationFunction::TanH;
4870 activationDesc.m_A = 1.0f;
4871 activationDesc.m_B = 1.0f;
4872 layerName += ":TANH";
4873 break;
4874 }
4875
4876 // I only put these here as a reminder what others we could support
4877 case tflite::ActivationFunctionType_RELU_N1_TO_1:
4878 case tflite::ActivationFunctionType_SIGN_BIT:
4879 default:
4880 {
4881 throw ParseException(
Mike Kelly377fb212023-01-10 15:55:28 +00004882 fmt::format("TfLite parser doesn't support fused activation: "
James Ward58dec6b2020-09-11 17:32:44 +01004883 "{}/{} {} ",
4884 activationType,
4885 tflite::EnumNameActivationFunctionType(activationType),
4886 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01004887
4888 }
4889 }
4890
4891 IConnectableLayer* activationLayer =
4892 m_Network->AddActivationLayer(activationDesc, layerName.c_str());
4893
4894 auto & prevOutputSlot = prevLayer->GetOutputSlot(outputSlot);
4895 prevOutputSlot.Connect(activationLayer->GetInputSlot(0));
4896 activationLayer->GetOutputSlot(0).SetTensorInfo(prevOutputSlot.GetTensorInfo());
4897 return activationLayer;
4898}
4899
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004900armnn::IConnectableLayer* TfLiteParserImpl::AddFusedFloorLayer(armnn::IConnectableLayer* prevLayer,
4901 unsigned int outputSlot)
4902{
Teresa Charlin725728e2022-05-05 13:33:33 +01004903
4904 auto& prevOutputSlot = prevLayer->GetOutputSlot(outputSlot);
4905 DataType dataType = prevOutputSlot.GetTensorInfo().GetDataType();
4906
4907 if (dataType == DataType::Signed32)
4908 {
4909 return prevLayer;
4910 }
4911
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004912 std::string layerName = prevLayer->GetName();
4913 IConnectableLayer* floorLayer = m_Network->AddFloorLayer(layerName.c_str());
4914
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004915 prevOutputSlot.Connect(floorLayer->GetInputSlot(0));
4916 floorLayer->GetOutputSlot(0).SetTensorInfo(prevOutputSlot.GetTensorInfo());
Teresa Charlin725728e2022-05-05 13:33:33 +01004917
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004918 return floorLayer;
4919}
4920
Mike Kelly0d77ae12022-01-07 17:42:27 +00004921TfLiteParserImpl::ModelPtr TfLiteParserImpl::LoadModelFromFile(const char* fileName)
telsoa01c577f2c2018-08-31 09:22:23 +01004922{
4923 if (fileName == nullptr)
4924 {
James Ward58dec6b2020-09-11 17:32:44 +01004925 throw InvalidArgumentException(fmt::format("Invalid (null) file name {}",
telsoa01c577f2c2018-08-31 09:22:23 +01004926 CHECK_LOCATION().AsString()));
4927 }
Francis Murtagh532a29d2020-06-29 11:50:01 +01004928 std::error_code errorCode;
4929 fs::path pathToFile(fileName);
4930 if (!fs::exists(pathToFile, errorCode))
telsoa01c577f2c2018-08-31 09:22:23 +01004931 {
James Ward58dec6b2020-09-11 17:32:44 +01004932 //fmt::format() could not be used here (format error)
4933 std::stringstream msg;
4934 msg << "Cannot find the file (" << fileName << ") errorCode: " << errorCode
4935 << " " << CHECK_LOCATION().AsString();
James Ward58dec6b2020-09-11 17:32:44 +01004936 throw FileNotFoundException(msg.str());
telsoa01c577f2c2018-08-31 09:22:23 +01004937 }
Colm Donelan0dfb2652023-06-22 10:19:17 +01004938 if (!fs::is_regular_file(pathToFile))
4939 {
4940 // Exclude non regular files.
4941 throw InvalidArgumentException(fmt::format("File \"{}\" is not a regular file and cannot be loaded.",
4942 pathToFile.c_str()));
4943 }
4944
telsoa01c577f2c2018-08-31 09:22:23 +01004945 std::ifstream file(fileName, std::ios::binary);
4946 std::string fileContent((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
4947 return LoadModelFromBinary(reinterpret_cast<const uint8_t *>(fileContent.c_str()),
4948 fileContent.size());
4949}
4950
Mike Kelly0d77ae12022-01-07 17:42:27 +00004951TfLiteParserImpl::ModelPtr TfLiteParserImpl::LoadModelFromBinary(const uint8_t* binaryContent, size_t len)
telsoa01c577f2c2018-08-31 09:22:23 +01004952{
4953 if (binaryContent == nullptr)
4954 {
James Ward58dec6b2020-09-11 17:32:44 +01004955 throw InvalidArgumentException(fmt::format("Invalid (null) binary content {}",
telsoa01c577f2c2018-08-31 09:22:23 +01004956 CHECK_LOCATION().AsString()));
4957 }
4958 flatbuffers::Verifier verifier(binaryContent, len);
4959 if (verifier.VerifyBuffer<tflite::Model>() == false)
4960 {
4961 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01004962 fmt::format("Buffer doesn't conform to the expected Tensorflow Lite "
4963 "flatbuffers format. size:{} {}",
4964 len,
4965 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01004966 }
4967 return tflite::UnPackModel(binaryContent);
4968}
4969
Mike Kelly0d77ae12022-01-07 17:42:27 +00004970TfLiteParserImpl::TensorRawPtrVector TfLiteParserImpl::GetInputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00004971 size_t subgraphIndex,
4972 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004973{
4974 CHECK_MODEL(model, subgraphIndex, operatorIndex);
4975
Mike Kelly0d77ae12022-01-07 17:42:27 +00004976 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
4977 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01004978
4979 size_t inputCount = operatorPtr->inputs.size();
mathad01c21025d2021-04-26 10:09:37 +01004980 TensorRawPtrVector result;
Mike Kelly0d77ae12022-01-07 17:42:27 +00004981 for (size_t i = 0; i < inputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01004982 {
mathad01c21025d2021-04-26 10:09:37 +01004983 // If the input location is -1 then assume input is turned off.
4984 if (operatorPtr->inputs[i] == -1)
4985 {
4986 continue;
4987 }
4988 else
4989 {
4990 uint32_t inputId = CHECKED_NON_NEGATIVE(operatorPtr->inputs[i]);
4991 result.push_back(subgraphPtr->tensors[inputId].get());
4992 }
telsoa01c577f2c2018-08-31 09:22:23 +01004993 }
4994 return result;
4995}
4996
Mike Kelly0d77ae12022-01-07 17:42:27 +00004997TfLiteParserImpl::TensorRawPtrVector TfLiteParserImpl::GetOutputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00004998 size_t subgraphIndex,
4999 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005000{
5001 CHECK_MODEL(model, subgraphIndex, operatorIndex);
5002
Mike Kelly0d77ae12022-01-07 17:42:27 +00005003 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
5004 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01005005
5006 size_t outputCount = operatorPtr->outputs.size();
5007 TensorRawPtrVector result(outputCount);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005008 for (size_t i = 0; i < outputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01005009 {
5010 uint32_t outputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[i]);
5011 CHECK_TENSOR(model, subgraphIndex, outputId);
Derek Lambertiff05cc52019-04-26 13:05:17 +01005012 result[i] = subgraphPtr->tensors[outputId].get();
telsoa01c577f2c2018-08-31 09:22:23 +01005013 }
5014 return result;
5015}
5016
Mike Kelly0d77ae12022-01-07 17:42:27 +00005017TfLiteParserImpl::TensorIdRawPtrVector TfLiteParserImpl::GetSubgraphInputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00005018 size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005019{
5020 CHECK_SUBGRAPH(model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005021 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01005022
Derek Lambertiff05cc52019-04-26 13:05:17 +01005023 size_t inputCount = subgraphPtr->inputs.size();
telsoa01c577f2c2018-08-31 09:22:23 +01005024 TensorIdRawPtrVector result(inputCount);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005025 for (size_t i = 0; i < inputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01005026 {
Derek Lambertiff05cc52019-04-26 13:05:17 +01005027 uint32_t inputId = CHECKED_NON_NEGATIVE(subgraphPtr->inputs[i]);
telsoa01c577f2c2018-08-31 09:22:23 +01005028 CHECK_TENSOR(model, subgraphIndex, inputId);
Derek Lambertiff05cc52019-04-26 13:05:17 +01005029 result[i] = std::make_pair(inputId, subgraphPtr->tensors[inputId].get());
telsoa01c577f2c2018-08-31 09:22:23 +01005030 }
5031 return result;
5032}
5033
Mike Kelly0d77ae12022-01-07 17:42:27 +00005034TfLiteParserImpl::TensorIdRawPtrVector TfLiteParserImpl::GetSubgraphOutputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00005035 size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005036{
5037 CHECK_SUBGRAPH(model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005038 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01005039
Derek Lambertiff05cc52019-04-26 13:05:17 +01005040 size_t outputCount = subgraphPtr->outputs.size();
telsoa01c577f2c2018-08-31 09:22:23 +01005041 TensorIdRawPtrVector result(outputCount);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005042 for (size_t i = 0; i < outputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01005043 {
Derek Lambertiff05cc52019-04-26 13:05:17 +01005044 uint32_t outputId = CHECKED_NON_NEGATIVE(subgraphPtr->outputs[i]);
5045 result[i] = std::make_pair(outputId, subgraphPtr->tensors[outputId].get());
telsoa01c577f2c2018-08-31 09:22:23 +01005046 }
5047 return result;
5048}
5049
Kevin May7d96b162021-02-03 17:38:41 +00005050std::vector<int32_t>& TfLiteParserImpl::GetInputTensorIds(const ModelPtr& model,
5051 size_t subgraphIndex,
5052 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005053{
5054 CHECK_MODEL(model, subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005055 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
5056 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01005057 return operatorPtr->inputs;
5058}
5059
Kevin May7d96b162021-02-03 17:38:41 +00005060std::vector<int32_t>& TfLiteParserImpl::GetOutputTensorIds(const ModelPtr& model,
5061 size_t subgraphIndex,
5062 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005063{
5064 CHECK_MODEL(model, subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005065 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
5066 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01005067 return operatorPtr->outputs;
5068}
5069
Kevin May7d96b162021-02-03 17:38:41 +00005070void TfLiteParserImpl::RegisterInputSlots(size_t subgraphIndex,
5071 size_t operatorIndex,
5072 IConnectableLayer* layer,
Finn Williamsd4fa5452021-03-01 12:31:41 +00005073 const std::vector<unsigned int>& tensorIndexes,
5074 unsigned int startingSlotIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005075{
5076 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01005077 ARMNN_ASSERT(layer != nullptr);
Matthew Sloyan81beae32021-07-13 19:46:11 +01005078
Finn Williamsd4fa5452021-03-01 12:31:41 +00005079 if (tensorIndexes.size() + startingSlotIndex != layer->GetNumInputSlots())
telsoa01c577f2c2018-08-31 09:22:23 +01005080 {
5081 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01005082 fmt::format("The number of tensor inputs ({}) does not match the number expected ({})"
5083 " for subgraph:{} operator index:{} {}",
5084 tensorIndexes.size(),
5085 layer->GetNumInputSlots(),
5086 subgraphIndex,
5087 operatorIndex,
5088 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01005089 }
5090
Finn Williamsd4fa5452021-03-01 12:31:41 +00005091 for (unsigned int index = 0; index < tensorIndexes.size() ; ++index)
telsoa01c577f2c2018-08-31 09:22:23 +01005092 {
Finn Williamsd4fa5452021-03-01 12:31:41 +00005093 unsigned int tensorIndex = tensorIndexes[index];
5094 armnn::IInputSlot* slot = &(layer->GetInputSlot(startingSlotIndex + index));
telsoa01c577f2c2018-08-31 09:22:23 +01005095 RegisterConsumerOfTensor(subgraphIndex, tensorIndex, slot);
5096 }
5097}
5098
Kevin May7d96b162021-02-03 17:38:41 +00005099void TfLiteParserImpl::RegisterOutputSlots(size_t subgraphIndex,
5100 size_t operatorIndex,
5101 IConnectableLayer* layer,
5102 const std::vector<unsigned int>& tensorIndexes)
telsoa01c577f2c2018-08-31 09:22:23 +01005103{
5104 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01005105 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01005106 if (tensorIndexes.size() != layer->GetNumOutputSlots())
5107 {
5108 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01005109 fmt::format("The number of tensor outputs ({}) does not match the number expected ({})"
5110 " for subgraph:{} operator index:{} {}",
5111 tensorIndexes.size(),
5112 layer->GetNumOutputSlots(),
5113 subgraphIndex,
5114 operatorIndex,
5115 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01005116 }
5117
5118 for (unsigned int slotIndex = 0; slotIndex < layer->GetNumOutputSlots(); ++slotIndex)
5119 {
5120 unsigned int tensorIndex = tensorIndexes[slotIndex];
5121 armnn::IOutputSlot* slot = &(layer->GetOutputSlot(slotIndex));
5122 RegisterProducerOfTensor(subgraphIndex, tensorIndex, slot);
5123 }
5124}
5125
Mike Kelly377fb212023-01-10 15:55:28 +00005126void TfLiteParserImpl::SetupInputLayerTensorInfos(size_t subgraphIndex)
5127{
5128 CHECK_SUBGRAPH(m_Model, subgraphIndex);
5129
5130 auto inputs = GetSubgraphInputs(m_Model, subgraphIndex);
5131 for (auto const& tensorIdAndPtr : inputs)
5132 {
5133 auto tensorInfo = ToTensorInfo(tensorIdAndPtr.second);
5134 m_TensorInfos.insert({tensorIdAndPtr.first, tensorInfo});
5135 }
5136}
5137
Kevin May7d96b162021-02-03 17:38:41 +00005138void TfLiteParserImpl::SetupInputLayers(size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005139{
5140 CHECK_SUBGRAPH(m_Model, subgraphIndex);
5141
5142 auto inputs = GetSubgraphInputs(m_Model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005143 for (auto const& tensorIdAndPtr : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005144 {
5145 auto bindingId = GenerateLayerBindingId(subgraphIndex, tensorIdAndPtr.first);
5146 IConnectableLayer* layer =
5147 m_Network->AddInputLayer(bindingId, tensorIdAndPtr.second->name.c_str());
5148
5149 auto tensorInfo = ToTensorInfo(tensorIdAndPtr.second);
5150 layer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
5151
5152 RegisterOutputSlots(subgraphIndex,
5153 VIRTUAL_OPERATOR_ID,
5154 layer,
5155 { static_cast<uint32_t>(tensorIdAndPtr.first) });
5156 }
5157}
5158
Kevin May7d96b162021-02-03 17:38:41 +00005159void TfLiteParserImpl::SetupOutputLayers(size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005160{
5161 CHECK_SUBGRAPH(m_Model, subgraphIndex);
5162
5163 auto outputs = GetSubgraphOutputs(m_Model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005164 for (auto const& tensorIdAndPtr : outputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005165 {
5166 auto bindingId = GenerateLayerBindingId(subgraphIndex, tensorIdAndPtr.first);
5167 IConnectableLayer* layer =
5168 m_Network->AddOutputLayer(bindingId, tensorIdAndPtr.second->name.c_str());
5169
5170 RegisterInputSlots(subgraphIndex,
5171 VIRTUAL_OPERATOR_ID,
5172 layer,
5173 { static_cast<uint32_t>(tensorIdAndPtr.first) });
5174 }
5175}
5176
Mike Kelly377fb212023-01-10 15:55:28 +00005177void TfLiteParserImpl::SetupConstantLayerTensorInfos(size_t subgraph)
5178{
5179 CHECK_SUBGRAPH(m_Model, subgraph);
5180
5181 const auto & subgraphPtr = m_Model->subgraphs[subgraph];
5182 for (unsigned int subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex)
5183 {
5184 for (unsigned int tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex)
5185 {
5186 if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot == nullptr &&
5187 m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size() > 0)
5188 {
5189 TensorRawPtr tensorPtr = subgraphPtr->tensors[tensorIndex].get();
5190
5191 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
5192
5193 m_TensorInfos.insert({tensorIndex, tensorInfo});
5194 }
5195 }
5196 }
5197}
5198
Mike Kelly5880b912022-01-28 16:18:54 +00005199void TfLiteParserImpl::SetupConstantLayers(size_t subgraph)
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005200{
Mike Kelly5880b912022-01-28 16:18:54 +00005201 CHECK_SUBGRAPH(m_Model, subgraph);
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005202
Mike Kelly5880b912022-01-28 16:18:54 +00005203 const auto & subgraphPtr = m_Model->subgraphs[subgraph];
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005204 for (unsigned int subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex)
5205 {
5206 for (unsigned int tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex)
5207 {
5208 if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot == nullptr &&
5209 m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size() > 0)
5210 {
Derek Lambertiff05cc52019-04-26 13:05:17 +01005211 TensorRawPtr tensorPtr = subgraphPtr->tensors[tensorIndex].get();
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005212
Mike Kelly5880b912022-01-28 16:18:54 +00005213 if (IsConstTensor(tensorPtr))
Matthew Sloyan81beae32021-07-13 19:46:11 +01005214 {
5215 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
Mike Kelly5880b912022-01-28 16:18:54 +00005216 armnn::DataType dataType = tensorInfo.GetDataType();
5217
5218 if (std::find(m_ConstantsToDequantize.begin(), m_ConstantsToDequantize.end(), tensorPtr->buffer)
5219 != m_ConstantsToDequantize.end())
5220 {
5221 dataType = DataType::Float32;
5222 }
5223 auto tensorAndData = CreateConstTensorNonPermuted(tensorPtr, tensorInfo, dataType);
5224
5225 std::string layerName = fmt::format("Constant:{}", tensorPtr->name);
5226 IConnectableLayer *layer = m_Network->AddConstantLayer(tensorAndData.first, layerName.c_str());
5227
5228 layer->GetOutputSlot(0).SetTensorInfo(tensorAndData.first.GetInfo());
5229 RegisterOutputSlots(subgraphIndex,
5230 VIRTUAL_OPERATOR_ID,
5231 layer,
5232 { tensorIndex });
5233 }
5234 else if (ShouldConstantTensorBeCreated(tensorIndex))
5235 {
5236 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
5237 armnn::DataType dataType = tensorInfo.GetDataType();
5238
5239 if (std::find(m_ConstantsToDequantize.begin(), m_ConstantsToDequantize.end(), tensorPtr->buffer)
5240 != m_ConstantsToDequantize.end())
5241 {
5242 dataType = DataType::Float32;
5243 }
5244 // Make sure isConstant flag is set.
5245 tensorInfo.SetConstant();
5246 tensorInfo.SetDataType(dataType);
5247
5248 auto tensorAndData = ConstTensor(tensorInfo, std::vector<uint8_t>(tensorInfo.GetNumBytes()));
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005249
Matthew Sloyan81beae32021-07-13 19:46:11 +01005250 std::string layerName = fmt::format("Constant:{}", tensorPtr->name);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005251 IConnectableLayer* layer = m_Network->AddConstantLayer(tensorAndData, layerName.c_str());
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005252
Matthew Sloyan81beae32021-07-13 19:46:11 +01005253 layer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
5254 RegisterOutputSlots(subgraphIndex,
5255 VIRTUAL_OPERATOR_ID,
5256 layer,
Mike Kelly5880b912022-01-28 16:18:54 +00005257 {tensorIndex});
Matthew Sloyan81beae32021-07-13 19:46:11 +01005258 }
5259 else
5260 {
5261 throw ParseException(
5262 fmt::format("Invalid Tensor: Tensor should be constant. {}",
5263 CHECK_LOCATION().AsString()));
5264 }
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005265 }
5266 }
5267 }
5268}
5269
telsoa01c577f2c2018-08-31 09:22:23 +01005270// example usage: BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[0]->buffer);
Kevin May7d96b162021-02-03 17:38:41 +00005271TfLiteParserImpl::BufferRawPtr TfLiteParserImpl::GetBuffer(const ModelPtr& model, size_t bufferIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005272{
5273 CHECK_BUFFER(model, bufferIndex);
5274 return model->buffers[bufferIndex].get();
5275}
5276
Matteo Martincigh747ef822018-12-18 09:26:39 +00005277template<typename T>
Kevin May7d96b162021-02-03 17:38:41 +00005278std::pair<armnn::ConstTensor, TfLiteParserImpl::SupportedDataStorage>
5279TfLiteParserImpl::CreateConstTensorAndStoreData(TfLiteParserImpl::BufferRawPtr bufferPtr,
5280 TfLiteParserImpl::TensorRawPtr tensorPtr,
Matteo Martincigh747ef822018-12-18 09:26:39 +00005281 armnn::TensorInfo& tensorInfo,
5282 armnn::Optional<armnn::PermutationVector&> permutationVector)
5283{
Matthew Sloyan81beae32021-07-13 19:46:11 +01005284 // Make sure isConstant flag is set.
5285 tensorInfo.SetConstant();
5286
Matteo Martincigh747ef822018-12-18 09:26:39 +00005287 auto constData = CreateConstTensorImpl<T>(bufferPtr,
5288 tensorPtr,
5289 tensorInfo,
5290 permutationVector);
Kevin May7d96b162021-02-03 17:38:41 +00005291 TfLiteParserImpl::SupportedDataStorage storage(std::move(constData.second));
Matteo Martincigh747ef822018-12-18 09:26:39 +00005292 return std::make_pair(constData.first, std::move(storage));
5293}
5294
Mike Kelly5880b912022-01-28 16:18:54 +00005295bool TfLiteParserImpl::ShouldConstantTensorBeCreated(unsigned int tensorIndex)
5296{
5297 // If the TensorIndex appears in the list of ConstantsToBeCreated then return true
5298 return (std::find(m_ConstantsToBeCreated.begin(), m_ConstantsToBeCreated.end(), tensorIndex)
5299 != m_ConstantsToBeCreated.end());
5300}
5301
Finn Williamsd4fa5452021-03-01 12:31:41 +00005302bool TfLiteParserImpl::IsConstTensor(TensorRawPtr tensorPtr)
5303{
5304 CHECK_TENSOR_PTR(tensorPtr);
mathad01bf7edb62021-04-20 16:12:45 +01005305 bool isConst = true;
5306
5307 auto buffer = GetBuffer(m_Model, tensorPtr->buffer);
5308 if (buffer->data.size() == 0)
5309 {
5310 isConst = false;
5311 }
5312
5313 return isConst;
Finn Williamsd4fa5452021-03-01 12:31:41 +00005314}
5315
Kevin May7d96b162021-02-03 17:38:41 +00005316std::pair<armnn::ConstTensor, TfLiteParserImpl::SupportedDataStorage>
Finn Williamsd4fa5452021-03-01 12:31:41 +00005317TfLiteParserImpl::CreateConstTensorPermuted(TensorRawPtr tensorPtr,
5318 armnn::TensorInfo& tensorInfo,
5319 armnn::Optional<armnn::PermutationVector&> permutationVector)
telsoa01c577f2c2018-08-31 09:22:23 +01005320{
5321 CHECK_TENSOR_PTR(tensorPtr);
5322 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5323 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5324
Matthew Sloyan81beae32021-07-13 19:46:11 +01005325 // Make sure isConstant flag is set.
5326 tensorInfo.SetConstant();
5327
telsoa01c577f2c2018-08-31 09:22:23 +01005328 switch (tensorInfo.GetDataType())
5329 {
5330 case armnn::DataType::Float32:
Matteo Martincigh747ef822018-12-18 09:26:39 +00005331 return CreateConstTensorAndStoreData<float>(bufferPtr,
5332 tensorPtr,
5333 tensorInfo,
5334 permutationVector);
Derek Lambertif90c56d2020-01-10 17:14:08 +00005335 case armnn::DataType::QAsymmU8:
Matteo Martincigh747ef822018-12-18 09:26:39 +00005336 return CreateConstTensorAndStoreData<uint8_t>(bufferPtr,
5337 tensorPtr,
5338 tensorInfo,
5339 permutationVector);
Keith Davisd305e1a2020-01-22 11:57:54 +00005340 case armnn::DataType::QSymmS8:
5341 return CreateConstTensorAndStoreData<int8_t>(bufferPtr,
5342 tensorPtr,
5343 tensorInfo,
5344 permutationVector);
Keith Davis67e6c542020-02-19 10:08:33 +00005345 case armnn::DataType::QAsymmS8:
5346 return CreateConstTensorAndStoreData<int8_t>(bufferPtr,
5347 tensorPtr,
5348 tensorInfo,
5349 permutationVector);
telsoa01c577f2c2018-08-31 09:22:23 +01005350 case armnn::DataType::Signed32:
Matteo Martincigh747ef822018-12-18 09:26:39 +00005351 return CreateConstTensorAndStoreData<int32_t>(bufferPtr,
5352 tensorPtr,
5353 tensorInfo,
5354 permutationVector);
telsoa01c577f2c2018-08-31 09:22:23 +01005355 default:
5356 {
5357 std::stringstream errString;
5358 errString << "Unexpected datatype when creating const tensor: "
5359 << armnn::GetDataTypeName(tensorInfo.GetDataType())
5360 << " shape:" << tensorInfo.GetShape()
5361 << CHECK_LOCATION().AsString();
5362 throw ParseException(errString.str());
5363 }
5364 }
5365}
5366
Finn Williamsd4fa5452021-03-01 12:31:41 +00005367armnn::ConstTensor TfLiteParserImpl::CreateConstTensorNonPermuted(TensorRawPtr tensorPtr,
5368 armnn::TensorInfo& tensorInfo)
5369{
5370 CHECK_TENSOR_PTR(tensorPtr);
5371 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5372 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5373
Matthew Sloyan81beae32021-07-13 19:46:11 +01005374 // Make sure isConstant flag is set.
5375 tensorInfo.SetConstant();
5376
Finn Williamsd4fa5452021-03-01 12:31:41 +00005377 return ConstTensor(tensorInfo, bufferPtr->data.data());
5378}
5379
Mike Kelly5880b912022-01-28 16:18:54 +00005380std::pair<armnn::ConstTensor, std::unique_ptr<float[]>>
5381TfLiteParserImpl::CreateConstTensorNonPermuted(TensorRawPtr tensorPtr,
5382 armnn::TensorInfo& tensorInfo,
5383 armnn::DataType inputDataType)
5384{
5385 CHECK_TENSOR_PTR(tensorPtr);
5386 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5387 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5388
5389 // Make sure isConstant flag is set.
5390 tensorInfo.SetConstant();
5391
Mike Kelly0506ef02023-01-03 16:29:44 +00005392 if (inputDataType == DataType::Float32 && tensorInfo.GetDataType() != DataType::Float32)
Mike Kelly5880b912022-01-28 16:18:54 +00005393 {
Mike Kelly0506ef02023-01-03 16:29:44 +00005394 try
5395 {
5396 TensorInfo constTensorInfo(tensorInfo.GetShape(), DataType::Float32, 0.0f, 0, true);
5397 std::unique_ptr<float[]> data = armnnUtils::ToFloatArray(bufferPtr->data, tensorInfo);
5398 return std::make_pair(ConstTensor(constTensorInfo, data.get()), std::move(data));
5399 }
Cathal Corbett9c843c32023-01-09 17:51:37 +00005400 catch (InvalidArgumentException&)
Mike Kelly0506ef02023-01-03 16:29:44 +00005401 {
5402 throw ParseException(
5403 fmt::format("Unsupported input/weights combination: Input {} not supported with Weights {}",
5404 GetDataTypeName(DataType::Float32),
5405 GetDataTypeName(tensorInfo.GetDataType()),
5406 CHECK_LOCATION().AsString()));
5407 }
Mike Kelly5880b912022-01-28 16:18:54 +00005408 }
5409 else
5410 {
5411 return std::make_pair(ConstTensor(tensorInfo, bufferPtr->data.data()), std::unique_ptr<float[]>());
5412 }
5413}
5414
5415std::pair<armnn::ConstTensor*, std::unique_ptr<float[]>>
5416TfLiteParserImpl::CreateConstTensorPtr(TensorRawPtr tensorPtr, armnn::TensorInfo& inputTensorInfo)
5417{
5418 CHECK_TENSOR_PTR(tensorPtr);
5419 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
5420 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5421 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5422
5423 // Make sure isConstant flag is set.
5424 tensorInfo.SetConstant();
5425
5426 if (inputTensorInfo.GetDataType() == DataType::Float32 && tensorInfo.GetDataType() != DataType::Float32)
5427 {
Mike Kelly0506ef02023-01-03 16:29:44 +00005428 try
5429 {
5430 TensorInfo constTensorInfo(tensorInfo.GetShape(), DataType::Float32, 0.0f, 0, true);
5431 std::unique_ptr<float[]> data = armnnUtils::ToFloatArray(bufferPtr->data, tensorInfo);
5432 return std::make_pair(new ConstTensor(constTensorInfo, data.get()), std::move(data));
5433 }
Cathal Corbett9c843c32023-01-09 17:51:37 +00005434 catch (InvalidArgumentException&)
Mike Kelly0506ef02023-01-03 16:29:44 +00005435 {
5436 throw ParseException(
5437 fmt::format("Unsupported input/weights combination: Input {} not supported with Weights {}",
5438 GetDataTypeName(DataType::Float32),
5439 GetDataTypeName(tensorInfo.GetDataType()),
5440 CHECK_LOCATION().AsString()));
5441 }
Mike Kelly5880b912022-01-28 16:18:54 +00005442 }
5443 else
5444 {
5445 return std::make_pair(new ConstTensor(tensorInfo, bufferPtr->data.data()), std::unique_ptr<float[]>());
5446 }
5447}
5448
Kevin May7d96b162021-02-03 17:38:41 +00005449BindingPointInfo TfLiteParserImpl::GetNetworkInputBindingInfo(size_t subgraphId,
5450 const std::string& name) const
telsoa01c577f2c2018-08-31 09:22:23 +01005451{
5452 CHECK_SUBGRAPH(m_Model, subgraphId);
5453 auto inputs = GetSubgraphInputs(m_Model, subgraphId);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005454 for (auto const& input : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005455 {
5456 if (input.second->name == name)
5457 {
5458 auto bindingId = GenerateLayerBindingId(subgraphId, input.first);
Colm Donelan4bc993b2021-11-09 20:39:10 +00005459 auto inputTensorInfo = ToTensorInfo(input.second);
5460 // Input tensors are always treated as constant tensors during network execution.
5461 inputTensorInfo.SetConstant(true);
5462 return std::make_pair(bindingId, inputTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +01005463 }
5464 }
5465
5466 std::stringstream bindings;
Mike Kelly0d77ae12022-01-07 17:42:27 +00005467 for (auto const& input : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005468 {
5469 bindings << "'" << input.second->name << "' ";
5470 }
5471
5472 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01005473 fmt::format("No input binding found for subgraph:{} and name:{}. "
5474 "Possible inputs are: [{}] {}",
5475 subgraphId,
5476 name,
5477 bindings.str(),
5478 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01005479}
5480
Kevin May7d96b162021-02-03 17:38:41 +00005481BindingPointInfo TfLiteParserImpl::GetNetworkOutputBindingInfo(size_t subgraphId,
5482 const std::string& name) const
telsoa01c577f2c2018-08-31 09:22:23 +01005483{
5484 CHECK_SUBGRAPH(m_Model, subgraphId);
5485 auto outputs = GetSubgraphOutputs(m_Model, subgraphId);
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00005486 for (unsigned int i = 0; i < outputs.size(); ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01005487 {
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00005488 auto const output = outputs[i];
telsoa01c577f2c2018-08-31 09:22:23 +01005489 if (output.second->name == name)
5490 {
5491 auto bindingId = GenerateLayerBindingId(subgraphId, output.first);
Mike Kelly377fb212023-01-10 15:55:28 +00005492 std::vector<unsigned int> shape = m_OverriddenOutputShapes.size() > 0 ?
5493 m_OverriddenOutputShapes[i] : AsUnsignedVector(output.second->shape);
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00005494 return std::make_pair(bindingId, ToTensorInfo(output.second, shape));
telsoa01c577f2c2018-08-31 09:22:23 +01005495 }
5496 }
5497
5498 std::stringstream bindings;
Mike Kelly0d77ae12022-01-07 17:42:27 +00005499 for (auto const& output : outputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005500 {
5501 bindings << "'" << output.second->name << "' ";
5502 }
5503
5504 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01005505 fmt::format("No output binding found for subgraph:{} and name:{}. "
5506 "Possible outputs are: [{}] {}",
5507 subgraphId,
5508 name,
5509 bindings.str(),
5510 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01005511}
5512
Kevin May7d96b162021-02-03 17:38:41 +00005513size_t TfLiteParserImpl::GetSubgraphCount() const
telsoa01c577f2c2018-08-31 09:22:23 +01005514{
5515 return m_Model->subgraphs.size();
5516}
5517
Kevin May7d96b162021-02-03 17:38:41 +00005518std::vector<std::string> TfLiteParserImpl::GetSubgraphInputTensorNames(size_t subgraphId) const
telsoa01c577f2c2018-08-31 09:22:23 +01005519{
5520 CHECK_SUBGRAPH(m_Model, subgraphId);
5521 auto inputs = GetSubgraphInputs(m_Model, subgraphId);
5522 std::vector<std::string> result;
5523 result.reserve(inputs.size());
Mike Kelly0d77ae12022-01-07 17:42:27 +00005524 for (auto const& input : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005525 {
5526 result.push_back(input.second->name);
5527 }
5528 return result;
5529}
5530
Kevin May7d96b162021-02-03 17:38:41 +00005531std::vector<std::string> TfLiteParserImpl::GetSubgraphOutputTensorNames(size_t subgraphId) const
telsoa01c577f2c2018-08-31 09:22:23 +01005532{
5533 CHECK_SUBGRAPH(m_Model, subgraphId);
5534 auto outputs = GetSubgraphOutputs(m_Model, subgraphId);
5535 std::vector<std::string> result;
5536 result.reserve(outputs.size());
Mike Kelly0d77ae12022-01-07 17:42:27 +00005537 for (auto const& output : outputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005538 {
5539 result.push_back(output.second->name);
5540 }
5541 return result;
5542}
5543
Matthew Sloyanac001ee2021-02-03 10:43:04 +00005544const std::string TfLiteParserImpl::GetVersion()
5545{
5546 return TFLITE_PARSER_VERSION;
5547}
5548
Mike Kelly0d77ae12022-01-07 17:42:27 +00005549TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<float[]>&& data)
telsoa01c577f2c2018-08-31 09:22:23 +01005550: m_FloatData(std::move(data))
5551, m_Uint8Data(nullptr)
Keith Davisd305e1a2020-01-22 11:57:54 +00005552, m_Int8Data(nullptr)
telsoa01c577f2c2018-08-31 09:22:23 +01005553, m_Int32Data(nullptr)
5554{
5555}
5556
Mike Kelly0d77ae12022-01-07 17:42:27 +00005557TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<uint8_t[]>&& data)
telsoa01c577f2c2018-08-31 09:22:23 +01005558: m_FloatData(nullptr)
5559, m_Uint8Data(std::move(data))
Keith Davisd305e1a2020-01-22 11:57:54 +00005560, m_Int8Data(nullptr)
5561, m_Int32Data(nullptr)
5562{
5563}
5564
Mike Kelly0d77ae12022-01-07 17:42:27 +00005565TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<int8_t[]>&& data)
Keith Davisd305e1a2020-01-22 11:57:54 +00005566: m_FloatData(nullptr)
5567, m_Uint8Data(nullptr)
5568, m_Int8Data(std::move(data))
telsoa01c577f2c2018-08-31 09:22:23 +01005569, m_Int32Data(nullptr)
5570{
5571}
5572
Mike Kelly0d77ae12022-01-07 17:42:27 +00005573TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<int32_t[]>&& data)
telsoa01c577f2c2018-08-31 09:22:23 +01005574: m_FloatData(nullptr)
5575, m_Uint8Data(nullptr)
Keith Davisd305e1a2020-01-22 11:57:54 +00005576, m_Int8Data(nullptr)
telsoa01c577f2c2018-08-31 09:22:23 +01005577, m_Int32Data(std::move(data))
5578{
5579}
5580
5581} // armnnTfLiteParser