blob: 1c5b4fc9f02411ef78dd1e4b22699f56f9e277f9 [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;
Matthew Sloyaned7fce42021-04-15 20:46:24 +0100811 m_ParserFunctions[tflite::BuiltinOperator_RSQRT] = &TfLiteParserImpl::ParseRsqrt;
Teresa Charlinf0fce5b2022-05-04 17:24:43 +0100812 m_ParserFunctions[tflite::BuiltinOperator_SQRT] = &TfLiteParserImpl::ParseSqrt;
Keith Davis0176fd82021-06-01 17:36:32 +0100813 m_ParserFunctions[tflite::BuiltinOperator_SHAPE] = &TfLiteParserImpl::ParseShape;
Teresa Charlin28aa6692022-07-12 11:18:44 +0100814 m_ParserFunctions[tflite::BuiltinOperator_SIN] = &TfLiteParserImpl::ParseSin;
Kevin May7d96b162021-02-03 17:38:41 +0000815 m_ParserFunctions[tflite::BuiltinOperator_SLICE] = &TfLiteParserImpl::ParseSlice;
816 m_ParserFunctions[tflite::BuiltinOperator_SOFTMAX] = &TfLiteParserImpl::ParseSoftmax;
817 m_ParserFunctions[tflite::BuiltinOperator_SPACE_TO_BATCH_ND] = &TfLiteParserImpl::ParseSpaceToBatchND;
Teresa Charlin2a764ad2023-02-24 18:17:31 +0000818 m_ParserFunctions[tflite::BuiltinOperator_SPACE_TO_DEPTH] = &TfLiteParserImpl::ParseSpaceToDepth;
Kevin May7d96b162021-02-03 17:38:41 +0000819 m_ParserFunctions[tflite::BuiltinOperator_SPLIT] = &TfLiteParserImpl::ParseSplit;
820 m_ParserFunctions[tflite::BuiltinOperator_SPLIT_V] = &TfLiteParserImpl::ParseSplitV;
821 m_ParserFunctions[tflite::BuiltinOperator_SQUEEZE] = &TfLiteParserImpl::ParseSqueeze;
John Mcloughlin0ec00872023-05-15 17:03:49 +0100822 m_ParserFunctions[tflite::BuiltinOperator_SQUARED_DIFFERENCE] = &TfLiteParserImpl::ParseSquaredDifference;
Kevin May7d96b162021-02-03 17:38:41 +0000823 m_ParserFunctions[tflite::BuiltinOperator_STRIDED_SLICE] = &TfLiteParserImpl::ParseStridedSlice;
824 m_ParserFunctions[tflite::BuiltinOperator_SUB] = &TfLiteParserImpl::ParseSub;
825 m_ParserFunctions[tflite::BuiltinOperator_SUM] = &TfLiteParserImpl::ParseSum;
826 m_ParserFunctions[tflite::BuiltinOperator_TANH] = &TfLiteParserImpl::ParseTanH;
827 m_ParserFunctions[tflite::BuiltinOperator_TRANSPOSE] = &TfLiteParserImpl::ParseTranspose;
828 m_ParserFunctions[tflite::BuiltinOperator_TRANSPOSE_CONV] = &TfLiteParserImpl::ParseTransposeConv;
Mike Kelly5880b912022-01-28 16:18:54 +0000829 m_ParserFunctions[tflite::BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM]
830 = &TfLiteParserImpl::ParseUnidirectionalSequenceLSTM;
Kevin May7d96b162021-02-03 17:38:41 +0000831 m_ParserFunctions[tflite::BuiltinOperator_UNPACK] = &TfLiteParserImpl::ParseUnpack;
Matthew Sloyan28f177c2021-04-09 14:38:52 +0100832
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100833 // register supported custom operators
Kevin May7d96b162021-02-03 17:38:41 +0000834 m_CustomParserFunctions["TFLite_Detection_PostProcess"] = &TfLiteParserImpl::ParseDetectionPostProcess;
telsoa01c577f2c2018-08-31 09:22:23 +0100835}
836
Mike Kelly377fb212023-01-10 15:55:28 +0000837armnn::TensorInfo TfLiteParserImpl::InputTensorInfo(size_t subgraphIndex,
838 size_t operatorIndex,
839 int input)
840{
841 const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex];
842 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
843
844 uint32_t inputId = CHECKED_NON_NEGATIVE(operatorPtr->inputs[input]);
845 auto search = armnnTfLiteParser::TfLiteParserImpl::m_TensorInfos.find(inputId);
846
847 if (search != m_TensorInfos.end())
848 {
849 return m_TensorInfos[inputId];
850 }
851 else
852 {
853 auto tensorInfo = ::armnnTfLiteParser::ToTensorInfo(subgraphPtr->tensors[inputId].get());
854 m_TensorInfos.insert({ inputId, tensorInfo });
855 return tensorInfo;
856 }
857}
858
859armnn::TensorInfo TfLiteParserImpl::OutputTensorInfoFromInputs(size_t subgraphIndex,
860 size_t operatorIndex,
861 armnn::IConnectableLayer* layer,
862 int output,
863 std::vector<int> inputs)
864{
865 const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex];
866 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
867
868 uint32_t outputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[output]);
869
870 auto outputSearch = armnnTfLiteParser::TfLiteParserImpl::m_TensorInfos.find(outputId);
871
872 if (outputSearch != m_TensorInfos.end())
873 {
874 return m_TensorInfos[outputId];
875 }
876
877 const auto& outputTensorPtr = subgraphPtr->tensors[outputId].get();
878 TensorInfo tensor = ::armnnTfLiteParser::ToTensorInfo(outputTensorPtr, true);
879
880 if (IsDynamic(outputTensorPtr))
881 {
882 if (inputs.empty())
883 {
884 for (unsigned int i = 0; i < layer->GetNumInputSlots(); ++i)
885 {
886 inputs.emplace_back(i);
887 }
888 }
889 auto inputTensorIds = GetInputTensorIds(m_Model, subgraphIndex, operatorIndex);
890 std::vector<armnn::TensorShape> inputShapes;
891
892 for (unsigned int i = 0; i < inputs.size(); ++i)
893 {
894 uint32_t inputId = CHECKED_NON_NEGATIVE(operatorPtr->inputs[inputs[i]]);
895 auto search = armnnTfLiteParser::TfLiteParserImpl::m_TensorInfos.find(inputId);
896
897 if (search != m_TensorInfos.end())
898 {
899 auto &inputTensorInfo = m_TensorInfos[inputId];
900 inputShapes.push_back(inputTensorInfo.GetShape());
901 }
902 else
903 {
Mike Kelly377fb212023-01-10 15:55:28 +0000904 auto inputTensorInfo = ::armnnTfLiteParser::ToTensorInfo(subgraphPtr->tensors[inputId].get());
905 m_TensorInfos.insert({ inputId, inputTensorInfo});
906 inputShapes.push_back(inputTensorInfo.GetShape());
907 }
908 }
909 const auto outputShape = layer->InferOutputShapes(inputShapes)[output];
910 tensor.SetShape(outputShape);
911 }
912 m_TensorInfos.insert({ outputId, tensor});
913 return tensor;
914}
915
916armnn::TensorInfo TfLiteParserImpl::OutputTensorInfoFromShapes(size_t subgraphIndex,
917 size_t operatorIndex,
918 armnn::IConnectableLayer* layer,
919 int output,
920 std::vector<armnn::TensorShape> inputShapes)
921{
922 const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex];
923 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
924
925 uint32_t outputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[output]);
926 const auto& outputTensorPtr = subgraphPtr->tensors[outputId].get();
927 TensorInfo tensor = ::armnnTfLiteParser::ToTensorInfo(outputTensorPtr, true);
928
929 if (IsDynamic(outputTensorPtr))
930 {
931 const auto outputShape = layer->InferOutputShapes(inputShapes)[output];
932 tensor.SetShape(outputShape);
933 }
934 m_TensorInfos.insert({ outputId, tensor});
935 return tensor;
936}
937
Kevin May7d96b162021-02-03 17:38:41 +0000938void TfLiteParserImpl::ResetParser()
telsoa01c577f2c2018-08-31 09:22:23 +0100939{
940 m_Network = armnn::INetworkPtr(nullptr, nullptr);
941 m_Model = nullptr;
942 m_SubgraphConnections.clear();
Mike Kelly377fb212023-01-10 15:55:28 +0000943 m_OverriddenOutputShapes.clear();
Mike Kelly5880b912022-01-28 16:18:54 +0000944 m_ConstantsToDequantize.clear();
945 m_ConstantsToBeCreated.clear();
Mike Kelly377fb212023-01-10 15:55:28 +0000946 m_TensorInfos.clear();
telsoa01c577f2c2018-08-31 09:22:23 +0100947}
948
Kevin May7d96b162021-02-03 17:38:41 +0000949INetworkPtr TfLiteParserImpl::CreateNetworkFromBinaryFile(const char* graphFile)
telsoa01c577f2c2018-08-31 09:22:23 +0100950{
951 ResetParser();
952 m_Model = LoadModelFromFile(graphFile);
953 return CreateNetworkFromModel();
954}
955
Mike Kelly0d77ae12022-01-07 17:42:27 +0000956INetworkPtr TfLiteParserImpl::CreateNetworkFromBinary(const std::vector<uint8_t>& binaryContent)
telsoa01c577f2c2018-08-31 09:22:23 +0100957{
958 ResetParser();
959 m_Model = LoadModelFromBinary(binaryContent.data(), binaryContent.size());
960 return CreateNetworkFromModel();
961}
962
Finn Williamsb49ed182021-06-29 15:50:08 +0100963
964armnn::INetworkPtr TfLiteParserImpl::LoadModel(std::unique_ptr<tflite::ModelT> model)
965{
966 ResetParser();
967 m_Model = std::move(model);
968
969 return CreateNetworkFromModel();
970}
971
Kevin May7d96b162021-02-03 17:38:41 +0000972INetworkPtr TfLiteParserImpl::CreateNetworkFromModel()
telsoa01c577f2c2018-08-31 09:22:23 +0100973{
Sadik Armagand109a4d2020-07-28 10:42:13 +0100974
975 using NetworkOptions = std::vector<BackendOptions>;
976 NetworkOptions networkOptions = {};
Mike Kelly80512b02022-05-16 23:10:42 +0100977 if (m_Options)
Sadik Armagand109a4d2020-07-28 10:42:13 +0100978 {
Mike Kelly80512b02022-05-16 23:10:42 +0100979 if (m_Options.value().m_InferAndValidate)
980 {
981 BackendOptions shapeInferenceMethodOption("ShapeInferenceMethod",
982 {
983 { "InferAndValidate", true }
984 });
Sadik Armagand109a4d2020-07-28 10:42:13 +0100985
Mike Kelly80512b02022-05-16 23:10:42 +0100986 networkOptions.push_back(shapeInferenceMethodOption);
987 }
988 if (m_Options.value().m_AllowExpandedDims)
989 {
990 BackendOptions shapeInferenceMethodOption("AllowExpandedDims",
991 {
992 { "AllowExpandedDims", true }
993 });
994
995 networkOptions.push_back(shapeInferenceMethodOption);
996 }
Sadik Armagand109a4d2020-07-28 10:42:13 +0100997 }
Sadik Armagand109a4d2020-07-28 10:42:13 +0100998 m_Network = INetwork::Create(networkOptions);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100999 ARMNN_ASSERT(m_Model.get() != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01001000
telsoa01c577f2c2018-08-31 09:22:23 +01001001 if (m_Model->subgraphs.size() != 1)
1002 {
1003 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01001004 fmt::format("Current TfLite parser only supports 1 subgraph. Current one has: {} {}",
1005 m_Model->subgraphs.size(),
1006 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01001007 }
1008
1009 size_t subgraphIndex = 0;
Colm Donelan6350d272020-06-09 16:56:25 +01001010 size_t operatorIndex = 0;
1011 try
telsoa01c577f2c2018-08-31 09:22:23 +01001012 {
Colm Donelan6350d272020-06-09 16:56:25 +01001013 for (SubgraphPtr const& subgraph : m_Model->subgraphs)
telsoa01c577f2c2018-08-31 09:22:23 +01001014 {
Mike Kelly377fb212023-01-10 15:55:28 +00001015 SetupInputLayerTensorInfos(subgraphIndex);
1016 SetupConstantLayerTensorInfos(subgraphIndex);
1017
Colm Donelan6350d272020-06-09 16:56:25 +01001018 m_SubgraphConnections.emplace_back(subgraph->tensors.size());
1019 for (OperatorPtr const& op : subgraph->operators)
telsoa01c577f2c2018-08-31 09:22:23 +01001020 {
Colm Donelan6350d272020-06-09 16:56:25 +01001021 auto const& opCodePtr = m_Model->operator_codes[op->opcode_index];
Jim Flynnfca233e2021-09-23 12:16:53 +01001022
1023// 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 +01001024#if defined(ARMNN_POST_TFLITE_2_3)
Jim Flynnfca233e2021-09-23 12:16:53 +01001025 auto builtinCode = std::max(opCodePtr->builtin_code,
1026 static_cast<tflite::BuiltinOperator>(opCodePtr->deprecated_builtin_code));
1027#else
telsoa01c577f2c2018-08-31 09:22:23 +01001028 auto builtinCode = opCodePtr->builtin_code;
Jim Flynnfca233e2021-09-23 12:16:53 +01001029#endif
telsoa01c577f2c2018-08-31 09:22:23 +01001030
1031 if (builtinCode > tflite::BuiltinOperator_MAX)
1032 {
James Ward58dec6b2020-09-11 17:32:44 +01001033 throw ParseException(fmt::format("Operator code {} is out of range 0-{}. "
1034 "subgraph:{} operator idx:{}. {}",
1035 builtinCode, tflite::BuiltinOperator_MAX, subgraphIndex,
1036 operatorIndex, CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01001037 }
1038
1039 // lookup and call the parser function
Colm Donelan6350d272020-06-09 16:56:25 +01001040 auto& parserFunction = m_ParserFunctions[builtinCode];
telsoa01c577f2c2018-08-31 09:22:23 +01001041 (this->*parserFunction)(subgraphIndex, operatorIndex);
Colm Donelan6350d272020-06-09 16:56:25 +01001042 ++operatorIndex;
telsoa01c577f2c2018-08-31 09:22:23 +01001043 }
telsoa01c577f2c2018-08-31 09:22:23 +01001044
Colm Donelan6350d272020-06-09 16:56:25 +01001045 SetupInputLayers(subgraphIndex);
1046 SetupOutputLayers(subgraphIndex);
1047 SetupConstantLayers(subgraphIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001048
Colm Donelan6350d272020-06-09 16:56:25 +01001049 ++subgraphIndex;
1050 operatorIndex = 0;
telsoa01c577f2c2018-08-31 09:22:23 +01001051 }
telsoa01c577f2c2018-08-31 09:22:23 +01001052 }
Colm Donelan6350d272020-06-09 16:56:25 +01001053 catch (const ParseException& e)
telsoa01c577f2c2018-08-31 09:22:23 +01001054 {
Colm Donelan6350d272020-06-09 16:56:25 +01001055 std::stringstream errorString;
1056 errorString << "Failed to parse operator #" << operatorIndex << " within subgraph #"
1057 << subgraphIndex << " error: " << e.what();
1058 ARMNN_LOG(error) << errorString.str();
1059 std::stringstream errors;
1060 errors << errorString.str() << "\n";
telsoa01c577f2c2018-08-31 09:22:23 +01001061 throw ParseException(errors.str());
1062 }
1063
1064 // establish the connections from the layer outputs to the inputs of the subsequent layers
Colm Donelan6350d272020-06-09 16:56:25 +01001065 for (subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001066 {
1067 for (size_t tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex)
1068 {
1069 if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot != nullptr)
1070 {
1071 for (size_t inputSlotIdx = 0;
1072 inputSlotIdx < m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size();
1073 ++inputSlotIdx)
1074 {
1075 m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot->Connect(
1076 *(m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots[inputSlotIdx]));
1077 }
1078 }
1079 }
1080 }
telsoa01c577f2c2018-08-31 09:22:23 +01001081 return std::move(m_Network);
1082}
1083
Mike Kelly0506ef02023-01-03 16:29:44 +00001084bool TfLiteParserImpl::ShouldConstantTensorBeConverted(TfLiteParserImpl::TensorRawPtr tensorPtr,
1085 armnn::DataType inputDataType,
1086 armnn::DataType tensorDataType)
Mike Kelly5880b912022-01-28 16:18:54 +00001087{
Mike Kelly0506ef02023-01-03 16:29:44 +00001088 return (TfLiteParserImpl::IsConstTensor(tensorPtr) && inputDataType == DataType::Float32 &&
1089 (tensorDataType == DataType::QAsymmU8 ||
1090 tensorDataType == DataType::QAsymmS8 ||
1091 tensorDataType == DataType::QSymmS8 ||
1092 tensorDataType == DataType::Signed32 ||
1093 tensorDataType == DataType::Signed64));
Mike Kelly5880b912022-01-28 16:18:54 +00001094}
1095
Kevin May7d96b162021-02-03 17:38:41 +00001096void TfLiteParserImpl::RegisterProducerOfTensor(size_t subgraphIndex,
1097 size_t tensorIndex,
1098 armnn::IOutputSlot* slot)
telsoa01c577f2c2018-08-31 09:22:23 +01001099{
1100 CHECK_TENSOR(m_Model, subgraphIndex, tensorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001101 ARMNN_ASSERT(m_SubgraphConnections.size() > subgraphIndex);
1102 ARMNN_ASSERT(m_SubgraphConnections[subgraphIndex].size() > tensorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001103
1104 TensorSlots & tensorSlots = m_SubgraphConnections[subgraphIndex][tensorIndex];
1105
Nikhil Rajd4d1c312022-08-03 18:20:59 +01001106 if (slot->GetOwningIConnectableLayer().GetType() != LayerType::Constant)
telsoa01c577f2c2018-08-31 09:22:23 +01001107 {
telsoa01c577f2c2018-08-31 09:22:23 +01001108
Nikhil Rajd4d1c312022-08-03 18:20:59 +01001109 // assuming there is only one producer for that tensor
1110 if (tensorSlots.outputSlot != nullptr)
1111 {
1112 throw ParseException(fmt::format("Another layer has already registered itself as the producer of "
1113 "subgraph:{} tensor:{} {}",
1114 subgraphIndex,
1115 tensorIndex,
1116 CHECK_LOCATION().AsString()));
1117 }
1118 }
telsoa01c577f2c2018-08-31 09:22:23 +01001119 tensorSlots.outputSlot = slot;
1120}
1121
Kevin May7d96b162021-02-03 17:38:41 +00001122void TfLiteParserImpl::RegisterConsumerOfTensor(size_t subgraphIndex,
1123 size_t tensorIndex,
1124 armnn::IInputSlot* slot)
telsoa01c577f2c2018-08-31 09:22:23 +01001125{
1126 CHECK_TENSOR(m_Model, subgraphIndex, tensorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001127 ARMNN_ASSERT(m_SubgraphConnections.size() > subgraphIndex);
1128 ARMNN_ASSERT(m_SubgraphConnections[subgraphIndex].size() > tensorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001129
Finn Williamsd4fa5452021-03-01 12:31:41 +00001130 TensorSlots& tensorSlots = m_SubgraphConnections[subgraphIndex][tensorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01001131 tensorSlots.inputSlots.push_back(slot);
1132}
1133
Kevin May7d96b162021-02-03 17:38:41 +00001134void TfLiteParserImpl::ParseCustomOperator(size_t subgraphIndex, size_t operatorIndex)
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001135{
1136 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1137
1138 // NOTE: By default we presume the custom operator is not supported
Kevin May7d96b162021-02-03 17:38:41 +00001139 auto customParserFunction = &TfLiteParserImpl::ParseUnsupportedOperator;
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001140
1141 // Identify custom code defined for custom operator
1142 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1143 const auto& customCode = m_Model->operator_codes[operatorPtr->opcode_index]->custom_code;
1144
Mike Kelly377fb212023-01-10 15:55:28 +00001145 // Find parser function that corresponds to custom code (if any)
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001146 auto iterator = m_CustomParserFunctions.find(customCode);
1147 if (iterator != m_CustomParserFunctions.end())
1148 {
1149 customParserFunction = iterator->second;
1150 }
1151
1152 // Run parser function
1153 (this->*customParserFunction)(subgraphIndex, operatorIndex);
1154}
1155
Kevin May7d96b162021-02-03 17:38:41 +00001156void TfLiteParserImpl::ParseUnsupportedOperator(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001157{
1158 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001159
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001160 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1161
1162 auto opcodeIndex = operatorPtr->opcode_index;
Jim Flynnfca233e2021-09-23 12:16:53 +01001163
1164// 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 +01001165#if defined(ARMNN_POST_TFLITE_2_3)
Jim Flynnfca233e2021-09-23 12:16:53 +01001166 auto opcode = std::max(m_Model->operator_codes[opcodeIndex]->builtin_code,
1167 static_cast<tflite::BuiltinOperator>(m_Model->operator_codes[opcodeIndex]->deprecated_builtin_code));
1168#else
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001169 auto opcode = m_Model->operator_codes[opcodeIndex]->builtin_code;
Jim Flynnfca233e2021-09-23 12:16:53 +01001170#endif
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001171
1172 if (!m_Options || !m_Options.value().m_StandInLayerForUnsupported)
1173 {
1174 // Do not add StandInLayer, throw ParseException instead
1175 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01001176 fmt::format("Operator not supported. "
1177 "subgraph:{} operator:{} "
1178 "opcode_index:{} opcode:{} / {} {}",
1179 subgraphIndex,
1180 operatorIndex,
1181 opcodeIndex,
1182 opcode,
1183 tflite::EnumNameBuiltinOperator(opcode),
1184 CHECK_LOCATION().AsString()));
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001185 }
1186
1187 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1188 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1189
Matthew Sloyan589e3e82020-09-11 16:17:48 +01001190 const unsigned int numInputs = armnn::numeric_cast<unsigned int>(inputs.size());
1191 const unsigned int numOutputs = armnn::numeric_cast<unsigned int>(outputs.size());
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001192
1193 StandInDescriptor descriptor(numInputs, numOutputs);
James Ward58dec6b2020-09-11 17:32:44 +01001194 auto layerName = fmt::format("StandIn:{}:{}:{}", subgraphIndex, operatorIndex, opcode);
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001195
1196 // Add a non-executable StandInLayer as a placeholder for any unsupported operator
1197 IConnectableLayer* layer = m_Network->AddStandInLayer(descriptor, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01001198 ARMNN_ASSERT(layer != nullptr);
1199
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001200 for (unsigned int i = 0u; i < numOutputs; ++i)
1201 {
Mike Kelly04d82292023-01-19 18:29:40 +00001202 layer->GetOutputSlot(i).SetTensorInfo(ToTensorInfo(outputs[0], true));
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001203 }
1204
1205 auto inputTensorIds = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1206 auto outputTensorIds = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1207
1208 RegisterInputSlots(subgraphIndex, operatorIndex, layer, inputTensorIds);
1209 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIds);
telsoa01c577f2c2018-08-31 09:22:23 +01001210}
1211
mathad01b392e982021-04-07 12:07:30 +01001212void TfLiteParserImpl::ParseCast(size_t subgraphIndex, size_t operatorIndex)
1213{
1214 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1215
1216 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1217 CHECK_VALID_SIZE(inputs.size(), 1);
1218 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1219 CHECK_VALID_SIZE(outputs.size(), 1);
1220
1221 auto layerName = fmt::format("Cast:{}:{}", subgraphIndex, operatorIndex);
1222
1223 IConnectableLayer* layer = m_Network->AddCastLayer(layerName.c_str());
1224 ARMNN_ASSERT(layer != nullptr);
1225
Mike Kelly377fb212023-01-10 15:55:28 +00001226 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
mathad01b392e982021-04-07 12:07:30 +01001227 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1228
1229 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1230 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1231
1232 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1233 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
1234}
1235
Kevin May7d96b162021-02-03 17:38:41 +00001236void TfLiteParserImpl::ParseConv2D(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001237{
1238 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1239
Mike Kelly0d77ae12022-01-07 17:42:27 +00001240 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1241 const auto* options = operatorPtr->builtin_options.AsConv2DOptions();
telsoa01c577f2c2018-08-31 09:22:23 +01001242
1243 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1244
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001245 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1246 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1247 CHECK_VALID_SIZE(outputs.size(), 1);
1248
telsoa01c577f2c2018-08-31 09:22:23 +01001249 Convolution2dDescriptor desc;
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001250 inputs.size() == 3 ?
1251 desc.m_BiasEnabled = true : desc.m_BiasEnabled = false;
telsoa01c577f2c2018-08-31 09:22:23 +01001252 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1253 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
jimfly01c25411c2018-11-14 17:47:22 +00001254 desc.m_DataLayout = armnn::DataLayout::NHWC;
Pablo Tellof0bd6832019-04-26 17:58:13 +01001255 desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
1256 desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
Kevin May83add212019-03-26 11:39:19 +00001257
Mike Kelly377fb212023-01-10 15:55:28 +00001258 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1259 armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
telsoa01c577f2c2018-08-31 09:22:23 +01001260
1261 // assuming input is NHWC
1262 unsigned int inputHeight = inputTensorInfo.GetShape()[1];
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001263 unsigned int inputWidth = inputTensorInfo.GetShape()[2];
telsoa01c577f2c2018-08-31 09:22:23 +01001264
1265 // assuming the filter is OHWI : Output, H, W, Input
1266 // which is essentially the same as NHWC
1267 unsigned int filterHeight = filterTensorInfo.GetShape()[1];
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001268 unsigned int filterWidth = filterTensorInfo.GetShape()[2];
telsoa01c577f2c2018-08-31 09:22:23 +01001269
Pablo Tellof0bd6832019-04-26 17:58:13 +01001270 CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
1271 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
1272 CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
1273 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
telsoa01c577f2c2018-08-31 09:22:23 +01001274
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001275 // Add the first input and weights tensor to the registration list.
1276 // The constant weights will be added by SetupConstantLayers.
1277 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1278 std::vector<unsigned int> tensorIndexesToRegister = { inputTensorIndexes[0], inputTensorIndexes[1] };
telsoa01c577f2c2018-08-31 09:22:23 +01001279
James Ward58dec6b2020-09-11 17:32:44 +01001280 auto layerName = fmt::format("Conv2D:{}:{}", subgraphIndex, operatorIndex);
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001281 armnn::IConnectableLayer* layer = m_Network->AddConvolution2dLayer(desc, layerName.c_str());
telsoa01c577f2c2018-08-31 09:22:23 +01001282
Mike Kelly0506ef02023-01-03 16:29:44 +00001283 if (ShouldConstantTensorBeConverted(inputs[1], inputTensorInfo.GetDataType(), filterTensorInfo.GetDataType()))
telsoa01c577f2c2018-08-31 09:22:23 +01001284 {
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001285 m_ConstantsToDequantize.emplace_back(inputs[1]->buffer);
telsoa01c577f2c2018-08-31 09:22:23 +01001286 }
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001287
1288 if (desc.m_BiasEnabled)
telsoa01c577f2c2018-08-31 09:22:23 +01001289 {
Mike Kelly377fb212023-01-10 15:55:28 +00001290 armnn::TensorInfo biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001291
1292 // Add the biases input to the registration list, a constant layer will be added by SetupConstantLayers.
1293 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
1294
Mike Kelly0506ef02023-01-03 16:29:44 +00001295 if (ShouldConstantTensorBeConverted(inputs[2], inputTensorInfo.GetDataType(), biasTensorInfo.GetDataType()))
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001296 {
1297 m_ConstantsToDequantize.emplace_back(inputs[2]->buffer);
1298 }
telsoa01c577f2c2018-08-31 09:22:23 +01001299 }
1300
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001301 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01001302
Mike Kelly377fb212023-01-10 15:55:28 +00001303 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
jimfly01c25411c2018-11-14 17:47:22 +00001304 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +01001305
1306 // register the input connection slots for the layer, connections are made after all layers have been created
1307 // only the tensors for the inputs are relevant, exclude the const tensors
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001308 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister);
telsoa01c577f2c2018-08-31 09:22:23 +01001309
jimfly01c25411c2018-11-14 17:47:22 +00001310 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
telsoa01c577f2c2018-08-31 09:22:23 +01001311 // register the output connection slots for the layer, connections are made after all layers have been created
1312 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001313 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, { outputTensorIndexes[0] });
telsoa01c577f2c2018-08-31 09:22:23 +01001314}
1315
Matthew Sloyan4d217c02021-10-07 11:48:58 +01001316// Conv3D support was added in TF 2.5, so for backwards compatibility a hash define is needed.
Cathal Corbett80b4ef02022-05-25 11:21:11 +01001317#if defined(ARMNN_POST_TFLITE_2_4)
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001318void TfLiteParserImpl::ParseConv3D(size_t subgraphIndex, size_t operatorIndex)
1319{
1320 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1321
1322 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1323 const auto* options = operatorPtr->builtin_options.AsConv3DOptions();
1324
1325 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1326
1327 Convolution3dDescriptor desc;
1328 desc.m_BiasEnabled = false;
1329 desc.m_DataLayout = armnn::DataLayout::NDHWC;
1330 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1331 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1332 desc.m_StrideZ = CHECKED_NON_NEGATIVE(options->stride_d);
1333 desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
1334 desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
1335 desc.m_DilationZ = CHECKED_NON_NEGATIVE(options->dilation_d_factor);
1336
1337 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1338 CHECK_VALID_SIZE(inputs.size(), 2, 3);
1339
1340 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1341 CHECK_VALID_SIZE(outputs.size(), 1);
1342
Mike Kelly377fb212023-01-10 15:55:28 +00001343 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1344 armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001345
1346 // Assuming input is NDHWC
1347 unsigned int inputDepth = inputTensorInfo.GetShape()[1];
1348 unsigned int inputHeight = inputTensorInfo.GetShape()[2];
1349 unsigned int inputWidth = inputTensorInfo.GetShape()[3];
1350
1351 // Assuming the filter is DHWIO : Depth, Height, Width, OutputChannels, InputChannels
1352 unsigned int filterDepth = filterTensorInfo.GetShape()[0];
1353 unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1354 unsigned int filterWidth = filterTensorInfo.GetShape()[2];
1355
1356 CalcPadding(inputDepth, filterDepth, desc.m_StrideZ,
Teresa Charlin502ab942022-03-23 17:23:07 +00001357 desc.m_DilationZ, desc.m_PadFront, desc.m_PadBack, options->padding);
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001358 CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
1359 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
1360 CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
1361 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
1362
Mike Kelly5880b912022-01-28 16:18:54 +00001363 auto filterTensorAndData = CreateConstTensorNonPermuted(inputs[1], filterTensorInfo, inputTensorInfo.GetDataType());
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001364
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001365 auto layerName = fmt::format("Conv3D:{}:{}", subgraphIndex, operatorIndex);
1366
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001367 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1368 // Add the first input and weights tensor to the registration list.
1369 // The constant weights will be added by SetupConstantLayers.
1370 std::vector<unsigned int> tensorIndexesToRegister = {inputTensorIndexes[0], inputTensorIndexes[1]};
1371
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001372 if (inputs.size() == 3)
1373 {
1374 desc.m_BiasEnabled = true;
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001375
1376 // Add the biases input to the registration list, a constant layer will be added by SetupConstantLayers.
1377 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001378 }
1379
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001380 armnn::IConnectableLayer* layer = m_Network->AddConvolution3dLayer(desc, layerName.c_str());
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001381 ARMNN_ASSERT(layer != nullptr);
1382
Mike Kelly377fb212023-01-10 15:55:28 +00001383 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001384 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1385
1386 // Register the input connection slots for the layer, connections are made after all layers have been created
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001387 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister);
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001388
1389 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
1390 // Register the output connection slots for the layer, connections are made after all layers have been created
1391 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1392 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1393}
Matthew Sloyan4d217c02021-10-07 11:48:58 +01001394#endif
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001395
Kevin May7d96b162021-02-03 17:38:41 +00001396void TfLiteParserImpl::ParseDepthwiseConv2D(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001397{
1398 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1399
Mike Kelly0d77ae12022-01-07 17:42:27 +00001400 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1401 const auto* options = operatorPtr->builtin_options.AsDepthwiseConv2DOptions();
telsoa01c577f2c2018-08-31 09:22:23 +01001402
1403 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1404
1405 DepthwiseConvolution2dDescriptor desc;
telsoa01c577f2c2018-08-31 09:22:23 +01001406 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1407 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
jimfly01c25411c2018-11-14 17:47:22 +00001408 desc.m_DataLayout = armnn::DataLayout::NHWC;
Matthew Jacksond6a9dee2019-07-22 13:53:24 +01001409 CHECKED_NON_NEGATIVE(options->depth_multiplier);
telsoa01c577f2c2018-08-31 09:22:23 +01001410
1411 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1412 CHECK_VALID_SIZE(inputs.size(), 2, 3);
Cathal Corbett06902652022-04-14 17:55:11 +01001413 if (inputs.size() == 3)
1414 {
1415 desc.m_BiasEnabled = true;
1416 }
1417
telsoa01c577f2c2018-08-31 09:22:23 +01001418 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1419 CHECK_VALID_SIZE(outputs.size(), 1);
Pablo Tellof0bd6832019-04-26 17:58:13 +01001420 desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
1421 desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
Kevin May83add212019-03-26 11:39:19 +00001422
Mike Kelly377fb212023-01-10 15:55:28 +00001423 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1424 armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
telsoa01c577f2c2018-08-31 09:22:23 +01001425
Matteo Martincigh747ef822018-12-18 09:26:39 +00001426 // Assuming input is NHWC
telsoa01c577f2c2018-08-31 09:22:23 +01001427 unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1428 unsigned int inputWidth = inputTensorInfo.GetShape()[2];
Matteo Martincigh747ef822018-12-18 09:26:39 +00001429
1430 // TensorflowLite weights come in the format [1, H, W, I * M]
telsoa01c577f2c2018-08-31 09:22:23 +01001431 unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1432 unsigned int filterWidth = filterTensorInfo.GetShape()[2];
1433
Pablo Tellof0bd6832019-04-26 17:58:13 +01001434 CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
1435 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
1436 CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
1437 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
telsoa01c577f2c2018-08-31 09:22:23 +01001438
Jan Eilers53ef7952021-06-02 12:01:25 +01001439 // 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 +01001440 auto layerName = fmt::format("DepthwiseConv2D:{}:{}", subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001441
Cathal Corbett06902652022-04-14 17:55:11 +01001442 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1443 // Add the first input and weights tensor to the registration list.
1444 // The constant weights will be added by SetupConstantLayers.
1445 std::vector<unsigned int> tensorIndexesToRegister = {inputTensorIndexes[0], inputTensorIndexes[1]};
1446
1447 armnn::IConnectableLayer* layer = m_Network->AddDepthwiseConvolution2dLayer(desc, layerName.c_str());
1448
1449 if (desc.m_BiasEnabled)
telsoa01c577f2c2018-08-31 09:22:23 +01001450 {
1451 desc.m_BiasEnabled = true;
Mike Kelly377fb212023-01-10 15:55:28 +00001452 TensorInfo biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Cathal Corbett06902652022-04-14 17:55:11 +01001453
1454 // Add the biases input to the registration list, a constant layer will be added by SetupConstantLayers.
1455 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
telsoa01c577f2c2018-08-31 09:22:23 +01001456 }
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001457 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01001458
Mike Kelly377fb212023-01-10 15:55:28 +00001459 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
jimfly01c25411c2018-11-14 17:47:22 +00001460 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +01001461
1462 // register the input connection slots for the layer, connections are made after all layers have been created
1463 // only the tensors for the inputs are relevant, exclude the const tensors
Cathal Corbett06902652022-04-14 17:55:11 +01001464 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister);
telsoa01c577f2c2018-08-31 09:22:23 +01001465
jimfly01c25411c2018-11-14 17:47:22 +00001466 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
telsoa01c577f2c2018-08-31 09:22:23 +01001467 // register the output connection slots for the layer, connections are made after all layers have been created
1468 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1469 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1470}
1471
Kevin May7d96b162021-02-03 17:38:41 +00001472void TfLiteParserImpl::ParseDequantize(size_t subgraphIndex, size_t operatorIndex)
Finn Williamsed66d142019-12-06 09:55:55 +00001473{
1474 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1475
1476 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1477 CHECK_VALID_SIZE(inputs.size(), 1);
1478
1479 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1480 CHECK_VALID_SIZE(outputs.size(), 1);
1481
James Ward58dec6b2020-09-11 17:32:44 +01001482 auto layerName = fmt::format("Dequantize:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsed66d142019-12-06 09:55:55 +00001483
1484 IConnectableLayer* layer = m_Network->AddDequantizeLayer(layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001485 ARMNN_ASSERT(layer != nullptr);
Finn Williamsed66d142019-12-06 09:55:55 +00001486
Mike Kelly377fb212023-01-10 15:55:28 +00001487 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Finn Williamsed66d142019-12-06 09:55:55 +00001488 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1489
1490 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1491 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1492
1493 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1494 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
1495}
1496
Teresa Charlin3ab85482021-06-08 16:59:29 +01001497void TfLiteParserImpl::ParseExpandDims(size_t subgraphIndex, size_t operatorIndex)
1498{
1499 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1500
1501 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1502 CHECK_VALID_SIZE(inputs.size(), 2);
1503
1504 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1505 CHECK_VALID_SIZE(outputs.size(), 1);
1506
1507 auto layerName = fmt::format("ExpandDims:{}:{}", subgraphIndex, operatorIndex);
1508
Mike Kelly377fb212023-01-10 15:55:28 +00001509 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Teresa Charlin3ab85482021-06-08 16:59:29 +01001510 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Teresa Charlin3ab85482021-06-08 16:59:29 +01001511 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1512
Teresa Charlina7a605a2023-06-14 14:51:17 +01001513 armnn::TensorInfo axisTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
1514
1515 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1516 if (axisBufferPtr == nullptr)
1517 {
1518 throw ParseException(fmt::format("{}: Operation has invalid inputs. Failed to read axis.",
1519 CHECK_LOCATION().AsString()));
1520 }
1521
1522 std::vector<int32_t> axisData(axisTensorInfo.GetNumElements());
1523 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
1524 int32_t axis = axisData[0];
1525
1526 auto inputRank = static_cast<int32_t>(inputTensorInfo.GetShape().GetNumDimensions());
1527 auto outputRank = inputRank + 1;
1528 if((axis < -1 * outputRank) || (outputRank <= axis))
1529 {
1530 throw ParseException(fmt::format("{}: Axis {} is not within [-{}, {}) range.",
1531 CHECK_LOCATION().AsString(), axis, outputRank, outputRank));
1532 }
1533
1534 axis = axis < 0 ? (axis + outputRank) : axis;
1535
1536 std::vector<unsigned int> shape(static_cast<unsigned int>(outputRank));
1537 unsigned int inputShapeIndex = 0;
1538 for (unsigned int i = 0; i < static_cast<unsigned int>(outputRank); ++i)
1539 {
1540 if (i == static_cast<unsigned int>(axis))
1541 {
1542 shape[i] = 1;
1543 }
1544 else
1545 {
1546 shape[i] = inputTensorInfo.GetShape()[inputShapeIndex];
1547 ++inputShapeIndex;
1548 }
1549 }
1550
Teresa Charlin3ab85482021-06-08 16:59:29 +01001551 ReshapeDescriptor reshapeDesc;
Teresa Charlina7a605a2023-06-14 14:51:17 +01001552 reshapeDesc.m_TargetShape = TensorShape(static_cast<unsigned int>(outputRank), shape.data());
1553 outputTensorInfo.SetShape(reshapeDesc.m_TargetShape);
Teresa Charlin3ab85482021-06-08 16:59:29 +01001554
1555 IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
1556 ARMNN_ASSERT(layer != nullptr);
1557 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1558
Teresa Charlina7a605a2023-06-14 14:51:17 +01001559 auto outputTensorIds = GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex);
1560 m_TensorInfos[outputTensorIds[0]] = outputTensorInfo;
1561
Teresa Charlin3ab85482021-06-08 16:59:29 +01001562 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1563 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1564
1565 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1566 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1567}
1568
Kevin May7d96b162021-02-03 17:38:41 +00001569void TfLiteParserImpl::ParseTranspose(size_t subgraphIndex, size_t operatorIndex)
Keith Davis4cd29a02019-09-09 14:49:20 +01001570{
1571 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1572
1573 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Kevin May85d92602019-09-27 17:21:06 +01001574 CHECK_VALID_SIZE(inputs.size(), 1, 2);
Keith Davis4cd29a02019-09-09 14:49:20 +01001575
1576 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1577 CHECK_VALID_SIZE(outputs.size(), 1);
1578
James Ward58dec6b2020-09-11 17:32:44 +01001579 auto layerName = fmt::format("Transpose:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly08759e22020-03-02 11:41:31 +00001580 TransposeDescriptor desc;
Keith Davis4cd29a02019-09-09 14:49:20 +01001581
josh minorba424d22019-11-13 10:55:17 -06001582 if (inputs.size() == 2)
Kevin May85d92602019-09-27 17:21:06 +01001583 {
Mike Kelly377fb212023-01-10 15:55:28 +00001584 armnn::TensorInfo permuteTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Kevin May85d92602019-09-27 17:21:06 +01001585 BufferRawPtr permuteBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
josh minorba424d22019-11-13 10:55:17 -06001586 auto numPermVecElements = permuteTensorInfo.GetNumElements();
1587 std::vector<unsigned int> permuteShape(numPermVecElements);
Kevin May85d92602019-09-27 17:21:06 +01001588 ::memcpy(permuteShape.data(), permuteBufferPtr->data.data(), permuteTensorInfo.GetNumBytes());
Mike Kelly08759e22020-03-02 11:41:31 +00001589 PermutationVector permutationVector(permuteShape.data(), permuteTensorInfo.GetNumElements());
Kevin May85d92602019-09-27 17:21:06 +01001590
Mike Kelly08759e22020-03-02 11:41:31 +00001591 desc = TransposeDescriptor(permutationVector);
Kevin May85d92602019-09-27 17:21:06 +01001592 }
Mike Kelly377fb212023-01-10 15:55:28 +00001593 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Keith Davis4cd29a02019-09-09 14:49:20 +01001594
James Conroy05102392020-06-24 15:39:55 +01001595 IConnectableLayer* layer = m_Network->AddTransposeLayer(desc, layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001596 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00001597
1598 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
1599 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Keith Davis4cd29a02019-09-09 14:49:20 +01001600 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1601
1602 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1603 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1604
1605 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1606 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1607}
1608
Kevin May7d96b162021-02-03 17:38:41 +00001609void TfLiteParserImpl::ParseTransposeConv(size_t subgraphIndex, size_t operatorIndex)
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001610{
1611 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1612
Mike Kelly0d77ae12022-01-07 17:42:27 +00001613 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1614 const auto* options = operatorPtr->builtin_options.AsTransposeConvOptions();
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001615
1616 TransposeConvolution2dDescriptor desc;
1617 desc.m_BiasEnabled = false;
1618 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1619 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1620 desc.m_DataLayout = armnn::DataLayout::NHWC;
1621
1622 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
David Monahan61683802021-01-12 09:11:07 +00001623 if (inputs.size() == 4)
1624 {
1625 desc.m_BiasEnabled = true;
1626 }
1627 else
1628 {
1629 CHECK_VALID_SIZE(inputs.size(), 3);
1630 }
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001631
1632 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1633 CHECK_VALID_SIZE(outputs.size(), 1);
1634
Teresa Charlin024ef0b2023-04-26 11:19:03 +01001635
1636 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
1637 armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
1638
1639 // TfLite uses NHWC tensors
1640 const unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1641 const unsigned int inputWidth = inputTensorInfo.GetShape()[2];
1642
1643 const unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1644 const unsigned int filterWidth = filterTensorInfo.GetShape()[2];
1645
Ryan OSheaf0a35b82023-02-21 18:32:30 +00001646 // This block determines the output shape of the transpose convolution. If the output shape tensor ptr is not null
1647 // And the tensor is a constant, we can access the data at load time and set the output shape of the
1648 // layer. If this is not constant, We do not have access to the shape data, so we have to use
1649 // infer output shape and skip this code block.
1650 if (inputs[0] && IsConstTensor(inputs[0]))
Colm Donelan0ad3ef12020-07-03 15:54:28 +01001651 {
Mike Kelly377fb212023-01-10 15:55:28 +00001652 armnn::TensorInfo tensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Colm Donelan0ad3ef12020-07-03 15:54:28 +01001653 std::vector<int> output_shape(tensorInfo.GetNumElements());
Mike Kelly377fb212023-01-10 15:55:28 +00001654
Colm Donelan0ad3ef12020-07-03 15:54:28 +01001655 if (tensorInfo.GetDataType() == DataType::Signed32)
1656 {
1657 ::memcpy(output_shape.data(), GetBuffer(m_Model, inputs[0]->buffer)->data.data(), tensorInfo.GetNumBytes());
1658 }
1659 if (tensorInfo.GetDataType() == DataType::QAsymmU8)
1660 {
1661 for(unsigned int i=0; i < tensorInfo.GetNumElements(); i++)
1662 {
1663 output_shape[i] = GetBuffer(m_Model, inputs[0]->buffer)->data.data()[i];
1664 }
1665 }
1666 // Change from signed to unsigned int to store in TransposeConvolution2dDescriptor.
1667 for (int dimension : output_shape)
1668 {
1669 desc.m_OutputShape.push_back(static_cast<unsigned int>(dimension));
1670 }
1671 desc.m_OutputShapeEnabled = true;
Teresa Charlin024ef0b2023-04-26 11:19:03 +01001672
1673 // TfLite uses NHWC tensors
1674 const unsigned int outputHeight = desc.m_OutputShape[1];
1675 const unsigned int outputWidth = desc.m_OutputShape[2];
1676
1677 CalcPadding(inputHeight,
1678 filterHeight,
1679 desc.m_StrideY,
1680 1, // DilationY
1681 desc.m_PadTop,
1682 desc.m_PadBottom,
1683 options->padding,
1684 outputHeight);
1685
1686 CalcPadding(inputWidth,
1687 filterWidth,
1688 desc.m_StrideX,
1689 1, // DilationX
1690 desc.m_PadLeft,
1691 desc.m_PadRight,
1692 options->padding,
1693 outputWidth);
Colm Donelan0ad3ef12020-07-03 15:54:28 +01001694 }
Teresa Charlin024ef0b2023-04-26 11:19:03 +01001695 else
1696 {
1697 CalcPadding(inputHeight,
1698 filterHeight,
1699 desc.m_StrideY,
1700 1, // DilationY
1701 desc.m_PadTop,
1702 desc.m_PadBottom,
1703 options->padding);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001704
Teresa Charlin024ef0b2023-04-26 11:19:03 +01001705 CalcPadding(inputWidth,
1706 filterWidth,
1707 desc.m_StrideX,
1708 1, // DilationX
1709 desc.m_PadLeft,
1710 desc.m_PadRight,
1711 options->padding);
1712 }
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001713
Mike Kelly5880b912022-01-28 16:18:54 +00001714 auto filterTensorAndData = CreateConstTensorNonPermuted(inputs[1], filterTensorInfo, inputTensorInfo.GetDataType());
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001715
1716 armnn::IConnectableLayer* layer = nullptr;
James Ward58dec6b2020-09-11 17:32:44 +01001717 auto layerName = fmt::format("TransposeConv:{}:{}", subgraphIndex, operatorIndex);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001718
David Monahan61683802021-01-12 09:11:07 +00001719 if (desc.m_BiasEnabled)
1720 {
Mike Kelly377fb212023-01-10 15:55:28 +00001721 auto biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 3);
Mike Kelly5880b912022-01-28 16:18:54 +00001722 auto biasConstTensor = CreateConstTensorNonPermuted(inputs[3], biasTensorInfo, inputTensorInfo.GetDataType());
David Monahan61683802021-01-12 09:11:07 +00001723 layer = m_Network->AddTransposeConvolution2dLayer(desc,
Mike Kelly5880b912022-01-28 16:18:54 +00001724 filterTensorAndData.first,
1725 biasConstTensor.first,
David Monahan61683802021-01-12 09:11:07 +00001726 layerName.c_str());
1727 }
1728 else
1729 {
1730 layer = m_Network->AddTransposeConvolution2dLayer(desc,
Mike Kelly5880b912022-01-28 16:18:54 +00001731 filterTensorAndData.first,
David Monahan61683802021-01-12 09:11:07 +00001732 EmptyOptional(),
1733 layerName.c_str());
1734 }
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001735
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001736 ARMNN_ASSERT(layer != nullptr);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001737
Mike Kelly377fb212023-01-10 15:55:28 +00001738 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0 , { 2, 1 });
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001739 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1740
1741 // only the tensors for the inputs are relevant, exclude the const (filter) tensor
1742 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Matthew Jacksonccb25ea2019-08-20 17:18:33 +01001743 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[2]});
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001744
1745 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1746 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1747}
1748
Kevin May7d96b162021-02-03 17:38:41 +00001749void TfLiteParserImpl::ParseAveragePool2D(size_t subgraphIndex, size_t operatorIndex)
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001750{
1751 ParsePool(subgraphIndex, operatorIndex, PoolingAlgorithm::Average);
1752}
1753
Samuel Yapfd3ba5a2022-08-24 17:04:34 +01001754void TfLiteParserImpl::ParseBatchMatMul(size_t subgraphIndex, size_t operatorIndex)
1755{
1756 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1757
1758 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1759 CHECK_VALID_SIZE(inputs.size(), 2);
1760
1761 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1762 CHECK_VALID_SIZE(outputs.size(), 1);
1763
1764 auto layerName = fmt::format("BatchMatMul:{}:{}", subgraphIndex, operatorIndex);
1765
Mike Kelly377fb212023-01-10 15:55:28 +00001766 TensorInfo inputXTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1767 TensorInfo inputYTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Samuel Yapfd3ba5a2022-08-24 17:04:34 +01001768
1769 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1770 const auto* options = operatorPtr->builtin_options.AsBatchMatMulOptions();
1771
Teresa Charlinbc37a6b2022-09-22 10:12:58 +01001772 // Adjoint in tensorflow lite performs transpose operation
1773 BatchMatMulDescriptor descriptor(options->adj_x,
1774 options->adj_y,
Samuel Yapfd3ba5a2022-08-24 17:04:34 +01001775 false,
Teresa Charlinbc37a6b2022-09-22 10:12:58 +01001776 false);
Samuel Yapfd3ba5a2022-08-24 17:04:34 +01001777 // Arbitrary DataLayout
1778
1779 IConnectableLayer* layer = m_Network->AddBatchMatMulLayer(descriptor, layerName.c_str());
1780 ARMNN_ASSERT(layer != nullptr);
1781
Mike Kelly377fb212023-01-10 15:55:28 +00001782 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Samuel Yapfd3ba5a2022-08-24 17:04:34 +01001783 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1784
1785 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1786 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
1787
1788 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1789 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1790}
1791
Kevin May7d96b162021-02-03 17:38:41 +00001792void TfLiteParserImpl::ParseBatchToSpaceND(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001793{
1794 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1795
1796 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1797 CHECK_VALID_SIZE(inputs.size(), 3);
1798
1799 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1800 CHECK_VALID_SIZE(outputs.size(), 1);
1801
Mike Kelly377fb212023-01-10 15:55:28 +00001802 armnn::TensorInfo blockShapeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001803 BufferRawPtr blockShapeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1804
Mike Kelly377fb212023-01-10 15:55:28 +00001805 armnn::TensorInfo cropsTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001806 BufferRawPtr cropsBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
1807
1808 std::vector<unsigned int> blockShape(blockShapeTensorInfo.GetNumElements());
1809 ::memcpy(blockShape.data(), blockShapeBufferPtr->data.data(), blockShapeTensorInfo.GetNumBytes());
1810
1811 std::vector<unsigned int> cropsVector(cropsTensorInfo.GetNumElements());
1812 ::memcpy(cropsVector.data(), cropsBufferPtr->data.data(), cropsTensorInfo.GetNumBytes());
1813
1814 size_t step = 2;
1815 std::vector<std::pair<unsigned int, unsigned int>> crops;
1816 for (unsigned int i = 0; i < cropsTensorInfo.GetNumElements() / step; ++i)
1817 {
1818 crops.emplace_back(cropsVector[i * step], cropsVector[i * step + 1]);
1819 }
1820
1821 armnn::BatchToSpaceNdDescriptor desc;
1822 desc.m_BlockShape = blockShape;
1823 desc.m_Crops = crops;
1824 desc.m_DataLayout = armnn::DataLayout::NHWC;
1825
James Ward58dec6b2020-09-11 17:32:44 +01001826 auto layerName = fmt::format("BatchToSpaceND:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001827
Mike Kelly377fb212023-01-10 15:55:28 +00001828 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
James Conroy05102392020-06-24 15:39:55 +01001829
1830 IConnectableLayer* layer = m_Network->AddBatchToSpaceNdLayer(desc, layerName.c_str());
1831 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00001832
1833 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
1834 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001835 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1836
1837 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1838 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1839
1840 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1841 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1842}
1843
Kevin May7d96b162021-02-03 17:38:41 +00001844void TfLiteParserImpl::ParseL2Normalization(size_t subgraphIndex, size_t operatorIndex)
Matthew Jackson28c94572019-07-18 10:47:03 +01001845{
1846 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1847
1848 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1849 CHECK_VALID_SIZE(inputs.size(), 1);
1850
1851 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1852 CHECK_VALID_SIZE(outputs.size(), 1);
1853
1854 L2NormalizationDescriptor desc;
1855 desc.m_DataLayout = armnn::DataLayout::NHWC;
James Ward58dec6b2020-09-11 17:32:44 +01001856 auto layerName = fmt::format("L2Normalization:{}:{}", subgraphIndex, operatorIndex);
Matthew Jackson28c94572019-07-18 10:47:03 +01001857 IConnectableLayer* layer = m_Network->AddL2NormalizationLayer(desc, layerName.c_str());
1858
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001859 ARMNN_ASSERT(layer != nullptr);
Matthew Jackson28c94572019-07-18 10:47:03 +01001860
Mike Kelly377fb212023-01-10 15:55:28 +00001861 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Matthew Jackson28c94572019-07-18 10:47:03 +01001862 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1863
1864 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1865 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1866
1867 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1868 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1869}
1870
Kevin May7d96b162021-02-03 17:38:41 +00001871void TfLiteParserImpl::ParseMaxPool2D(size_t subgraphIndex, size_t operatorIndex)
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001872{
1873 ParsePool(subgraphIndex, operatorIndex, PoolingAlgorithm::Max);
1874}
1875
Kevin May7d96b162021-02-03 17:38:41 +00001876void TfLiteParserImpl::ParseMaximum(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001877{
1878 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1879
1880 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1881 CHECK_VALID_SIZE(inputs.size(), 2);
1882
1883 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1884 CHECK_VALID_SIZE(outputs.size(), 1);
1885
James Ward58dec6b2020-09-11 17:32:44 +01001886 auto layerName = fmt::format("Maximum:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01001887
Mike Kelly377fb212023-01-10 15:55:28 +00001888 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1889 TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
James Conroy05102392020-06-24 15:39:55 +01001890 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001891
Mike Kelly3ec30772023-03-08 13:47:17 +00001892 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Maximum, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01001893 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00001894
1895 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
1896 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001897 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1898
1899 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01001900 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001901
1902 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1903 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1904}
1905
Kevin May7d96b162021-02-03 17:38:41 +00001906void TfLiteParserImpl::ParseMinimum(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001907{
1908 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1909
1910 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1911 CHECK_VALID_SIZE(inputs.size(), 2);
1912
1913 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1914 CHECK_VALID_SIZE(outputs.size(), 1);
1915
James Ward58dec6b2020-09-11 17:32:44 +01001916 auto layerName = fmt::format("Minimum:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01001917
Mike Kelly377fb212023-01-10 15:55:28 +00001918 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1919 TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
James Conroy05102392020-06-24 15:39:55 +01001920 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001921
Mike Kelly3ec30772023-03-08 13:47:17 +00001922 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Minimum, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01001923 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00001924
1925 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
1926 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001927 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1928
1929 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01001930 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001931
1932 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1933 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1934}
1935
Kevin May7d96b162021-02-03 17:38:41 +00001936void TfLiteParserImpl::ParsePool(size_t subgraphIndex,
1937 size_t operatorIndex,
1938 PoolingAlgorithm algorithm)
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001939{
1940 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1941
Mike Kelly0d77ae12022-01-07 17:42:27 +00001942 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1943 const auto* options = operatorPtr->builtin_options.AsPool2DOptions();
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001944
1945 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1946
1947 std::string layerName;
1948
1949 switch (algorithm)
1950 {
1951 case PoolingAlgorithm::Average:
1952 layerName =
James Ward58dec6b2020-09-11 17:32:44 +01001953 fmt::format("AveragePool2D:{}:{}", subgraphIndex, operatorIndex);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001954 break;
1955 case PoolingAlgorithm::Max:
1956 layerName =
James Ward58dec6b2020-09-11 17:32:44 +01001957 fmt::format("MaxPool2D:{}:{}", subgraphIndex, operatorIndex);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001958 break;
1959 default:
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001960 ARMNN_ASSERT_MSG(false, "Unsupported Pooling Algorithm");
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001961 }
1962
1963 Pooling2dDescriptor desc;
1964
1965 desc.m_PoolType = algorithm;
1966 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1967 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1968 desc.m_PoolWidth = CHECKED_NON_NEGATIVE(options->filter_width);
1969 desc.m_PoolHeight = CHECKED_NON_NEGATIVE(options->filter_height);
1970 desc.m_PaddingMethod = PaddingMethod::Exclude;
1971 desc.m_OutputShapeRounding = OutputShapeRounding::Floor;
jimfly01c25411c2018-11-14 17:47:22 +00001972 desc.m_DataLayout = armnn::DataLayout::NHWC;
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001973
1974 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1975 CHECK_VALID_SIZE(inputs.size(), 1);
Mike Kelly377fb212023-01-10 15:55:28 +00001976 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001977
1978 // assuming input is NHWC
1979 unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1980 unsigned int inputWidth = inputTensorInfo.GetShape()[2];
1981
Pablo Tellof0bd6832019-04-26 17:58:13 +01001982 CalcPadding(inputHeight, desc.m_PoolHeight, desc.m_StrideY, 1u,
1983 desc.m_PadTop, desc.m_PadBottom, options->padding);
1984 CalcPadding(inputWidth, desc.m_PoolWidth, desc.m_StrideX, 1u,
1985 desc.m_PadLeft, desc.m_PadRight, options->padding);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001986
1987 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1988 CHECK_VALID_SIZE(outputs.size(), 1);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001989
James Conroy05102392020-06-24 15:39:55 +01001990 IConnectableLayer* layer = m_Network->AddPooling2dLayer(desc, layerName.c_str());
1991 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00001992
1993 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
1994 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
jimfly01c25411c2018-11-14 17:47:22 +00001995 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001996
1997 // register the input connection slots for the layer, connections are made after all layers have been created
1998 // only the tensors for the inputs are relevant, exclude the const tensors
1999 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
jimfly01c25411c2018-11-14 17:47:22 +00002000 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01002001
jimfly01c25411c2018-11-14 17:47:22 +00002002 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01002003 // register the output connection slots for the layer, connections are made after all layers have been created
2004 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2005 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2006}
2007
Kevin May7d96b162021-02-03 17:38:41 +00002008void TfLiteParserImpl::ParseSlice(size_t subgraphIndex, size_t operatorIndex)
josh minorba424d22019-11-13 10:55:17 -06002009{
2010 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2011
2012 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2013 CHECK_VALID_SIZE(inputs.size(), 3);
2014 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2015 CHECK_VALID_SIZE(outputs.size(), 1);
2016
2017 SliceDescriptor desc;
2018
2019 // set begin tensor info for slice descriptor
Mike Kelly377fb212023-01-10 15:55:28 +00002020 armnn::TensorInfo beginTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
josh minorba424d22019-11-13 10:55:17 -06002021 BufferRawPtr beginBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2022
2023 std::vector<unsigned int> begin(beginTensorInfo.GetNumElements());
2024 ::memcpy(begin.data(), beginBufferPtr->data.data(), beginTensorInfo.GetNumBytes());
2025
2026 // set size tensor info for slice descriptor
Mike Kelly377fb212023-01-10 15:55:28 +00002027 armnn::TensorInfo sizeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
josh minorba424d22019-11-13 10:55:17 -06002028 BufferRawPtr sizeBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
2029
Cathal Corbettde33dda2022-09-20 16:40:09 +01002030 std::vector<int> signedSize(sizeTensorInfo.GetNumElements(), 1);
2031
2032 // if size buffer data is not specified, all contents of size vector remain as values of 1
2033 if (sizeBufferPtr->data.data())
2034 {
2035 ::memcpy(signedSize.data(), sizeBufferPtr->data.data(), sizeTensorInfo.GetNumBytes());
2036 }
2037
josh minorba424d22019-11-13 10:55:17 -06002038 std::vector<unsigned int> size(sizeTensorInfo.GetNumElements());
Mike Kelly377fb212023-01-10 15:55:28 +00002039 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Mike Kelly7ba84d62021-09-10 15:27:19 +01002040
2041 for (unsigned int i = 0; i < signedSize.size(); ++i)
2042 {
2043 int signedValue = signedSize[i];
Jim Flynnfca233e2021-09-23 12:16:53 +01002044
Mike Kelly7ba84d62021-09-10 15:27:19 +01002045 if (signedValue < -1 || signedValue > static_cast<int>(inputTensorInfo.GetShape()[i] - begin[i]))
2046 {
2047 throw ParseException(fmt::format("Invalid value for size {} size must be in range "
2048 "[-1, inputDimSize - begin] [-1, {}] inclusive {}",
2049 signedValue,
2050 inputTensorInfo.GetShape()[i] - begin[i],
2051 CHECK_LOCATION().AsString()));
2052 }
2053
2054 if (signedValue == -1)
2055 {
2056 size[i] = inputTensorInfo.GetShape()[i] - begin[i];
2057 }
2058 else
2059 {
2060 size[i] = static_cast<unsigned int>(signedValue);
2061 }
2062 }
2063
josh minorba424d22019-11-13 10:55:17 -06002064 desc = SliceDescriptor(begin, size);
2065
James Ward58dec6b2020-09-11 17:32:44 +01002066 auto layerName = fmt::format("Slice:{}:{}", subgraphIndex, operatorIndex);
josh minorba424d22019-11-13 10:55:17 -06002067
James Conroy05102392020-06-24 15:39:55 +01002068 IConnectableLayer* const layer = m_Network->AddSliceLayer(desc, layerName.c_str());
Mike Kelly377fb212023-01-10 15:55:28 +00002069
2070 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
2071 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
josh minorba424d22019-11-13 10:55:17 -06002072 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2073
2074 // register the input connection slots for the layer, connections are made after all layers have been created
2075 // only the tensors for the inputs are relevant, exclude the const tensors
2076 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2077 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2078
2079 // register the output connection slots for the layer, connections are made after all layers have been created
2080 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2081 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2082}
2083
Kevin May7d96b162021-02-03 17:38:41 +00002084void TfLiteParserImpl::ParseSoftmax(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01002085{
2086 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00002087 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2088 const auto* options = operatorPtr->builtin_options.AsSoftmaxOptions();
telsoa01c577f2c2018-08-31 09:22:23 +01002089
2090 SoftmaxDescriptor desc;
2091 desc.m_Beta = options->beta;
2092
2093 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2094 CHECK_VALID_SIZE(inputs.size(), 1);
2095 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2096 CHECK_VALID_SIZE(outputs.size(), 1);
2097
James Ward58dec6b2020-09-11 17:32:44 +01002098 auto layerName = fmt::format("Softmax:{}:{}", subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01002099 IConnectableLayer* const layer = m_Network->AddSoftmaxLayer(desc, layerName.c_str());
2100
Mike Kelly377fb212023-01-10 15:55:28 +00002101 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
telsoa01c577f2c2018-08-31 09:22:23 +01002102 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2103
2104 // register the input connection slots for the layer, connections are made after all layers have been created
2105 // only the tensors for the inputs are relevant, exclude the const tensors
2106 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2107 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2108
2109 // register the output connection slots for the layer, connections are made after all layers have been created
2110 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2111 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2112}
2113
Teresa Charlinfd33a692022-06-29 15:35:57 +01002114void TfLiteParserImpl::ParseLogSoftmax(size_t subgraphIndex, size_t operatorIndex)
2115{
2116 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2117
2118 LogSoftmaxDescriptor desc;
2119
2120 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2121 CHECK_VALID_SIZE(inputs.size(), 1);
2122 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2123 CHECK_VALID_SIZE(outputs.size(), 1);
2124
2125 auto layerName = fmt::format("LogSoftmax:{}:{}", subgraphIndex, operatorIndex);
2126 IConnectableLayer* const layer = m_Network->AddLogSoftmaxLayer(desc, layerName.c_str());
2127
Mike Kelly377fb212023-01-10 15:55:28 +00002128 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Teresa Charlinfd33a692022-06-29 15:35:57 +01002129 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2130
2131 // register the input connection slots for the layer, connections are made after all layers have been created
2132 // only the tensors for the inputs are relevant, exclude the const tensors
2133 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2134 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2135
2136 // register the output connection slots for the layer, connections are made after all layers have been created
2137 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2138 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2139}
2140
Kevin May7d96b162021-02-03 17:38:41 +00002141void TfLiteParserImpl::ParseSpaceToBatchND(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesbaded142019-02-08 19:02:48 -02002142{
2143 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2144
2145 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2146 CHECK_VALID_SIZE(inputs.size(), 3);
2147
2148 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2149 CHECK_VALID_SIZE(outputs.size(), 1);
2150
Mike Kelly377fb212023-01-10 15:55:28 +00002151 armnn::TensorInfo blockShapeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalvesbaded142019-02-08 19:02:48 -02002152 BufferRawPtr blockShapeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2153
Mike Kelly377fb212023-01-10 15:55:28 +00002154 armnn::TensorInfo padListTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Bruno Goncalvesbaded142019-02-08 19:02:48 -02002155 BufferRawPtr padListBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
2156
2157 std::vector<unsigned int> blockShape(blockShapeTensorInfo.GetNumElements());
2158 ::memcpy(blockShape.data(), blockShapeBufferPtr->data.data(), blockShapeTensorInfo.GetNumBytes());
2159
2160 std::vector<unsigned int> padListVector(padListTensorInfo.GetNumElements());
2161 ::memcpy(padListVector.data(), padListBufferPtr->data.data(), padListTensorInfo.GetNumBytes());
2162
2163 size_t step = 2;
2164 std::vector<std::pair<unsigned int, unsigned int>> padList;
2165 for (unsigned int i = 0; i < padListTensorInfo.GetNumElements() / step; ++i)
2166 {
2167 padList.emplace_back(padListVector[i * step], padListVector[i * step + 1]);
2168 }
2169
2170 armnn::SpaceToBatchNdDescriptor desc;
2171 desc.m_BlockShape = blockShape;
2172 desc.m_PadList = padList;
2173 desc.m_DataLayout = armnn::DataLayout::NHWC;
2174
James Ward58dec6b2020-09-11 17:32:44 +01002175 auto layerName = fmt::format("SpaceToBatchND:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesbaded142019-02-08 19:02:48 -02002176
Mike Kelly377fb212023-01-10 15:55:28 +00002177 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
James Conroy05102392020-06-24 15:39:55 +01002178
2179 IConnectableLayer* layer = m_Network->AddSpaceToBatchNdLayer(desc, layerName.c_str());
2180 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00002181
2182 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
2183 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Bruno Goncalvesbaded142019-02-08 19:02:48 -02002184 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2185
2186 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2187 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2188
2189 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2190 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2191}
2192
Teresa Charlin2a764ad2023-02-24 18:17:31 +00002193void TfLiteParserImpl::ParseSpaceToDepth(size_t subgraphIndex, size_t operatorIndex)
2194{
2195 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2196
2197 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2198 CHECK_VALID_SIZE(inputs.size(), 1);
2199 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2200 CHECK_VALID_SIZE(outputs.size(), 1);
2201
2202 armnn::SpaceToDepthDescriptor descriptor;
2203
2204 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2205 const auto* options = operatorPtr->builtin_options.AsSpaceToDepthOptions();
2206 auto blockSize = options->block_size;
2207 if (blockSize < 2)
2208 {
2209 throw ParseException(
2210 fmt::format("Operation has invalid block size: {} Block size should be >= 2 {}",
2211 blockSize,
2212 CHECK_LOCATION().AsString()));
2213 }
2214 descriptor.m_BlockSize = armnn::numeric_cast<uint32_t>(blockSize);
2215
2216 auto layerName = fmt::format("SpaceToDepth:{}:{}", subgraphIndex, operatorIndex);
2217 IConnectableLayer* layer = m_Network->AddSpaceToDepthLayer(descriptor, layerName.c_str());
2218 ARMNN_ASSERT(layer != nullptr);
2219 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
2220 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2221
2222 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2223 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2224
2225 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2226 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2227}
2228
Teresa Charlin3ab85482021-06-08 16:59:29 +01002229armnn::TensorInfo TfLiteParserImpl::OutputShapeOfSqueeze(std::vector<uint32_t> squeezeDims,
Mike Kelly0d77ae12022-01-07 17:42:27 +00002230 const armnn::TensorInfo& inputTensorInfo)
telsoa01c577f2c2018-08-31 09:22:23 +01002231{
Teresa Charlin3ab85482021-06-08 16:59:29 +01002232 CHECK_VALID_SIZE(squeezeDims.size(), 0, 1, 2, 3, 4);
telsoa01c577f2c2018-08-31 09:22:23 +01002233 static const uint32_t dimensionSequence[] = { 0, 1, 2, 3 };
2234
2235 if (inputTensorInfo.GetNumDimensions() > 4)
2236 {
2237 std::stringstream ss;
2238 ss << "Input tensor has unexpected number of dimensions:" << inputTensorInfo.GetNumDimensions()
2239 << " shape:" << inputTensorInfo.GetShape() << " "
2240 << CHECK_LOCATION().AsString();
2241 throw ParseException(ss.str());
2242 }
2243
2244 if (squeezeDims.empty())
2245 {
2246 squeezeDims.assign(dimensionSequence,
2247 dimensionSequence+inputTensorInfo.GetNumDimensions());
2248 }
2249
2250 std::vector<uint32_t> outputDims;
2251 for(unsigned int i = 0; i < inputTensorInfo.GetNumDimensions(); i++)
2252 {
2253 bool skipSqueeze = (std::find(squeezeDims.begin(), squeezeDims.end(), i) == squeezeDims.end());
2254 auto currentDimension = inputTensorInfo.GetShape()[i];
2255 if (skipSqueeze || currentDimension != 1)
2256 {
2257 outputDims.push_back(currentDimension);
2258 }
2259 }
2260
2261 if (outputDims.size() > 4)
2262 {
2263 std::stringstream ss;
2264 ss << "Output tensor has unexpected number of dimensions:" << inputTensorInfo.GetNumDimensions()
2265 << " shape:" << inputTensorInfo.GetShape() << " "
2266 << CHECK_LOCATION().AsString();
2267 throw ParseException(ss.str());
2268 }
2269
2270 TensorShape outShape = TensorShape(static_cast<unsigned int>(outputDims.size()),
2271 outputDims.data());
2272
2273 // we need to preserve the tensor type and the quantization data as well
2274 TensorInfo outTensorInfo = inputTensorInfo;
2275 outTensorInfo.SetShape(outShape);
2276
2277 return outTensorInfo;
2278}
2279
Keith Davis0176fd82021-06-01 17:36:32 +01002280void TfLiteParserImpl::ParseShape(size_t subgraphIndex, size_t operatorIndex)
2281{
2282 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2283
2284 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2285 CHECK_VALID_SIZE(inputs.size(), 1);
2286 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2287 CHECK_VALID_SIZE(outputs.size(), 1);
2288
2289 auto layerName = fmt::format("Shape:{}:{}", subgraphIndex, operatorIndex);
2290
2291 IConnectableLayer* layer = m_Network->AddShapeLayer(layerName.c_str());
2292 ARMNN_ASSERT(layer != nullptr);
2293
Mike Kelly377fb212023-01-10 15:55:28 +00002294 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Keith Davis0176fd82021-06-01 17:36:32 +01002295 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2296
2297 // Check if output tensor type is Signed32 or Signed64
2298 if (outputTensorInfo.GetDataType() != armnn::DataType::Signed32 &&
2299 outputTensorInfo.GetDataType() != armnn::DataType::Signed64)
2300 {
2301 throw ParseException(
2302 fmt::format(
2303 "Output tensor data type is not supported. (Supported types: Signed32 & Signed64) {}",
2304 CHECK_LOCATION().AsString()));
2305 }
2306
2307 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2308 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2309
2310 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2311 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2312}
2313
Kevin May7d96b162021-02-03 17:38:41 +00002314void TfLiteParserImpl::ParseSqueeze(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01002315{
2316 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2317
2318 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2319 CHECK_VALID_SIZE(inputs.size(), 1);
2320
2321 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2322 CHECK_VALID_SIZE(outputs.size(), 1);
2323
2324 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2325 const auto * options = operatorPtr->builtin_options.AsSqueezeOptions();
James Ward58dec6b2020-09-11 17:32:44 +01002326 auto layerName = fmt::format("Squeeze:{}:{}", subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01002327
Mike Kelly377fb212023-01-10 15:55:28 +00002328 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Teresa Charlin3ab85482021-06-08 16:59:29 +01002329
2330 std::vector<uint32_t> squeezeDim;
2331 // A single negative dim index is interpreted as a negative index in python
2332 // Meaning the index will be the shape size plus the negative index value
2333 if (options->squeeze_dims.size() == 1 && options->squeeze_dims[0] < 0)
2334 {
2335 int32_t dim = static_cast<int32_t>(inputTensorInfo.GetShape().GetNumDimensions()) + options->squeeze_dims[0];
2336 squeezeDim.push_back(static_cast<uint32_t>(dim));
2337 }
2338 else
2339 {
2340 squeezeDim = AsUnsignedVector(options->squeeze_dims);
2341 }
2342
2343 armnn::TensorInfo outputTensorInfo = TfLiteParserImpl::OutputShapeOfSqueeze(squeezeDim, inputTensorInfo);
2344
James Conroy05102392020-06-24 15:39:55 +01002345 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
telsoa01c577f2c2018-08-31 09:22:23 +01002346
2347 ReshapeDescriptor reshapeDesc;
2348 reshapeDesc.m_TargetShape = outputTensorInfo.GetShape();
2349
Mike Kellyb2293702023-02-14 17:16:12 +00002350 auto outputTensorIds = GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex);
2351 m_TensorInfos[outputTensorIds[0]] = outputTensorInfo;
2352
telsoa01c577f2c2018-08-31 09:22:23 +01002353 IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002354 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01002355 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2356
2357 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2358 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2359
2360 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2361 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2362}
2363
Kevin May7d96b162021-02-03 17:38:41 +00002364void TfLiteParserImpl::ParseStridedSlice(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002365{
2366 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2367
2368 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2369 CHECK_VALID_SIZE(inputs.size(), 4);
2370
2371 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2372 CHECK_VALID_SIZE(outputs.size(), 1);
2373
Mike Kelly0d77ae12022-01-07 17:42:27 +00002374 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2375 const auto* options = operatorPtr->builtin_options.AsStridedSliceOptions();
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002376
2377 StridedSliceDescriptor desc;
2378 desc.m_BeginMask = options->begin_mask;
2379 desc.m_EllipsisMask = options->ellipsis_mask;
2380 desc.m_EndMask = options->end_mask;
2381 desc.m_NewAxisMask = options->new_axis_mask;
2382 desc.m_ShrinkAxisMask = options->shrink_axis_mask;
2383 desc.m_DataLayout = armnn::DataLayout::NHWC;
2384
Mike Kelly377fb212023-01-10 15:55:28 +00002385 armnn::TensorInfo beginTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002386 BufferRawPtr beginBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2387
2388 std::vector<int> begin(beginTensorInfo.GetNumElements());
2389 ::memcpy(begin.data(), beginBufferPtr->data.data(), beginTensorInfo.GetNumBytes());
2390
Mike Kelly377fb212023-01-10 15:55:28 +00002391 armnn::TensorInfo endTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002392 BufferRawPtr endBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
2393
2394 std::vector<int> end(endTensorInfo.GetNumElements());
2395 ::memcpy(end.data(), endBufferPtr->data.data(), endTensorInfo.GetNumBytes());
2396
Mike Kelly377fb212023-01-10 15:55:28 +00002397 armnn::TensorInfo strideTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 3);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002398 BufferRawPtr strideBufferPtr = GetBuffer(m_Model, inputs[3]->buffer);
2399
2400 std::vector<int> stride(strideTensorInfo.GetNumElements());
2401 ::memcpy(stride.data(), strideBufferPtr->data.data(), strideTensorInfo.GetNumBytes());
2402
2403 desc.m_Begin = begin;
2404 desc.m_End = end;
2405 desc.m_Stride = stride;
2406
James Ward58dec6b2020-09-11 17:32:44 +01002407 auto layerName = fmt::format("StridedSlice:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002408 IConnectableLayer* layer = m_Network->AddStridedSliceLayer(desc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002409 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002410
Mike Kelly377fb212023-01-10 15:55:28 +00002411 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002412 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2413
2414 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2415 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2416
2417 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2418 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2419}
2420
Kevin May7d96b162021-02-03 17:38:41 +00002421void TfLiteParserImpl::ParseSub(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002422{
2423 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2424
Mike Kelly0d77ae12022-01-07 17:42:27 +00002425 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2426 const auto* options = operatorPtr->builtin_options.AsSubOptions();
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002427
2428 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2429 CHECK_VALID_SIZE(inputs.size(), 2);
2430
2431 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2432 CHECK_VALID_SIZE(outputs.size(), 1);
2433
Mike Kelly377fb212023-01-10 15:55:28 +00002434 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2435 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002436
James Ward58dec6b2020-09-11 17:32:44 +01002437 auto layerName = fmt::format("Sub:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +00002438 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Sub, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002439 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002440
Mike Kelly377fb212023-01-10 15:55:28 +00002441 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002442 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2443
2444 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002445 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Teresa Charlind04873f2023-05-23 14:16:28 +01002446 if (options)
2447 {
2448 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2449 }
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002450
2451 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2452 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2453}
2454
Kevin May7d96b162021-02-03 17:38:41 +00002455void TfLiteParserImpl::ParseDiv(size_t subgraphIndex, size_t operatorIndex)
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302456{
2457 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2458
Mike Kelly0d77ae12022-01-07 17:42:27 +00002459 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2460 const auto* options = operatorPtr->builtin_options.AsDivOptions();
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302461
2462 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2463 CHECK_VALID_SIZE(inputs.size(), 2);
2464
2465 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2466 CHECK_VALID_SIZE(outputs.size(), 1);
2467
Mike Kelly377fb212023-01-10 15:55:28 +00002468 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2469 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302470
James Ward58dec6b2020-09-11 17:32:44 +01002471 auto layerName = fmt::format("Div:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +00002472 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Div, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002473 ARMNN_ASSERT(layer != nullptr);
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302474
Mike Kelly377fb212023-01-10 15:55:28 +00002475 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302476 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2477
2478 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002479 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Teresa Charlind04873f2023-05-23 14:16:28 +01002480 if (options)
2481 {
2482 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2483 }
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302484
2485 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2486 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2487}
2488
Teresa Charlincdbd40b2022-02-25 13:21:55 +00002489void TfLiteParserImpl::ParseFloorDiv(size_t subgraphIndex, size_t operatorIndex)
2490{
2491 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2492
2493 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2494 CHECK_VALID_SIZE(inputs.size(), 2);
2495
2496 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2497 CHECK_VALID_SIZE(outputs.size(), 1);
2498
Mike Kelly377fb212023-01-10 15:55:28 +00002499 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2500 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Teresa Charlincdbd40b2022-02-25 13:21:55 +00002501
2502 auto layerName = fmt::format("Div:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +00002503 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Div, layerName.c_str());
Teresa Charlincdbd40b2022-02-25 13:21:55 +00002504 ARMNN_ASSERT(layer != nullptr);
2505
Mike Kelly377fb212023-01-10 15:55:28 +00002506 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Teresa Charlincdbd40b2022-02-25 13:21:55 +00002507 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2508
2509 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2510 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
2511 layer = AddFusedFloorLayer(layer, 0);
2512
2513 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2514 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2515}
2516
Kevin May7d96b162021-02-03 17:38:41 +00002517void TfLiteParserImpl::ParseAdd(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002518{
2519 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2520
Mike Kelly0d77ae12022-01-07 17:42:27 +00002521 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2522 const auto* options = operatorPtr->builtin_options.AsAddOptions();
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002523
2524 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2525 CHECK_VALID_SIZE(inputs.size(), 2);
2526
2527 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2528 CHECK_VALID_SIZE(outputs.size(), 1);
2529
Mike Kelly377fb212023-01-10 15:55:28 +00002530 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2531 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves9c761a62018-12-27 14:20:35 -02002532
James Ward58dec6b2020-09-11 17:32:44 +01002533 auto layerName = fmt::format("Add:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +00002534 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Add, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002535 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002536
Mike Kelly377fb212023-01-10 15:55:28 +00002537 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002538 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2539
2540 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002541 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Teresa Charlind04873f2023-05-23 14:16:28 +01002542 if (options)
2543 {
2544 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2545 }
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002546
2547 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2548 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2549}
2550
Kevin May7d96b162021-02-03 17:38:41 +00002551void TfLiteParserImpl::ParseMul(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002552{
2553 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2554
Mike Kelly0d77ae12022-01-07 17:42:27 +00002555 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2556 const auto* options = operatorPtr->builtin_options.AsMulOptions();
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002557
2558 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2559 CHECK_VALID_SIZE(inputs.size(), 2);
2560
2561 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2562 CHECK_VALID_SIZE(outputs.size(), 1);
2563
Mike Kelly377fb212023-01-10 15:55:28 +00002564 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2565 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves9c761a62018-12-27 14:20:35 -02002566
James Ward58dec6b2020-09-11 17:32:44 +01002567 auto layerName = fmt::format("Mul:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +00002568 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Mul, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002569 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002570
Mike Kelly377fb212023-01-10 15:55:28 +00002571 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002572 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2573
2574 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002575 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Teresa Charlind04873f2023-05-23 14:16:28 +01002576 if (options)
2577 {
2578 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2579 }
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002580
2581 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2582 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2583}
2584
Kevin May7d96b162021-02-03 17:38:41 +00002585void TfLiteParserImpl::ParseMean(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002586{
2587 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2588
2589 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2590
2591 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2592 CHECK_VALID_SIZE(outputs.size(), 1);
2593
Teresa Charlin046e2cb2023-03-28 17:20:19 +01002594 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2595 TensorInfo dimTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002596
2597 armnn::MeanDescriptor desc;
Teresa Charlin046e2cb2023-03-28 17:20:19 +01002598 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2599 // Get const axis value from model and set it to descriptor.
2600 if (axisBufferPtr != nullptr)
2601 {
2602 std::vector<int32_t> axisData(dimTensorInfo.GetNumElements());
2603 ::memcpy(axisData.data(), axisBufferPtr->data.data(), dimTensorInfo.GetNumBytes());
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002604
Teresa Charlin046e2cb2023-03-28 17:20:19 +01002605 // Convert the axis to unsigned int and remove duplicates.
2606 auto rank = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
2607 std::set<unsigned int> uniqueAxis;
2608 std::transform(axisData.begin(),
2609 axisData.end(),
2610 std::inserter(uniqueAxis, uniqueAxis.begin()),
2611 [rank](int i)->unsigned int{
2612 return static_cast<uint32_t>(((i + rank) % rank)); });
2613 desc.m_Axis.assign(uniqueAxis.begin(), uniqueAxis.end());
2614 }
2615 else
2616 {
2617 for (uint32_t i = 0; i < inputTensorInfo.GetNumDimensions(); ++i)
2618 {
2619 desc.m_Axis.push_back(i);
2620 }
2621 }
2622
Sadik Armagand109a4d2020-07-28 10:42:13 +01002623 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002624
Teresa Charlin046e2cb2023-03-28 17:20:19 +01002625 desc.m_KeepDims = inputTensorInfo.GetNumDimensions() == outputTensorInfo.GetNumDimensions() ? true : false;
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002626
James Ward58dec6b2020-09-11 17:32:44 +01002627 auto layerName = fmt::format("Mean:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002628 IConnectableLayer* layer = m_Network->AddMeanLayer(desc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002629 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002630
Mike Kelly377fb212023-01-10 15:55:28 +00002631 outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002632 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2633
2634 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2635 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2636
2637 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2638 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2639}
2640
Kevin May7d96b162021-02-03 17:38:41 +00002641void TfLiteParserImpl::ParsePad(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002642{
2643 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2644
Kevin May7d96b162021-02-03 17:38:41 +00002645 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002646
Kevin May7d96b162021-02-03 17:38:41 +00002647 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002648 CHECK_VALID_SIZE(outputs.size(), 1);
2649
Mike Kelly377fb212023-01-10 15:55:28 +00002650 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2651 armnn::TensorInfo padTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002652
Mike Kelly0d77ae12022-01-07 17:42:27 +00002653 std::vector<unsigned int> padBuffer = GetUIntBuffer(padTensorInfo, m_Model, inputs[1]->buffer);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002654
2655 size_t step = 2;
2656 armnn::PadDescriptor desc;
Mike Kelly0d77ae12022-01-07 17:42:27 +00002657 auto opcode = GetOpCode(m_Model, subgraphIndex, operatorIndex);
2658
2659 if (opcode == tflite::BuiltinOperator_PAD)
Narumol Prangnawarat8719d222020-11-27 16:57:56 +00002660 {
Mike Kelly0d77ae12022-01-07 17:42:27 +00002661 CHECK_VALID_SIZE(inputs.size(), 2);
2662
2663 if (inputTensorInfo.IsQuantized())
2664 {
2665 desc.m_PadValue = static_cast<float>(inputTensorInfo.GetQuantizationOffset());
2666 }
Narumol Prangnawarat8719d222020-11-27 16:57:56 +00002667 }
Mike Kelly0d77ae12022-01-07 17:42:27 +00002668 else if (opcode == tflite::BuiltinOperator_PADV2)
2669 {
2670 CHECK_VALID_SIZE(inputs.size(), 3);
2671
Mike Kelly377fb212023-01-10 15:55:28 +00002672 armnn::TensorInfo padValueTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Mike Kelly0d77ae12022-01-07 17:42:27 +00002673
2674 if (padValueTensorInfo.GetNumElements() != 1)
2675 {
2676 ARMNN_THROW_PARSE_EXCEPTION("Multiple padding values are not supported in PADV2");
2677 }
2678 BufferRawPtr padValueBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
2679
2680 // Get the pad value from the input tensor
2681 if (padValueBufferPtr->data.size() > 0)
2682 {
2683 switch (padValueTensorInfo.GetDataType())
2684 {
2685 case armnn::DataType::Float32:
2686 {
2687 std::vector<float> padValueBuffer(padValueTensorInfo.GetNumElements());
2688 ::memcpy(padValueBuffer.data(), padValueBufferPtr->data.data(), padValueBufferPtr->data.size());
2689 desc.m_PadValue = padValueBuffer[0];
2690 break;
2691 }
2692 case armnn::DataType::QAsymmU8:
2693 {
2694 std::vector<uint8_t> padValueBuffer(padValueTensorInfo.GetNumElements());
2695 ::memcpy(padValueBuffer.data(), padValueBufferPtr->data.data(), padValueBufferPtr->data.size());
2696 desc.m_PadValue = armnn::Dequantize<uint8_t>(padValueBuffer[0],
2697 padValueTensorInfo.GetQuantizationScale(),
2698 padValueTensorInfo.GetQuantizationOffset());
2699 break;
2700 }
2701 case armnn::DataType::QAsymmS8:
2702 case armnn::DataType::QSymmS8:
2703 {
2704 std::vector<int8_t> padValueBuffer(padValueTensorInfo.GetNumElements());
2705 ::memcpy(padValueBuffer.data(), padValueBufferPtr->data.data(), padValueBufferPtr->data.size());
2706 desc.m_PadValue = armnn::Dequantize<int8_t>(padValueBuffer[0],
2707 padValueTensorInfo.GetQuantizationScale(),
2708 padValueTensorInfo.GetQuantizationOffset());
2709 break;
2710 }
2711 default: ARMNN_THROW_PARSE_EXCEPTION("Unsupported DataType");
2712 }
2713 }
2714 else if (inputTensorInfo.IsQuantized())
2715 {
2716 desc.m_PadValue = static_cast<float>(inputTensorInfo.GetQuantizationOffset());
2717 }
2718 }
2719
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002720 for (unsigned int i = 0; i < padTensorInfo.GetNumElements() / step; ++i)
2721 {
2722 desc.m_PadList.emplace_back(padBuffer[i * step], padBuffer[i * step + 1]);
2723 }
2724
Mike Kelly0d77ae12022-01-07 17:42:27 +00002725 auto layerName = (opcode == tflite::BuiltinOperator_PAD) ? fmt::format("Pad:{}:{}", subgraphIndex, operatorIndex)
2726 : fmt::format("PadV2:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01002727
2728 IConnectableLayer* layer = m_Network->AddPadLayer(desc, layerName.c_str());
2729 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00002730 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002731 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2732
2733 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2734 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2735
2736 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2737 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2738}
2739
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002740void TfLiteParserImpl::ParseMirrorPad(size_t subgraphIndex, size_t operatorIndex)
2741{
2742 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2743
2744 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2745 CHECK_VALID_SIZE(inputs.size(), 2);
2746
2747 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2748 CHECK_VALID_SIZE(outputs.size(), 1);
2749
Mike Kelly377fb212023-01-10 15:55:28 +00002750 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002751
Mike Kelly377fb212023-01-10 15:55:28 +00002752 armnn::TensorInfo padTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002753 BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2754
2755 std::vector<unsigned int> padBuffer(padTensorInfo.GetNumElements());
2756 ::memcpy(padBuffer.data(), bufferPtr->data.data(), padTensorInfo.GetNumBytes());
2757
2758 size_t step = 2;
2759 armnn::PadDescriptor desc;
2760 for (unsigned int i = 0; i < padTensorInfo.GetNumElements() / step; ++i)
2761 {
2762 desc.m_PadList.emplace_back(padBuffer[i * step], padBuffer[i * step + 1]);
2763 }
2764
2765 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2766 const auto* options = operatorPtr->builtin_options.AsMirrorPadOptions();
2767
2768 if (options->mode == tflite::MirrorPadMode_REFLECT)
2769 {
2770 desc.m_PaddingMode = PaddingMode::Reflect;
2771 }
2772 else if (options->mode == tflite::MirrorPadMode_SYMMETRIC)
2773 {
2774 desc.m_PaddingMode = PaddingMode::Symmetric;
2775 }
2776 else
2777 {
2778 ARMNN_THROW_PARSE_EXCEPTION("PaddingMode must be either REFLECT or SYMMETRIC");
2779 }
2780
2781 // If padding mode is Reflect then both paddings must be no greater than inputShape(i) - 1.
2782 // If padding mode is Symmetric then both paddings must be no greater than inputShape(i).
2783 auto inputShape = inputTensorInfo.GetShape();
2784 auto padList = desc.m_PadList;
2785
2786 const unsigned int isReflect = static_cast<unsigned int>(desc.m_PaddingMode == PaddingMode::Reflect);
2787 for(unsigned int i = 0; i < padList.size(); ++i)
2788 {
2789 if(padList.at(i).first > (inputShape[i] - isReflect) ||
2790 padList.at(i).second > (inputShape[i] - isReflect))
2791 {
2792 ARMNN_THROW_PARSE_EXCEPTION("Padding values must be less (Reflect) or "
2793 "equal (Symmetric) to the dimension size.");
2794 }
2795 }
2796
2797 auto layerName = fmt::format("MirrorPad:{}:{}", subgraphIndex, operatorIndex);
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002798
2799 IConnectableLayer* layer = m_Network->AddPadLayer(desc, layerName.c_str());
2800 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00002801 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002802 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2803
2804 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2805 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2806
2807 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2808 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2809}
2810
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002811void TfLiteParserImpl::ParsePrelu(size_t subgraphIndex, size_t operatorIndex)
2812{
2813 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2814
2815 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2816 CHECK_VALID_SIZE(inputs.size(), 2);
2817
2818 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2819 CHECK_VALID_SIZE(outputs.size(), 1);
2820
2821 auto layerName = fmt::format("Prelu:{}:{}", subgraphIndex, operatorIndex);
2822
Mike Kelly377fb212023-01-10 15:55:28 +00002823 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2824 armnn::TensorInfo alphaTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002825
2826 IConnectableLayer* layer = m_Network->AddPreluLayer(layerName.c_str());
2827 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00002828
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002829
2830 if (IsConstTensor(inputs[1]))
2831 {
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002832 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawaratbf99b5f2021-05-27 09:55:43 +01002833 armnn::IInputSlot* slot = &(layer->GetInputSlot(0));
2834 RegisterConsumerOfTensor(subgraphIndex, inputTensorIndexes[0], slot);
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002835
Mike Kelly5880b912022-01-28 16:18:54 +00002836 auto alphaTensorAndData = CreateConstTensorNonPermuted(inputs[1], alphaTensorInfo,
2837 inputTensorInfo.GetDataType());
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002838 std::string constLayerName = fmt::format("Constant:{}", inputs[1]->name);
2839 IConnectableLayer* constLayer =
Mike Kelly5880b912022-01-28 16:18:54 +00002840 m_Network->AddConstantLayer(alphaTensorAndData.first, constLayerName.c_str());
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002841 ARMNN_ASSERT(constLayer != nullptr);
2842
2843 constLayer->GetOutputSlot(0).SetTensorInfo(alphaTensorInfo);
2844 constLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1));
2845 RegisterOutputSlots(subgraphIndex,
2846 VIRTUAL_OPERATOR_ID,
2847 constLayer,
2848 { inputTensorIndexes[1] });
2849 }
2850 else
2851 {
2852 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2853 RegisterInputSlots(subgraphIndex, operatorIndex, layer, inputTensorIndexes);
2854 }
2855
Mike Kelly377fb212023-01-10 15:55:28 +00002856 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
2857 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
2858 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2859
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002860 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2861 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2862}
2863
Kevin May7d96b162021-02-03 17:38:41 +00002864void TfLiteParserImpl::ParseQuantize(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan66dedc72019-12-10 16:32:07 +00002865{
2866 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2867
2868 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2869 CHECK_VALID_SIZE(inputs.size(), 1);
2870
2871 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2872 CHECK_VALID_SIZE(outputs.size(), 1);
2873
James Ward58dec6b2020-09-11 17:32:44 +01002874 auto layerName = fmt::format("Quantize:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan66dedc72019-12-10 16:32:07 +00002875
2876 IConnectableLayer* layer = m_Network->AddQuantizeLayer(layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01002877 ARMNN_ASSERT(layer != nullptr);
Sadik Armagan66dedc72019-12-10 16:32:07 +00002878
Mike Kelly377fb212023-01-10 15:55:28 +00002879 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Sadik Armagan66dedc72019-12-10 16:32:07 +00002880 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2881
2882 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2883 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2884
2885 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2886 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2887}
Finn Williamsc42c3842019-01-22 14:18:11 +00002888
Kevin May7d96b162021-02-03 17:38:41 +00002889void TfLiteParserImpl::ParseRelu(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan58f39192018-09-17 14:14:39 +01002890{
Finn Williamsc42c3842019-01-22 14:18:11 +00002891 ParseActivation(subgraphIndex,operatorIndex, ActivationFunction::ReLu);
Sadik Armagan58f39192018-09-17 14:14:39 +01002892}
2893
Kevin May7d96b162021-02-03 17:38:41 +00002894void TfLiteParserImpl::ParseRelu6(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan58f39192018-09-17 14:14:39 +01002895{
Finn Williamsc42c3842019-01-22 14:18:11 +00002896 ParseActivation(subgraphIndex,operatorIndex, ActivationFunction::BoundedReLu);
2897}
Sadik Armagan58f39192018-09-17 14:14:39 +01002898
Kevin May7d96b162021-02-03 17:38:41 +00002899void TfLiteParserImpl::ParseLeakyRelu(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan12239e72020-05-27 11:06:17 +01002900{
Jan Eilers2f746b32020-07-28 14:00:06 +01002901 ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::LeakyReLu);
Sadik Armagan12239e72020-05-27 11:06:17 +01002902}
2903
Kevin May7d96b162021-02-03 17:38:41 +00002904void TfLiteParserImpl::ParseLogistic(size_t subgraphIndex, size_t operatorIndex)
Finn Williamsc42c3842019-01-22 14:18:11 +00002905{
2906 ParseActivation(subgraphIndex,operatorIndex,ActivationFunction::Sigmoid);
2907}
2908
Kevin May7d96b162021-02-03 17:38:41 +00002909void TfLiteParserImpl::ParseTanH(size_t subgraphIndex, size_t operatorIndex)
Nina Drozd99851762019-04-09 09:37:38 +01002910{
2911 ParseActivation(subgraphIndex,operatorIndex,ActivationFunction::TanH);
2912}
2913
Kevin May7d96b162021-02-03 17:38:41 +00002914void TfLiteParserImpl::ParseElu(size_t subgraphIndex, size_t operatorIndex)
Matthew Sloyan7515d072020-12-16 12:50:01 +00002915{
2916 ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::Elu);
2917}
2918
Kevin May7d96b162021-02-03 17:38:41 +00002919void TfLiteParserImpl::ParseHardSwish(size_t subgraphIndex, size_t operatorIndex)
Jan Eilers2f746b32020-07-28 14:00:06 +01002920{
2921 ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::HardSwish);
2922}
Finn Williamsc42c3842019-01-22 14:18:11 +00002923
Kevin May7d96b162021-02-03 17:38:41 +00002924void TfLiteParserImpl::ParseActivation(size_t subgraphIndex, size_t operatorIndex, ActivationFunction activationType)
Finn Williamsc42c3842019-01-22 14:18:11 +00002925{
2926 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00002927 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
Jan Eilers8eb25602020-03-09 12:13:48 +00002928 IgnoreUnused(operatorPtr);
Sadik Armagan58f39192018-09-17 14:14:39 +01002929
2930 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2931 CHECK_VALID_SIZE(inputs.size(), 1);
2932
2933 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2934 CHECK_VALID_SIZE(outputs.size(), 1);
2935
James Ward58dec6b2020-09-11 17:32:44 +01002936 auto layerName = fmt::format("Activation:");
Sadik Armagan58f39192018-09-17 14:14:39 +01002937 ActivationDescriptor activationDesc;
Finn Williamsc42c3842019-01-22 14:18:11 +00002938 activationDesc.m_Function = activationType;
2939
2940 switch (activationType)
2941 {
2942 case ActivationFunction::ReLu:
2943 {
James Ward58dec6b2020-09-11 17:32:44 +01002944 layerName += fmt::format("RELU:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsc42c3842019-01-22 14:18:11 +00002945 break;
2946 }
2947 case ActivationFunction::BoundedReLu:
2948 {
James Ward58dec6b2020-09-11 17:32:44 +01002949 layerName += fmt::format("RELU6:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsc42c3842019-01-22 14:18:11 +00002950 activationDesc.m_A = 6.0f;
2951 activationDesc.m_B = 0.0f;
2952 break;
2953 }
2954 case ActivationFunction::Sigmoid:
2955 {
James Ward58dec6b2020-09-11 17:32:44 +01002956 layerName += fmt::format("SIGMOID:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsc42c3842019-01-22 14:18:11 +00002957 break;
2958 }
Nina Drozd99851762019-04-09 09:37:38 +01002959 case ActivationFunction::TanH:
2960 {
James Ward58dec6b2020-09-11 17:32:44 +01002961 layerName += fmt::format("TANH:{}:{}", subgraphIndex, operatorIndex);
Nina Drozd99851762019-04-09 09:37:38 +01002962 activationDesc.m_A = 1.0f;
2963 activationDesc.m_B = 1.0f;
2964 break;
2965 }
Sadik Armagan12239e72020-05-27 11:06:17 +01002966 case ActivationFunction::LeakyReLu:
2967 {
James Ward58dec6b2020-09-11 17:32:44 +01002968 layerName += fmt::format("LEAKYRELU:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00002969 const auto* options = operatorPtr->builtin_options.AsLeakyReluOptions();
Sadik Armagan12239e72020-05-27 11:06:17 +01002970 activationDesc.m_A = options->alpha;
2971 break;
2972 }
Matthew Sloyan7515d072020-12-16 12:50:01 +00002973 case ActivationFunction::Elu:
2974 {
2975 layerName += fmt::format("ELU:{}:{}", subgraphIndex, operatorIndex);
2976 activationDesc.m_A = 1.0f;
2977 break;
2978 }
Jan Eilers2f746b32020-07-28 14:00:06 +01002979 case ActivationFunction::HardSwish:
Matthew Sloyan7515d072020-12-16 12:50:01 +00002980 {
James Ward58dec6b2020-09-11 17:32:44 +01002981 layerName += fmt::format("HARDSWISH:{}:{}", subgraphIndex, operatorIndex);
Jan Eilers2f746b32020-07-28 14:00:06 +01002982 break;
Matthew Sloyan7515d072020-12-16 12:50:01 +00002983 }
Finn Williamsc42c3842019-01-22 14:18:11 +00002984 default:
2985 {
2986 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01002987 fmt::format("Unexpected ActivationFunction[{}] when creating layerName {} ",
2988 static_cast<int>(activationType), CHECK_LOCATION().AsString()));
Finn Williamsc42c3842019-01-22 14:18:11 +00002989 }
2990 }
2991
2992 IConnectableLayer* const layer = m_Network->AddActivationLayer(activationDesc, layerName.c_str());
Sadik Armagan58f39192018-09-17 14:14:39 +01002993
Mike Kelly377fb212023-01-10 15:55:28 +00002994 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Sadik Armagan58f39192018-09-17 14:14:39 +01002995 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2996
2997 // register the input connection slots for the layer, connections are made after all layers have been created
2998 // only the tensors for the inputs are relevant, exclude the const tensors
2999 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3000 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3001
3002 // register the output connection slots for the layer, connections are made after all layers have been created
3003 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3004 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3005}
Mike Kelly0d77ae12022-01-07 17:42:27 +00003006armnn::TensorInfo TfLiteParserImpl::OutputShapeOfReshape(const armnn::TensorInfo& inputTensorInfo,
3007 const std::vector<int32_t>& targetDimsIn)
Sadikb94967b2018-09-19 15:30:00 +01003008{
3009 std::vector<unsigned int> outputDims(targetDimsIn.begin(), targetDimsIn.end());
3010 const auto stretchDim = std::find(targetDimsIn.begin(), targetDimsIn.end(), -1);
3011
3012 if (stretchDim != targetDimsIn.end())
3013 {
3014 if (std::find(std::next(stretchDim), targetDimsIn.end(), -1) != targetDimsIn.end())
3015 {
3016 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003017 fmt::format("At most one component of shape can be -1 {}", CHECK_LOCATION().AsString()));
Sadikb94967b2018-09-19 15:30:00 +01003018 }
3019
3020 auto targetNumElements =
Matthew Sloyan589e3e82020-09-11 16:17:48 +01003021 armnn::numeric_cast<unsigned int>(
Sadikb94967b2018-09-19 15:30:00 +01003022 std::accumulate(targetDimsIn.begin(), targetDimsIn.end(), -1, std::multiplies<int32_t>()));
3023
3024 auto stretchIndex = static_cast<size_t>(std::distance(targetDimsIn.begin(), stretchDim));
3025 outputDims[stretchIndex] = inputTensorInfo.GetNumElements() / targetNumElements;
3026 }
3027
3028 TensorShape outputShape = TensorShape(static_cast<unsigned int>(outputDims.size()), outputDims.data());
3029
3030 TensorInfo reshapeInfo = inputTensorInfo;
3031 reshapeInfo.SetShape(outputShape);
3032
3033 return reshapeInfo;
3034}
3035
Kevin May7d96b162021-02-03 17:38:41 +00003036void TfLiteParserImpl::ParseReshape(size_t subgraphIndex, size_t operatorIndex)
Sadikb94967b2018-09-19 15:30:00 +01003037{
3038 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3039
3040 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Sadikb94967b2018-09-19 15:30:00 +01003041
3042 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3043 CHECK_VALID_SIZE(outputs.size(), 1);
3044
Mike Kelly0d77ae12022-01-07 17:42:27 +00003045 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3046 const auto* options = operatorPtr->builtin_options.AsReshapeOptions();
James Ward58dec6b2020-09-11 17:32:44 +01003047 auto layerName = fmt::format("Reshape:{}:{}", subgraphIndex, operatorIndex);
Sadikb94967b2018-09-19 15:30:00 +01003048
Mike Kelly377fb212023-01-10 15:55:28 +00003049 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
kevmay0171972a82018-12-17 14:28:03 +00003050 armnn::TensorInfo actualOutputTensorInfo = ToTensorInfo(outputs[0]);
James Conroy05102392020-06-24 15:39:55 +01003051 CheckMatchingQuantization(inputTensorInfo, actualOutputTensorInfo, layerName, "Input 0", "Output 0");
Derek Lambertic9e52792020-03-11 11:42:26 +00003052
Jan Eilersbac9b352020-07-13 13:40:24 +01003053 // Extracting new shape for the output
3054 // There are two ways it can be passed
3055 // * First is to define the target shape in the operator built-in options
3056 // * Second is to pass it as a second input tensor
Derek Lambertic9e52792020-03-11 11:42:26 +00003057 std::vector<int32_t> targetShape;
Jan Eilersbac9b352020-07-13 13:40:24 +01003058 bool targetShapeFound = false;
3059 // Check if built-in options were given
3060 if (options != nullptr)
Derek Lambertic9e52792020-03-11 11:42:26 +00003061 {
Jan Eilersbac9b352020-07-13 13:40:24 +01003062 // make sure the parameter is given
3063 if (options->new_shape.empty() == false)
Derek Lambertic9e52792020-03-11 11:42:26 +00003064 {
Jan Eilersbac9b352020-07-13 13:40:24 +01003065 targetShape = options->new_shape;
3066 targetShapeFound = true;
Derek Lambertif4a953f2020-03-17 14:25:57 +00003067 }
Derek Lambertic9e52792020-03-11 11:42:26 +00003068 }
Jan Eilersbac9b352020-07-13 13:40:24 +01003069
3070 // If there is no built-in option given or if the built-in new_shape parameter was empty
3071 if (!targetShapeFound)
Derek Lambertic9e52792020-03-11 11:42:26 +00003072 {
Teresa Charlin6a056a42021-12-01 10:25:43 +00003073 // Check for a second input tensor
3074 if (inputs.size() > 1 && inputs[1] != nullptr)
Jan Eilersbac9b352020-07-13 13:40:24 +01003075 {
3076 if (inputs[1]->is_variable)
3077 {
3078 ARMNN_THROW_PARSE_EXCEPTION( "Target shapes defined in non-const input tensors is not supported");
3079 }
3080
3081 if (inputs[1]->shape.size() != 1)
3082 {
3083 ARMNN_THROW_PARSE_EXCEPTION("Target 'shape' input is not a 1D tensor");
3084 }
3085
3086 if (inputs[1]->type != tflite::TensorType_INT32)
3087 {
3088 ARMNN_THROW_PARSE_EXCEPTION("Target 'shape' input is not an int32 type");
3089 }
3090
Teresa Charlin6a056a42021-12-01 10:25:43 +00003091 // Extract target shape from input
3092 auto bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
3093 auto values = reinterpret_cast<const int32_t*>(bufferPtr->data.data());
Cathal Corbettd2f73232021-12-10 13:38:52 +00003094 if (values)
Sadik Armagan19a1c032021-01-20 12:17:00 +00003095 {
Cathal Corbettd2f73232021-12-10 13:38:52 +00003096 for (int i = 0; i < inputs[1]->shape[0]; ++i)
3097 {
3098 targetShape.push_back(values[i]);
3099 }
Sadik Armagan19a1c032021-01-20 12:17:00 +00003100 }
Cathal Corbettd2f73232021-12-10 13:38:52 +00003101 else
Jan Eilersbac9b352020-07-13 13:40:24 +01003102 {
Cathal Corbettd2f73232021-12-10 13:38:52 +00003103 try
3104 {
3105 // We attempt to infer during Runtime.
Mike Kelly04d82292023-01-19 18:29:40 +00003106 TensorShape reshapeShapes = ToTensorInfo(inputs[1]).GetShape();
3107
3108 if (reshapeShapes[0] == actualOutputTensorInfo.GetNumDimensions())
3109 {
3110 for (unsigned int i = 0; i < actualOutputTensorInfo.GetShape().GetNumDimensions(); ++i)
3111 {
3112 targetShape.push_back(actualOutputTensorInfo.GetShape()[i]);
3113 }
3114 }
Cathal Corbettd2f73232021-12-10 13:38:52 +00003115 // The parser only supports shape (batch, -1) or (-1) for non-constant shape input.
Mike Kelly04d82292023-01-19 18:29:40 +00003116 else if (reshapeShapes[0] > 2)
Cathal Corbettd2f73232021-12-10 13:38:52 +00003117 {
3118 throw ParseException(fmt::format("Invalid input shape '{}' in Reshape layer '{}' {}. "
3119 "When inferring during runtime, the parser only supports "
3120 "shape (batch, -1) or (-1) for target shape input.",
3121 reshapeShapes[0],
3122 layerName,
3123 CHECK_LOCATION().AsString()));
3124 }
Mike Kelly04d82292023-01-19 18:29:40 +00003125 else
Cathal Corbettd2f73232021-12-10 13:38:52 +00003126 {
Mike Kelly04d82292023-01-19 18:29:40 +00003127 const int32_t numInputElements = inputTensorInfo.GetNumElements();
3128 const int32_t inputTensorShape = inputTensorInfo.GetShape()[0];
3129 if (reshapeShapes[0] == 1)
3130 {
3131 targetShape = {numInputElements};
3132 }
3133 else if (reshapeShapes[0] == 2)
3134 {
3135 targetShape = {inputTensorShape, numInputElements / inputTensorShape};
3136 }
Cathal Corbettd2f73232021-12-10 13:38:52 +00003137 }
3138 }
3139 catch (const std::exception& exc)
3140 {
3141 ARMNN_THROW_PARSE_EXCEPTION("Failed attempt to infer during runtime the target shape input for "
3142 "Reshape operation. Reshape operator target shape input buffer data "
3143 "is null. " << exc.what());
3144 }
Jan Eilersbac9b352020-07-13 13:40:24 +01003145 }
3146 }
3147 else
Derek Lambertic9e52792020-03-11 11:42:26 +00003148 {
3149 ARMNN_THROW_PARSE_EXCEPTION("Target shape not defined in reshape parameters or input tensor. "
3150 "At least one method required");
3151 }
Derek Lambertic9e52792020-03-11 11:42:26 +00003152 }
3153
kevmay0171972a82018-12-17 14:28:03 +00003154 armnn::TensorInfo reshapeOutputTensorInfo =
Kevin May7d96b162021-02-03 17:38:41 +00003155 TfLiteParserImpl::OutputShapeOfReshape(inputTensorInfo, targetShape);
Sadikb94967b2018-09-19 15:30:00 +01003156
kevmay0171972a82018-12-17 14:28:03 +00003157 // Check for valid input size and that reshape parameters equal output shape
Cathal Corbett2b922e22022-09-23 15:49:24 +01003158 // The output shape can be provided to us in 2 ways:
3159 // 1. through the normal 'shape' parameter given by outputs[indx]->shape
3160 // 2. through additional parameter 'shape_signature' given by outputs[indx]->buffer.
3161 // This parameter can sometimes contain -1 value not visible in the 'shape' parameter.
Aron Virginas-Tar70672f62019-01-23 14:00:00 +00003162 const armnn::TensorShape& reshapeOutputTensorShape = reshapeOutputTensorInfo.GetShape();
3163 if (inputs.size() > 1 && !CheckShape(reshapeOutputTensorShape, outputs[0]->shape))
kevmay0171972a82018-12-17 14:28:03 +00003164 {
Cathal Corbett2b922e22022-09-23 15:49:24 +01003165 // Attempt to extract output shape from secondary 'shape_signature'
3166 // parameter and try to CheckShape() with this param.
3167 std::vector<int32_t> secondaryOutputTargetShape = outputs[0]->shape_signature;
3168
3169 // if outputs[0]->shape_signature contain a -1 value, we need to compute its actual value
3170 // from reshape input in order to correctly verify reshape parameters equal output shape
3171 armnn::TensorInfo secondaryReshapeOutputTensorInfo =
3172 TfLiteParserImpl::OutputShapeOfReshape(inputTensorInfo, secondaryOutputTargetShape);
3173
3174 if (!CheckShape(reshapeOutputTensorShape, secondaryReshapeOutputTensorInfo.GetShape()))
3175 {
3176 std::stringstream ss;
3177 ss << "New shape defined in reshape parameters "
3178 << reshapeOutputTensorShape
3179 << " does not equal output shape "
3180 << actualOutputTensorInfo.GetShape()
3181 << ": "
3182 << CHECK_LOCATION().AsString();
3183 throw ParseException(ss.str());
3184 }
kevmay0171972a82018-12-17 14:28:03 +00003185 }
Mike Kelly377fb212023-01-10 15:55:28 +00003186 auto outputTensorIds = GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex);
kevmay0171972a82018-12-17 14:28:03 +00003187
Sadikb94967b2018-09-19 15:30:00 +01003188 ReshapeDescriptor reshapeDesc;
kevmay0171972a82018-12-17 14:28:03 +00003189 reshapeDesc.m_TargetShape = reshapeOutputTensorInfo.GetShape();
Mike Kelly377fb212023-01-10 15:55:28 +00003190 m_TensorInfos[outputTensorIds[0]] = reshapeOutputTensorInfo;
Sadikb94967b2018-09-19 15:30:00 +01003191
Sadikb94967b2018-09-19 15:30:00 +01003192 IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01003193 ARMNN_ASSERT(layer != nullptr);
kevmay0171972a82018-12-17 14:28:03 +00003194 layer->GetOutputSlot(0).SetTensorInfo(reshapeOutputTensorInfo);
Sadikb94967b2018-09-19 15:30:00 +01003195
3196 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3197 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3198
3199 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3200 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3201}
3202
Kevin May7d96b162021-02-03 17:38:41 +00003203void TfLiteParserImpl::ParseResizeBilinear(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003204{
Sadik Armagana3b31f02019-12-05 09:08:53 +00003205 ParseResize(subgraphIndex, operatorIndex, ResizeMethod::Bilinear);
3206}
3207
Kevin May7d96b162021-02-03 17:38:41 +00003208void TfLiteParserImpl::ParseResizeNearestNeighbor(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagana3b31f02019-12-05 09:08:53 +00003209{
3210 ParseResize(subgraphIndex, operatorIndex, ResizeMethod::NearestNeighbor);
3211}
3212
Kevin May7d96b162021-02-03 17:38:41 +00003213void TfLiteParserImpl::ParseResize(size_t subgraphIndex, size_t operatorIndex, ResizeMethod resizeMethod)
Sadik Armagana3b31f02019-12-05 09:08:53 +00003214{
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003215 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3216
3217 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3218 CHECK_VALID_SIZE(inputs.size(), 2);
3219
3220 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3221 CHECK_VALID_SIZE(outputs.size(), 1);
3222
Mike Kelly377fb212023-01-10 15:55:28 +00003223 armnn::TensorInfo sizeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003224
3225 // Data for the parsed tensor args (size) must be stored locally.
3226 std::vector<int32_t> sizeTensorData(sizeTensorInfo.GetNumElements());
3227
3228 BufferRawPtr sizeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
3229 ::memcpy(sizeTensorData.data(), sizeBufferPtr->data.data(), sizeTensorInfo.GetNumBytes());
3230
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01003231 ResizeDescriptor desc;
Sadik Armagana3b31f02019-12-05 09:08:53 +00003232 desc.m_Method = resizeMethod;
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003233 desc.m_TargetHeight = static_cast<uint32_t> (sizeTensorData[0]);
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01003234 desc.m_TargetWidth = static_cast<uint32_t> (sizeTensorData[1]);
3235 desc.m_DataLayout = armnn::DataLayout::NHWC;
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003236
James Ward58dec6b2020-09-11 17:32:44 +01003237 auto layerName = fmt::format("Resize:");
Sadik Armagana3b31f02019-12-05 09:08:53 +00003238
3239 switch (resizeMethod)
3240 {
3241 case ResizeMethod::Bilinear:
3242 {
James Ward58dec6b2020-09-11 17:32:44 +01003243 layerName += fmt::format("BILINEAR:{}:{}", subgraphIndex, operatorIndex);
Sang-Hoon Park820eb142020-01-08 10:25:24 +00003244
3245 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3246 const auto * options = operatorPtr->builtin_options.AsResizeBilinearOptions();
3247
David Monahan4a0c9b92020-05-30 09:48:39 +01003248 desc.m_AlignCorners = options->align_corners;
Sadik Armagana3b31f02019-12-05 09:08:53 +00003249 break;
3250 }
3251 case ResizeMethod::NearestNeighbor:
3252 {
James Ward58dec6b2020-09-11 17:32:44 +01003253 layerName += fmt::format("NEARESTNEIGHBOR:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagana3b31f02019-12-05 09:08:53 +00003254 break;
3255 }
3256 default:
3257 {
3258 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003259 fmt::format("Unexpected ResizeMethod[{}] when creating layerName {} ",
3260 static_cast<int>(resizeMethod), CHECK_LOCATION().AsString()));
Sadik Armagana3b31f02019-12-05 09:08:53 +00003261 }
3262 }
3263
Mike Kelly377fb212023-01-10 15:55:28 +00003264 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
James Conroy05102392020-06-24 15:39:55 +01003265
3266 IConnectableLayer* layer = m_Network->AddResizeLayer(desc, layerName.c_str());
3267 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00003268 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
3269 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003270 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3271
3272 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3273 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3274
3275 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3276 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
3277}
3278
Kevin May7d96b162021-02-03 17:38:41 +00003279void TfLiteParserImpl::ParseConcatenation(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan479045b2018-10-01 11:51:37 +01003280{
3281 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3282
Mike Kelly0d77ae12022-01-07 17:42:27 +00003283 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3284 const auto* options = operatorPtr->builtin_options.AsConcatenationOptions();
Sadik Armagan479045b2018-10-01 11:51:37 +01003285
3286 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
3287
3288 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3289 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Mike Kelly377fb212023-01-10 15:55:28 +00003290 auto inputTensorIds = GetInputTensorIds(m_Model, subgraphIndex, operatorIndex);
3291
Sadik Armagan479045b2018-10-01 11:51:37 +01003292 CHECK_VALID_SIZE(outputs.size(), 1);
3293
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003294 unsigned int numConcatView = static_cast<unsigned int>(inputs.size());
Mike Kelly377fb212023-01-10 15:55:28 +00003295 uint32_t inputRank = InputTensorInfo(subgraphIndex, operatorIndex, 0).GetNumDimensions();
Sadik Armagan479045b2018-10-01 11:51:37 +01003296
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003297 const unsigned int concatDimInput = static_cast<unsigned int>(
Mike Kelly377fb212023-01-10 15:55:28 +00003298 (static_cast<int>(inputRank) + options->axis) % static_cast<int>(inputRank));
Sadik Armagan479045b2018-10-01 11:51:37 +01003299
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003300 OriginsDescriptor concatDescriptor(static_cast<uint32_t>(numConcatView), inputRank);
3301 concatDescriptor.SetConcatAxis(concatDimInput);
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003302 unsigned int mergeDimOrigin = 0;
Sadik Armagan479045b2018-10-01 11:51:37 +01003303
3304 for (unsigned int viewIndex = 0; viewIndex < numConcatView; ++viewIndex)
3305 {
Mike Kelly377fb212023-01-10 15:55:28 +00003306 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, viewIndex);
Sadik Armagan479045b2018-10-01 11:51:37 +01003307
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003308 // This set up concatDescriptor view origin
3309 armnnUtils::ProcessConcatInputTensorInfo(
Mike Kelly377fb212023-01-10 15:55:28 +00003310 inputTensorInfo, concatDescriptor, concatDimInput, viewIndex, mergeDimOrigin);
Sadik Armagan479045b2018-10-01 11:51:37 +01003311 }
3312
James Ward58dec6b2020-09-11 17:32:44 +01003313 auto layerName = fmt::format("Concatenation:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01003314
Jim Flynn906f9462019-05-10 13:55:21 +01003315 IConnectableLayer* layer = m_Network->AddConcatLayer(concatDescriptor, layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01003316 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00003317 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {});
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003318 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
Sadik Armagan479045b2018-10-01 11:51:37 +01003319
James Conroy05102392020-06-24 15:39:55 +01003320 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003321 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes});
Sadik Armagan479045b2018-10-01 11:51:37 +01003322
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003323 // add fused activation layer
3324 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
Sadik Armagan479045b2018-10-01 11:51:37 +01003325
Sadik Armagan479045b2018-10-01 11:51:37 +01003326 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3327 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3328}
3329
Kevin May7d96b162021-02-03 17:38:41 +00003330void TfLiteParserImpl::ParseFullyConnected(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003331{
3332 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3333
Mike Kelly0d77ae12022-01-07 17:42:27 +00003334 const auto& operatorRfr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003335 const auto options = operatorRfr->builtin_options.AsFullyConnectedOptions();
3336
3337 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
3338
3339 FullyConnectedDescriptor desc;
3340 desc.m_BiasEnabled = false;
Nattapat Chaimanowongd8eee592018-10-26 10:24:14 +01003341 desc.m_TransposeWeightMatrix = true;
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003342
3343 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3344 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3345 CHECK_VALID_SIZE(outputs.size(), 1);
3346
Mike Kelly377fb212023-01-10 15:55:28 +00003347 armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003348
3349 // Fully Connected Layer accepts two dimensional weights input
3350 int32_t weightsDimension = static_cast<int32_t>(filterTensorInfo.GetNumDimensions());
3351 if (weightsDimension != 2)
3352 {
3353 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003354 fmt::format("Dimension {} for Fully Connected weights is not supported by Armnn. "
3355 "Node {}",
3356 weightsDimension,
3357 CHECK_LOCATION().AsString()));
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003358 }
3359
Matthew Jackson74bf7da2019-08-16 16:51:42 +01003360 armnn::IConnectableLayer* layer = nullptr;
James Ward58dec6b2020-09-11 17:32:44 +01003361 auto layerName = fmt::format("FullyConnected:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003362
Matthew Sloyan81beae32021-07-13 19:46:11 +01003363 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3364 // Add the first input tensor to the registration list
3365 std::vector<unsigned int> tensorIndexesToRegister = {inputTensorIndexes[0]};
Mike Kelly377fb212023-01-10 15:55:28 +00003366 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Finn Williamsd4fa5452021-03-01 12:31:41 +00003367
3368 desc.m_ConstantWeights = IsConstTensor(inputs[1]);
3369
Matthew Sloyan81beae32021-07-13 19:46:11 +01003370 // Add the weights input to the registration list, constant layers will be added by SetupConstantLayers if constant.
3371 tensorIndexesToRegister.emplace_back(inputTensorIndexes[1]);
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003372
Mike Kelly0506ef02023-01-03 16:29:44 +00003373 if (ShouldConstantTensorBeConverted(inputs[1], inputTensorInfo.GetDataType(), filterTensorInfo.GetDataType()))
Mike Kelly5880b912022-01-28 16:18:54 +00003374 {
3375 m_ConstantsToDequantize.emplace_back(inputs[1]->buffer);
3376 }
3377
Finn Williamsd4fa5452021-03-01 12:31:41 +00003378 if (inputs.size() == 3)
3379 {
3380 desc.m_BiasEnabled = true;
Mike Kelly377fb212023-01-10 15:55:28 +00003381 armnn::TensorInfo biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Matthew Sloyan81beae32021-07-13 19:46:11 +01003382
3383 // Add the biases input to the registration list, constant layer will be added by SetupConstantLayers.
3384 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
Mike Kelly5880b912022-01-28 16:18:54 +00003385
Mike Kelly0506ef02023-01-03 16:29:44 +00003386 if (ShouldConstantTensorBeConverted(inputs[2], inputTensorInfo.GetDataType(), biasTensorInfo.GetDataType()))
Mike Kelly5880b912022-01-28 16:18:54 +00003387 {
3388 m_ConstantsToDequantize.emplace_back(inputs[2]->buffer);
3389 }
Finn Williamsd4fa5452021-03-01 12:31:41 +00003390 }
3391
Matthew Sloyan81beae32021-07-13 19:46:11 +01003392 // Filters and biases are always passed to fully connected as inputs
3393 layer = m_Network->AddFullyConnectedLayer(desc, layerName.c_str());
Finn Williamsd4fa5452021-03-01 12:31:41 +00003394
3395 ARMNN_ASSERT(layer != nullptr);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003396
Finn Williamsd4fa5452021-03-01 12:31:41 +00003397 unsigned int startingSlotIndex = 0;
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003398 if (inputTensorInfo.GetNumDimensions() > 2)
3399 {
3400 // Add reshape to flatten to 2D [batch_size, input_size],
3401 // where "input_size" corresponds to the number of inputs to the layer,
3402 // matching the second dimension of weights,
3403 // and "batch_size" is calculated by dividing the number of elements by "input_size".
3404 std::vector<unsigned int> reshapedDimensions(2);
3405 reshapedDimensions[1] = filterTensorInfo.GetShape()[1];
3406 reshapedDimensions[0] = inputTensorInfo.GetNumElements() / reshapedDimensions[1];
3407
3408 if (inputTensorInfo.GetNumElements() % reshapedDimensions[1] != 0)
3409 {
3410 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003411 fmt::format("Failed to deduce input tensor shape from filter size {} {}",
3412 reshapedDimensions[1],
3413 CHECK_LOCATION().AsString()));
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003414 }
3415
Mike Kelly377fb212023-01-10 15:55:28 +00003416 armnn::TensorInfo reshapedTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003417 reshapedTensorInfo.SetShape(armnn::TensorShape{ 2, reshapedDimensions.data() });
Mike Kelly377fb212023-01-10 15:55:28 +00003418 inputTensorInfo = reshapedTensorInfo;
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003419
James Ward58dec6b2020-09-11 17:32:44 +01003420 std::string reshapeLayerName = fmt::format("Reshape_for:{}", layer->GetName());
Finn Williamsd4fa5452021-03-01 12:31:41 +00003421 armnn::ReshapeDescriptor reshapeDescriptor;
3422 reshapeDescriptor.m_TargetShape = reshapedTensorInfo.GetShape();
Mike Kelly04d82292023-01-19 18:29:40 +00003423 armnn::IConnectableLayer* reshapeLayer = m_Network->AddReshapeLayer(reshapeDescriptor,
3424 reshapeLayerName.c_str());
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003425
3426 reshapeLayer->GetOutputSlot(0).SetTensorInfo(reshapedTensorInfo);
3427 reshapeLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
3428
3429 RegisterInputSlots(subgraphIndex, operatorIndex, reshapeLayer, {inputTensorIndexes[0]});
Finn Williamsd4fa5452021-03-01 12:31:41 +00003430 // Fc layer connects to the reshape layer, so we skip the first input slot when registering fc's input slots
3431 tensorIndexesToRegister.erase(tensorIndexesToRegister.begin());
3432 startingSlotIndex = 1;
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003433 }
Finn Williamsd4fa5452021-03-01 12:31:41 +00003434
3435 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister, startingSlotIndex);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003436
Mike Kelly377fb212023-01-10 15:55:28 +00003437 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromShapes(subgraphIndex, operatorIndex, layer, 0,
3438 { inputTensorInfo.GetShape(),
3439 filterTensorInfo.GetShape() });
Mike Kelly04d82292023-01-19 18:29:40 +00003440
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003441 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3442
Mike Kelly04d82292023-01-19 18:29:40 +00003443 if (outputTensorInfo.GetNumDimensions() > 2)
3444 {
3445 // Calculate reshape to flatten to 2D [batch_size, input_size]
3446 std::vector<unsigned int> reshapedDimensions(2);
3447 reshapedDimensions[1] = filterTensorInfo.GetShape()[0];
3448 reshapedDimensions[0] = outputTensorInfo.GetNumElements() / reshapedDimensions[1];
3449 armnn::TensorInfo reshapedOutputTensorInfo = outputTensorInfo;
3450 if (outputTensorInfo.GetNumElements() % reshapedDimensions[1] != 0)
3451 {
3452 throw ParseException(
3453 fmt::format("Failed to deduce output tensor shape from filter size {} {}",
3454 reshapedDimensions[1],
3455 CHECK_LOCATION().AsString()));
3456 }
3457 reshapedOutputTensorInfo.SetShape(armnn::TensorShape{ 2, reshapedDimensions.data() });
3458 layer->GetOutputSlot(0).SetTensorInfo(reshapedOutputTensorInfo);
3459
3460 std::string reshapeLayerName = fmt::format("ExpandDims:{}:{}", subgraphIndex, operatorIndex);
3461 layer = AddReshapeLayer(layer, 0, reshapeLayerName, outputTensorInfo);
3462 }
3463
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003464 // we need to add the activation layer and fortunately we don't need to care about the data layout
3465 armnn::IConnectableLayer* fusedActivationLayer = AddFusedActivationLayer(layer, 0,
3466 options->fused_activation_function);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003467
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003468 // register the output connection slots for the layer, connections are made after all layers have been created
3469 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3470 RegisterOutputSlots(subgraphIndex, operatorIndex, fusedActivationLayer, {outputTensorIndexes[0]});
Mike Kelly04d82292023-01-19 18:29:40 +00003471
3472 m_TensorInfos[outputTensorIndexes[0]] = layer->GetOutputSlot(0).GetTensorInfo();
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003473}
3474
Kevin May7d96b162021-02-03 17:38:41 +00003475void TfLiteParserImpl::ParseDetectionPostProcess(size_t subgraphIndex, size_t operatorIndex)
keidav011b3e2ea2019-02-21 10:07:37 +00003476{
3477 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3478
Mike Kelly0d77ae12022-01-07 17:42:27 +00003479 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
keidav011b3e2ea2019-02-21 10:07:37 +00003480
3481 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3482 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3483 CHECK_VALID_SIZE(outputs.size(), 4);
3484
3485 // Obtain custom options from flexbuffers
3486 auto custom_options = operatorPtr->custom_options;
3487 const flexbuffers::Map& m = flexbuffers::GetRoot(custom_options.data(), custom_options.size()).AsMap();
3488
3489 // Obtain descriptor information from tf lite
3490 DetectionPostProcessDescriptor desc;
3491 desc.m_MaxDetections = m["max_detections"].AsUInt32();
3492 desc.m_MaxClassesPerDetection = m["max_classes_per_detection"].AsUInt32();
3493 desc.m_NmsScoreThreshold = m["nms_score_threshold"].AsFloat();
3494 desc.m_NmsIouThreshold = m["nms_iou_threshold"].AsFloat();
3495 desc.m_NumClasses = m["num_classes"].AsUInt32();
3496 desc.m_ScaleH = m["h_scale"].AsFloat();
3497 desc.m_ScaleW = m["w_scale"].AsFloat();
3498 desc.m_ScaleX = m["x_scale"].AsFloat();
3499 desc.m_ScaleY = m["y_scale"].AsFloat();
3500
keidav0107d58c72019-02-26 11:57:39 +00003501 if (!(m["use_regular_nms"].IsNull()))
keidav011b3e2ea2019-02-21 10:07:37 +00003502 {
keidav0107d58c72019-02-26 11:57:39 +00003503 desc.m_UseRegularNms = m["use_regular_nms"].AsBool();
keidav011b3e2ea2019-02-21 10:07:37 +00003504 }
3505 if (!(m["detections_per_class"].IsNull()))
3506 {
3507 desc.m_DetectionsPerClass = m["detections_per_class"].AsUInt32();
3508 }
3509
3510 if (desc.m_NmsIouThreshold <= 0.0f || desc.m_NmsIouThreshold > 1.0f)
3511 {
3512 throw InvalidArgumentException("DetectionPostProcessTFLiteParser: Intersection over union threshold "
3513 "must be positive and less than or equal to 1.");
3514 }
3515
Mike Kelly377fb212023-01-10 15:55:28 +00003516 armnn::TensorInfo anchorTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Finn Williamsd4fa5452021-03-01 12:31:41 +00003517 auto anchorTensorAndData = CreateConstTensorNonPermuted(inputs[2], anchorTensorInfo);
keidav011b3e2ea2019-02-21 10:07:37 +00003518
James Ward58dec6b2020-09-11 17:32:44 +01003519 auto layerName = fmt::format("DetectionPostProcess:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsd4fa5452021-03-01 12:31:41 +00003520 IConnectableLayer* layer = m_Network->AddDetectionPostProcessLayer(desc, anchorTensorAndData,
keidav011b3e2ea2019-02-21 10:07:37 +00003521 layerName.c_str());
3522
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01003523 ARMNN_ASSERT(layer != nullptr);
keidav011b3e2ea2019-02-21 10:07:37 +00003524
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00003525 // The model does not specify the output shapes.
3526 // The output shapes are calculated from the max_detection and max_classes_per_detection.
3527 unsigned int numDetectedBox = desc.m_MaxDetections * desc.m_MaxClassesPerDetection;
Mike Kelly377fb212023-01-10 15:55:28 +00003528 m_OverriddenOutputShapes.push_back({ 1, numDetectedBox, 4 });
3529 m_OverriddenOutputShapes.push_back({ 1, numDetectedBox });
3530 m_OverriddenOutputShapes.push_back({ 1, numDetectedBox });
3531 m_OverriddenOutputShapes.push_back({ 1 });
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00003532
keidav011b3e2ea2019-02-21 10:07:37 +00003533 for (unsigned int i = 0 ; i < outputs.size() ; ++i)
3534 {
Mike Kelly377fb212023-01-10 15:55:28 +00003535 armnn::TensorInfo detectionBoxOutputTensorInfo = ToTensorInfo(outputs[i], m_OverriddenOutputShapes[i]);
keidav011b3e2ea2019-02-21 10:07:37 +00003536 layer->GetOutputSlot(i).SetTensorInfo(detectionBoxOutputTensorInfo);
3537 }
3538
3539 // Register the input connection slots for the layer, connections are made after all layers have been created
3540 // only the tensors for the inputs are relevant, exclude the const tensors
3541 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3542 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
3543
3544 // Register the output connection slots for the layer, connections are made after all layers have been created
3545 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3546 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0],
3547 outputTensorIndexes[1],
3548 outputTensorIndexes[2],
3549 outputTensorIndexes[3]});
3550}
3551
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003552/// The TfLite Pack operator is equivalent to the ArmNN Stack operator
Kevin May7d96b162021-02-03 17:38:41 +00003553void TfLiteParserImpl::ParsePack(size_t subgraphIndex, size_t operatorIndex)
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003554{
3555 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3556
3557 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3558 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3559 CHECK_VALID_SIZE(outputs.size(), 1);
3560
3561 if (inputs.size() < 1)
3562 {
3563 throw ParseException("Pack must have at least one input.");
3564 }
3565
3566 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3567 const auto* options = operatorPtr->builtin_options.AsPackOptions();
3568
3569 StackDescriptor desc;
3570 desc.m_Axis = static_cast<uint32_t>(options->axis);
3571 desc.m_NumInputs = static_cast<uint32_t>(inputs.size());
3572
3573 // Use the tensor shape of the first input as the "correct" input shape in the descriptor
Mike Kelly377fb212023-01-10 15:55:28 +00003574 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003575 desc.m_InputShape = inputTensorInfo.GetShape();
3576
James Ward58dec6b2020-09-11 17:32:44 +01003577 auto layerName = fmt::format("Pack:{}:{}", subgraphIndex, operatorIndex);
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003578 IConnectableLayer* layer = m_Network->AddStackLayer(desc, layerName.c_str());
3579
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01003580 ARMNN_ASSERT(layer != nullptr);
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003581
Mike Kelly377fb212023-01-10 15:55:28 +00003582 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {});
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003583 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3584
3585 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3586 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes});
3587
3588 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3589 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3590}
3591
Mike Kelly5880b912022-01-28 16:18:54 +00003592void TfLiteParserImpl::ParseUnidirectionalSequenceLSTM(size_t subgraphIndex, size_t operatorIndex)
3593{
3594 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3595
3596 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3597 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3598
3599 if (inputs.size() < 2)
3600 {
3601 throw ParseException("UnidirectionalSequenceLSTM must have at least 2 input.");
3602 }
3603
3604 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3605 const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex];
3606 const auto nodeParams = operatorPtr->builtin_options.AsUnidirectionalSequenceLSTMOptions();
3607 CHECK_SUPPORTED_FUSED_ACTIVATION(nodeParams, subgraphIndex, operatorIndex);
Mike Kelly377fb212023-01-10 15:55:28 +00003608 auto inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Mike Kelly5880b912022-01-28 16:18:54 +00003609 auto outputTensorInfo = ToTensorInfo(outputs[0]);
3610
3611 // Set the params structure for the AddUnidirectionalSequenceLstmLayer call
3612 // Please refer to each operand at
3613 // https://www.tensorflow.org/mlir/tfl_ops#tflunidirectional_sequence_lstm_tflunidirectionalsequencelstmop
3614 armnn::LstmInputParams params;
3615
3616 if (IsOptionalOperandPresent(operatorPtr->inputs[1]))
3617 {
3618 params.m_InputToInputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[1]].get(),
3619 inputTensorInfo).first;
3620 }
3621
3622 params.m_InputToForgetWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[2]].get(),
3623 inputTensorInfo).first;
3624 params.m_InputToCellWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[3]].get(),
3625 inputTensorInfo).first;
3626 params.m_InputToOutputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[4]].get(),
3627 inputTensorInfo).first;
3628
3629 // Recurrent weight tensors of size {n_cell, n_output}
3630 if (IsOptionalOperandPresent(operatorPtr->inputs[5]))
3631 {
3632 params.m_RecurrentToInputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[5]].get(),
3633 inputTensorInfo).first;
3634 }
3635
3636 params.m_RecurrentToForgetWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[6]].get(),
3637 inputTensorInfo).first;
3638 params.m_RecurrentToCellWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[7]].get(),
3639 inputTensorInfo).first;
3640 params.m_RecurrentToOutputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[8]].get(),
3641 inputTensorInfo).first;
3642
3643 // Peephole weights tensors of size {n_cell}, representing a diagonal matrix.
3644 if (IsOptionalOperandPresent(operatorPtr->inputs[9]))
3645 {
3646 params.m_CellToInputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[9]].get(),
3647 inputTensorInfo).first;
3648 }
3649
3650 if (IsOptionalOperandPresent(operatorPtr->inputs[10]))
3651 {
3652 params.m_CellToForgetWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[10]].get(),
3653 inputTensorInfo).first;
3654 }
3655
3656 if (IsOptionalOperandPresent(operatorPtr->inputs[11]))
3657 {
3658 params.m_CellToOutputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[11]].get(),
3659 inputTensorInfo).first;
3660 }
3661
3662 // Gates bias tensors of size {n_cell}
3663 if (IsOptionalOperandPresent(operatorPtr->inputs[12]))
3664 {
3665 params.m_InputGateBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[12]].get(),
3666 inputTensorInfo).first;
3667 }
3668
3669 params.m_ForgetGateBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[13]].get(),
3670 inputTensorInfo).first;
3671 params.m_CellBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[14]].get(),
3672 inputTensorInfo).first;
3673 params.m_OutputGateBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[15]].get(),
3674 inputTensorInfo).first;
3675
3676 // Projection weight tensor of size {n_output, n_cell}
3677 if (IsOptionalOperandPresent(operatorPtr->inputs[16]))
3678 {
3679 params.m_ProjectionWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[16]].get(),
3680 inputTensorInfo).first;
3681 }
3682 // Projection bias tensor of size {n_output}
3683 if (IsOptionalOperandPresent(operatorPtr->inputs[17]))
3684 {
3685 params.m_ProjectionBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[17]].get(),
3686 inputTensorInfo).first;
3687 }
3688
3689 // These state tensors are defined as variable tensors, and will be modified by this op.
3690 armnn::TensorInfo outputStateInInfo = ToTensorInfo(subgraphPtr->tensors[operatorPtr->inputs[18]].get());
3691 m_ConstantsToBeCreated.push_back(operatorPtr->inputs[18]);
3692 armnn::TensorInfo cellStateInInfo = ToTensorInfo(subgraphPtr->tensors[operatorPtr->inputs[19]].get());
3693 m_ConstantsToBeCreated.push_back(operatorPtr->inputs[19]);
3694
3695 // Layer norm coefficient tensors of size {n_cell}, representing a diagonal matrix.
3696 if (inputs.size() >= 21 && IsOptionalOperandPresent(operatorPtr->inputs[20]))
3697 {
3698 params.m_InputLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[20]].get(),
3699 inputTensorInfo).first;
3700 }
3701
3702 if (inputs.size() >= 22 && IsOptionalOperandPresent(operatorPtr->inputs[21]))
3703 {
3704 params.m_ForgetLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[21]].get(),
3705 inputTensorInfo).first;
3706 }
3707
3708 if (inputs.size() >= 23 && IsOptionalOperandPresent(operatorPtr->inputs[22]))
3709 {
3710 params.m_CellLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[22]].get(),
3711 inputTensorInfo).first;
3712 }
3713
3714 if (inputs.size() >= 24 && IsOptionalOperandPresent(operatorPtr->inputs[23]))
3715 {
3716 params.m_OutputLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[23]].get(),
3717 inputTensorInfo).first;
3718 }
3719
3720 // set the layer descriptor
3721 armnn::UnidirectionalSequenceLstmDescriptor desc;
3722 desc.m_ActivationFunc = nodeParams->fused_activation_function;
3723 desc.m_ClippingThresCell = nodeParams->cell_clip;
3724 desc.m_ClippingThresProj = nodeParams->proj_clip;
3725 desc.m_CifgEnabled = (params.m_InputToInputWeights == nullptr
3726 || params.m_RecurrentToInputWeights == nullptr
3727 || params.m_InputGateBias == nullptr);
3728 desc.m_PeepholeEnabled = (params.m_CellToForgetWeights != nullptr || params.m_CellToOutputWeights != nullptr);
3729 desc.m_ProjectionEnabled = (params.m_ProjectionWeights != nullptr);
3730 desc.m_LayerNormEnabled = (params.m_InputLayerNormWeights != nullptr
3731 || params.m_ForgetLayerNormWeights != nullptr
3732 || params.m_CellLayerNormWeights != nullptr
3733 || params.m_OutputLayerNormWeights != nullptr);
3734 desc.m_TimeMajor = nodeParams->time_major;
3735
Mike Kellyc0800a32022-06-15 10:57:52 +01003736 if (operatorPtr->intermediates.size() > 3 && desc.m_LayerNormEnabled)
Mike Kelly5880b912022-01-28 16:18:54 +00003737 {
3738 auto inputIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[0]].get(),
3739 inputTensorInfo).first;
3740 auto inputIntermediateTensorInfo = inputIntermediate->GetInfo();
3741 desc.m_InputIntermediateScale = inputIntermediateTensorInfo.GetQuantizationScale();
3742
3743 auto forgetIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[1]].get(),
3744 inputTensorInfo).first;
3745 auto forgetIntermediateTensorInfo = forgetIntermediate->GetInfo();
3746 desc.m_ForgetIntermediateScale = forgetIntermediateTensorInfo.GetQuantizationScale();
3747
3748 auto cellIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[2]].get(),
3749 inputTensorInfo).first;
3750 auto cellIntermediateTensorInfo = cellIntermediate->GetInfo();
3751 desc.m_CellIntermediateScale = cellIntermediateTensorInfo.GetQuantizationScale();
3752
3753 auto outputIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[3]].get(),
3754 inputTensorInfo).first;
3755 auto outputIntermediateTensorInfo = outputIntermediate->GetInfo();
3756 desc.m_OutputIntermediateScale = outputIntermediateTensorInfo.GetQuantizationScale();
3757 }
3758 else
3759 {
3760 float defaultIntermediate = std::pow(2, -12);
3761 desc.m_InputIntermediateScale = defaultIntermediate;
3762 desc.m_ForgetIntermediateScale = defaultIntermediate;
3763 desc.m_CellIntermediateScale = defaultIntermediate;
3764 desc.m_OutputIntermediateScale = defaultIntermediate;
3765 }
3766
Mike Kellyc0800a32022-06-15 10:57:52 +01003767 if (operatorPtr->intermediates.size() > 4)
3768 {
3769 auto hiddentensor = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[4]].get(),
3770 inputTensorInfo).first;
Mike Kelly5880b912022-01-28 16:18:54 +00003771
Mike Kellyc0800a32022-06-15 10:57:52 +01003772 desc.m_HiddenStateScale = hiddentensor->GetInfo().GetQuantizationScale();
3773 desc.m_HiddenStateZeroPoint = hiddentensor->GetInfo().GetQuantizationOffset();
3774 }
Mike Kelly5880b912022-01-28 16:18:54 +00003775 unsigned int batchSize = inputTensorInfo.GetShape()[0];
3776 unsigned int outputSize = outputTensorInfo.GetShape()[2];
3777 unsigned int numUnits = cellStateInInfo.GetShape()[1];
3778
3779 armnn::DataType dataType = inputTensorInfo.GetDataType();
3780 float qScale = inputTensorInfo.GetQuantizationScale();
3781 float qOffset = inputTensorInfo.GetQuantizationOffset();
3782
3783 armnn::TensorInfo scratchBufferTensorInfo({batchSize, numUnits * 3}, dataType, qScale, qOffset);
3784 if (!desc.m_CifgEnabled)
3785 {
3786 scratchBufferTensorInfo = armnn::TensorInfo({batchSize, numUnits * 4}, dataType, qScale, qOffset);
3787 }
3788 armnn::TensorInfo cellStateOutTensorInfo({batchSize, numUnits},
3789 cellStateInInfo.GetDataType(),
3790 cellStateInInfo.GetQuantizationScale(),
3791 cellStateInInfo.GetQuantizationOffset());
3792 armnn::TensorInfo outputStateOutTensorInfo({batchSize, outputSize}, dataType, qScale, qOffset);
3793
3794 armnn::LstmInputParamsInfo paramsInfo;
3795 paramsInfo.m_InputToForgetWeights = &(params.m_InputToForgetWeights->GetInfo());
3796 paramsInfo.m_InputToCellWeights = &(params.m_InputToCellWeights->GetInfo());
3797 paramsInfo.m_InputToOutputWeights = &(params.m_InputToOutputWeights->GetInfo());
3798 paramsInfo.m_RecurrentToForgetWeights = &(params.m_RecurrentToForgetWeights->GetInfo());
3799 paramsInfo.m_RecurrentToCellWeights = &(params.m_RecurrentToCellWeights->GetInfo());
3800 paramsInfo.m_RecurrentToOutputWeights = &(params.m_RecurrentToOutputWeights->GetInfo());
3801 paramsInfo.m_ForgetGateBias = &(params.m_ForgetGateBias->GetInfo());
3802 paramsInfo.m_CellBias = &(params.m_CellBias->GetInfo());
3803 paramsInfo.m_OutputGateBias = &(params.m_OutputGateBias->GetInfo());
3804
3805 if (!desc.m_CifgEnabled)
3806 {
3807 paramsInfo.m_InputToInputWeights = &(params.m_InputToInputWeights->GetInfo());
3808 paramsInfo.m_RecurrentToInputWeights = &(params.m_RecurrentToInputWeights->GetInfo());
3809 if (params.m_CellToInputWeights != nullptr)
3810 {
3811 paramsInfo.m_CellToInputWeights = &(params.m_CellToInputWeights->GetInfo());
3812 }
3813 paramsInfo.m_InputGateBias = &(params.m_InputGateBias->GetInfo());
3814 }
3815
3816 if (desc.m_ProjectionEnabled)
3817 {
3818 paramsInfo.m_ProjectionWeights = &(params.m_ProjectionWeights->GetInfo());
3819 if (params.m_ProjectionBias != nullptr)
3820 {
3821 paramsInfo.m_ProjectionBias = &(params.m_ProjectionBias->GetInfo());
3822 }
3823 }
3824
3825 if (desc.m_PeepholeEnabled)
3826 {
3827 paramsInfo.m_CellToForgetWeights = &(params.m_CellToForgetWeights->GetInfo());
3828 paramsInfo.m_CellToOutputWeights = &(params.m_CellToOutputWeights->GetInfo());
3829 }
3830
3831 if (desc.m_LayerNormEnabled)
3832 {
3833 if(!desc.m_CifgEnabled)
3834 {
3835 paramsInfo.m_InputLayerNormWeights = &(params.m_InputLayerNormWeights->GetInfo());
3836 }
3837 paramsInfo.m_ForgetLayerNormWeights = &(params.m_ForgetLayerNormWeights->GetInfo());
3838 paramsInfo.m_CellLayerNormWeights = &(params.m_CellLayerNormWeights->GetInfo());
3839 paramsInfo.m_OutputLayerNormWeights = &(params.m_OutputLayerNormWeights->GetInfo());
3840 }
3841
3842 auto layerName = fmt::format("UnidirectionalSequenceLSTM:{}:{}", subgraphIndex, operatorIndex);
3843 armnn::IConnectableLayer* layer = m_Network->AddUnidirectionalSequenceLstmLayer(desc, params);
3844 ARMNN_ASSERT(layer != nullptr);
3845
3846 // register the input connection slots for the layer, connections are made after all layers have been created
3847 // only the tensors for the inputs are relevant, exclude the const tensors
3848 auto inputTensorIndexes = AsUnsignedVector({operatorPtr->inputs[0],
3849 operatorPtr->inputs[18],
3850 operatorPtr->inputs[19]});
3851 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0],
3852 inputTensorIndexes[1],
3853 inputTensorIndexes[2]});
3854
3855 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3856
3857 layer->GetOutputSlot(0).SetTensorInfo(outputStateOutTensorInfo);
3858 layer->GetOutputSlot(1).SetTensorInfo(cellStateOutTensorInfo);
3859 layer->GetOutputSlot(2).SetTensorInfo(outputTensorInfo);
3860
3861 unsigned int tensorIndex = outputTensorIndexes[0];
3862 armnn::IOutputSlot* slot = &(layer->GetOutputSlot(2));
3863 RegisterProducerOfTensor(subgraphIndex, tensorIndex, slot);
3864}
3865
Kevin May7d96b162021-02-03 17:38:41 +00003866void TfLiteParserImpl::ParseUnpack(size_t subgraphIndex, size_t operatorIndex)
Nina Drozd200e3802019-04-15 09:47:39 +01003867{
3868 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3869
Mike Kelly0d77ae12022-01-07 17:42:27 +00003870 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3871 const auto* options = operatorPtr->builtin_options.AsUnpackOptions();
Nina Drozd200e3802019-04-15 09:47:39 +01003872
3873 // This unpackAxis indicates the axis to unpack
3874 const unsigned int unpackAxis = CHECKED_NON_NEGATIVE(options->axis);
3875
3876 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3877 CHECK_VALID_SIZE(inputs.size(), 1);
3878
Mike Kelly377fb212023-01-10 15:55:28 +00003879 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003880
3881 if (unpackAxis >= inputTensorInfo.GetNumDimensions())
3882 {
3883 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003884 fmt::format("The unpack axis: {} cannot be greater than or equal to "
3885 "the number of input dimension {} {}",
3886 unpackAxis,
3887 inputTensorInfo.GetNumDimensions(),
3888 CHECK_LOCATION().AsString()));
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003889 }
3890
Nina Drozd200e3802019-04-15 09:47:39 +01003891 unsigned int unpackNum = CHECKED_NON_NEGATIVE(options->num);
3892 // If num is not defined, automatically infer from the length of the dimension axis.
3893 if(unpackNum == 0)
3894 {
3895 unpackNum = inputTensorInfo.GetShape()[unpackAxis];
3896 }
3897
3898 // If unpack number cannot be inferred and is still zero, throw ParseException.
3899 if(unpackNum == 0)
3900 {
3901 throw ParseException("Number to unpack must greater than zero.");
3902 }
3903
3904 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3905 CHECK_VALID_SIZE(outputs.size(), unpackNum);
3906
3907 auto inputDimSize = inputTensorInfo.GetNumDimensions();
3908 std::vector<unsigned int> unpackDimSizes(inputDimSize);
3909
3910 // Add current input shape to unpackDimSizes
3911 for (unsigned int i = 0; i < inputDimSize; ++i)
3912 {
3913 unpackDimSizes[i] = inputTensorInfo.GetShape()[i];
3914 }
3915
3916 if (unpackDimSizes[unpackAxis] != unpackNum)
3917 {
3918 throw ParseException("Number to unpack must be the same as length of the dimension to "
3919 "unpack along.");
3920 }
3921
3922 unpackDimSizes[unpackAxis] /= unpackNum;
3923
3924 SplitterDescriptor splitDesc(unpackNum, static_cast<unsigned int>(unpackDimSizes.size()));
3925 for (unsigned int j = 0; j < unpackNum; ++j)
3926 {
3927 // Set the size of the views.
3928 for (unsigned int dimIdx = 0; dimIdx < unpackDimSizes.size(); ++dimIdx)
3929 {
3930 splitDesc.SetViewSize(j, dimIdx, unpackDimSizes[dimIdx]);
3931 }
3932 splitDesc.SetViewOriginCoord(j, unpackAxis, unpackDimSizes[unpackAxis] * j);
3933 }
3934
James Ward58dec6b2020-09-11 17:32:44 +01003935 auto layerName = fmt::format("Unpack:{}:{}", subgraphIndex, operatorIndex);
Nina Drozd200e3802019-04-15 09:47:39 +01003936 IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01003937 ARMNN_ASSERT(layer != nullptr);
Nina Drozd200e3802019-04-15 09:47:39 +01003938
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003939 TensorShape splitOutShape = TensorShape(static_cast<unsigned int>(unpackDimSizes.size()),
3940 unpackDimSizes.data());
3941
Nina Drozd200e3802019-04-15 09:47:39 +01003942 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3943 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3944
Finn Williamsb49ed182021-06-29 15:50:08 +01003945 std::vector<unsigned int> reshapeDims;
3946 for (unsigned int axis = 0; axis < splitOutShape.GetNumDimensions(); ++axis)
3947 {
3948 if (axis != unpackAxis)
3949 {
3950 reshapeDims.push_back(splitOutShape[axis]);
3951 }
3952 }
3953
3954 TensorShape reshapeOutputShape(splitOutShape.GetNumDimensions() -1, reshapeDims.data());
3955
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003956 // Create reshape to remove the unpacked dimension for unpack operator of each output from Splitter.
3957 for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
3958 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01003959 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[k], true);
James Ward58dec6b2020-09-11 17:32:44 +01003960 std::string reshapeLayerName = fmt::format("Reshape_for:{}", layer->GetName());
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003961 armnn::ReshapeDescriptor desc;
Finn Williamsb49ed182021-06-29 15:50:08 +01003962 desc.m_TargetShape = reshapeOutputShape;
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003963 armnn::IConnectableLayer* reshapeLayer = m_Network->AddReshapeLayer(desc, layerName.c_str());
3964
Narumol Prangnawarat2c526462019-10-21 14:58:26 +01003965 layer->GetOutputSlot(k).SetTensorInfo(armnn::TensorInfo(splitOutShape,
3966 outputTensorInfo.GetDataType(),
3967 outputTensorInfo.GetQuantizationScale(),
3968 outputTensorInfo.GetQuantizationOffset()));
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003969 layer->GetOutputSlot(k).Connect(reshapeLayer->GetInputSlot(0));
3970
Narumol Prangnawarat2c526462019-10-21 14:58:26 +01003971 reshapeLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003972
3973 uint32_t reshapedOutputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[k]);
3974 armnn::IOutputSlot* slot = &(reshapeLayer->GetOutputSlot(0));
3975 RegisterProducerOfTensor(subgraphIndex, reshapedOutputId, slot);
3976 }
Nina Drozd200e3802019-04-15 09:47:39 +01003977}
3978
Kevin May7d96b162021-02-03 17:38:41 +00003979void TfLiteParserImpl::ParseSplit(size_t subgraphIndex, size_t operatorIndex)
Nina Drozd0324f482019-04-08 10:52:10 +01003980{
3981 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3982
Mike Kelly0d77ae12022-01-07 17:42:27 +00003983 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3984 const auto* options = operatorPtr->builtin_options.AsSplitOptions();
Nina Drozd0324f482019-04-08 10:52:10 +01003985
3986 const unsigned int numSplits = CHECKED_NON_NEGATIVE(options->num_splits);
3987
Nina Drozd200e3802019-04-15 09:47:39 +01003988 // If number of splits cannot be inferred and is zero, throw ParseException.
3989 if(numSplits == 0)
3990 {
3991 throw ParseException("Number to splits must greater than zero.");
3992 }
3993
Nina Drozd0324f482019-04-08 10:52:10 +01003994 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3995 CHECK_VALID_SIZE(inputs.size(), 2);
3996 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3997 CHECK_VALID_SIZE(outputs.size(), numSplits);
3998
Mike Kelly377fb212023-01-10 15:55:28 +00003999 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
4000 armnn::TensorInfo axisTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004001 ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
Nina Drozd0324f482019-04-08 10:52:10 +01004002
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01004003 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[0]->buffer);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004004 if (axisBufferPtr == nullptr)
4005 {
4006 throw ParseException(
4007 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
4008 CHECK_LOCATION().AsString()));
4009 }
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01004010
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004011 std::vector<int32_t> axisData(axisTensorInfo.GetNumElements());
4012 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
4013 int32_t axis = axisData[0];
4014
4015 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
4016 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
4017 {
4018 // Square bracket denotes inclusive n while parenthesis denotes exclusive n
4019 // E.g. Rank 4 tensor can have axis in range [-4, 3)
4020 // -1 == 3, -2 == 2, -3 == 1, -4 == 0
4021 throw ParseException(
4022 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
4023 axis,
4024 CHECK_LOCATION().AsString()));
4025 }
4026
4027 const unsigned int splitDim = armnnUtils::GetUnsignedAxis(inputTensorInfo.GetNumDimensions(), axis);
Nina Drozd0324f482019-04-08 10:52:10 +01004028
Nina Drozd0324f482019-04-08 10:52:10 +01004029 auto inputDimSize = inputTensorInfo.GetNumDimensions();
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01004030 if (inputDimSize > MaxNumOfTensorDimensions)
Nina Drozd0324f482019-04-08 10:52:10 +01004031 {
4032 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01004033 fmt::format("The number of dimensions: {} for input tensors of the split op cannot be greater than {} {}",
4034 inputTensorInfo.GetNumDimensions(),
4035 MaxNumOfTensorDimensions,
4036 CHECK_LOCATION().AsString()));
Nina Drozd0324f482019-04-08 10:52:10 +01004037 }
4038
4039 std::vector<unsigned int> splitterDimSizes(inputDimSize);
4040
4041 // Add current input shape to splitterDimSizes
4042 for (unsigned int i = 0; i < inputDimSize; ++i)
4043 {
4044 splitterDimSizes[i] = inputTensorInfo.GetShape()[i];
4045 }
4046
4047 if (splitterDimSizes[splitDim] % numSplits != 0)
4048 {
4049 throw ParseException("Number of splits must evenly divide the dimension");
4050 }
4051 splitterDimSizes[splitDim] /= numSplits;
4052
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01004053 SplitterDescriptor splitDesc(numSplits, inputDimSize);
Nina Drozd0324f482019-04-08 10:52:10 +01004054 for (unsigned int j = 0; j < numSplits; ++j)
4055 {
4056 // Set the size of the views.
4057 for (unsigned int dimIdx = 0; dimIdx < splitterDimSizes.size(); ++dimIdx)
4058 {
4059 splitDesc.SetViewSize(j, dimIdx, splitterDimSizes[dimIdx]);
4060 }
4061 splitDesc.SetViewOriginCoord(j, splitDim, splitterDimSizes[splitDim] * j);
4062 }
4063
James Ward58dec6b2020-09-11 17:32:44 +01004064 auto layerName = fmt::format("Split:{}:{}", subgraphIndex, operatorIndex);
Nina Drozd0324f482019-04-08 10:52:10 +01004065 IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01004066 ARMNN_ASSERT(layer != nullptr);
Nina Drozd0324f482019-04-08 10:52:10 +01004067
4068 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01004069 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[1]});
Nina Drozd0324f482019-04-08 10:52:10 +01004070
Nina Drozd0324f482019-04-08 10:52:10 +01004071 for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
4072 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01004073 armnn::TensorInfo tensorInfo = ToTensorInfo(outputs[k], true);
Francis Murtagh98d6b3d2019-10-21 10:52:54 +01004074 layer->GetOutputSlot(k).SetTensorInfo(tensorInfo);
Nina Drozd0324f482019-04-08 10:52:10 +01004075 }
4076
4077 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4078 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4079}
4080
Derek Lambertif0176992020-04-28 13:37:49 +01004081unsigned int ComputeWrappedIndex(int idx, unsigned int numDimsIn)
4082{
4083 int numDims = armnn::numeric_cast<int>(numDimsIn);
4084 int v = idx < 0 ? numDims + idx : idx;
4085 ARMNN_ASSERT(v >= 0);
4086 ARMNN_ASSERT(v < numDims);
4087
4088 return static_cast<unsigned int>(v);
4089}
4090
Kevin May7d96b162021-02-03 17:38:41 +00004091void TfLiteParserImpl::ParseSplitV(size_t subgraphIndex, size_t operatorIndex)
Derek Lambertif0176992020-04-28 13:37:49 +01004092{
4093 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4094
Mike Kelly0d77ae12022-01-07 17:42:27 +00004095 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4096 const auto* options = operatorPtr->builtin_options.AsSplitVOptions();
Derek Lambertif0176992020-04-28 13:37:49 +01004097
4098 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4099 CHECK_VALID_SIZE(inputs.size(), 3);
4100
4101 auto& inputTensor = inputs[0];
4102 auto& splitsTensor = inputs[1];
4103 auto& axisTensor = inputs[2];
4104
4105 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputTensor);
4106 armnn::TensorInfo splitsInfo = ToTensorInfo(splitsTensor);
4107 armnn::TensorInfo axisTensorInfo = ToTensorInfo(axisTensor);
4108 ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
4109
4110 // Inputs
4111 auto inputDimSize = inputTensorInfo.GetNumDimensions();
4112 if (inputDimSize > MaxNumOfTensorDimensions)
4113 {
4114 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01004115 fmt::format("The number of dimensions: {} for input tensors of the "
4116 "SplitV op cannot be greater than {} {}",
4117 inputTensorInfo.GetNumDimensions(),
4118 MaxNumOfTensorDimensions,
4119 CHECK_LOCATION().AsString()));
Derek Lambertif0176992020-04-28 13:37:49 +01004120 }
4121
4122 // Get split axis
4123 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, axisTensor->buffer);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004124 if (axisBufferPtr == nullptr)
4125 {
4126 throw ParseException(
4127 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
4128 CHECK_LOCATION().AsString()));
4129 }
4130
Derek Lambertif0176992020-04-28 13:37:49 +01004131 std::vector<int> axisData(axisTensorInfo.GetNumElements());
4132 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004133 int32_t axis = axisData[0];
4134
4135 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
4136 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
4137 {
4138 // Square bracket denotes inclusive n while parenthesis denotes exclusive n
4139 // E.g. Rank 4 tensor can have axis in range [-4, 3)
4140 // -1 == 3, -2 == 2, -3 == 1, -4 == 0
4141 throw ParseException(
4142 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
4143 axis,
4144 CHECK_LOCATION().AsString()));
4145 }
4146 const unsigned int splitDim = ComputeWrappedIndex(axis, inputTensorInfo.GetNumDimensions());
Derek Lambertif0176992020-04-28 13:37:49 +01004147
Derek Lambertif0176992020-04-28 13:37:49 +01004148 // Set split sizes
Derek Lambertif0176992020-04-28 13:37:49 +01004149 CHECK_VALID_SIZE(splitsInfo.GetNumDimensions(), 1);
Ryan OShea86704732020-05-26 11:41:04 +01004150 unsigned int numSplits{0};
4151
4152 if(options)
Derek Lambertif0176992020-04-28 13:37:49 +01004153 {
4154 numSplits = CHECKED_NON_NEGATIVE(options->num_splits);
Derek Lambertif0176992020-04-28 13:37:49 +01004155 }
4156 else
4157 {
Ryan OShea86704732020-05-26 11:41:04 +01004158 numSplits = splitsInfo.GetNumElements();
Derek Lambertif0176992020-04-28 13:37:49 +01004159 }
4160
4161 if (numSplits <=0)
4162 {
4163 throw ParseException("SplitV has invalid number of splits");
4164 }
4165
Jan Eilersc0761e92020-06-29 16:48:44 +01004166 std::vector<int> splitsData(numSplits);
Ryan OShea86704732020-05-26 11:41:04 +01004167 BufferRawPtr splitsBufferPtr = GetBuffer(m_Model, splitsTensor->buffer);
Jan Eilersc0761e92020-06-29 16:48:44 +01004168 ::memcpy(splitsData.data(), splitsBufferPtr->data.data(), splitsInfo.GetNumBytes());
Ryan OShea86704732020-05-26 11:41:04 +01004169
Jan Eilersc0761e92020-06-29 16:48:44 +01004170 unsigned int idx = 0;
Ryan OShea86704732020-05-26 11:41:04 +01004171 int numInferred{0};
4172 unsigned int inferIdx{0};
4173 int splitSum{0};
4174 for (auto split : splitsData)
4175 {
4176 if (split < 0)
4177 {
4178 numInferred++;
4179 inferIdx = idx;
4180 }
4181 else
4182 {
4183 splitSum += split;
4184 }
4185 idx++;
4186 }
4187 // Check for inferred Axis
4188 if (numInferred == 0)
4189 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +01004190 if (splitSum != armnn::numeric_cast<int>(inputTensorInfo.GetShape()[splitDim]))
Ryan OShea86704732020-05-26 11:41:04 +01004191 {
4192 throw ParseException("SplitV split_sizes does not sum to the dimension of value along split_dim.");
4193 }
4194 }
4195 else if (numInferred == 1)
4196 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +01004197 splitsData[inferIdx] = armnn::numeric_cast<int>(inputTensorInfo.GetShape()[splitDim]) - splitSum;
Ryan OShea86704732020-05-26 11:41:04 +01004198 }
4199 else
4200 {
4201 throw ParseException("Cannot infer split size for more than one split");
4202 }
4203
Derek Lambertif0176992020-04-28 13:37:49 +01004204 //Ouput size validation
4205 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4206 CHECK_VALID_SIZE(outputs.size(), numSplits);
4207
4208 // Setup Armnn descriptor
4209 SplitterDescriptor splitDesc(numSplits, inputDimSize);
4210 unsigned int accumSplit = 0;
4211 for (unsigned int j = 0; j < numSplits; ++j)
4212 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +01004213 unsigned int splitSize = armnn::numeric_cast<unsigned int>(splitsData[j]);
Derek Lambertif0176992020-04-28 13:37:49 +01004214
4215 // Set the size of the views.
4216 for (unsigned int dimIdx = 0; dimIdx < inputTensorInfo.GetNumDimensions(); ++dimIdx)
4217 {
4218 unsigned int dimSize = inputTensorInfo.GetShape()[dimIdx];
4219 if (dimIdx == splitDim)
4220 {
4221 dimSize = splitSize;
4222 }
4223 splitDesc.SetViewSize(j, dimIdx, dimSize);
4224 }
4225
4226 splitDesc.SetViewOriginCoord(j, splitDim, accumSplit);
4227 accumSplit += splitSize;
4228 }
4229
James Ward58dec6b2020-09-11 17:32:44 +01004230 auto layerName = fmt::format("SplitV:{}:{}", subgraphIndex, operatorIndex);
Derek Lambertif0176992020-04-28 13:37:49 +01004231 IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01004232 ARMNN_ASSERT(layer != nullptr);
Derek Lambertif0176992020-04-28 13:37:49 +01004233
4234 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4235 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4236
4237 for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
4238 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01004239 armnn::TensorInfo tensorInfo = ToTensorInfo(outputs[k], true);
Derek Lambertif0176992020-04-28 13:37:49 +01004240 layer->GetOutputSlot(k).SetTensorInfo(tensorInfo);
4241 }
4242
4243 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4244 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4245}
4246
Matthew Sloyan28f177c2021-04-09 14:38:52 +01004247void TfLiteParserImpl::ParseArgMin(size_t subgraphIndex, size_t operatorIndex)
4248{
4249 ParseArgMinMax(subgraphIndex, operatorIndex, armnn::ArgMinMaxFunction::Min);
4250}
4251
Kevin May7d96b162021-02-03 17:38:41 +00004252void TfLiteParserImpl::ParseArgMax(size_t subgraphIndex, size_t operatorIndex)
Inki Daed4619e22020-09-10 15:33:54 +09004253{
Matthew Sloyan28f177c2021-04-09 14:38:52 +01004254 ParseArgMinMax(subgraphIndex, operatorIndex, armnn::ArgMinMaxFunction::Max);
4255}
4256
4257void TfLiteParserImpl::ParseArgMinMax(size_t subgraphIndex, size_t operatorIndex, ArgMinMaxFunction argMinMaxFunction)
4258{
Inki Daed4619e22020-09-10 15:33:54 +09004259 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4260 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4261 CHECK_VALID_SIZE(inputs.size(), 2);
4262
4263 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4264 CHECK_VALID_SIZE(outputs.size(), 1);
4265
Mike Kelly377fb212023-01-10 15:55:28 +00004266 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4267 armnn::TensorInfo axisTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Inki Daed4619e22020-09-10 15:33:54 +09004268 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004269 ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
Matthew Sloyan28f177c2021-04-09 14:38:52 +01004270
4271 // Check if output tensor type is Signed32 or Signed64
Mike Kelly1f140f72021-04-06 12:25:55 +01004272 if (outputTensorInfo.GetDataType() != armnn::DataType::Signed32 &&
4273 outputTensorInfo.GetDataType() != armnn::DataType::Signed64)
4274 {
4275 throw ParseException(
4276 fmt::format(
4277 "Output tensor data type is not supported. (Supported types: Signed32 & Signed64) {}",
4278 CHECK_LOCATION().AsString()));
4279 }
Matthew Sloyan28f177c2021-04-09 14:38:52 +01004280
4281 // Get const axis value from model and set it to descriptor.
4282 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
4283 if (axisBufferPtr == nullptr)
4284 {
4285 throw ParseException(
4286 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
4287 CHECK_LOCATION().AsString()));
4288 }
4289
4290 std::vector<int32_t> axisData(axisTensorInfo.GetNumElements());
4291 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
4292 int32_t axis = axisData.front();
4293
4294 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
4295 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
4296 {
4297 // Square bracket denotes inclusive n while parenthesis denotes exclusive n
4298 // E.g. Rank 4 tensor can have axis in range [-4, 3)
4299 // -1 == 3, -2 == 2, -3 == 1, -4 == 0
4300 throw ParseException(
4301 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
4302 axis,
4303 CHECK_LOCATION().AsString()));
4304 }
4305
4306 ArgMinMaxDescriptor desc;
4307 desc.m_Axis = axis;
4308 desc.m_Function = argMinMaxFunction;
4309
4310 // Register a ArgMin/ArgMax layer.
4311 auto layerName = argMinMaxFunction == ArgMinMaxFunction::Max ? "ArgMax:{}:{}" : "ArgMin:{}:{}";
4312 auto layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4313 IConnectableLayer *layer = m_Network->AddArgMinMaxLayer(desc, layerNameFormatted.c_str());
4314 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00004315 outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Inki Daed4619e22020-09-10 15:33:54 +09004316 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4317
4318 // Register input tensor to the layer.
4319 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4320 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4321
4322 // Register output tensor to the layer.
4323 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4324 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4325}
4326
Kevin May7d96b162021-02-03 17:38:41 +00004327void TfLiteParserImpl::ParseGather(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan26868492021-01-22 14:25:31 +00004328{
4329 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4330
Kevin May7d96b162021-02-03 17:38:41 +00004331 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00004332 CHECK_VALID_SIZE(inputs.size(), 2);
Kevin May7d96b162021-02-03 17:38:41 +00004333 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00004334 CHECK_VALID_SIZE(outputs.size(), 1);
4335
Mike Kelly377fb212023-01-10 15:55:28 +00004336 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4337 armnn::TensorInfo indicesTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
4338 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
Sadik Armagan26868492021-01-22 14:25:31 +00004339
4340 armnn::GatherDescriptor gatherDescriptor;
4341
Mike Kelly0d77ae12022-01-07 17:42:27 +00004342 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4343 const auto* options = operatorPtr->builtin_options.AsGatherOptions();
Sadik Armagan26868492021-01-22 14:25:31 +00004344 auto axis = options->axis;
4345
Mike Kelly377fb212023-01-10 15:55:28 +00004346 auto layerName = fmt::format("Gather:{}:{}", subgraphIndex, operatorIndex);
4347
Sadik Armagan26868492021-01-22 14:25:31 +00004348 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
4349 auto indicesDimensions = indicesTensorInfo.GetNumDimensions();
4350 auto outputDimensions = outputTensorInfo.GetNumDimensions();
4351 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
4352 {
4353 throw ParseException(
4354 fmt::format("Operation has invalid axis: {} It is out of bounds [ -{}, {} ) {}",
4355 axis,
4356 inputDimensions, inputDimensions,
4357 CHECK_LOCATION().AsString()));
4358 }
4359 if (outputDimensions != static_cast<unsigned int>(inputDimensions) + indicesDimensions - 1)
4360 {
4361 throw ParseException(
4362 fmt::format("Operation has invalid output dimensions: {} Output must be an ({} + {} - 1) -D tensor {}",
4363 outputDimensions,
4364 inputDimensions, indicesDimensions,
4365 CHECK_LOCATION().AsString()));
4366 }
4367
4368 gatherDescriptor.m_Axis = axis;
4369
Sadik Armagan26868492021-01-22 14:25:31 +00004370 IConnectableLayer* layer = m_Network->AddGatherLayer(gatherDescriptor, layerName.c_str());
4371 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00004372 outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Sadik Armagan26868492021-01-22 14:25:31 +00004373 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4374
4375 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4376 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4377
4378 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4379 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4380}
4381
Teresa Charlin91a53ea2022-04-25 15:47:29 +01004382void TfLiteParserImpl::ParseGatherNd(size_t subgraphIndex, size_t operatorIndex)
4383{
4384 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4385
4386 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4387 CHECK_VALID_SIZE(inputs.size(), 2);
4388 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4389 CHECK_VALID_SIZE(outputs.size(), 1);
4390
Mike Kelly377fb212023-01-10 15:55:28 +00004391 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4392 armnn::TensorInfo indicesTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Teresa Charlin91a53ea2022-04-25 15:47:29 +01004393
4394 auto layerName = fmt::format("GatherNd:{}:{}", subgraphIndex, operatorIndex);
4395 IConnectableLayer* layer = m_Network->AddGatherNdLayer(layerName.c_str());
4396 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00004397 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Teresa Charlin91a53ea2022-04-25 15:47:29 +01004398 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4399
4400 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4401 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4402
4403 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4404 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4405}
4406
Kevin May7d96b162021-02-03 17:38:41 +00004407void TfLiteParserImpl::ParseDepthToSpace(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan26868492021-01-22 14:25:31 +00004408{
4409 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4410
Kevin May7d96b162021-02-03 17:38:41 +00004411 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00004412 CHECK_VALID_SIZE(inputs.size(), 1);
Kevin May7d96b162021-02-03 17:38:41 +00004413 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00004414 CHECK_VALID_SIZE(outputs.size(), 1);
4415
4416 armnn::DepthToSpaceDescriptor descriptor;
4417
Mike Kelly0d77ae12022-01-07 17:42:27 +00004418 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4419 const auto* options = operatorPtr->builtin_options.AsDepthToSpaceOptions();
Sadik Armagan26868492021-01-22 14:25:31 +00004420 auto blockSize = options->block_size;
4421 if (blockSize < 2)
4422 {
4423 throw ParseException(
4424 fmt::format("Operation has invalid block size: {} Block size should be >= 2 {}",
4425 blockSize,
4426 CHECK_LOCATION().AsString()));
4427 }
4428 descriptor.m_BlockSize = armnn::numeric_cast<uint32_t>(blockSize);
4429
4430 auto layerName = fmt::format("DepthToSpace:{}:{}", subgraphIndex, operatorIndex);
4431 IConnectableLayer* layer = m_Network->AddDepthToSpaceLayer(descriptor, layerName.c_str());
4432 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00004433 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Sadik Armagan26868492021-01-22 14:25:31 +00004434 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4435
4436 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4437 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4438
4439 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4440 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4441}
4442
Kevin May7d96b162021-02-03 17:38:41 +00004443void TfLiteParserImpl::ParseSum(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004444{
Sadik Armagana2747482021-02-09 10:28:54 +00004445 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Sum);
4446}
4447
Teresa Charlin4e3e8312021-08-05 12:34:37 +01004448void TfLiteParserImpl::ParseReduceProd(size_t subgraphIndex, size_t operatorIndex)
4449{
4450 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Prod);
4451}
4452
Sadik Armagana2747482021-02-09 10:28:54 +00004453void TfLiteParserImpl::ParseReduceMax(size_t subgraphIndex, size_t operatorIndex)
4454{
4455 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Max);
4456}
4457
4458void TfLiteParserImpl::ParseReduceMin(size_t subgraphIndex, size_t operatorIndex)
4459{
4460 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Min);
4461}
4462
4463void TfLiteParserImpl::ParseReduce(size_t subgraphIndex, size_t operatorIndex, ReduceOperation reduceOperation)
4464{
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004465 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4466
Mike Kelly0d77ae12022-01-07 17:42:27 +00004467 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4468 const auto* options = operatorPtr->builtin_options.AsReducerOptions();
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004469
4470 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4471 CHECK_VALID_SIZE(inputs.size(), 2);
4472
4473 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4474 CHECK_VALID_SIZE(outputs.size(), 1);
4475
Sadik Armagana2747482021-02-09 10:28:54 +00004476 auto layerName = fmt::format("Reduce:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004477
Mike Kelly377fb212023-01-10 15:55:28 +00004478 armnn::TensorInfo inputTensorInfo0 = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4479 armnn::TensorInfo inputTensorInfo1 = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004480
4481 ReduceDescriptor desc;
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004482 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
4483 // Get const axis value from model and set it to descriptor.
4484 if (axisBufferPtr != nullptr)
4485 {
Sadik Armagan49bdb792021-02-11 13:57:07 +00004486 std::vector<int32_t> axisData(inputTensorInfo1.GetNumElements());
4487 ::memcpy(axisData.data(), axisBufferPtr->data.data(), inputTensorInfo1.GetNumBytes());
4488
4489 // Convert the axis to unsigned int and remove duplicates.
4490 auto rank = static_cast<int32_t>(inputTensorInfo0.GetNumDimensions());
4491 std::set<unsigned int> uniqueAxis;
4492 std::transform(axisData.begin(),
4493 axisData.end(),
4494 std::inserter(uniqueAxis, uniqueAxis.begin()),
4495 [rank](int i)->unsigned int{
4496 return static_cast<uint32_t>(((i + rank) % rank)); });
4497 desc.m_vAxis.assign(uniqueAxis.begin(), uniqueAxis.end());
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004498 }
Sadik Armagana2747482021-02-09 10:28:54 +00004499 else
4500 {
4501 for (uint32_t i = 0; i < inputTensorInfo0.GetNumDimensions(); ++i)
4502 {
4503 desc.m_vAxis.push_back(i);
4504 }
4505 }
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004506
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004507 desc.m_KeepDims = options->keep_dims;
Sadik Armagana2747482021-02-09 10:28:54 +00004508 desc.m_ReduceOperation = reduceOperation;
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004509
4510 // Register a new layer object, Sum.
Mike Kelly0d77ae12022-01-07 17:42:27 +00004511 IConnectableLayer* layer = m_Network->AddReduceLayer(desc, layerName.c_str());
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004512
Mike Kelly377fb212023-01-10 15:55:28 +00004513 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004514 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4515
4516 // Register input tensor to the layer.
4517 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4518 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4519
4520 // Register output tensor to the layer.
4521 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4522 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4523}
4524
Mike Kelly31dce2b2021-09-01 21:22:37 +01004525void TfLiteParserImpl::ParseLocalResponseNormalization(size_t subgraphIndex, size_t operatorIndex)
4526{
4527 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4528
4529 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4530 CHECK_VALID_SIZE(inputs.size(), 1);
4531
4532 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4533 CHECK_VALID_SIZE(outputs.size(), 1);
4534
4535 auto layerName = fmt::format("LRN:{}:{}", subgraphIndex, operatorIndex);
4536 std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4537
Mike Kelly377fb212023-01-10 15:55:28 +00004538 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Mike Kelly31dce2b2021-09-01 21:22:37 +01004539
4540 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4541 const auto* options = operatorPtr->builtin_options.AsLocalResponseNormalizationOptions();
4542
4543 armnn::NormalizationDescriptor descriptor;
4544 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
4545 descriptor.m_NormChannelType = armnn::NormalizationAlgorithmChannel::Across;
4546 descriptor.m_NormMethodType = armnn::NormalizationAlgorithmMethod::LocalBrightness;
4547 descriptor.m_NormSize = static_cast<uint32_t>(options->radius);
4548 descriptor.m_K = options->bias;
4549 descriptor.m_Alpha = options->alpha;
4550 descriptor.m_Beta = options->beta;
4551
4552 // ArmNN expects normSize to be the full size of the normalization
4553 // window rather than the radius as in TfLite.
4554 descriptor.m_NormSize = 1 + (2 * descriptor.m_NormSize);
4555
4556 IConnectableLayer* layer = m_Network->AddNormalizationLayer(descriptor, layerNameFormatted.c_str());
4557 ARMNN_ASSERT(layer != nullptr);
4558
Mike Kelly377fb212023-01-10 15:55:28 +00004559 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Mike Kelly31dce2b2021-09-01 21:22:37 +01004560 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4561
4562 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4563 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4564
4565 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4566 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4567}
4568
Teresa Charlin28aa6692022-07-12 11:18:44 +01004569void TfLiteParserImpl::ParseAbs(size_t subgraphIndex, size_t operatorIndex)
4570{
4571 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Abs);
4572}
4573
Teresa Charlin93f0ad02023-03-23 15:28:02 +00004574void TfLiteParserImpl::ParseCeil(size_t subgraphIndex, size_t operatorIndex)
4575{
4576 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Ceil);
4577}
4578
Teresa Charlin28aa6692022-07-12 11:18:44 +01004579void TfLiteParserImpl::ParseExp(size_t subgraphIndex, size_t operatorIndex)
4580{
4581 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Exp);
4582}
4583
4584void TfLiteParserImpl::ParseLog(size_t subgraphIndex, size_t operatorIndex)
4585{
4586 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Log);
4587}
4588
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004589void TfLiteParserImpl::ParseLogicalNot(size_t subgraphIndex, size_t operatorIndex)
4590{
4591 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::LogicalNot);
4592}
4593
4594void TfLiteParserImpl::ParseNeg(size_t subgraphIndex, size_t operatorIndex)
4595{
4596 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Neg);
4597}
4598
John Mcloughlin0ec00872023-05-15 17:03:49 +01004599void TfLiteParserImpl::ParsePower(size_t subgraphIndex, size_t operatorIndex)
4600{
4601 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4602
4603 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4604 CHECK_VALID_SIZE(inputs.size(), 2);
4605
4606 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4607 CHECK_VALID_SIZE(outputs.size(), 1);
4608
4609 auto layerName = fmt::format("Power:{}:{}", subgraphIndex, operatorIndex);
4610
4611 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4612 TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
4613 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
4614
4615 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::Power, layerName.c_str());
4616 ARMNN_ASSERT(layer != nullptr);
4617
4618 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
4619 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
4620 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4621
4622 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4623 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4624
4625 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4626 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4627}
4628
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004629void TfLiteParserImpl::ParseRsqrt(size_t subgraphIndex, size_t operatorIndex)
4630{
4631 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Rsqrt);
4632}
4633
Teresa Charlin28aa6692022-07-12 11:18:44 +01004634void TfLiteParserImpl::ParseSin(size_t subgraphIndex, size_t operatorIndex)
4635{
4636 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Sin);
4637}
4638
Teresa Charlinf0fce5b2022-05-04 17:24:43 +01004639void TfLiteParserImpl::ParseSqrt(size_t subgraphIndex, size_t operatorIndex)
4640{
4641 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Sqrt);
4642}
4643
John Mcloughlin0ec00872023-05-15 17:03:49 +01004644void TfLiteParserImpl::ParseSquaredDifference(size_t subgraphIndex, size_t operatorIndex)
4645{
4646 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4647
4648 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4649 CHECK_VALID_SIZE(inputs.size(), 2);
4650
4651 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4652 CHECK_VALID_SIZE(outputs.size(), 1);
4653
4654 auto layerName = fmt::format("SquaredDifference:{}:{}", subgraphIndex, operatorIndex);
4655
4656 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4657 TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
4658 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
4659
4660 IConnectableLayer* layer = m_Network->AddElementwiseBinaryLayer(BinaryOperation::SqDiff, layerName.c_str());
4661 ARMNN_ASSERT(layer != nullptr);
4662
4663 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
4664 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
4665 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4666
4667 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4668 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4669
4670 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4671 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4672}
4673
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004674void TfLiteParserImpl::ParseElementwiseUnary(size_t subgraphIndex, size_t operatorIndex, UnaryOperation unaryOperation)
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 std::string layerName = std::string(GetUnaryOperationAsCString(unaryOperation)) + ":{}:{}";
4685 std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4686
4687 ElementwiseUnaryDescriptor desc;
4688 desc.m_Operation = unaryOperation;
4689 IConnectableLayer* layer = m_Network->AddElementwiseUnaryLayer(desc, layerNameFormatted.c_str());
4690 ARMNN_ASSERT(layer != nullptr);
4691
Mike Kelly377fb212023-01-10 15:55:28 +00004692 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004693 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4694
4695 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4696 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4697
4698 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4699 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4700}
4701
Bruno Goncalves2d0eb862021-07-11 14:10:15 -03004702void TfLiteParserImpl::ParseEqual(size_t subgraphIndex, size_t operatorIndex)
4703{
4704 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::Equal);
4705}
4706
4707void TfLiteParserImpl::ParseNotEqual(size_t subgraphIndex, size_t operatorIndex)
4708{
4709 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::NotEqual);
4710}
4711
4712void TfLiteParserImpl::ParseGreater(size_t subgraphIndex, size_t operatorIndex)
4713{
4714 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::Greater);
4715}
4716
4717void TfLiteParserImpl::ParseGreaterOrEqual(size_t subgraphIndex, size_t operatorIndex)
4718{
4719 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::GreaterOrEqual);
4720}
4721
4722void TfLiteParserImpl::ParseLess(size_t subgraphIndex, size_t operatorIndex)
4723{
4724 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::Less);
4725}
4726
4727void TfLiteParserImpl::ParseLessOrEqual(size_t subgraphIndex, size_t operatorIndex)
4728{
4729 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::LessOrEqual);
4730}
4731
4732void TfLiteParserImpl::ParseComparison(size_t subgraphIndex, size_t operatorIndex,
4733 ComparisonOperation comparisonOperation)
4734{
4735 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4736
4737 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4738 CHECK_VALID_SIZE(inputs.size(), 2);
4739
4740 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4741 CHECK_VALID_SIZE(outputs.size(), 1);
4742
4743 auto layerName = std::string(GetComparisonOperationAsCString(comparisonOperation)) + ":{}:{}";
4744 std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4745
Mike Kelly377fb212023-01-10 15:55:28 +00004746 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4747 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves2d0eb862021-07-11 14:10:15 -03004748 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerNameFormatted, "Input 0", "Input 1");
4749
4750 ComparisonDescriptor desc;
4751 desc.m_Operation = comparisonOperation;
4752 IConnectableLayer* layer = m_Network->AddComparisonLayer(desc, layerNameFormatted.c_str());
4753 ARMNN_ASSERT(layer != nullptr);
4754
Mike Kelly377fb212023-01-10 15:55:28 +00004755 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Bruno Goncalves2d0eb862021-07-11 14:10:15 -03004756 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4757
4758 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4759 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4760
4761 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4762 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4763}
4764
Mike Kelly04d82292023-01-19 18:29:40 +00004765armnn::IConnectableLayer* TfLiteParserImpl::AddReshapeLayer(armnn::IConnectableLayer* layer,
4766 unsigned int outputSlot,
4767 std::string reshapeLayerName,
4768 armnn::TensorInfo outputShape)
4769{
4770 ReshapeDescriptor desc;
4771 desc.m_TargetShape = outputShape.GetShape();
4772
4773 IConnectableLayer* reshapeLayer =
4774 m_Network->AddReshapeLayer(desc, reshapeLayerName.c_str());
4775
4776 auto & prevOutputSlot = layer->GetOutputSlot(outputSlot);
4777 prevOutputSlot.Connect(reshapeLayer->GetInputSlot(0));
4778 reshapeLayer->GetOutputSlot(0).SetTensorInfo(outputShape);
4779 return reshapeLayer;
4780}
4781
Kevin May7d96b162021-02-03 17:38:41 +00004782armnn::IConnectableLayer* TfLiteParserImpl::AddFusedActivationLayer(armnn::IConnectableLayer* prevLayer,
4783 unsigned int outputSlot,
4784 tflite::ActivationFunctionType activationType)
telsoa01c577f2c2018-08-31 09:22:23 +01004785{
4786 ActivationDescriptor activationDesc;
4787 std::string layerName = prevLayer->GetName();
4788
4789 switch(activationType)
4790 {
4791 case tflite::ActivationFunctionType_NONE:
4792 {
4793 // this is a no-op: return previous layer
4794 return prevLayer;
4795 }
4796 case tflite::ActivationFunctionType_RELU:
4797 {
4798 activationDesc.m_Function = ActivationFunction::ReLu;
4799 layerName += ":RELU";
4800 break;
4801 }
4802 case tflite::ActivationFunctionType_RELU6:
4803 {
4804 activationDesc.m_Function = ActivationFunction::BoundedReLu;
4805 activationDesc.m_A = 6.0f;
4806 activationDesc.m_B = 0.0f;
4807 layerName += ":RELU6";
4808 break;
4809 }
4810 case tflite::ActivationFunctionType_TANH:
4811 {
4812 activationDesc.m_Function = ActivationFunction::TanH;
4813 activationDesc.m_A = 1.0f;
4814 activationDesc.m_B = 1.0f;
4815 layerName += ":TANH";
4816 break;
4817 }
4818
4819 // I only put these here as a reminder what others we could support
4820 case tflite::ActivationFunctionType_RELU_N1_TO_1:
4821 case tflite::ActivationFunctionType_SIGN_BIT:
4822 default:
4823 {
4824 throw ParseException(
Mike Kelly377fb212023-01-10 15:55:28 +00004825 fmt::format("TfLite parser doesn't support fused activation: "
James Ward58dec6b2020-09-11 17:32:44 +01004826 "{}/{} {} ",
4827 activationType,
4828 tflite::EnumNameActivationFunctionType(activationType),
4829 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01004830
4831 }
4832 }
4833
4834 IConnectableLayer* activationLayer =
4835 m_Network->AddActivationLayer(activationDesc, layerName.c_str());
4836
4837 auto & prevOutputSlot = prevLayer->GetOutputSlot(outputSlot);
4838 prevOutputSlot.Connect(activationLayer->GetInputSlot(0));
4839 activationLayer->GetOutputSlot(0).SetTensorInfo(prevOutputSlot.GetTensorInfo());
4840 return activationLayer;
4841}
4842
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004843armnn::IConnectableLayer* TfLiteParserImpl::AddFusedFloorLayer(armnn::IConnectableLayer* prevLayer,
4844 unsigned int outputSlot)
4845{
Teresa Charlin725728e2022-05-05 13:33:33 +01004846
4847 auto& prevOutputSlot = prevLayer->GetOutputSlot(outputSlot);
4848 DataType dataType = prevOutputSlot.GetTensorInfo().GetDataType();
4849
4850 if (dataType == DataType::Signed32)
4851 {
4852 return prevLayer;
4853 }
4854
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004855 std::string layerName = prevLayer->GetName();
4856 IConnectableLayer* floorLayer = m_Network->AddFloorLayer(layerName.c_str());
4857
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004858 prevOutputSlot.Connect(floorLayer->GetInputSlot(0));
4859 floorLayer->GetOutputSlot(0).SetTensorInfo(prevOutputSlot.GetTensorInfo());
Teresa Charlin725728e2022-05-05 13:33:33 +01004860
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004861 return floorLayer;
4862}
4863
Mike Kelly0d77ae12022-01-07 17:42:27 +00004864TfLiteParserImpl::ModelPtr TfLiteParserImpl::LoadModelFromFile(const char* fileName)
telsoa01c577f2c2018-08-31 09:22:23 +01004865{
4866 if (fileName == nullptr)
4867 {
James Ward58dec6b2020-09-11 17:32:44 +01004868 throw InvalidArgumentException(fmt::format("Invalid (null) file name {}",
telsoa01c577f2c2018-08-31 09:22:23 +01004869 CHECK_LOCATION().AsString()));
4870 }
Francis Murtagh532a29d2020-06-29 11:50:01 +01004871 std::error_code errorCode;
4872 fs::path pathToFile(fileName);
4873 if (!fs::exists(pathToFile, errorCode))
telsoa01c577f2c2018-08-31 09:22:23 +01004874 {
James Ward58dec6b2020-09-11 17:32:44 +01004875 //fmt::format() could not be used here (format error)
4876 std::stringstream msg;
4877 msg << "Cannot find the file (" << fileName << ") errorCode: " << errorCode
4878 << " " << CHECK_LOCATION().AsString();
James Ward58dec6b2020-09-11 17:32:44 +01004879 throw FileNotFoundException(msg.str());
telsoa01c577f2c2018-08-31 09:22:23 +01004880 }
Colm Donelan0dfb2652023-06-22 10:19:17 +01004881 if (!fs::is_regular_file(pathToFile))
4882 {
4883 // Exclude non regular files.
4884 throw InvalidArgumentException(fmt::format("File \"{}\" is not a regular file and cannot be loaded.",
4885 pathToFile.c_str()));
4886 }
4887
telsoa01c577f2c2018-08-31 09:22:23 +01004888 std::ifstream file(fileName, std::ios::binary);
4889 std::string fileContent((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
4890 return LoadModelFromBinary(reinterpret_cast<const uint8_t *>(fileContent.c_str()),
4891 fileContent.size());
4892}
4893
Mike Kelly0d77ae12022-01-07 17:42:27 +00004894TfLiteParserImpl::ModelPtr TfLiteParserImpl::LoadModelFromBinary(const uint8_t* binaryContent, size_t len)
telsoa01c577f2c2018-08-31 09:22:23 +01004895{
4896 if (binaryContent == nullptr)
4897 {
James Ward58dec6b2020-09-11 17:32:44 +01004898 throw InvalidArgumentException(fmt::format("Invalid (null) binary content {}",
telsoa01c577f2c2018-08-31 09:22:23 +01004899 CHECK_LOCATION().AsString()));
4900 }
4901 flatbuffers::Verifier verifier(binaryContent, len);
4902 if (verifier.VerifyBuffer<tflite::Model>() == false)
4903 {
4904 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01004905 fmt::format("Buffer doesn't conform to the expected Tensorflow Lite "
4906 "flatbuffers format. size:{} {}",
4907 len,
4908 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01004909 }
4910 return tflite::UnPackModel(binaryContent);
4911}
4912
Mike Kelly0d77ae12022-01-07 17:42:27 +00004913TfLiteParserImpl::TensorRawPtrVector TfLiteParserImpl::GetInputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00004914 size_t subgraphIndex,
4915 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004916{
4917 CHECK_MODEL(model, subgraphIndex, operatorIndex);
4918
Mike Kelly0d77ae12022-01-07 17:42:27 +00004919 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
4920 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01004921
4922 size_t inputCount = operatorPtr->inputs.size();
mathad01c21025d2021-04-26 10:09:37 +01004923 TensorRawPtrVector result;
Mike Kelly0d77ae12022-01-07 17:42:27 +00004924 for (size_t i = 0; i < inputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01004925 {
mathad01c21025d2021-04-26 10:09:37 +01004926 // If the input location is -1 then assume input is turned off.
4927 if (operatorPtr->inputs[i] == -1)
4928 {
4929 continue;
4930 }
4931 else
4932 {
4933 uint32_t inputId = CHECKED_NON_NEGATIVE(operatorPtr->inputs[i]);
4934 result.push_back(subgraphPtr->tensors[inputId].get());
4935 }
telsoa01c577f2c2018-08-31 09:22:23 +01004936 }
4937 return result;
4938}
4939
Mike Kelly0d77ae12022-01-07 17:42:27 +00004940TfLiteParserImpl::TensorRawPtrVector TfLiteParserImpl::GetOutputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00004941 size_t subgraphIndex,
4942 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004943{
4944 CHECK_MODEL(model, subgraphIndex, operatorIndex);
4945
Mike Kelly0d77ae12022-01-07 17:42:27 +00004946 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
4947 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01004948
4949 size_t outputCount = operatorPtr->outputs.size();
4950 TensorRawPtrVector result(outputCount);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004951 for (size_t i = 0; i < outputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01004952 {
4953 uint32_t outputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[i]);
4954 CHECK_TENSOR(model, subgraphIndex, outputId);
Derek Lambertiff05cc52019-04-26 13:05:17 +01004955 result[i] = subgraphPtr->tensors[outputId].get();
telsoa01c577f2c2018-08-31 09:22:23 +01004956 }
4957 return result;
4958}
4959
Mike Kelly0d77ae12022-01-07 17:42:27 +00004960TfLiteParserImpl::TensorIdRawPtrVector TfLiteParserImpl::GetSubgraphInputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00004961 size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004962{
4963 CHECK_SUBGRAPH(model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004964 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01004965
Derek Lambertiff05cc52019-04-26 13:05:17 +01004966 size_t inputCount = subgraphPtr->inputs.size();
telsoa01c577f2c2018-08-31 09:22:23 +01004967 TensorIdRawPtrVector result(inputCount);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004968 for (size_t i = 0; i < inputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01004969 {
Derek Lambertiff05cc52019-04-26 13:05:17 +01004970 uint32_t inputId = CHECKED_NON_NEGATIVE(subgraphPtr->inputs[i]);
telsoa01c577f2c2018-08-31 09:22:23 +01004971 CHECK_TENSOR(model, subgraphIndex, inputId);
Derek Lambertiff05cc52019-04-26 13:05:17 +01004972 result[i] = std::make_pair(inputId, subgraphPtr->tensors[inputId].get());
telsoa01c577f2c2018-08-31 09:22:23 +01004973 }
4974 return result;
4975}
4976
Mike Kelly0d77ae12022-01-07 17:42:27 +00004977TfLiteParserImpl::TensorIdRawPtrVector TfLiteParserImpl::GetSubgraphOutputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00004978 size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004979{
4980 CHECK_SUBGRAPH(model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004981 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01004982
Derek Lambertiff05cc52019-04-26 13:05:17 +01004983 size_t outputCount = subgraphPtr->outputs.size();
telsoa01c577f2c2018-08-31 09:22:23 +01004984 TensorIdRawPtrVector result(outputCount);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004985 for (size_t i = 0; i < outputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01004986 {
Derek Lambertiff05cc52019-04-26 13:05:17 +01004987 uint32_t outputId = CHECKED_NON_NEGATIVE(subgraphPtr->outputs[i]);
4988 result[i] = std::make_pair(outputId, subgraphPtr->tensors[outputId].get());
telsoa01c577f2c2018-08-31 09:22:23 +01004989 }
4990 return result;
4991}
4992
Kevin May7d96b162021-02-03 17:38:41 +00004993std::vector<int32_t>& TfLiteParserImpl::GetInputTensorIds(const ModelPtr& model,
4994 size_t subgraphIndex,
4995 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004996{
4997 CHECK_MODEL(model, subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004998 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
4999 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01005000 return operatorPtr->inputs;
5001}
5002
Kevin May7d96b162021-02-03 17:38:41 +00005003std::vector<int32_t>& TfLiteParserImpl::GetOutputTensorIds(const ModelPtr& model,
5004 size_t subgraphIndex,
5005 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005006{
5007 CHECK_MODEL(model, subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005008 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
5009 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01005010 return operatorPtr->outputs;
5011}
5012
Kevin May7d96b162021-02-03 17:38:41 +00005013void TfLiteParserImpl::RegisterInputSlots(size_t subgraphIndex,
5014 size_t operatorIndex,
5015 IConnectableLayer* layer,
Finn Williamsd4fa5452021-03-01 12:31:41 +00005016 const std::vector<unsigned int>& tensorIndexes,
5017 unsigned int startingSlotIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005018{
5019 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01005020 ARMNN_ASSERT(layer != nullptr);
Matthew Sloyan81beae32021-07-13 19:46:11 +01005021
Finn Williamsd4fa5452021-03-01 12:31:41 +00005022 if (tensorIndexes.size() + startingSlotIndex != layer->GetNumInputSlots())
telsoa01c577f2c2018-08-31 09:22:23 +01005023 {
5024 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01005025 fmt::format("The number of tensor inputs ({}) does not match the number expected ({})"
5026 " for subgraph:{} operator index:{} {}",
5027 tensorIndexes.size(),
5028 layer->GetNumInputSlots(),
5029 subgraphIndex,
5030 operatorIndex,
5031 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01005032 }
5033
Finn Williamsd4fa5452021-03-01 12:31:41 +00005034 for (unsigned int index = 0; index < tensorIndexes.size() ; ++index)
telsoa01c577f2c2018-08-31 09:22:23 +01005035 {
Finn Williamsd4fa5452021-03-01 12:31:41 +00005036 unsigned int tensorIndex = tensorIndexes[index];
5037 armnn::IInputSlot* slot = &(layer->GetInputSlot(startingSlotIndex + index));
telsoa01c577f2c2018-08-31 09:22:23 +01005038 RegisterConsumerOfTensor(subgraphIndex, tensorIndex, slot);
5039 }
5040}
5041
Kevin May7d96b162021-02-03 17:38:41 +00005042void TfLiteParserImpl::RegisterOutputSlots(size_t subgraphIndex,
5043 size_t operatorIndex,
5044 IConnectableLayer* layer,
5045 const std::vector<unsigned int>& tensorIndexes)
telsoa01c577f2c2018-08-31 09:22:23 +01005046{
5047 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01005048 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01005049 if (tensorIndexes.size() != layer->GetNumOutputSlots())
5050 {
5051 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01005052 fmt::format("The number of tensor outputs ({}) does not match the number expected ({})"
5053 " for subgraph:{} operator index:{} {}",
5054 tensorIndexes.size(),
5055 layer->GetNumOutputSlots(),
5056 subgraphIndex,
5057 operatorIndex,
5058 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01005059 }
5060
5061 for (unsigned int slotIndex = 0; slotIndex < layer->GetNumOutputSlots(); ++slotIndex)
5062 {
5063 unsigned int tensorIndex = tensorIndexes[slotIndex];
5064 armnn::IOutputSlot* slot = &(layer->GetOutputSlot(slotIndex));
5065 RegisterProducerOfTensor(subgraphIndex, tensorIndex, slot);
5066 }
5067}
5068
Mike Kelly377fb212023-01-10 15:55:28 +00005069void TfLiteParserImpl::SetupInputLayerTensorInfos(size_t subgraphIndex)
5070{
5071 CHECK_SUBGRAPH(m_Model, subgraphIndex);
5072
5073 auto inputs = GetSubgraphInputs(m_Model, subgraphIndex);
5074 for (auto const& tensorIdAndPtr : inputs)
5075 {
5076 auto tensorInfo = ToTensorInfo(tensorIdAndPtr.second);
5077 m_TensorInfos.insert({tensorIdAndPtr.first, tensorInfo});
5078 }
5079}
5080
Kevin May7d96b162021-02-03 17:38:41 +00005081void TfLiteParserImpl::SetupInputLayers(size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005082{
5083 CHECK_SUBGRAPH(m_Model, subgraphIndex);
5084
5085 auto inputs = GetSubgraphInputs(m_Model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005086 for (auto const& tensorIdAndPtr : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005087 {
5088 auto bindingId = GenerateLayerBindingId(subgraphIndex, tensorIdAndPtr.first);
5089 IConnectableLayer* layer =
5090 m_Network->AddInputLayer(bindingId, tensorIdAndPtr.second->name.c_str());
5091
5092 auto tensorInfo = ToTensorInfo(tensorIdAndPtr.second);
5093 layer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
5094
5095 RegisterOutputSlots(subgraphIndex,
5096 VIRTUAL_OPERATOR_ID,
5097 layer,
5098 { static_cast<uint32_t>(tensorIdAndPtr.first) });
5099 }
5100}
5101
Kevin May7d96b162021-02-03 17:38:41 +00005102void TfLiteParserImpl::SetupOutputLayers(size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005103{
5104 CHECK_SUBGRAPH(m_Model, subgraphIndex);
5105
5106 auto outputs = GetSubgraphOutputs(m_Model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005107 for (auto const& tensorIdAndPtr : outputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005108 {
5109 auto bindingId = GenerateLayerBindingId(subgraphIndex, tensorIdAndPtr.first);
5110 IConnectableLayer* layer =
5111 m_Network->AddOutputLayer(bindingId, tensorIdAndPtr.second->name.c_str());
5112
5113 RegisterInputSlots(subgraphIndex,
5114 VIRTUAL_OPERATOR_ID,
5115 layer,
5116 { static_cast<uint32_t>(tensorIdAndPtr.first) });
5117 }
5118}
5119
Mike Kelly377fb212023-01-10 15:55:28 +00005120void TfLiteParserImpl::SetupConstantLayerTensorInfos(size_t subgraph)
5121{
5122 CHECK_SUBGRAPH(m_Model, subgraph);
5123
5124 const auto & subgraphPtr = m_Model->subgraphs[subgraph];
5125 for (unsigned int subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex)
5126 {
5127 for (unsigned int tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex)
5128 {
5129 if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot == nullptr &&
5130 m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size() > 0)
5131 {
5132 TensorRawPtr tensorPtr = subgraphPtr->tensors[tensorIndex].get();
5133
5134 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
5135
5136 m_TensorInfos.insert({tensorIndex, tensorInfo});
5137 }
5138 }
5139 }
5140}
5141
Mike Kelly5880b912022-01-28 16:18:54 +00005142void TfLiteParserImpl::SetupConstantLayers(size_t subgraph)
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005143{
Mike Kelly5880b912022-01-28 16:18:54 +00005144 CHECK_SUBGRAPH(m_Model, subgraph);
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005145
Mike Kelly5880b912022-01-28 16:18:54 +00005146 const auto & subgraphPtr = m_Model->subgraphs[subgraph];
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005147 for (unsigned int subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex)
5148 {
5149 for (unsigned int tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex)
5150 {
5151 if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot == nullptr &&
5152 m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size() > 0)
5153 {
Derek Lambertiff05cc52019-04-26 13:05:17 +01005154 TensorRawPtr tensorPtr = subgraphPtr->tensors[tensorIndex].get();
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005155
Mike Kelly5880b912022-01-28 16:18:54 +00005156 if (IsConstTensor(tensorPtr))
Matthew Sloyan81beae32021-07-13 19:46:11 +01005157 {
5158 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
Mike Kelly5880b912022-01-28 16:18:54 +00005159 armnn::DataType dataType = tensorInfo.GetDataType();
5160
5161 if (std::find(m_ConstantsToDequantize.begin(), m_ConstantsToDequantize.end(), tensorPtr->buffer)
5162 != m_ConstantsToDequantize.end())
5163 {
5164 dataType = DataType::Float32;
5165 }
5166 auto tensorAndData = CreateConstTensorNonPermuted(tensorPtr, tensorInfo, dataType);
5167
5168 std::string layerName = fmt::format("Constant:{}", tensorPtr->name);
5169 IConnectableLayer *layer = m_Network->AddConstantLayer(tensorAndData.first, layerName.c_str());
5170
5171 layer->GetOutputSlot(0).SetTensorInfo(tensorAndData.first.GetInfo());
5172 RegisterOutputSlots(subgraphIndex,
5173 VIRTUAL_OPERATOR_ID,
5174 layer,
5175 { tensorIndex });
5176 }
5177 else if (ShouldConstantTensorBeCreated(tensorIndex))
5178 {
5179 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
5180 armnn::DataType dataType = tensorInfo.GetDataType();
5181
5182 if (std::find(m_ConstantsToDequantize.begin(), m_ConstantsToDequantize.end(), tensorPtr->buffer)
5183 != m_ConstantsToDequantize.end())
5184 {
5185 dataType = DataType::Float32;
5186 }
5187 // Make sure isConstant flag is set.
5188 tensorInfo.SetConstant();
5189 tensorInfo.SetDataType(dataType);
5190
5191 auto tensorAndData = ConstTensor(tensorInfo, std::vector<uint8_t>(tensorInfo.GetNumBytes()));
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005192
Matthew Sloyan81beae32021-07-13 19:46:11 +01005193 std::string layerName = fmt::format("Constant:{}", tensorPtr->name);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005194 IConnectableLayer* layer = m_Network->AddConstantLayer(tensorAndData, layerName.c_str());
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005195
Matthew Sloyan81beae32021-07-13 19:46:11 +01005196 layer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
5197 RegisterOutputSlots(subgraphIndex,
5198 VIRTUAL_OPERATOR_ID,
5199 layer,
Mike Kelly5880b912022-01-28 16:18:54 +00005200 {tensorIndex});
Matthew Sloyan81beae32021-07-13 19:46:11 +01005201 }
5202 else
5203 {
5204 throw ParseException(
5205 fmt::format("Invalid Tensor: Tensor should be constant. {}",
5206 CHECK_LOCATION().AsString()));
5207 }
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02005208 }
5209 }
5210 }
5211}
5212
telsoa01c577f2c2018-08-31 09:22:23 +01005213// example usage: BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[0]->buffer);
Kevin May7d96b162021-02-03 17:38:41 +00005214TfLiteParserImpl::BufferRawPtr TfLiteParserImpl::GetBuffer(const ModelPtr& model, size_t bufferIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01005215{
5216 CHECK_BUFFER(model, bufferIndex);
5217 return model->buffers[bufferIndex].get();
5218}
5219
Matteo Martincigh747ef822018-12-18 09:26:39 +00005220template<typename T>
Kevin May7d96b162021-02-03 17:38:41 +00005221std::pair<armnn::ConstTensor, TfLiteParserImpl::SupportedDataStorage>
5222TfLiteParserImpl::CreateConstTensorAndStoreData(TfLiteParserImpl::BufferRawPtr bufferPtr,
5223 TfLiteParserImpl::TensorRawPtr tensorPtr,
Matteo Martincigh747ef822018-12-18 09:26:39 +00005224 armnn::TensorInfo& tensorInfo,
5225 armnn::Optional<armnn::PermutationVector&> permutationVector)
5226{
Matthew Sloyan81beae32021-07-13 19:46:11 +01005227 // Make sure isConstant flag is set.
5228 tensorInfo.SetConstant();
5229
Matteo Martincigh747ef822018-12-18 09:26:39 +00005230 auto constData = CreateConstTensorImpl<T>(bufferPtr,
5231 tensorPtr,
5232 tensorInfo,
5233 permutationVector);
Kevin May7d96b162021-02-03 17:38:41 +00005234 TfLiteParserImpl::SupportedDataStorage storage(std::move(constData.second));
Matteo Martincigh747ef822018-12-18 09:26:39 +00005235 return std::make_pair(constData.first, std::move(storage));
5236}
5237
Mike Kelly5880b912022-01-28 16:18:54 +00005238bool TfLiteParserImpl::ShouldConstantTensorBeCreated(unsigned int tensorIndex)
5239{
5240 // If the TensorIndex appears in the list of ConstantsToBeCreated then return true
5241 return (std::find(m_ConstantsToBeCreated.begin(), m_ConstantsToBeCreated.end(), tensorIndex)
5242 != m_ConstantsToBeCreated.end());
5243}
5244
Finn Williamsd4fa5452021-03-01 12:31:41 +00005245bool TfLiteParserImpl::IsConstTensor(TensorRawPtr tensorPtr)
5246{
5247 CHECK_TENSOR_PTR(tensorPtr);
mathad01bf7edb62021-04-20 16:12:45 +01005248 bool isConst = true;
5249
5250 auto buffer = GetBuffer(m_Model, tensorPtr->buffer);
5251 if (buffer->data.size() == 0)
5252 {
5253 isConst = false;
5254 }
5255
5256 return isConst;
Finn Williamsd4fa5452021-03-01 12:31:41 +00005257}
5258
Kevin May7d96b162021-02-03 17:38:41 +00005259std::pair<armnn::ConstTensor, TfLiteParserImpl::SupportedDataStorage>
Finn Williamsd4fa5452021-03-01 12:31:41 +00005260TfLiteParserImpl::CreateConstTensorPermuted(TensorRawPtr tensorPtr,
5261 armnn::TensorInfo& tensorInfo,
5262 armnn::Optional<armnn::PermutationVector&> permutationVector)
telsoa01c577f2c2018-08-31 09:22:23 +01005263{
5264 CHECK_TENSOR_PTR(tensorPtr);
5265 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5266 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5267
Matthew Sloyan81beae32021-07-13 19:46:11 +01005268 // Make sure isConstant flag is set.
5269 tensorInfo.SetConstant();
5270
telsoa01c577f2c2018-08-31 09:22:23 +01005271 switch (tensorInfo.GetDataType())
5272 {
5273 case armnn::DataType::Float32:
Matteo Martincigh747ef822018-12-18 09:26:39 +00005274 return CreateConstTensorAndStoreData<float>(bufferPtr,
5275 tensorPtr,
5276 tensorInfo,
5277 permutationVector);
Derek Lambertif90c56d2020-01-10 17:14:08 +00005278 case armnn::DataType::QAsymmU8:
Matteo Martincigh747ef822018-12-18 09:26:39 +00005279 return CreateConstTensorAndStoreData<uint8_t>(bufferPtr,
5280 tensorPtr,
5281 tensorInfo,
5282 permutationVector);
Keith Davisd305e1a2020-01-22 11:57:54 +00005283 case armnn::DataType::QSymmS8:
5284 return CreateConstTensorAndStoreData<int8_t>(bufferPtr,
5285 tensorPtr,
5286 tensorInfo,
5287 permutationVector);
Keith Davis67e6c542020-02-19 10:08:33 +00005288 case armnn::DataType::QAsymmS8:
5289 return CreateConstTensorAndStoreData<int8_t>(bufferPtr,
5290 tensorPtr,
5291 tensorInfo,
5292 permutationVector);
telsoa01c577f2c2018-08-31 09:22:23 +01005293 case armnn::DataType::Signed32:
Matteo Martincigh747ef822018-12-18 09:26:39 +00005294 return CreateConstTensorAndStoreData<int32_t>(bufferPtr,
5295 tensorPtr,
5296 tensorInfo,
5297 permutationVector);
telsoa01c577f2c2018-08-31 09:22:23 +01005298 default:
5299 {
5300 std::stringstream errString;
5301 errString << "Unexpected datatype when creating const tensor: "
5302 << armnn::GetDataTypeName(tensorInfo.GetDataType())
5303 << " shape:" << tensorInfo.GetShape()
5304 << CHECK_LOCATION().AsString();
5305 throw ParseException(errString.str());
5306 }
5307 }
5308}
5309
Finn Williamsd4fa5452021-03-01 12:31:41 +00005310armnn::ConstTensor TfLiteParserImpl::CreateConstTensorNonPermuted(TensorRawPtr tensorPtr,
5311 armnn::TensorInfo& tensorInfo)
5312{
5313 CHECK_TENSOR_PTR(tensorPtr);
5314 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5315 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5316
Matthew Sloyan81beae32021-07-13 19:46:11 +01005317 // Make sure isConstant flag is set.
5318 tensorInfo.SetConstant();
5319
Finn Williamsd4fa5452021-03-01 12:31:41 +00005320 return ConstTensor(tensorInfo, bufferPtr->data.data());
5321}
5322
Mike Kelly5880b912022-01-28 16:18:54 +00005323std::pair<armnn::ConstTensor, std::unique_ptr<float[]>>
5324TfLiteParserImpl::CreateConstTensorNonPermuted(TensorRawPtr tensorPtr,
5325 armnn::TensorInfo& tensorInfo,
5326 armnn::DataType inputDataType)
5327{
5328 CHECK_TENSOR_PTR(tensorPtr);
5329 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5330 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5331
5332 // Make sure isConstant flag is set.
5333 tensorInfo.SetConstant();
5334
Mike Kelly0506ef02023-01-03 16:29:44 +00005335 if (inputDataType == DataType::Float32 && tensorInfo.GetDataType() != DataType::Float32)
Mike Kelly5880b912022-01-28 16:18:54 +00005336 {
Mike Kelly0506ef02023-01-03 16:29:44 +00005337 try
5338 {
5339 TensorInfo constTensorInfo(tensorInfo.GetShape(), DataType::Float32, 0.0f, 0, true);
5340 std::unique_ptr<float[]> data = armnnUtils::ToFloatArray(bufferPtr->data, tensorInfo);
5341 return std::make_pair(ConstTensor(constTensorInfo, data.get()), std::move(data));
5342 }
Cathal Corbett9c843c32023-01-09 17:51:37 +00005343 catch (InvalidArgumentException&)
Mike Kelly0506ef02023-01-03 16:29:44 +00005344 {
5345 throw ParseException(
5346 fmt::format("Unsupported input/weights combination: Input {} not supported with Weights {}",
5347 GetDataTypeName(DataType::Float32),
5348 GetDataTypeName(tensorInfo.GetDataType()),
5349 CHECK_LOCATION().AsString()));
5350 }
Mike Kelly5880b912022-01-28 16:18:54 +00005351 }
5352 else
5353 {
5354 return std::make_pair(ConstTensor(tensorInfo, bufferPtr->data.data()), std::unique_ptr<float[]>());
5355 }
5356}
5357
5358std::pair<armnn::ConstTensor*, std::unique_ptr<float[]>>
5359TfLiteParserImpl::CreateConstTensorPtr(TensorRawPtr tensorPtr, armnn::TensorInfo& inputTensorInfo)
5360{
5361 CHECK_TENSOR_PTR(tensorPtr);
5362 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
5363 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5364 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5365
5366 // Make sure isConstant flag is set.
5367 tensorInfo.SetConstant();
5368
5369 if (inputTensorInfo.GetDataType() == DataType::Float32 && tensorInfo.GetDataType() != DataType::Float32)
5370 {
Mike Kelly0506ef02023-01-03 16:29:44 +00005371 try
5372 {
5373 TensorInfo constTensorInfo(tensorInfo.GetShape(), DataType::Float32, 0.0f, 0, true);
5374 std::unique_ptr<float[]> data = armnnUtils::ToFloatArray(bufferPtr->data, tensorInfo);
5375 return std::make_pair(new ConstTensor(constTensorInfo, data.get()), std::move(data));
5376 }
Cathal Corbett9c843c32023-01-09 17:51:37 +00005377 catch (InvalidArgumentException&)
Mike Kelly0506ef02023-01-03 16:29:44 +00005378 {
5379 throw ParseException(
5380 fmt::format("Unsupported input/weights combination: Input {} not supported with Weights {}",
5381 GetDataTypeName(DataType::Float32),
5382 GetDataTypeName(tensorInfo.GetDataType()),
5383 CHECK_LOCATION().AsString()));
5384 }
Mike Kelly5880b912022-01-28 16:18:54 +00005385 }
5386 else
5387 {
5388 return std::make_pair(new ConstTensor(tensorInfo, bufferPtr->data.data()), std::unique_ptr<float[]>());
5389 }
5390}
5391
Kevin May7d96b162021-02-03 17:38:41 +00005392BindingPointInfo TfLiteParserImpl::GetNetworkInputBindingInfo(size_t subgraphId,
5393 const std::string& name) const
telsoa01c577f2c2018-08-31 09:22:23 +01005394{
5395 CHECK_SUBGRAPH(m_Model, subgraphId);
5396 auto inputs = GetSubgraphInputs(m_Model, subgraphId);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005397 for (auto const& input : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005398 {
5399 if (input.second->name == name)
5400 {
5401 auto bindingId = GenerateLayerBindingId(subgraphId, input.first);
Colm Donelan4bc993b2021-11-09 20:39:10 +00005402 auto inputTensorInfo = ToTensorInfo(input.second);
5403 // Input tensors are always treated as constant tensors during network execution.
5404 inputTensorInfo.SetConstant(true);
5405 return std::make_pair(bindingId, inputTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +01005406 }
5407 }
5408
5409 std::stringstream bindings;
Mike Kelly0d77ae12022-01-07 17:42:27 +00005410 for (auto const& input : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005411 {
5412 bindings << "'" << input.second->name << "' ";
5413 }
5414
5415 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01005416 fmt::format("No input binding found for subgraph:{} and name:{}. "
5417 "Possible inputs are: [{}] {}",
5418 subgraphId,
5419 name,
5420 bindings.str(),
5421 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01005422}
5423
Kevin May7d96b162021-02-03 17:38:41 +00005424BindingPointInfo TfLiteParserImpl::GetNetworkOutputBindingInfo(size_t subgraphId,
5425 const std::string& name) const
telsoa01c577f2c2018-08-31 09:22:23 +01005426{
5427 CHECK_SUBGRAPH(m_Model, subgraphId);
5428 auto outputs = GetSubgraphOutputs(m_Model, subgraphId);
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00005429 for (unsigned int i = 0; i < outputs.size(); ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01005430 {
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00005431 auto const output = outputs[i];
telsoa01c577f2c2018-08-31 09:22:23 +01005432 if (output.second->name == name)
5433 {
5434 auto bindingId = GenerateLayerBindingId(subgraphId, output.first);
Mike Kelly377fb212023-01-10 15:55:28 +00005435 std::vector<unsigned int> shape = m_OverriddenOutputShapes.size() > 0 ?
5436 m_OverriddenOutputShapes[i] : AsUnsignedVector(output.second->shape);
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00005437 return std::make_pair(bindingId, ToTensorInfo(output.second, shape));
telsoa01c577f2c2018-08-31 09:22:23 +01005438 }
5439 }
5440
5441 std::stringstream bindings;
Mike Kelly0d77ae12022-01-07 17:42:27 +00005442 for (auto const& output : outputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005443 {
5444 bindings << "'" << output.second->name << "' ";
5445 }
5446
5447 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01005448 fmt::format("No output binding found for subgraph:{} and name:{}. "
5449 "Possible outputs are: [{}] {}",
5450 subgraphId,
5451 name,
5452 bindings.str(),
5453 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01005454}
5455
Kevin May7d96b162021-02-03 17:38:41 +00005456size_t TfLiteParserImpl::GetSubgraphCount() const
telsoa01c577f2c2018-08-31 09:22:23 +01005457{
5458 return m_Model->subgraphs.size();
5459}
5460
Kevin May7d96b162021-02-03 17:38:41 +00005461std::vector<std::string> TfLiteParserImpl::GetSubgraphInputTensorNames(size_t subgraphId) const
telsoa01c577f2c2018-08-31 09:22:23 +01005462{
5463 CHECK_SUBGRAPH(m_Model, subgraphId);
5464 auto inputs = GetSubgraphInputs(m_Model, subgraphId);
5465 std::vector<std::string> result;
5466 result.reserve(inputs.size());
Mike Kelly0d77ae12022-01-07 17:42:27 +00005467 for (auto const& input : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005468 {
5469 result.push_back(input.second->name);
5470 }
5471 return result;
5472}
5473
Kevin May7d96b162021-02-03 17:38:41 +00005474std::vector<std::string> TfLiteParserImpl::GetSubgraphOutputTensorNames(size_t subgraphId) const
telsoa01c577f2c2018-08-31 09:22:23 +01005475{
5476 CHECK_SUBGRAPH(m_Model, subgraphId);
5477 auto outputs = GetSubgraphOutputs(m_Model, subgraphId);
5478 std::vector<std::string> result;
5479 result.reserve(outputs.size());
Mike Kelly0d77ae12022-01-07 17:42:27 +00005480 for (auto const& output : outputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005481 {
5482 result.push_back(output.second->name);
5483 }
5484 return result;
5485}
5486
Matthew Sloyanac001ee2021-02-03 10:43:04 +00005487const std::string TfLiteParserImpl::GetVersion()
5488{
5489 return TFLITE_PARSER_VERSION;
5490}
5491
Mike Kelly0d77ae12022-01-07 17:42:27 +00005492TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<float[]>&& data)
telsoa01c577f2c2018-08-31 09:22:23 +01005493: m_FloatData(std::move(data))
5494, m_Uint8Data(nullptr)
Keith Davisd305e1a2020-01-22 11:57:54 +00005495, m_Int8Data(nullptr)
telsoa01c577f2c2018-08-31 09:22:23 +01005496, m_Int32Data(nullptr)
5497{
5498}
5499
Mike Kelly0d77ae12022-01-07 17:42:27 +00005500TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<uint8_t[]>&& data)
telsoa01c577f2c2018-08-31 09:22:23 +01005501: m_FloatData(nullptr)
5502, m_Uint8Data(std::move(data))
Keith Davisd305e1a2020-01-22 11:57:54 +00005503, m_Int8Data(nullptr)
5504, m_Int32Data(nullptr)
5505{
5506}
5507
Mike Kelly0d77ae12022-01-07 17:42:27 +00005508TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<int8_t[]>&& data)
Keith Davisd305e1a2020-01-22 11:57:54 +00005509: m_FloatData(nullptr)
5510, m_Uint8Data(nullptr)
5511, m_Int8Data(std::move(data))
telsoa01c577f2c2018-08-31 09:22:23 +01005512, m_Int32Data(nullptr)
5513{
5514}
5515
Mike Kelly0d77ae12022-01-07 17:42:27 +00005516TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<int32_t[]>&& data)
telsoa01c577f2c2018-08-31 09:22:23 +01005517: m_FloatData(nullptr)
5518, m_Uint8Data(nullptr)
Keith Davisd305e1a2020-01-22 11:57:54 +00005519, m_Int8Data(nullptr)
telsoa01c577f2c2018-08-31 09:22:23 +01005520, m_Int32Data(std::move(data))
5521{
5522}
5523
5524} // armnnTfLiteParser