blob: a3bec923c1a9375d03090ca912aad8eab6cf179f [file] [log] [blame]
telsoa01c577f2c2018-08-31 09:22:23 +01001//
Mike Kelly377fb212023-01-10 15:55:28 +00002// Copyright © 2018-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
Kevin May7d96b162021-02-03 17:38:41 +0000414armnn::TensorInfo ToTensorInfo(TfLiteParserImpl::TensorRawPtr tensorPtr,
Finn Williamsb49ed182021-06-29 15:50:08 +0100415 const std::vector<unsigned int>& shape,
Sadik Armagand109a4d2020-07-28 10:42:13 +0100416 const bool outputTensor = false)
telsoa01c577f2c2018-08-31 09:22:23 +0100417{
418 armnn::DataType type;
419 CHECK_TENSOR_PTR(tensorPtr);
420
421 switch (tensorPtr->type)
422 {
423 case tflite::TensorType_UINT8:
Derek Lambertif90c56d2020-01-10 17:14:08 +0000424 type = armnn::DataType::QAsymmU8;
telsoa01c577f2c2018-08-31 09:22:23 +0100425 break;
426 case tflite::TensorType_FLOAT32:
427 type = armnn::DataType::Float32;
428 break;
Keith Davisb4dd5cc2022-04-07 11:32:00 +0100429 case tflite::TensorType_FLOAT16:
430 type = armnn::DataType::Float16;
431 break;
Finn Williamsed66d142019-12-06 09:55:55 +0000432 case tflite::TensorType_INT8:
Keith Davis67e6c542020-02-19 10:08:33 +0000433 if (tensorPtr->quantization->zero_point.size() == 1)
Ryan OShea03181ff2020-02-07 17:22:22 +0000434 {
Keith Davis0c2eeac2020-02-11 16:51:50 +0000435 // Per-tensor
Ryan OShea03181ff2020-02-07 17:22:22 +0000436 type = armnn::DataType::QAsymmS8;
437 }
438 else
439 {
Keith Davis0c2eeac2020-02-11 16:51:50 +0000440 // Per-channel
Ryan OShea03181ff2020-02-07 17:22:22 +0000441 type = armnn::DataType::QSymmS8;
442 }
Finn Williamsed66d142019-12-06 09:55:55 +0000443 break;
444 case tflite::TensorType_INT16:
Derek Lambertif90c56d2020-01-10 17:14:08 +0000445 type = armnn::DataType::QSymmS16;
Finn Williamsed66d142019-12-06 09:55:55 +0000446 break;
telsoa01c577f2c2018-08-31 09:22:23 +0100447 case tflite::TensorType_INT32:
448 type = armnn::DataType::Signed32;
449 break;
Inki Daed4619e22020-09-10 15:33:54 +0900450 case tflite::TensorType_INT64:
451 type = armnn::DataType::Signed64;
452 break;
Matthew Sloyaned7fce42021-04-15 20:46:24 +0100453 case tflite::TensorType_BOOL:
454 type = armnn::DataType::Boolean;
455 break;
telsoa01c577f2c2018-08-31 09:22:23 +0100456 default:
457 {
458 CheckLocation location = CHECK_LOCATION();
459 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100460 fmt::format("Unsupported data type {} = {} for tensor: {}. {}",
461 tensorPtr->type,
462 tflite::EnumNameTensorType(tensorPtr->type),
463 tensorPtr->name,
464 location.AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +0100465 }
466 }
Finn Williamsb49ed182021-06-29 15:50:08 +0100467 TensorShape tensorShape;
468
469 std::vector<unsigned int> safeShape = shape;
470 if (shape.size() == 0)
Narumol Prangnawarat4818d462019-04-17 11:22:38 +0100471 {
472 safeShape.push_back(1);
Finn Williamsb49ed182021-06-29 15:50:08 +0100473 }
474
475 if (!outputTensor)
476 {
477 tensorShape = TensorShape(armnn::numeric_cast<unsigned int>(safeShape.size()), safeShape.data());
478 }
479 else
480 {
Rob Hughesd812a312021-08-06 13:10:53 +0100481 size_t shapeSignatureSize = tensorPtr->shape_signature.size();
Finn Williamsb49ed182021-06-29 15:50:08 +0100482
483 // If a shape signature exists we will use that to infer dynamic tensors
484 if (shapeSignatureSize != 0)
Sadik Armagand109a4d2020-07-28 10:42:13 +0100485 {
Finn Williamsb49ed182021-06-29 15:50:08 +0100486 // If the shape is incompatible with the shape signature override the shape
487 if (shapeSignatureSize != shape.size())
488 {
489 safeShape = {};
490
491 for (unsigned int i = 0; i < shapeSignatureSize; ++i)
492 {
493 unsigned int dim = tensorPtr->shape_signature[i] > -1 ?
494 static_cast<unsigned int>(tensorPtr->shape_signature[i]) : 0;
495 safeShape.push_back(dim);
496 }
497 }
498
Rob Hughesd812a312021-08-06 13:10:53 +0100499 std::unique_ptr<bool[]> dimMask = std::make_unique<bool[]>(tensorPtr->shape_signature.size());
Finn Williamsb49ed182021-06-29 15:50:08 +0100500 for (unsigned int i = 0; i < tensorPtr->shape_signature.size(); ++i)
501 {
502 dimMask[i] = tensorPtr->shape_signature[i] == -1 ? false : true;
503 }
Rob Hughesd812a312021-08-06 13:10:53 +0100504 tensorShape = TensorShape(static_cast<unsigned int>(safeShape.size()), safeShape.data(), dimMask.get());
Finn Williamsb49ed182021-06-29 15:50:08 +0100505 }
506 // If there is no shape signature treat the tensor as dynamic if the shape has a size of zero
507 else if (shape.size() == 0)
508 {
509 tensorShape = TensorShape(1, false);
510 }
511 else
512 {
513 tensorShape = TensorShape(armnn::numeric_cast<unsigned int>(shape.size()), shape.data());
Sadik Armagand109a4d2020-07-28 10:42:13 +0100514 }
Narumol Prangnawarat4818d462019-04-17 11:22:38 +0100515 }
516
Keith Davisd305e1a2020-01-22 11:57:54 +0000517 float quantizationScale = 0.0f;
518 int32_t quantizationOffset = 0;
519
520 if (tensorPtr->quantization.get())
521 {
522 if (tensorPtr->quantization->scale.size() <= 1)
523 {
524 CHECK_VALID_SIZE(tensorPtr->quantization->zero_point.size(), 0, 1);
525 CHECK_VALID_SIZE(tensorPtr->quantization->zero_point.size(), 0, 1);
526
527 if (tensorPtr->quantization->scale.size() == 1)
528 {
529 quantizationScale = tensorPtr->quantization->scale[0];
530 }
531 if (tensorPtr->quantization->zero_point.size() == 1)
532 {
533 // NOTE: we lose precision here when converting from 64 bit to 32
Ryan OShea03181ff2020-02-07 17:22:22 +0000534 // but this is what we support at the moment in ArmNN
Matthew Sloyan589e3e82020-09-11 16:17:48 +0100535 quantizationOffset = armnn::numeric_cast<int32_t>(tensorPtr->quantization->zero_point[0]);
Keith Davisd305e1a2020-01-22 11:57:54 +0000536 }
537
Sadik Armagand109a4d2020-07-28 10:42:13 +0100538 armnn::TensorInfo result(tensorShape,
539 type,
540 quantizationScale,
541 quantizationOffset);
Keith Davisd305e1a2020-01-22 11:57:54 +0000542 return result;
543 }
544 else
545 {
546 std::vector<float> quantizationScales;
547 std::vector<int32_t> quantizationOffsets;
548
549 // Scale
550 std::copy(tensorPtr->quantization->scale.begin(),
551 tensorPtr->quantization->scale.end(),
552 std::back_inserter(quantizationScales));
553
Keith Davis0c2eeac2020-02-11 16:51:50 +0000554 // QSymmS8 Per-axis
Sadik Armagand109a4d2020-07-28 10:42:13 +0100555 armnn::TensorInfo result(tensorShape,
556 type,
557 quantizationScales,
Jan Eilers7612bd62021-04-06 17:29:03 +0100558 armnn::numeric_cast<unsigned int>(tensorPtr->quantization->quantized_dimension));
Keith Davisd305e1a2020-01-22 11:57:54 +0000559 return result;
560 }
561 }
562 else
563 {
Sadik Armagand109a4d2020-07-28 10:42:13 +0100564 armnn::TensorInfo result(tensorShape,
Keith Davisd305e1a2020-01-22 11:57:54 +0000565 type,
566 quantizationScale,
567 quantizationOffset);
568 return result;
569 }
telsoa01c577f2c2018-08-31 09:22:23 +0100570}
571
Kevin May7d96b162021-02-03 17:38:41 +0000572armnn::TensorInfo ToTensorInfo(TfLiteParserImpl::TensorRawPtr tensorPtr,
Mike Kelly377fb212023-01-10 15:55:28 +0000573 const bool outputTensor = false)
Sadik Armagand109a4d2020-07-28 10:42:13 +0100574{
Mike Kelly0d77ae12022-01-07 17:42:27 +0000575 auto const& dimensions = AsUnsignedVector(tensorPtr->shape);
Jan Eilers7612bd62021-04-06 17:29:03 +0100576 return ToTensorInfo(tensorPtr, dimensions, outputTensor);
Sadik Armagand109a4d2020-07-28 10:42:13 +0100577}
578
telsoa01c577f2c2018-08-31 09:22:23 +0100579template<typename T>
580std::pair<armnn::ConstTensor, std::unique_ptr<T[]>>
Kevin May7d96b162021-02-03 17:38:41 +0000581CreateConstTensorImpl(TfLiteParserImpl::BufferRawPtr bufferPtr,
582 TfLiteParserImpl::TensorRawPtr tensorPtr,
Matteo Martincigh747ef822018-12-18 09:26:39 +0000583 armnn::TensorInfo& tensorInfo,
584 armnn::Optional<armnn::PermutationVector&> permutationVector)
telsoa01c577f2c2018-08-31 09:22:23 +0100585{
Jan Eilers8eb25602020-03-09 12:13:48 +0000586 IgnoreUnused(tensorPtr);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100587 ARMNN_ASSERT_MSG(tensorPtr != nullptr, "tensorPtr is null");
588 ARMNN_ASSERT_MSG(bufferPtr != nullptr,
James Ward58dec6b2020-09-11 17:32:44 +0100589 fmt::format("Buffer for buffer:{} is null", tensorPtr->buffer).c_str());
telsoa01c577f2c2018-08-31 09:22:23 +0100590
591 std::unique_ptr<T[]> data(new T[tensorInfo.GetNumElements()]);
Matteo Martincigh747ef822018-12-18 09:26:39 +0000592
593 if (permutationVector.has_value() && permutationVector.value().GetSize() > 0)
594 {
595 tensorInfo = armnnUtils::Permuted(tensorInfo, permutationVector.value());
Matteo Martincighd5b9e642019-01-04 18:01:21 +0000596 armnnUtils::Permute(tensorInfo.GetShape(), permutationVector.value(),
597 reinterpret_cast<const T*>(bufferPtr->data.data()), data.get(), sizeof(T));
Matteo Martincigh747ef822018-12-18 09:26:39 +0000598 }
599 else
600 {
601 ::memcpy(data.get(), bufferPtr->data.data(), tensorInfo.GetNumBytes());
602 }
603
Matthew Sloyan81beae32021-07-13 19:46:11 +0100604 // Make sure isConstant flag is set.
605 tensorInfo.SetConstant();
606
telsoa01c577f2c2018-08-31 09:22:23 +0100607 return std::make_pair(ConstTensor(tensorInfo, data.get()), std::move(data));
608}
609
telsoa01c577f2c2018-08-31 09:22:23 +0100610armnn::LayerBindingId GenerateLayerBindingId(size_t subgraphIndex, size_t tensorIndex)
611{
612 // generate the binding id by shifting the tensor id by 8 bit
613 // and add the subgraph id, which allows 256 subgraphs
614 return static_cast<armnn::LayerBindingId>((tensorIndex<<8)+subgraphIndex);
615}
616
Aron Virginas-Tar70672f62019-01-23 14:00:00 +0000617bool CheckShape(const armnn::TensorShape& actual, const std::vector<int32_t>& expected)
618{
619 const unsigned int actualSize = actual.GetNumDimensions();
620 if (actualSize != expected.size())
621 {
622 return false;
623 }
624
625 for (unsigned int i = 0u; i < actualSize; i++)
626 {
627 if (expected[i] < 0 ||
628 actual[i] != static_cast<unsigned int>(expected[i]))
629 {
630 return false;
631 }
632 }
633
634 return true;
635}
636
Cathal Corbett2b922e22022-09-23 15:49:24 +0100637bool CheckShape(const armnn::TensorShape& actual, const armnn::TensorShape& expected)
638{
639 std::vector<int32_t> expectedVec;
640 for (uint32_t i = 0; i < expected.GetNumDimensions(); i++)
641 {
642 expectedVec.push_back(expected[i]);
643 }
644 return CheckShape(actual, expectedVec);
645}
646
James Conroy05102392020-06-24 15:39:55 +0100647void CheckMatchingQuantization(const TensorInfo& first,
648 const TensorInfo& second,
649 const std::string& descName,
650 std::string const& firstName,
651 std::string const& secondName)
652{
653 if (!first.IsQuantized() ||
654 !second.IsQuantized())
655 {
656 // Not a quantized type, ignore the validation
657 return;
658 }
659
660 DataType firstDataType = first.GetDataType();
661 DataType secondDataType = second.GetDataType();
662
663 if (firstDataType != secondDataType)
664 {
665 throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
666 " must be of the same quantized type, " +
667 firstName + " is " + GetDataTypeName(firstDataType) + ", " +
668 secondName + " is " + GetDataTypeName(secondDataType));
669 }
670
671 if (!first.IsTypeSpaceMatch(second))
672 {
673 throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
674 " must have the same quantization space, " +
675 firstName + " has offset " + std::to_string(first.GetQuantizationOffset()) +
676 " and scale " + std::to_string(first.GetQuantizationScale()) + ", " +
677 secondName + " has offset " + std::to_string(second.GetQuantizationOffset()) +
678 " and scale " + std::to_string(second.GetQuantizationScale()));
679 }
680}
681
Mike Kelly377fb212023-01-10 15:55:28 +0000682bool IsDynamic(TfLiteParserImpl::TensorRawPtr tensorPtr)
683{
684 auto shape = tensorPtr->shape;
685
686 if (shape.empty())
687 {
688 return true;
689 }
690 auto shapeSig = tensorPtr->shape_signature;
691
692 if (shapeSig.empty())
693 {
694 return false;
695 }
696
697 for (unsigned int i = 0; i < shapeSig.size() ; ++i)
698 {
699 if (shapeSig[i] == -1)
700 {
701 return true;
702 }
703 }
704 return false;
705}
706
telsoa01c577f2c2018-08-31 09:22:23 +0100707} // <anonymous>
708
Kevin May7d96b162021-02-03 17:38:41 +0000709TfLiteParserImpl::TfLiteParserImpl(const Optional<ITfLiteParser::TfLiteParserOptions>& options)
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100710: m_Options(options)
711, m_Network(nullptr, nullptr)
Kevin May7d96b162021-02-03 17:38:41 +0000712, m_ParserFunctions(tflite::BuiltinOperator_MAX+1, &TfLiteParserImpl::ParseUnsupportedOperator)
telsoa01c577f2c2018-08-31 09:22:23 +0100713{
714 // register supported operators
Matthew Sloyaned7fce42021-04-15 20:46:24 +0100715 m_ParserFunctions[tflite::BuiltinOperator_ABS] = &TfLiteParserImpl::ParseAbs;
Kevin May7d96b162021-02-03 17:38:41 +0000716 m_ParserFunctions[tflite::BuiltinOperator_ADD] = &TfLiteParserImpl::ParseAdd;
Matthew Sloyan28f177c2021-04-09 14:38:52 +0100717 m_ParserFunctions[tflite::BuiltinOperator_ARG_MIN] = &TfLiteParserImpl::ParseArgMin;
718 m_ParserFunctions[tflite::BuiltinOperator_ARG_MAX] = &TfLiteParserImpl::ParseArgMax;
Kevin May7d96b162021-02-03 17:38:41 +0000719 m_ParserFunctions[tflite::BuiltinOperator_AVERAGE_POOL_2D] = &TfLiteParserImpl::ParseAveragePool2D;
720 m_ParserFunctions[tflite::BuiltinOperator_BATCH_TO_SPACE_ND] = &TfLiteParserImpl::ParseBatchToSpaceND;
Samuel Yapfd3ba5a2022-08-24 17:04:34 +0100721 m_ParserFunctions[tflite::BuiltinOperator_BATCH_MATMUL] = &TfLiteParserImpl::ParseBatchMatMul;
mathad01b392e982021-04-07 12:07:30 +0100722 m_ParserFunctions[tflite::BuiltinOperator_CAST] = &TfLiteParserImpl::ParseCast;
Kevin May7d96b162021-02-03 17:38:41 +0000723 m_ParserFunctions[tflite::BuiltinOperator_CONCATENATION] = &TfLiteParserImpl::ParseConcatenation;
724 m_ParserFunctions[tflite::BuiltinOperator_CONV_2D] = &TfLiteParserImpl::ParseConv2D;
Matthew Sloyan4d217c02021-10-07 11:48:58 +0100725 // Conv3D support was added in TF 2.5, so for backwards compatibility a hash define is needed.
Cathal Corbett80b4ef02022-05-25 11:21:11 +0100726 #if defined(ARMNN_POST_TFLITE_2_4)
Matthew Sloyaneb5f8102021-10-05 17:31:42 +0100727 m_ParserFunctions[tflite::BuiltinOperator_CONV_3D] = &TfLiteParserImpl::ParseConv3D;
Matthew Sloyan4d217c02021-10-07 11:48:58 +0100728 #endif
Kevin May7d96b162021-02-03 17:38:41 +0000729 m_ParserFunctions[tflite::BuiltinOperator_CUSTOM] = &TfLiteParserImpl::ParseCustomOperator;
730 m_ParserFunctions[tflite::BuiltinOperator_DEPTH_TO_SPACE] = &TfLiteParserImpl::ParseDepthToSpace;
731 m_ParserFunctions[tflite::BuiltinOperator_DEPTHWISE_CONV_2D] = &TfLiteParserImpl::ParseDepthwiseConv2D;
732 m_ParserFunctions[tflite::BuiltinOperator_DEQUANTIZE] = &TfLiteParserImpl::ParseDequantize;
Matthew Sloyan28f177c2021-04-09 14:38:52 +0100733 m_ParserFunctions[tflite::BuiltinOperator_DIV] = &TfLiteParserImpl::ParseDiv;
Kevin May7d96b162021-02-03 17:38:41 +0000734 m_ParserFunctions[tflite::BuiltinOperator_ELU] = &TfLiteParserImpl::ParseElu;
Bruno Goncalves2d0eb862021-07-11 14:10:15 -0300735 m_ParserFunctions[tflite::BuiltinOperator_EQUAL] = &TfLiteParserImpl::ParseEqual;
Kevin May7d96b162021-02-03 17:38:41 +0000736 m_ParserFunctions[tflite::BuiltinOperator_EXP] = &TfLiteParserImpl::ParseExp;
Teresa Charlin3ab85482021-06-08 16:59:29 +0100737 m_ParserFunctions[tflite::BuiltinOperator_EXPAND_DIMS] = &TfLiteParserImpl::ParseExpandDims;
Teresa Charlincdbd40b2022-02-25 13:21:55 +0000738 m_ParserFunctions[tflite::BuiltinOperator_FLOOR_DIV] = &TfLiteParserImpl::ParseFloorDiv;
Kevin May7d96b162021-02-03 17:38:41 +0000739 m_ParserFunctions[tflite::BuiltinOperator_FULLY_CONNECTED] = &TfLiteParserImpl::ParseFullyConnected;
740 m_ParserFunctions[tflite::BuiltinOperator_GATHER] = &TfLiteParserImpl::ParseGather;
Teresa Charlin91a53ea2022-04-25 15:47:29 +0100741 m_ParserFunctions[tflite::BuiltinOperator_GATHER_ND] = &TfLiteParserImpl::ParseGatherNd;
Bruno Goncalves2d0eb862021-07-11 14:10:15 -0300742 m_ParserFunctions[tflite::BuiltinOperator_GREATER] = &TfLiteParserImpl::ParseGreater;
743 m_ParserFunctions[tflite::BuiltinOperator_GREATER_EQUAL] = &TfLiteParserImpl::ParseGreaterOrEqual;
Kevin May7d96b162021-02-03 17:38:41 +0000744 m_ParserFunctions[tflite::BuiltinOperator_HARD_SWISH] = &TfLiteParserImpl::ParseHardSwish;
745 m_ParserFunctions[tflite::BuiltinOperator_LEAKY_RELU] = &TfLiteParserImpl::ParseLeakyRelu;
Bruno Goncalves2d0eb862021-07-11 14:10:15 -0300746 m_ParserFunctions[tflite::BuiltinOperator_LESS] = &TfLiteParserImpl::ParseLess;
747 m_ParserFunctions[tflite::BuiltinOperator_LESS_EQUAL] = &TfLiteParserImpl::ParseLessOrEqual;
Mike Kelly31dce2b2021-09-01 21:22:37 +0100748 m_ParserFunctions[tflite::BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION]
749 = &TfLiteParserImpl::ParseLocalResponseNormalization;
Teresa Charlin28aa6692022-07-12 11:18:44 +0100750 m_ParserFunctions[tflite::BuiltinOperator_LOG] = &TfLiteParserImpl::ParseLog;
Matthew Sloyaned7fce42021-04-15 20:46:24 +0100751 m_ParserFunctions[tflite::BuiltinOperator_LOGICAL_NOT] = &TfLiteParserImpl::ParseLogicalNot;
Kevin May7d96b162021-02-03 17:38:41 +0000752 m_ParserFunctions[tflite::BuiltinOperator_LOGISTIC] = &TfLiteParserImpl::ParseLogistic;
Teresa Charlinfd33a692022-06-29 15:35:57 +0100753 m_ParserFunctions[tflite::BuiltinOperator_LOG_SOFTMAX] = &TfLiteParserImpl::ParseLogSoftmax;
Kevin May7d96b162021-02-03 17:38:41 +0000754 m_ParserFunctions[tflite::BuiltinOperator_L2_NORMALIZATION] = &TfLiteParserImpl::ParseL2Normalization;
755 m_ParserFunctions[tflite::BuiltinOperator_MAX_POOL_2D] = &TfLiteParserImpl::ParseMaxPool2D;
756 m_ParserFunctions[tflite::BuiltinOperator_MAXIMUM] = &TfLiteParserImpl::ParseMaximum;
757 m_ParserFunctions[tflite::BuiltinOperator_MEAN] = &TfLiteParserImpl::ParseMean;
758 m_ParserFunctions[tflite::BuiltinOperator_MINIMUM] = &TfLiteParserImpl::ParseMinimum;
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +0100759 m_ParserFunctions[tflite::BuiltinOperator_MIRROR_PAD] = &TfLiteParserImpl::ParseMirrorPad;
Kevin May7d96b162021-02-03 17:38:41 +0000760 m_ParserFunctions[tflite::BuiltinOperator_MUL] = &TfLiteParserImpl::ParseMul;
761 m_ParserFunctions[tflite::BuiltinOperator_NEG] = &TfLiteParserImpl::ParseNeg;
Bruno Goncalves2d0eb862021-07-11 14:10:15 -0300762 m_ParserFunctions[tflite::BuiltinOperator_NOT_EQUAL] = &TfLiteParserImpl::ParseNotEqual;
Kevin May7d96b162021-02-03 17:38:41 +0000763 m_ParserFunctions[tflite::BuiltinOperator_PACK] = &TfLiteParserImpl::ParsePack;
764 m_ParserFunctions[tflite::BuiltinOperator_PAD] = &TfLiteParserImpl::ParsePad;
Mike Kelly0d77ae12022-01-07 17:42:27 +0000765 m_ParserFunctions[tflite::BuiltinOperator_PADV2] = &TfLiteParserImpl::ParsePad;
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +0100766 m_ParserFunctions[tflite::BuiltinOperator_PRELU] = &TfLiteParserImpl::ParsePrelu;
Kevin May7d96b162021-02-03 17:38:41 +0000767 m_ParserFunctions[tflite::BuiltinOperator_QUANTIZE] = &TfLiteParserImpl::ParseQuantize;
768 m_ParserFunctions[tflite::BuiltinOperator_RELU] = &TfLiteParserImpl::ParseRelu;
769 m_ParserFunctions[tflite::BuiltinOperator_RELU6] = &TfLiteParserImpl::ParseRelu6;
Sadik Armagana2747482021-02-09 10:28:54 +0000770 m_ParserFunctions[tflite::BuiltinOperator_REDUCE_MAX] = &TfLiteParserImpl::ParseReduceMax;
771 m_ParserFunctions[tflite::BuiltinOperator_REDUCE_MIN] = &TfLiteParserImpl::ParseReduceMin;
Teresa Charlin4e3e8312021-08-05 12:34:37 +0100772 m_ParserFunctions[tflite::BuiltinOperator_REDUCE_PROD] = &TfLiteParserImpl::ParseReduceProd;
Kevin May7d96b162021-02-03 17:38:41 +0000773 m_ParserFunctions[tflite::BuiltinOperator_RESHAPE] = &TfLiteParserImpl::ParseReshape;
774 m_ParserFunctions[tflite::BuiltinOperator_RESIZE_BILINEAR] = &TfLiteParserImpl::ParseResizeBilinear;
775 m_ParserFunctions[tflite::BuiltinOperator_RESIZE_NEAREST_NEIGHBOR] = &TfLiteParserImpl::ParseResizeNearestNeighbor;
Matthew Sloyaned7fce42021-04-15 20:46:24 +0100776 m_ParserFunctions[tflite::BuiltinOperator_RSQRT] = &TfLiteParserImpl::ParseRsqrt;
Teresa Charlinf0fce5b2022-05-04 17:24:43 +0100777 m_ParserFunctions[tflite::BuiltinOperator_SQRT] = &TfLiteParserImpl::ParseSqrt;
Keith Davis0176fd82021-06-01 17:36:32 +0100778 m_ParserFunctions[tflite::BuiltinOperator_SHAPE] = &TfLiteParserImpl::ParseShape;
Teresa Charlin28aa6692022-07-12 11:18:44 +0100779 m_ParserFunctions[tflite::BuiltinOperator_SIN] = &TfLiteParserImpl::ParseSin;
Kevin May7d96b162021-02-03 17:38:41 +0000780 m_ParserFunctions[tflite::BuiltinOperator_SLICE] = &TfLiteParserImpl::ParseSlice;
781 m_ParserFunctions[tflite::BuiltinOperator_SOFTMAX] = &TfLiteParserImpl::ParseSoftmax;
782 m_ParserFunctions[tflite::BuiltinOperator_SPACE_TO_BATCH_ND] = &TfLiteParserImpl::ParseSpaceToBatchND;
783 m_ParserFunctions[tflite::BuiltinOperator_SPLIT] = &TfLiteParserImpl::ParseSplit;
784 m_ParserFunctions[tflite::BuiltinOperator_SPLIT_V] = &TfLiteParserImpl::ParseSplitV;
785 m_ParserFunctions[tflite::BuiltinOperator_SQUEEZE] = &TfLiteParserImpl::ParseSqueeze;
786 m_ParserFunctions[tflite::BuiltinOperator_STRIDED_SLICE] = &TfLiteParserImpl::ParseStridedSlice;
787 m_ParserFunctions[tflite::BuiltinOperator_SUB] = &TfLiteParserImpl::ParseSub;
788 m_ParserFunctions[tflite::BuiltinOperator_SUM] = &TfLiteParserImpl::ParseSum;
789 m_ParserFunctions[tflite::BuiltinOperator_TANH] = &TfLiteParserImpl::ParseTanH;
790 m_ParserFunctions[tflite::BuiltinOperator_TRANSPOSE] = &TfLiteParserImpl::ParseTranspose;
791 m_ParserFunctions[tflite::BuiltinOperator_TRANSPOSE_CONV] = &TfLiteParserImpl::ParseTransposeConv;
Mike Kelly5880b912022-01-28 16:18:54 +0000792 m_ParserFunctions[tflite::BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM]
793 = &TfLiteParserImpl::ParseUnidirectionalSequenceLSTM;
Kevin May7d96b162021-02-03 17:38:41 +0000794 m_ParserFunctions[tflite::BuiltinOperator_UNPACK] = &TfLiteParserImpl::ParseUnpack;
Matthew Sloyan28f177c2021-04-09 14:38:52 +0100795
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100796 // register supported custom operators
Kevin May7d96b162021-02-03 17:38:41 +0000797 m_CustomParserFunctions["TFLite_Detection_PostProcess"] = &TfLiteParserImpl::ParseDetectionPostProcess;
telsoa01c577f2c2018-08-31 09:22:23 +0100798}
799
Mike Kelly377fb212023-01-10 15:55:28 +0000800armnn::TensorInfo TfLiteParserImpl::InputTensorInfo(size_t subgraphIndex,
801 size_t operatorIndex,
802 int input)
803{
804 const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex];
805 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
806
807 uint32_t inputId = CHECKED_NON_NEGATIVE(operatorPtr->inputs[input]);
808 auto search = armnnTfLiteParser::TfLiteParserImpl::m_TensorInfos.find(inputId);
809
810 if (search != m_TensorInfos.end())
811 {
812 return m_TensorInfos[inputId];
813 }
814 else
815 {
816 auto tensorInfo = ::armnnTfLiteParser::ToTensorInfo(subgraphPtr->tensors[inputId].get());
817 m_TensorInfos.insert({ inputId, tensorInfo });
818 return tensorInfo;
819 }
820}
821
822armnn::TensorInfo TfLiteParserImpl::OutputTensorInfoFromInputs(size_t subgraphIndex,
823 size_t operatorIndex,
824 armnn::IConnectableLayer* layer,
825 int output,
826 std::vector<int> inputs)
827{
828 const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex];
829 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
830
831 uint32_t outputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[output]);
832
833 auto outputSearch = armnnTfLiteParser::TfLiteParserImpl::m_TensorInfos.find(outputId);
834
835 if (outputSearch != m_TensorInfos.end())
836 {
837 return m_TensorInfos[outputId];
838 }
839
840 const auto& outputTensorPtr = subgraphPtr->tensors[outputId].get();
841 TensorInfo tensor = ::armnnTfLiteParser::ToTensorInfo(outputTensorPtr, true);
842
843 if (IsDynamic(outputTensorPtr))
844 {
845 if (inputs.empty())
846 {
847 for (unsigned int i = 0; i < layer->GetNumInputSlots(); ++i)
848 {
849 inputs.emplace_back(i);
850 }
851 }
852 auto inputTensorIds = GetInputTensorIds(m_Model, subgraphIndex, operatorIndex);
853 std::vector<armnn::TensorShape> inputShapes;
854
855 for (unsigned int i = 0; i < inputs.size(); ++i)
856 {
857 uint32_t inputId = CHECKED_NON_NEGATIVE(operatorPtr->inputs[inputs[i]]);
858 auto search = armnnTfLiteParser::TfLiteParserImpl::m_TensorInfos.find(inputId);
859
860 if (search != m_TensorInfos.end())
861 {
862 auto &inputTensorInfo = m_TensorInfos[inputId];
863 inputShapes.push_back(inputTensorInfo.GetShape());
864 }
865 else
866 {
867 m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
868 auto inputTensorInfo = ::armnnTfLiteParser::ToTensorInfo(subgraphPtr->tensors[inputId].get());
869 m_TensorInfos.insert({ inputId, inputTensorInfo});
870 inputShapes.push_back(inputTensorInfo.GetShape());
871 }
872 }
873 const auto outputShape = layer->InferOutputShapes(inputShapes)[output];
874 tensor.SetShape(outputShape);
875 }
876 m_TensorInfos.insert({ outputId, tensor});
877 return tensor;
878}
879
880armnn::TensorInfo TfLiteParserImpl::OutputTensorInfoFromShapes(size_t subgraphIndex,
881 size_t operatorIndex,
882 armnn::IConnectableLayer* layer,
883 int output,
884 std::vector<armnn::TensorShape> inputShapes)
885{
886 const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex];
887 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
888
889 uint32_t outputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[output]);
890 const auto& outputTensorPtr = subgraphPtr->tensors[outputId].get();
891 TensorInfo tensor = ::armnnTfLiteParser::ToTensorInfo(outputTensorPtr, true);
892
893 if (IsDynamic(outputTensorPtr))
894 {
895 const auto outputShape = layer->InferOutputShapes(inputShapes)[output];
896 tensor.SetShape(outputShape);
897 }
898 m_TensorInfos.insert({ outputId, tensor});
899 return tensor;
900}
901
Kevin May7d96b162021-02-03 17:38:41 +0000902void TfLiteParserImpl::ResetParser()
telsoa01c577f2c2018-08-31 09:22:23 +0100903{
904 m_Network = armnn::INetworkPtr(nullptr, nullptr);
905 m_Model = nullptr;
906 m_SubgraphConnections.clear();
Mike Kelly377fb212023-01-10 15:55:28 +0000907 m_OverriddenOutputShapes.clear();
Mike Kelly5880b912022-01-28 16:18:54 +0000908 m_ConstantsToDequantize.clear();
909 m_ConstantsToBeCreated.clear();
Mike Kelly377fb212023-01-10 15:55:28 +0000910 m_TensorInfos.clear();
telsoa01c577f2c2018-08-31 09:22:23 +0100911}
912
Kevin May7d96b162021-02-03 17:38:41 +0000913INetworkPtr TfLiteParserImpl::CreateNetworkFromBinaryFile(const char* graphFile)
telsoa01c577f2c2018-08-31 09:22:23 +0100914{
915 ResetParser();
916 m_Model = LoadModelFromFile(graphFile);
917 return CreateNetworkFromModel();
918}
919
Mike Kelly0d77ae12022-01-07 17:42:27 +0000920INetworkPtr TfLiteParserImpl::CreateNetworkFromBinary(const std::vector<uint8_t>& binaryContent)
telsoa01c577f2c2018-08-31 09:22:23 +0100921{
922 ResetParser();
923 m_Model = LoadModelFromBinary(binaryContent.data(), binaryContent.size());
924 return CreateNetworkFromModel();
925}
926
Finn Williamsb49ed182021-06-29 15:50:08 +0100927
928armnn::INetworkPtr TfLiteParserImpl::LoadModel(std::unique_ptr<tflite::ModelT> model)
929{
930 ResetParser();
931 m_Model = std::move(model);
932
933 return CreateNetworkFromModel();
934}
935
Kevin May7d96b162021-02-03 17:38:41 +0000936INetworkPtr TfLiteParserImpl::CreateNetworkFromModel()
telsoa01c577f2c2018-08-31 09:22:23 +0100937{
Sadik Armagand109a4d2020-07-28 10:42:13 +0100938
939 using NetworkOptions = std::vector<BackendOptions>;
940 NetworkOptions networkOptions = {};
Mike Kelly80512b02022-05-16 23:10:42 +0100941 if (m_Options)
Sadik Armagand109a4d2020-07-28 10:42:13 +0100942 {
Mike Kelly80512b02022-05-16 23:10:42 +0100943 if (m_Options.value().m_InferAndValidate)
944 {
945 BackendOptions shapeInferenceMethodOption("ShapeInferenceMethod",
946 {
947 { "InferAndValidate", true }
948 });
Sadik Armagand109a4d2020-07-28 10:42:13 +0100949
Mike Kelly80512b02022-05-16 23:10:42 +0100950 networkOptions.push_back(shapeInferenceMethodOption);
951 }
952 if (m_Options.value().m_AllowExpandedDims)
953 {
954 BackendOptions shapeInferenceMethodOption("AllowExpandedDims",
955 {
956 { "AllowExpandedDims", true }
957 });
958
959 networkOptions.push_back(shapeInferenceMethodOption);
960 }
Sadik Armagand109a4d2020-07-28 10:42:13 +0100961 }
Sadik Armagand109a4d2020-07-28 10:42:13 +0100962 m_Network = INetwork::Create(networkOptions);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100963 ARMNN_ASSERT(m_Model.get() != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +0100964
telsoa01c577f2c2018-08-31 09:22:23 +0100965 if (m_Model->subgraphs.size() != 1)
966 {
967 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100968 fmt::format("Current TfLite parser only supports 1 subgraph. Current one has: {} {}",
969 m_Model->subgraphs.size(),
970 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +0100971 }
972
973 size_t subgraphIndex = 0;
Colm Donelan6350d272020-06-09 16:56:25 +0100974 size_t operatorIndex = 0;
975 try
telsoa01c577f2c2018-08-31 09:22:23 +0100976 {
Colm Donelan6350d272020-06-09 16:56:25 +0100977 for (SubgraphPtr const& subgraph : m_Model->subgraphs)
telsoa01c577f2c2018-08-31 09:22:23 +0100978 {
Mike Kelly377fb212023-01-10 15:55:28 +0000979 SetupInputLayerTensorInfos(subgraphIndex);
980 SetupConstantLayerTensorInfos(subgraphIndex);
981
Colm Donelan6350d272020-06-09 16:56:25 +0100982 m_SubgraphConnections.emplace_back(subgraph->tensors.size());
983 for (OperatorPtr const& op : subgraph->operators)
telsoa01c577f2c2018-08-31 09:22:23 +0100984 {
Colm Donelan6350d272020-06-09 16:56:25 +0100985 auto const& opCodePtr = m_Model->operator_codes[op->opcode_index];
Jim Flynnfca233e2021-09-23 12:16:53 +0100986
987// 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 +0100988#if defined(ARMNN_POST_TFLITE_2_3)
Jim Flynnfca233e2021-09-23 12:16:53 +0100989 auto builtinCode = std::max(opCodePtr->builtin_code,
990 static_cast<tflite::BuiltinOperator>(opCodePtr->deprecated_builtin_code));
991#else
telsoa01c577f2c2018-08-31 09:22:23 +0100992 auto builtinCode = opCodePtr->builtin_code;
Jim Flynnfca233e2021-09-23 12:16:53 +0100993#endif
telsoa01c577f2c2018-08-31 09:22:23 +0100994
995 if (builtinCode > tflite::BuiltinOperator_MAX)
996 {
James Ward58dec6b2020-09-11 17:32:44 +0100997 throw ParseException(fmt::format("Operator code {} is out of range 0-{}. "
998 "subgraph:{} operator idx:{}. {}",
999 builtinCode, tflite::BuiltinOperator_MAX, subgraphIndex,
1000 operatorIndex, CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01001001 }
1002
1003 // lookup and call the parser function
Colm Donelan6350d272020-06-09 16:56:25 +01001004 auto& parserFunction = m_ParserFunctions[builtinCode];
telsoa01c577f2c2018-08-31 09:22:23 +01001005 (this->*parserFunction)(subgraphIndex, operatorIndex);
Colm Donelan6350d272020-06-09 16:56:25 +01001006 ++operatorIndex;
telsoa01c577f2c2018-08-31 09:22:23 +01001007 }
telsoa01c577f2c2018-08-31 09:22:23 +01001008
Colm Donelan6350d272020-06-09 16:56:25 +01001009 SetupInputLayers(subgraphIndex);
1010 SetupOutputLayers(subgraphIndex);
1011 SetupConstantLayers(subgraphIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001012
Colm Donelan6350d272020-06-09 16:56:25 +01001013 ++subgraphIndex;
1014 operatorIndex = 0;
telsoa01c577f2c2018-08-31 09:22:23 +01001015 }
telsoa01c577f2c2018-08-31 09:22:23 +01001016 }
Colm Donelan6350d272020-06-09 16:56:25 +01001017 catch (const ParseException& e)
telsoa01c577f2c2018-08-31 09:22:23 +01001018 {
Colm Donelan6350d272020-06-09 16:56:25 +01001019 std::stringstream errorString;
1020 errorString << "Failed to parse operator #" << operatorIndex << " within subgraph #"
1021 << subgraphIndex << " error: " << e.what();
1022 ARMNN_LOG(error) << errorString.str();
1023 std::stringstream errors;
1024 errors << errorString.str() << "\n";
telsoa01c577f2c2018-08-31 09:22:23 +01001025 throw ParseException(errors.str());
1026 }
1027
1028 // establish the connections from the layer outputs to the inputs of the subsequent layers
Colm Donelan6350d272020-06-09 16:56:25 +01001029 for (subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001030 {
1031 for (size_t tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex)
1032 {
1033 if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot != nullptr)
1034 {
1035 for (size_t inputSlotIdx = 0;
1036 inputSlotIdx < m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size();
1037 ++inputSlotIdx)
1038 {
1039 m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot->Connect(
1040 *(m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots[inputSlotIdx]));
1041 }
1042 }
1043 }
1044 }
telsoa01c577f2c2018-08-31 09:22:23 +01001045 return std::move(m_Network);
1046}
1047
Mike Kelly0506ef02023-01-03 16:29:44 +00001048bool TfLiteParserImpl::ShouldConstantTensorBeConverted(TfLiteParserImpl::TensorRawPtr tensorPtr,
1049 armnn::DataType inputDataType,
1050 armnn::DataType tensorDataType)
Mike Kelly5880b912022-01-28 16:18:54 +00001051{
Mike Kelly0506ef02023-01-03 16:29:44 +00001052 return (TfLiteParserImpl::IsConstTensor(tensorPtr) && inputDataType == DataType::Float32 &&
1053 (tensorDataType == DataType::QAsymmU8 ||
1054 tensorDataType == DataType::QAsymmS8 ||
1055 tensorDataType == DataType::QSymmS8 ||
1056 tensorDataType == DataType::Signed32 ||
1057 tensorDataType == DataType::Signed64));
Mike Kelly5880b912022-01-28 16:18:54 +00001058}
1059
Kevin May7d96b162021-02-03 17:38:41 +00001060void TfLiteParserImpl::RegisterProducerOfTensor(size_t subgraphIndex,
1061 size_t tensorIndex,
1062 armnn::IOutputSlot* slot)
telsoa01c577f2c2018-08-31 09:22:23 +01001063{
1064 CHECK_TENSOR(m_Model, subgraphIndex, tensorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001065 ARMNN_ASSERT(m_SubgraphConnections.size() > subgraphIndex);
1066 ARMNN_ASSERT(m_SubgraphConnections[subgraphIndex].size() > tensorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001067
1068 TensorSlots & tensorSlots = m_SubgraphConnections[subgraphIndex][tensorIndex];
1069
Nikhil Rajd4d1c312022-08-03 18:20:59 +01001070 if (slot->GetOwningIConnectableLayer().GetType() != LayerType::Constant)
telsoa01c577f2c2018-08-31 09:22:23 +01001071 {
telsoa01c577f2c2018-08-31 09:22:23 +01001072
Nikhil Rajd4d1c312022-08-03 18:20:59 +01001073 // assuming there is only one producer for that tensor
1074 if (tensorSlots.outputSlot != nullptr)
1075 {
1076 throw ParseException(fmt::format("Another layer has already registered itself as the producer of "
1077 "subgraph:{} tensor:{} {}",
1078 subgraphIndex,
1079 tensorIndex,
1080 CHECK_LOCATION().AsString()));
1081 }
1082 }
telsoa01c577f2c2018-08-31 09:22:23 +01001083 tensorSlots.outputSlot = slot;
1084}
1085
Kevin May7d96b162021-02-03 17:38:41 +00001086void TfLiteParserImpl::RegisterConsumerOfTensor(size_t subgraphIndex,
1087 size_t tensorIndex,
1088 armnn::IInputSlot* slot)
telsoa01c577f2c2018-08-31 09:22:23 +01001089{
1090 CHECK_TENSOR(m_Model, subgraphIndex, tensorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001091 ARMNN_ASSERT(m_SubgraphConnections.size() > subgraphIndex);
1092 ARMNN_ASSERT(m_SubgraphConnections[subgraphIndex].size() > tensorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001093
Finn Williamsd4fa5452021-03-01 12:31:41 +00001094 TensorSlots& tensorSlots = m_SubgraphConnections[subgraphIndex][tensorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01001095 tensorSlots.inputSlots.push_back(slot);
1096}
1097
Kevin May7d96b162021-02-03 17:38:41 +00001098void TfLiteParserImpl::ParseCustomOperator(size_t subgraphIndex, size_t operatorIndex)
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001099{
1100 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1101
1102 // NOTE: By default we presume the custom operator is not supported
Kevin May7d96b162021-02-03 17:38:41 +00001103 auto customParserFunction = &TfLiteParserImpl::ParseUnsupportedOperator;
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001104
1105 // Identify custom code defined for custom operator
1106 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1107 const auto& customCode = m_Model->operator_codes[operatorPtr->opcode_index]->custom_code;
1108
Mike Kelly377fb212023-01-10 15:55:28 +00001109 // Find parser function that corresponds to custom code (if any)
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001110 auto iterator = m_CustomParserFunctions.find(customCode);
1111 if (iterator != m_CustomParserFunctions.end())
1112 {
1113 customParserFunction = iterator->second;
1114 }
1115
1116 // Run parser function
1117 (this->*customParserFunction)(subgraphIndex, operatorIndex);
1118}
1119
Kevin May7d96b162021-02-03 17:38:41 +00001120void TfLiteParserImpl::ParseUnsupportedOperator(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001121{
1122 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001123
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001124 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1125
1126 auto opcodeIndex = operatorPtr->opcode_index;
Jim Flynnfca233e2021-09-23 12:16:53 +01001127
1128// 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 +01001129#if defined(ARMNN_POST_TFLITE_2_3)
Jim Flynnfca233e2021-09-23 12:16:53 +01001130 auto opcode = std::max(m_Model->operator_codes[opcodeIndex]->builtin_code,
1131 static_cast<tflite::BuiltinOperator>(m_Model->operator_codes[opcodeIndex]->deprecated_builtin_code));
1132#else
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001133 auto opcode = m_Model->operator_codes[opcodeIndex]->builtin_code;
Jim Flynnfca233e2021-09-23 12:16:53 +01001134#endif
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001135
1136 if (!m_Options || !m_Options.value().m_StandInLayerForUnsupported)
1137 {
1138 // Do not add StandInLayer, throw ParseException instead
1139 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01001140 fmt::format("Operator not supported. "
1141 "subgraph:{} operator:{} "
1142 "opcode_index:{} opcode:{} / {} {}",
1143 subgraphIndex,
1144 operatorIndex,
1145 opcodeIndex,
1146 opcode,
1147 tflite::EnumNameBuiltinOperator(opcode),
1148 CHECK_LOCATION().AsString()));
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001149 }
1150
1151 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1152 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1153
Matthew Sloyan589e3e82020-09-11 16:17:48 +01001154 const unsigned int numInputs = armnn::numeric_cast<unsigned int>(inputs.size());
1155 const unsigned int numOutputs = armnn::numeric_cast<unsigned int>(outputs.size());
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001156
1157 StandInDescriptor descriptor(numInputs, numOutputs);
James Ward58dec6b2020-09-11 17:32:44 +01001158 auto layerName = fmt::format("StandIn:{}:{}:{}", subgraphIndex, operatorIndex, opcode);
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001159
1160 // Add a non-executable StandInLayer as a placeholder for any unsupported operator
1161 IConnectableLayer* layer = m_Network->AddStandInLayer(descriptor, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01001162 ARMNN_ASSERT(layer != nullptr);
1163
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001164 for (unsigned int i = 0u; i < numOutputs; ++i)
1165 {
Mike Kelly377fb212023-01-10 15:55:28 +00001166 layer->GetOutputSlot(i).SetTensorInfo(OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, i, {}));
Aron Virginas-Tarc975f922019-10-23 17:38:17 +01001167 }
1168
1169 auto inputTensorIds = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1170 auto outputTensorIds = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1171
1172 RegisterInputSlots(subgraphIndex, operatorIndex, layer, inputTensorIds);
1173 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIds);
telsoa01c577f2c2018-08-31 09:22:23 +01001174}
1175
mathad01b392e982021-04-07 12:07:30 +01001176void TfLiteParserImpl::ParseCast(size_t subgraphIndex, size_t operatorIndex)
1177{
1178 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1179
1180 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1181 CHECK_VALID_SIZE(inputs.size(), 1);
1182 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1183 CHECK_VALID_SIZE(outputs.size(), 1);
1184
1185 auto layerName = fmt::format("Cast:{}:{}", subgraphIndex, operatorIndex);
1186
1187 IConnectableLayer* layer = m_Network->AddCastLayer(layerName.c_str());
1188 ARMNN_ASSERT(layer != nullptr);
1189
Mike Kelly377fb212023-01-10 15:55:28 +00001190 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
mathad01b392e982021-04-07 12:07:30 +01001191 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1192
1193 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1194 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1195
1196 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1197 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
1198}
1199
Kevin May7d96b162021-02-03 17:38:41 +00001200void TfLiteParserImpl::ParseConv2D(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001201{
1202 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1203
Mike Kelly0d77ae12022-01-07 17:42:27 +00001204 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1205 const auto* options = operatorPtr->builtin_options.AsConv2DOptions();
telsoa01c577f2c2018-08-31 09:22:23 +01001206
1207 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1208
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001209 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1210 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1211 CHECK_VALID_SIZE(outputs.size(), 1);
1212
telsoa01c577f2c2018-08-31 09:22:23 +01001213 Convolution2dDescriptor desc;
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001214 inputs.size() == 3 ?
1215 desc.m_BiasEnabled = true : desc.m_BiasEnabled = false;
telsoa01c577f2c2018-08-31 09:22:23 +01001216 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1217 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
jimfly01c25411c2018-11-14 17:47:22 +00001218 desc.m_DataLayout = armnn::DataLayout::NHWC;
Pablo Tellof0bd6832019-04-26 17:58:13 +01001219 desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
1220 desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
Kevin May83add212019-03-26 11:39:19 +00001221
Mike Kelly377fb212023-01-10 15:55:28 +00001222 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1223 armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
telsoa01c577f2c2018-08-31 09:22:23 +01001224
1225 // assuming input is NHWC
1226 unsigned int inputHeight = inputTensorInfo.GetShape()[1];
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001227 unsigned int inputWidth = inputTensorInfo.GetShape()[2];
telsoa01c577f2c2018-08-31 09:22:23 +01001228
1229 // assuming the filter is OHWI : Output, H, W, Input
1230 // which is essentially the same as NHWC
1231 unsigned int filterHeight = filterTensorInfo.GetShape()[1];
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001232 unsigned int filterWidth = filterTensorInfo.GetShape()[2];
telsoa01c577f2c2018-08-31 09:22:23 +01001233
Pablo Tellof0bd6832019-04-26 17:58:13 +01001234 CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
1235 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
1236 CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
1237 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
telsoa01c577f2c2018-08-31 09:22:23 +01001238
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001239 // Add the first input and weights tensor to the registration list.
1240 // The constant weights will be added by SetupConstantLayers.
1241 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1242 std::vector<unsigned int> tensorIndexesToRegister = { inputTensorIndexes[0], inputTensorIndexes[1] };
telsoa01c577f2c2018-08-31 09:22:23 +01001243
James Ward58dec6b2020-09-11 17:32:44 +01001244 auto layerName = fmt::format("Conv2D:{}:{}", subgraphIndex, operatorIndex);
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001245 armnn::IConnectableLayer* layer = m_Network->AddConvolution2dLayer(desc, layerName.c_str());
telsoa01c577f2c2018-08-31 09:22:23 +01001246
Mike Kelly0506ef02023-01-03 16:29:44 +00001247 if (ShouldConstantTensorBeConverted(inputs[1], inputTensorInfo.GetDataType(), filterTensorInfo.GetDataType()))
telsoa01c577f2c2018-08-31 09:22:23 +01001248 {
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001249 m_ConstantsToDequantize.emplace_back(inputs[1]->buffer);
telsoa01c577f2c2018-08-31 09:22:23 +01001250 }
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001251
1252 if (desc.m_BiasEnabled)
telsoa01c577f2c2018-08-31 09:22:23 +01001253 {
Mike Kelly377fb212023-01-10 15:55:28 +00001254 armnn::TensorInfo biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001255
1256 // Add the biases input to the registration list, a constant layer will be added by SetupConstantLayers.
1257 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
1258
Mike Kelly0506ef02023-01-03 16:29:44 +00001259 if (ShouldConstantTensorBeConverted(inputs[2], inputTensorInfo.GetDataType(), biasTensorInfo.GetDataType()))
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001260 {
1261 m_ConstantsToDequantize.emplace_back(inputs[2]->buffer);
1262 }
telsoa01c577f2c2018-08-31 09:22:23 +01001263 }
1264
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001265 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01001266
Mike Kelly377fb212023-01-10 15:55:28 +00001267 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
jimfly01c25411c2018-11-14 17:47:22 +00001268 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +01001269
1270 // register the input connection slots for the layer, connections are made after all layers have been created
1271 // only the tensors for the inputs are relevant, exclude the const tensors
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001272 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister);
telsoa01c577f2c2018-08-31 09:22:23 +01001273
jimfly01c25411c2018-11-14 17:47:22 +00001274 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
telsoa01c577f2c2018-08-31 09:22:23 +01001275 // register the output connection slots for the layer, connections are made after all layers have been created
1276 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
Keith Davisb4dd5cc2022-04-07 11:32:00 +01001277 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, { outputTensorIndexes[0] });
telsoa01c577f2c2018-08-31 09:22:23 +01001278}
1279
Matthew Sloyan4d217c02021-10-07 11:48:58 +01001280// Conv3D support was added in TF 2.5, so for backwards compatibility a hash define is needed.
Cathal Corbett80b4ef02022-05-25 11:21:11 +01001281#if defined(ARMNN_POST_TFLITE_2_4)
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001282void TfLiteParserImpl::ParseConv3D(size_t subgraphIndex, size_t operatorIndex)
1283{
1284 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1285
1286 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1287 const auto* options = operatorPtr->builtin_options.AsConv3DOptions();
1288
1289 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1290
1291 Convolution3dDescriptor desc;
1292 desc.m_BiasEnabled = false;
1293 desc.m_DataLayout = armnn::DataLayout::NDHWC;
1294 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1295 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1296 desc.m_StrideZ = CHECKED_NON_NEGATIVE(options->stride_d);
1297 desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
1298 desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
1299 desc.m_DilationZ = CHECKED_NON_NEGATIVE(options->dilation_d_factor);
1300
1301 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1302 CHECK_VALID_SIZE(inputs.size(), 2, 3);
1303
1304 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1305 CHECK_VALID_SIZE(outputs.size(), 1);
1306
Mike Kelly377fb212023-01-10 15:55:28 +00001307 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1308 armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001309
1310 // Assuming input is NDHWC
1311 unsigned int inputDepth = inputTensorInfo.GetShape()[1];
1312 unsigned int inputHeight = inputTensorInfo.GetShape()[2];
1313 unsigned int inputWidth = inputTensorInfo.GetShape()[3];
1314
1315 // Assuming the filter is DHWIO : Depth, Height, Width, OutputChannels, InputChannels
1316 unsigned int filterDepth = filterTensorInfo.GetShape()[0];
1317 unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1318 unsigned int filterWidth = filterTensorInfo.GetShape()[2];
1319
1320 CalcPadding(inputDepth, filterDepth, desc.m_StrideZ,
Teresa Charlin502ab942022-03-23 17:23:07 +00001321 desc.m_DilationZ, desc.m_PadFront, desc.m_PadBack, options->padding);
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001322 CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
1323 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
1324 CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
1325 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
1326
Mike Kelly5880b912022-01-28 16:18:54 +00001327 auto filterTensorAndData = CreateConstTensorNonPermuted(inputs[1], filterTensorInfo, inputTensorInfo.GetDataType());
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001328
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001329 auto layerName = fmt::format("Conv3D:{}:{}", subgraphIndex, operatorIndex);
1330
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001331 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1332 // Add the first input and weights tensor to the registration list.
1333 // The constant weights will be added by SetupConstantLayers.
1334 std::vector<unsigned int> tensorIndexesToRegister = {inputTensorIndexes[0], inputTensorIndexes[1]};
1335
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001336 if (inputs.size() == 3)
1337 {
1338 desc.m_BiasEnabled = true;
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001339
1340 // Add the biases input to the registration list, a constant layer will be added by SetupConstantLayers.
1341 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001342 }
1343
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001344 armnn::IConnectableLayer* layer = m_Network->AddConvolution3dLayer(desc, layerName.c_str());
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001345 ARMNN_ASSERT(layer != nullptr);
1346
Mike Kelly377fb212023-01-10 15:55:28 +00001347 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001348 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1349
1350 // Register the input connection slots for the layer, connections are made after all layers have been created
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001351 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister);
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001352
1353 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
1354 // Register the output connection slots for the layer, connections are made after all layers have been created
1355 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1356 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1357}
Matthew Sloyan4d217c02021-10-07 11:48:58 +01001358#endif
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001359
Kevin May7d96b162021-02-03 17:38:41 +00001360void TfLiteParserImpl::ParseDepthwiseConv2D(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001361{
1362 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1363
Mike Kelly0d77ae12022-01-07 17:42:27 +00001364 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1365 const auto* options = operatorPtr->builtin_options.AsDepthwiseConv2DOptions();
telsoa01c577f2c2018-08-31 09:22:23 +01001366
1367 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1368
1369 DepthwiseConvolution2dDescriptor desc;
telsoa01c577f2c2018-08-31 09:22:23 +01001370 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1371 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
jimfly01c25411c2018-11-14 17:47:22 +00001372 desc.m_DataLayout = armnn::DataLayout::NHWC;
Matthew Jacksond6a9dee2019-07-22 13:53:24 +01001373 CHECKED_NON_NEGATIVE(options->depth_multiplier);
telsoa01c577f2c2018-08-31 09:22:23 +01001374
1375 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1376 CHECK_VALID_SIZE(inputs.size(), 2, 3);
Cathal Corbett06902652022-04-14 17:55:11 +01001377 if (inputs.size() == 3)
1378 {
1379 desc.m_BiasEnabled = true;
1380 }
1381
telsoa01c577f2c2018-08-31 09:22:23 +01001382 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1383 CHECK_VALID_SIZE(outputs.size(), 1);
Pablo Tellof0bd6832019-04-26 17:58:13 +01001384 desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
1385 desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
Kevin May83add212019-03-26 11:39:19 +00001386
Mike Kelly377fb212023-01-10 15:55:28 +00001387 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1388 armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
telsoa01c577f2c2018-08-31 09:22:23 +01001389
Matteo Martincigh747ef822018-12-18 09:26:39 +00001390 // Assuming input is NHWC
telsoa01c577f2c2018-08-31 09:22:23 +01001391 unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1392 unsigned int inputWidth = inputTensorInfo.GetShape()[2];
Matteo Martincigh747ef822018-12-18 09:26:39 +00001393
1394 // TensorflowLite weights come in the format [1, H, W, I * M]
telsoa01c577f2c2018-08-31 09:22:23 +01001395 unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1396 unsigned int filterWidth = filterTensorInfo.GetShape()[2];
1397
Pablo Tellof0bd6832019-04-26 17:58:13 +01001398 CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
1399 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
1400 CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
1401 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
telsoa01c577f2c2018-08-31 09:22:23 +01001402
Jan Eilers53ef7952021-06-02 12:01:25 +01001403 // 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 +01001404 auto layerName = fmt::format("DepthwiseConv2D:{}:{}", subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001405
Cathal Corbett06902652022-04-14 17:55:11 +01001406 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1407 // Add the first input and weights tensor to the registration list.
1408 // The constant weights will be added by SetupConstantLayers.
1409 std::vector<unsigned int> tensorIndexesToRegister = {inputTensorIndexes[0], inputTensorIndexes[1]};
1410
1411 armnn::IConnectableLayer* layer = m_Network->AddDepthwiseConvolution2dLayer(desc, layerName.c_str());
1412
1413 if (desc.m_BiasEnabled)
telsoa01c577f2c2018-08-31 09:22:23 +01001414 {
1415 desc.m_BiasEnabled = true;
Mike Kelly377fb212023-01-10 15:55:28 +00001416 TensorInfo biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Cathal Corbett06902652022-04-14 17:55:11 +01001417
1418 // Add the biases input to the registration list, a constant layer will be added by SetupConstantLayers.
1419 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
telsoa01c577f2c2018-08-31 09:22:23 +01001420 }
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001421 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01001422
Mike Kelly377fb212023-01-10 15:55:28 +00001423 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
jimfly01c25411c2018-11-14 17:47:22 +00001424 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +01001425
1426 // register the input connection slots for the layer, connections are made after all layers have been created
1427 // only the tensors for the inputs are relevant, exclude the const tensors
Cathal Corbett06902652022-04-14 17:55:11 +01001428 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister);
telsoa01c577f2c2018-08-31 09:22:23 +01001429
jimfly01c25411c2018-11-14 17:47:22 +00001430 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
telsoa01c577f2c2018-08-31 09:22:23 +01001431 // register the output connection slots for the layer, connections are made after all layers have been created
1432 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1433 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1434}
1435
Kevin May7d96b162021-02-03 17:38:41 +00001436void TfLiteParserImpl::ParseDequantize(size_t subgraphIndex, size_t operatorIndex)
Finn Williamsed66d142019-12-06 09:55:55 +00001437{
1438 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1439
1440 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1441 CHECK_VALID_SIZE(inputs.size(), 1);
1442
1443 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1444 CHECK_VALID_SIZE(outputs.size(), 1);
1445
James Ward58dec6b2020-09-11 17:32:44 +01001446 auto layerName = fmt::format("Dequantize:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsed66d142019-12-06 09:55:55 +00001447
1448 IConnectableLayer* layer = m_Network->AddDequantizeLayer(layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001449 ARMNN_ASSERT(layer != nullptr);
Finn Williamsed66d142019-12-06 09:55:55 +00001450
Mike Kelly377fb212023-01-10 15:55:28 +00001451 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Finn Williamsed66d142019-12-06 09:55:55 +00001452 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1453
1454 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1455 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1456
1457 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1458 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
1459}
1460
Teresa Charlin3ab85482021-06-08 16:59:29 +01001461void TfLiteParserImpl::ParseExpandDims(size_t subgraphIndex, size_t operatorIndex)
1462{
1463 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1464
1465 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1466 CHECK_VALID_SIZE(inputs.size(), 2);
1467
1468 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1469 CHECK_VALID_SIZE(outputs.size(), 1);
1470
1471 auto layerName = fmt::format("ExpandDims:{}:{}", subgraphIndex, operatorIndex);
1472
Mike Kelly377fb212023-01-10 15:55:28 +00001473 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Teresa Charlin3ab85482021-06-08 16:59:29 +01001474 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1475
1476 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1477
1478 ReshapeDescriptor reshapeDesc;
Finn Williamsb49ed182021-06-29 15:50:08 +01001479
1480 if (outputTensorInfo.GetShape().AreAllDimensionsSpecified())
1481 {
1482 reshapeDesc.m_TargetShape = outputTensorInfo.GetShape();
1483 }
1484 else
1485 {
1486 int32_t axis = inputs[1]->shape[0];
1487
1488 int32_t inputDimSize = static_cast<int32_t>(inputTensorInfo.GetShape().GetNumDimensions());
1489
1490 if (axis > inputDimSize || axis < 0 - (inputDimSize + 1))
1491 {
1492 throw ParseException("axis must be in range [0 - (inputDimSize + 1), inputDimSize] inclusive");
1493 }
1494
1495 if(axis < 0)
1496 {
1497 axis = inputDimSize + axis + 1;
1498 }
1499
Rob Hughesd812a312021-08-06 13:10:53 +01001500 std::vector<unsigned int> shape(static_cast<unsigned int>(inputDimSize) + 1);
Finn Williamsb49ed182021-06-29 15:50:08 +01001501 unsigned int inputShapeIndex = 0;
1502 for (unsigned int i = 0; i < static_cast<unsigned int>(inputDimSize + 1); ++i)
1503 {
1504 if (i == static_cast<unsigned int>(axis))
1505 {
1506 shape[i] = 1;
1507 }
1508 else
1509 {
1510 shape[i] = inputTensorInfo.GetShape()[inputShapeIndex];
1511 ++inputShapeIndex;
1512 }
1513 }
1514
Rob Hughesd812a312021-08-06 13:10:53 +01001515 reshapeDesc.m_TargetShape = TensorShape(static_cast<unsigned int>(inputDimSize + 1), shape.data());
Finn Williamsb49ed182021-06-29 15:50:08 +01001516 }
Teresa Charlin3ab85482021-06-08 16:59:29 +01001517
1518 IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
1519 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00001520
1521 reshapeDesc.m_TargetShape = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0}).GetShape();
1522 outputTensorInfo.SetShape(reshapeDesc.m_TargetShape);
1523
Teresa Charlin3ab85482021-06-08 16:59:29 +01001524 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1525
1526 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1527 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1528
1529 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1530 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1531}
1532
Kevin May7d96b162021-02-03 17:38:41 +00001533void TfLiteParserImpl::ParseTranspose(size_t subgraphIndex, size_t operatorIndex)
Keith Davis4cd29a02019-09-09 14:49:20 +01001534{
1535 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1536
1537 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Kevin May85d92602019-09-27 17:21:06 +01001538 CHECK_VALID_SIZE(inputs.size(), 1, 2);
Keith Davis4cd29a02019-09-09 14:49:20 +01001539
1540 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1541 CHECK_VALID_SIZE(outputs.size(), 1);
1542
James Ward58dec6b2020-09-11 17:32:44 +01001543 auto layerName = fmt::format("Transpose:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly08759e22020-03-02 11:41:31 +00001544 TransposeDescriptor desc;
Keith Davis4cd29a02019-09-09 14:49:20 +01001545
josh minorba424d22019-11-13 10:55:17 -06001546 if (inputs.size() == 2)
Kevin May85d92602019-09-27 17:21:06 +01001547 {
Mike Kelly377fb212023-01-10 15:55:28 +00001548 armnn::TensorInfo permuteTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Kevin May85d92602019-09-27 17:21:06 +01001549 BufferRawPtr permuteBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
josh minorba424d22019-11-13 10:55:17 -06001550 auto numPermVecElements = permuteTensorInfo.GetNumElements();
1551 std::vector<unsigned int> permuteShape(numPermVecElements);
Kevin May85d92602019-09-27 17:21:06 +01001552 ::memcpy(permuteShape.data(), permuteBufferPtr->data.data(), permuteTensorInfo.GetNumBytes());
Mike Kelly08759e22020-03-02 11:41:31 +00001553 PermutationVector permutationVector(permuteShape.data(), permuteTensorInfo.GetNumElements());
Kevin May85d92602019-09-27 17:21:06 +01001554
Mike Kelly08759e22020-03-02 11:41:31 +00001555 desc = TransposeDescriptor(permutationVector);
Kevin May85d92602019-09-27 17:21:06 +01001556 }
Mike Kelly377fb212023-01-10 15:55:28 +00001557 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Keith Davis4cd29a02019-09-09 14:49:20 +01001558
James Conroy05102392020-06-24 15:39:55 +01001559 IConnectableLayer* layer = m_Network->AddTransposeLayer(desc, layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001560 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00001561
1562 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
1563 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Keith Davis4cd29a02019-09-09 14:49:20 +01001564 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1565
1566 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1567 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1568
1569 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1570 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1571}
1572
Kevin May7d96b162021-02-03 17:38:41 +00001573void TfLiteParserImpl::ParseTransposeConv(size_t subgraphIndex, size_t operatorIndex)
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001574{
1575 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1576
Mike Kelly0d77ae12022-01-07 17:42:27 +00001577 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1578 const auto* options = operatorPtr->builtin_options.AsTransposeConvOptions();
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001579
1580 TransposeConvolution2dDescriptor desc;
1581 desc.m_BiasEnabled = false;
1582 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1583 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1584 desc.m_DataLayout = armnn::DataLayout::NHWC;
1585
1586 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
David Monahan61683802021-01-12 09:11:07 +00001587 if (inputs.size() == 4)
1588 {
1589 desc.m_BiasEnabled = true;
1590 }
1591 else
1592 {
1593 CHECK_VALID_SIZE(inputs.size(), 3);
1594 }
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001595
1596 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1597 CHECK_VALID_SIZE(outputs.size(), 1);
1598
Colm Donelan0ad3ef12020-07-03 15:54:28 +01001599 if (inputs[0])
1600 {
Mike Kelly377fb212023-01-10 15:55:28 +00001601 armnn::TensorInfo tensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Colm Donelan0ad3ef12020-07-03 15:54:28 +01001602 std::vector<int> output_shape(tensorInfo.GetNumElements());
Mike Kelly377fb212023-01-10 15:55:28 +00001603
Colm Donelan0ad3ef12020-07-03 15:54:28 +01001604 if (tensorInfo.GetDataType() == DataType::Signed32)
1605 {
1606 ::memcpy(output_shape.data(), GetBuffer(m_Model, inputs[0]->buffer)->data.data(), tensorInfo.GetNumBytes());
1607 }
1608 if (tensorInfo.GetDataType() == DataType::QAsymmU8)
1609 {
1610 for(unsigned int i=0; i < tensorInfo.GetNumElements(); i++)
1611 {
1612 output_shape[i] = GetBuffer(m_Model, inputs[0]->buffer)->data.data()[i];
1613 }
1614 }
1615 // Change from signed to unsigned int to store in TransposeConvolution2dDescriptor.
1616 for (int dimension : output_shape)
1617 {
1618 desc.m_OutputShape.push_back(static_cast<unsigned int>(dimension));
1619 }
1620 desc.m_OutputShapeEnabled = true;
1621 }
Mike Kelly377fb212023-01-10 15:55:28 +00001622 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
1623 armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001624
1625 // TfLite uses NHWC tensors
1626 const unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1627 const unsigned int inputWidth = inputTensorInfo.GetShape()[2];
1628
1629 const unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1630 const unsigned int filterWidth = filterTensorInfo.GetShape()[2];
1631
1632 CalcPadding(inputHeight,
1633 filterHeight,
1634 desc.m_StrideY,
1635 1, // DilationY
1636 desc.m_PadTop,
1637 desc.m_PadBottom,
1638 options->padding);
1639
1640 CalcPadding(inputWidth,
1641 filterWidth,
1642 desc.m_StrideX,
1643 1, // DilationX
1644 desc.m_PadLeft,
1645 desc.m_PadRight,
1646 options->padding);
1647
Mike Kelly5880b912022-01-28 16:18:54 +00001648 auto filterTensorAndData = CreateConstTensorNonPermuted(inputs[1], filterTensorInfo, inputTensorInfo.GetDataType());
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001649
1650 armnn::IConnectableLayer* layer = nullptr;
James Ward58dec6b2020-09-11 17:32:44 +01001651 auto layerName = fmt::format("TransposeConv:{}:{}", subgraphIndex, operatorIndex);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001652
David Monahan61683802021-01-12 09:11:07 +00001653 if (desc.m_BiasEnabled)
1654 {
Mike Kelly377fb212023-01-10 15:55:28 +00001655 auto biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 3);
Mike Kelly5880b912022-01-28 16:18:54 +00001656 auto biasConstTensor = CreateConstTensorNonPermuted(inputs[3], biasTensorInfo, inputTensorInfo.GetDataType());
David Monahan61683802021-01-12 09:11:07 +00001657 layer = m_Network->AddTransposeConvolution2dLayer(desc,
Mike Kelly5880b912022-01-28 16:18:54 +00001658 filterTensorAndData.first,
1659 biasConstTensor.first,
David Monahan61683802021-01-12 09:11:07 +00001660 layerName.c_str());
1661 }
1662 else
1663 {
1664 layer = m_Network->AddTransposeConvolution2dLayer(desc,
Mike Kelly5880b912022-01-28 16:18:54 +00001665 filterTensorAndData.first,
David Monahan61683802021-01-12 09:11:07 +00001666 EmptyOptional(),
1667 layerName.c_str());
1668 }
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001669
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001670 ARMNN_ASSERT(layer != nullptr);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001671
Mike Kelly377fb212023-01-10 15:55:28 +00001672 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0 , { 2, 1 });
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001673 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1674
1675 // only the tensors for the inputs are relevant, exclude the const (filter) tensor
1676 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Matthew Jacksonccb25ea2019-08-20 17:18:33 +01001677 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[2]});
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001678
1679 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1680 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1681}
1682
Kevin May7d96b162021-02-03 17:38:41 +00001683void TfLiteParserImpl::ParseAveragePool2D(size_t subgraphIndex, size_t operatorIndex)
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001684{
1685 ParsePool(subgraphIndex, operatorIndex, PoolingAlgorithm::Average);
1686}
1687
Samuel Yapfd3ba5a2022-08-24 17:04:34 +01001688void TfLiteParserImpl::ParseBatchMatMul(size_t subgraphIndex, size_t operatorIndex)
1689{
1690 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1691
1692 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1693 CHECK_VALID_SIZE(inputs.size(), 2);
1694
1695 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1696 CHECK_VALID_SIZE(outputs.size(), 1);
1697
1698 auto layerName = fmt::format("BatchMatMul:{}:{}", subgraphIndex, operatorIndex);
1699
Mike Kelly377fb212023-01-10 15:55:28 +00001700 TensorInfo inputXTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1701 TensorInfo inputYTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Samuel Yapfd3ba5a2022-08-24 17:04:34 +01001702
1703 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1704 const auto* options = operatorPtr->builtin_options.AsBatchMatMulOptions();
1705
Teresa Charlinbc37a6b2022-09-22 10:12:58 +01001706 // Adjoint in tensorflow lite performs transpose operation
1707 BatchMatMulDescriptor descriptor(options->adj_x,
1708 options->adj_y,
Samuel Yapfd3ba5a2022-08-24 17:04:34 +01001709 false,
Teresa Charlinbc37a6b2022-09-22 10:12:58 +01001710 false);
Samuel Yapfd3ba5a2022-08-24 17:04:34 +01001711 // Arbitrary DataLayout
1712
1713 IConnectableLayer* layer = m_Network->AddBatchMatMulLayer(descriptor, layerName.c_str());
1714 ARMNN_ASSERT(layer != nullptr);
1715
Mike Kelly377fb212023-01-10 15:55:28 +00001716 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Samuel Yapfd3ba5a2022-08-24 17:04:34 +01001717 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1718
1719 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1720 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
1721
1722 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1723 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1724}
1725
Kevin May7d96b162021-02-03 17:38:41 +00001726void TfLiteParserImpl::ParseBatchToSpaceND(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001727{
1728 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1729
1730 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1731 CHECK_VALID_SIZE(inputs.size(), 3);
1732
1733 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1734 CHECK_VALID_SIZE(outputs.size(), 1);
1735
Mike Kelly377fb212023-01-10 15:55:28 +00001736 armnn::TensorInfo blockShapeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001737 BufferRawPtr blockShapeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1738
Mike Kelly377fb212023-01-10 15:55:28 +00001739 armnn::TensorInfo cropsTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001740 BufferRawPtr cropsBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
1741
1742 std::vector<unsigned int> blockShape(blockShapeTensorInfo.GetNumElements());
1743 ::memcpy(blockShape.data(), blockShapeBufferPtr->data.data(), blockShapeTensorInfo.GetNumBytes());
1744
1745 std::vector<unsigned int> cropsVector(cropsTensorInfo.GetNumElements());
1746 ::memcpy(cropsVector.data(), cropsBufferPtr->data.data(), cropsTensorInfo.GetNumBytes());
1747
1748 size_t step = 2;
1749 std::vector<std::pair<unsigned int, unsigned int>> crops;
1750 for (unsigned int i = 0; i < cropsTensorInfo.GetNumElements() / step; ++i)
1751 {
1752 crops.emplace_back(cropsVector[i * step], cropsVector[i * step + 1]);
1753 }
1754
1755 armnn::BatchToSpaceNdDescriptor desc;
1756 desc.m_BlockShape = blockShape;
1757 desc.m_Crops = crops;
1758 desc.m_DataLayout = armnn::DataLayout::NHWC;
1759
James Ward58dec6b2020-09-11 17:32:44 +01001760 auto layerName = fmt::format("BatchToSpaceND:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001761
Mike Kelly377fb212023-01-10 15:55:28 +00001762 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
James Conroy05102392020-06-24 15:39:55 +01001763
1764 IConnectableLayer* layer = m_Network->AddBatchToSpaceNdLayer(desc, layerName.c_str());
1765 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00001766
1767 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
1768 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001769 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1770
1771 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1772 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1773
1774 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1775 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1776}
1777
Kevin May7d96b162021-02-03 17:38:41 +00001778void TfLiteParserImpl::ParseL2Normalization(size_t subgraphIndex, size_t operatorIndex)
Matthew Jackson28c94572019-07-18 10:47:03 +01001779{
1780 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1781
1782 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1783 CHECK_VALID_SIZE(inputs.size(), 1);
1784
1785 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1786 CHECK_VALID_SIZE(outputs.size(), 1);
1787
1788 L2NormalizationDescriptor desc;
1789 desc.m_DataLayout = armnn::DataLayout::NHWC;
James Ward58dec6b2020-09-11 17:32:44 +01001790 auto layerName = fmt::format("L2Normalization:{}:{}", subgraphIndex, operatorIndex);
Matthew Jackson28c94572019-07-18 10:47:03 +01001791 IConnectableLayer* layer = m_Network->AddL2NormalizationLayer(desc, layerName.c_str());
1792
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001793 ARMNN_ASSERT(layer != nullptr);
Matthew Jackson28c94572019-07-18 10:47:03 +01001794
Mike Kelly377fb212023-01-10 15:55:28 +00001795 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Matthew Jackson28c94572019-07-18 10:47:03 +01001796 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1797
1798 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1799 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1800
1801 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1802 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1803}
1804
Kevin May7d96b162021-02-03 17:38:41 +00001805void TfLiteParserImpl::ParseMaxPool2D(size_t subgraphIndex, size_t operatorIndex)
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001806{
1807 ParsePool(subgraphIndex, operatorIndex, PoolingAlgorithm::Max);
1808}
1809
Kevin May7d96b162021-02-03 17:38:41 +00001810void TfLiteParserImpl::ParseMaximum(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001811{
1812 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1813
1814 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1815 CHECK_VALID_SIZE(inputs.size(), 2);
1816
1817 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1818 CHECK_VALID_SIZE(outputs.size(), 1);
1819
James Ward58dec6b2020-09-11 17:32:44 +01001820 auto layerName = fmt::format("Maximum:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01001821
Mike Kelly377fb212023-01-10 15:55:28 +00001822 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1823 TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
James Conroy05102392020-06-24 15:39:55 +01001824 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001825
James Conroy05102392020-06-24 15:39:55 +01001826 IConnectableLayer* layer = m_Network->AddMaximumLayer(layerName.c_str());
1827 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00001828
1829 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
1830 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001831 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1832
1833 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01001834 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001835
1836 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1837 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1838}
1839
Kevin May7d96b162021-02-03 17:38:41 +00001840void TfLiteParserImpl::ParseMinimum(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001841{
1842 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1843
1844 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1845 CHECK_VALID_SIZE(inputs.size(), 2);
1846
1847 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1848 CHECK_VALID_SIZE(outputs.size(), 1);
1849
James Ward58dec6b2020-09-11 17:32:44 +01001850 auto layerName = fmt::format("Minimum:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01001851
Mike Kelly377fb212023-01-10 15:55:28 +00001852 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
1853 TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
James Conroy05102392020-06-24 15:39:55 +01001854 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001855
James Conroy05102392020-06-24 15:39:55 +01001856 IConnectableLayer* layer = m_Network->AddMinimumLayer(layerName.c_str());
1857 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00001858
1859 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
1860 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001861 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1862
1863 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01001864 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001865
1866 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1867 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1868}
1869
Kevin May7d96b162021-02-03 17:38:41 +00001870void TfLiteParserImpl::ParsePool(size_t subgraphIndex,
1871 size_t operatorIndex,
1872 PoolingAlgorithm algorithm)
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001873{
1874 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1875
Mike Kelly0d77ae12022-01-07 17:42:27 +00001876 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1877 const auto* options = operatorPtr->builtin_options.AsPool2DOptions();
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001878
1879 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1880
1881 std::string layerName;
1882
1883 switch (algorithm)
1884 {
1885 case PoolingAlgorithm::Average:
1886 layerName =
James Ward58dec6b2020-09-11 17:32:44 +01001887 fmt::format("AveragePool2D:{}:{}", subgraphIndex, operatorIndex);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001888 break;
1889 case PoolingAlgorithm::Max:
1890 layerName =
James Ward58dec6b2020-09-11 17:32:44 +01001891 fmt::format("MaxPool2D:{}:{}", subgraphIndex, operatorIndex);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001892 break;
1893 default:
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001894 ARMNN_ASSERT_MSG(false, "Unsupported Pooling Algorithm");
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001895 }
1896
1897 Pooling2dDescriptor desc;
1898
1899 desc.m_PoolType = algorithm;
1900 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1901 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1902 desc.m_PoolWidth = CHECKED_NON_NEGATIVE(options->filter_width);
1903 desc.m_PoolHeight = CHECKED_NON_NEGATIVE(options->filter_height);
1904 desc.m_PaddingMethod = PaddingMethod::Exclude;
1905 desc.m_OutputShapeRounding = OutputShapeRounding::Floor;
jimfly01c25411c2018-11-14 17:47:22 +00001906 desc.m_DataLayout = armnn::DataLayout::NHWC;
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001907
1908 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1909 CHECK_VALID_SIZE(inputs.size(), 1);
Mike Kelly377fb212023-01-10 15:55:28 +00001910 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001911
1912 // assuming input is NHWC
1913 unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1914 unsigned int inputWidth = inputTensorInfo.GetShape()[2];
1915
Pablo Tellof0bd6832019-04-26 17:58:13 +01001916 CalcPadding(inputHeight, desc.m_PoolHeight, desc.m_StrideY, 1u,
1917 desc.m_PadTop, desc.m_PadBottom, options->padding);
1918 CalcPadding(inputWidth, desc.m_PoolWidth, desc.m_StrideX, 1u,
1919 desc.m_PadLeft, desc.m_PadRight, options->padding);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001920
1921 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1922 CHECK_VALID_SIZE(outputs.size(), 1);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001923
James Conroy05102392020-06-24 15:39:55 +01001924 IConnectableLayer* layer = m_Network->AddPooling2dLayer(desc, layerName.c_str());
1925 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00001926
1927 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
1928 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
jimfly01c25411c2018-11-14 17:47:22 +00001929 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001930
1931 // register the input connection slots for the layer, connections are made after all layers have been created
1932 // only the tensors for the inputs are relevant, exclude the const tensors
1933 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
jimfly01c25411c2018-11-14 17:47:22 +00001934 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001935
jimfly01c25411c2018-11-14 17:47:22 +00001936 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001937 // register the output connection slots for the layer, connections are made after all layers have been created
1938 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1939 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1940}
1941
Kevin May7d96b162021-02-03 17:38:41 +00001942void TfLiteParserImpl::ParseSlice(size_t subgraphIndex, size_t operatorIndex)
josh minorba424d22019-11-13 10:55:17 -06001943{
1944 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1945
1946 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1947 CHECK_VALID_SIZE(inputs.size(), 3);
1948 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1949 CHECK_VALID_SIZE(outputs.size(), 1);
1950
1951 SliceDescriptor desc;
1952
1953 // set begin tensor info for slice descriptor
Mike Kelly377fb212023-01-10 15:55:28 +00001954 armnn::TensorInfo beginTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
josh minorba424d22019-11-13 10:55:17 -06001955 BufferRawPtr beginBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1956
1957 std::vector<unsigned int> begin(beginTensorInfo.GetNumElements());
1958 ::memcpy(begin.data(), beginBufferPtr->data.data(), beginTensorInfo.GetNumBytes());
1959
1960 // set size tensor info for slice descriptor
Mike Kelly377fb212023-01-10 15:55:28 +00001961 armnn::TensorInfo sizeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
josh minorba424d22019-11-13 10:55:17 -06001962 BufferRawPtr sizeBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
1963
Cathal Corbettde33dda2022-09-20 16:40:09 +01001964 std::vector<int> signedSize(sizeTensorInfo.GetNumElements(), 1);
1965
1966 // if size buffer data is not specified, all contents of size vector remain as values of 1
1967 if (sizeBufferPtr->data.data())
1968 {
1969 ::memcpy(signedSize.data(), sizeBufferPtr->data.data(), sizeTensorInfo.GetNumBytes());
1970 }
1971
josh minorba424d22019-11-13 10:55:17 -06001972 std::vector<unsigned int> size(sizeTensorInfo.GetNumElements());
Mike Kelly377fb212023-01-10 15:55:28 +00001973 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Mike Kelly7ba84d62021-09-10 15:27:19 +01001974
1975 for (unsigned int i = 0; i < signedSize.size(); ++i)
1976 {
1977 int signedValue = signedSize[i];
Jim Flynnfca233e2021-09-23 12:16:53 +01001978
Mike Kelly7ba84d62021-09-10 15:27:19 +01001979 if (signedValue < -1 || signedValue > static_cast<int>(inputTensorInfo.GetShape()[i] - begin[i]))
1980 {
1981 throw ParseException(fmt::format("Invalid value for size {} size must be in range "
1982 "[-1, inputDimSize - begin] [-1, {}] inclusive {}",
1983 signedValue,
1984 inputTensorInfo.GetShape()[i] - begin[i],
1985 CHECK_LOCATION().AsString()));
1986 }
1987
1988 if (signedValue == -1)
1989 {
1990 size[i] = inputTensorInfo.GetShape()[i] - begin[i];
1991 }
1992 else
1993 {
1994 size[i] = static_cast<unsigned int>(signedValue);
1995 }
1996 }
1997
josh minorba424d22019-11-13 10:55:17 -06001998 desc = SliceDescriptor(begin, size);
1999
James Ward58dec6b2020-09-11 17:32:44 +01002000 auto layerName = fmt::format("Slice:{}:{}", subgraphIndex, operatorIndex);
josh minorba424d22019-11-13 10:55:17 -06002001
James Conroy05102392020-06-24 15:39:55 +01002002 IConnectableLayer* const layer = m_Network->AddSliceLayer(desc, layerName.c_str());
Mike Kelly377fb212023-01-10 15:55:28 +00002003
2004 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
2005 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
josh minorba424d22019-11-13 10:55:17 -06002006 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2007
2008 // register the input connection slots for the layer, connections are made after all layers have been created
2009 // only the tensors for the inputs are relevant, exclude the const tensors
2010 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2011 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2012
2013 // register the output connection slots for the layer, connections are made after all layers have been created
2014 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2015 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2016}
2017
Kevin May7d96b162021-02-03 17:38:41 +00002018void TfLiteParserImpl::ParseSoftmax(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01002019{
2020 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00002021 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2022 const auto* options = operatorPtr->builtin_options.AsSoftmaxOptions();
telsoa01c577f2c2018-08-31 09:22:23 +01002023
2024 SoftmaxDescriptor desc;
2025 desc.m_Beta = options->beta;
2026
2027 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2028 CHECK_VALID_SIZE(inputs.size(), 1);
2029 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2030 CHECK_VALID_SIZE(outputs.size(), 1);
2031
James Ward58dec6b2020-09-11 17:32:44 +01002032 auto layerName = fmt::format("Softmax:{}:{}", subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01002033 IConnectableLayer* const layer = m_Network->AddSoftmaxLayer(desc, layerName.c_str());
2034
Mike Kelly377fb212023-01-10 15:55:28 +00002035 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
telsoa01c577f2c2018-08-31 09:22:23 +01002036 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2037
2038 // register the input connection slots for the layer, connections are made after all layers have been created
2039 // only the tensors for the inputs are relevant, exclude the const tensors
2040 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2041 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2042
2043 // register the output connection slots for the layer, connections are made after all layers have been created
2044 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2045 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2046}
2047
Teresa Charlinfd33a692022-06-29 15:35:57 +01002048void TfLiteParserImpl::ParseLogSoftmax(size_t subgraphIndex, size_t operatorIndex)
2049{
2050 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2051
2052 LogSoftmaxDescriptor desc;
2053
2054 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2055 CHECK_VALID_SIZE(inputs.size(), 1);
2056 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2057 CHECK_VALID_SIZE(outputs.size(), 1);
2058
2059 auto layerName = fmt::format("LogSoftmax:{}:{}", subgraphIndex, operatorIndex);
2060 IConnectableLayer* const layer = m_Network->AddLogSoftmaxLayer(desc, layerName.c_str());
2061
Mike Kelly377fb212023-01-10 15:55:28 +00002062 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Teresa Charlinfd33a692022-06-29 15:35:57 +01002063 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2064
2065 // register the input connection slots for the layer, connections are made after all layers have been created
2066 // only the tensors for the inputs are relevant, exclude the const tensors
2067 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2068 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2069
2070 // register the output connection slots for the layer, connections are made after all layers have been created
2071 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2072 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2073}
2074
Kevin May7d96b162021-02-03 17:38:41 +00002075void TfLiteParserImpl::ParseSpaceToBatchND(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesbaded142019-02-08 19:02:48 -02002076{
2077 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2078
2079 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2080 CHECK_VALID_SIZE(inputs.size(), 3);
2081
2082 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2083 CHECK_VALID_SIZE(outputs.size(), 1);
2084
Mike Kelly377fb212023-01-10 15:55:28 +00002085 armnn::TensorInfo blockShapeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalvesbaded142019-02-08 19:02:48 -02002086 BufferRawPtr blockShapeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2087
Mike Kelly377fb212023-01-10 15:55:28 +00002088 armnn::TensorInfo padListTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Bruno Goncalvesbaded142019-02-08 19:02:48 -02002089 BufferRawPtr padListBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
2090
2091 std::vector<unsigned int> blockShape(blockShapeTensorInfo.GetNumElements());
2092 ::memcpy(blockShape.data(), blockShapeBufferPtr->data.data(), blockShapeTensorInfo.GetNumBytes());
2093
2094 std::vector<unsigned int> padListVector(padListTensorInfo.GetNumElements());
2095 ::memcpy(padListVector.data(), padListBufferPtr->data.data(), padListTensorInfo.GetNumBytes());
2096
2097 size_t step = 2;
2098 std::vector<std::pair<unsigned int, unsigned int>> padList;
2099 for (unsigned int i = 0; i < padListTensorInfo.GetNumElements() / step; ++i)
2100 {
2101 padList.emplace_back(padListVector[i * step], padListVector[i * step + 1]);
2102 }
2103
2104 armnn::SpaceToBatchNdDescriptor desc;
2105 desc.m_BlockShape = blockShape;
2106 desc.m_PadList = padList;
2107 desc.m_DataLayout = armnn::DataLayout::NHWC;
2108
James Ward58dec6b2020-09-11 17:32:44 +01002109 auto layerName = fmt::format("SpaceToBatchND:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesbaded142019-02-08 19:02:48 -02002110
Mike Kelly377fb212023-01-10 15:55:28 +00002111 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
James Conroy05102392020-06-24 15:39:55 +01002112
2113 IConnectableLayer* layer = m_Network->AddSpaceToBatchNdLayer(desc, layerName.c_str());
2114 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00002115
2116 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
2117 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Bruno Goncalvesbaded142019-02-08 19:02:48 -02002118 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2119
2120 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2121 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2122
2123 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2124 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2125}
2126
Teresa Charlin3ab85482021-06-08 16:59:29 +01002127armnn::TensorInfo TfLiteParserImpl::OutputShapeOfSqueeze(std::vector<uint32_t> squeezeDims,
Mike Kelly0d77ae12022-01-07 17:42:27 +00002128 const armnn::TensorInfo& inputTensorInfo)
telsoa01c577f2c2018-08-31 09:22:23 +01002129{
Teresa Charlin3ab85482021-06-08 16:59:29 +01002130 CHECK_VALID_SIZE(squeezeDims.size(), 0, 1, 2, 3, 4);
telsoa01c577f2c2018-08-31 09:22:23 +01002131 static const uint32_t dimensionSequence[] = { 0, 1, 2, 3 };
2132
2133 if (inputTensorInfo.GetNumDimensions() > 4)
2134 {
2135 std::stringstream ss;
2136 ss << "Input tensor has unexpected number of dimensions:" << inputTensorInfo.GetNumDimensions()
2137 << " shape:" << inputTensorInfo.GetShape() << " "
2138 << CHECK_LOCATION().AsString();
2139 throw ParseException(ss.str());
2140 }
2141
2142 if (squeezeDims.empty())
2143 {
2144 squeezeDims.assign(dimensionSequence,
2145 dimensionSequence+inputTensorInfo.GetNumDimensions());
2146 }
2147
2148 std::vector<uint32_t> outputDims;
2149 for(unsigned int i = 0; i < inputTensorInfo.GetNumDimensions(); i++)
2150 {
2151 bool skipSqueeze = (std::find(squeezeDims.begin(), squeezeDims.end(), i) == squeezeDims.end());
2152 auto currentDimension = inputTensorInfo.GetShape()[i];
2153 if (skipSqueeze || currentDimension != 1)
2154 {
2155 outputDims.push_back(currentDimension);
2156 }
2157 }
2158
2159 if (outputDims.size() > 4)
2160 {
2161 std::stringstream ss;
2162 ss << "Output tensor has unexpected number of dimensions:" << inputTensorInfo.GetNumDimensions()
2163 << " shape:" << inputTensorInfo.GetShape() << " "
2164 << CHECK_LOCATION().AsString();
2165 throw ParseException(ss.str());
2166 }
2167
2168 TensorShape outShape = TensorShape(static_cast<unsigned int>(outputDims.size()),
2169 outputDims.data());
2170
2171 // we need to preserve the tensor type and the quantization data as well
2172 TensorInfo outTensorInfo = inputTensorInfo;
2173 outTensorInfo.SetShape(outShape);
2174
2175 return outTensorInfo;
2176}
2177
Keith Davis0176fd82021-06-01 17:36:32 +01002178void TfLiteParserImpl::ParseShape(size_t subgraphIndex, size_t operatorIndex)
2179{
2180 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2181
2182 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2183 CHECK_VALID_SIZE(inputs.size(), 1);
2184 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2185 CHECK_VALID_SIZE(outputs.size(), 1);
2186
2187 auto layerName = fmt::format("Shape:{}:{}", subgraphIndex, operatorIndex);
2188
2189 IConnectableLayer* layer = m_Network->AddShapeLayer(layerName.c_str());
2190 ARMNN_ASSERT(layer != nullptr);
2191
Mike Kelly377fb212023-01-10 15:55:28 +00002192 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Keith Davis0176fd82021-06-01 17:36:32 +01002193 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2194
2195 // Check if output tensor type is Signed32 or Signed64
2196 if (outputTensorInfo.GetDataType() != armnn::DataType::Signed32 &&
2197 outputTensorInfo.GetDataType() != armnn::DataType::Signed64)
2198 {
2199 throw ParseException(
2200 fmt::format(
2201 "Output tensor data type is not supported. (Supported types: Signed32 & Signed64) {}",
2202 CHECK_LOCATION().AsString()));
2203 }
2204
2205 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2206 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2207
2208 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2209 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2210}
2211
Kevin May7d96b162021-02-03 17:38:41 +00002212void TfLiteParserImpl::ParseSqueeze(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01002213{
2214 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2215
2216 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2217 CHECK_VALID_SIZE(inputs.size(), 1);
2218
2219 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2220 CHECK_VALID_SIZE(outputs.size(), 1);
2221
2222 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2223 const auto * options = operatorPtr->builtin_options.AsSqueezeOptions();
James Ward58dec6b2020-09-11 17:32:44 +01002224 auto layerName = fmt::format("Squeeze:{}:{}", subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01002225
Mike Kelly377fb212023-01-10 15:55:28 +00002226 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Teresa Charlin3ab85482021-06-08 16:59:29 +01002227
2228 std::vector<uint32_t> squeezeDim;
2229 // A single negative dim index is interpreted as a negative index in python
2230 // Meaning the index will be the shape size plus the negative index value
2231 if (options->squeeze_dims.size() == 1 && options->squeeze_dims[0] < 0)
2232 {
2233 int32_t dim = static_cast<int32_t>(inputTensorInfo.GetShape().GetNumDimensions()) + options->squeeze_dims[0];
2234 squeezeDim.push_back(static_cast<uint32_t>(dim));
2235 }
2236 else
2237 {
2238 squeezeDim = AsUnsignedVector(options->squeeze_dims);
2239 }
2240
2241 armnn::TensorInfo outputTensorInfo = TfLiteParserImpl::OutputShapeOfSqueeze(squeezeDim, inputTensorInfo);
2242
James Conroy05102392020-06-24 15:39:55 +01002243 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
telsoa01c577f2c2018-08-31 09:22:23 +01002244
2245 ReshapeDescriptor reshapeDesc;
2246 reshapeDesc.m_TargetShape = outputTensorInfo.GetShape();
2247
telsoa01c577f2c2018-08-31 09:22:23 +01002248 IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002249 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01002250 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2251
2252 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2253 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2254
2255 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2256 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2257}
2258
Kevin May7d96b162021-02-03 17:38:41 +00002259void TfLiteParserImpl::ParseStridedSlice(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002260{
2261 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2262
2263 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2264 CHECK_VALID_SIZE(inputs.size(), 4);
2265
2266 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2267 CHECK_VALID_SIZE(outputs.size(), 1);
2268
Mike Kelly0d77ae12022-01-07 17:42:27 +00002269 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2270 const auto* options = operatorPtr->builtin_options.AsStridedSliceOptions();
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002271
2272 StridedSliceDescriptor desc;
2273 desc.m_BeginMask = options->begin_mask;
2274 desc.m_EllipsisMask = options->ellipsis_mask;
2275 desc.m_EndMask = options->end_mask;
2276 desc.m_NewAxisMask = options->new_axis_mask;
2277 desc.m_ShrinkAxisMask = options->shrink_axis_mask;
2278 desc.m_DataLayout = armnn::DataLayout::NHWC;
2279
Mike Kelly377fb212023-01-10 15:55:28 +00002280 armnn::TensorInfo beginTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002281 BufferRawPtr beginBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2282
2283 std::vector<int> begin(beginTensorInfo.GetNumElements());
2284 ::memcpy(begin.data(), beginBufferPtr->data.data(), beginTensorInfo.GetNumBytes());
2285
Mike Kelly377fb212023-01-10 15:55:28 +00002286 armnn::TensorInfo endTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002287 BufferRawPtr endBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
2288
2289 std::vector<int> end(endTensorInfo.GetNumElements());
2290 ::memcpy(end.data(), endBufferPtr->data.data(), endTensorInfo.GetNumBytes());
2291
Mike Kelly377fb212023-01-10 15:55:28 +00002292 armnn::TensorInfo strideTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 3);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002293 BufferRawPtr strideBufferPtr = GetBuffer(m_Model, inputs[3]->buffer);
2294
2295 std::vector<int> stride(strideTensorInfo.GetNumElements());
2296 ::memcpy(stride.data(), strideBufferPtr->data.data(), strideTensorInfo.GetNumBytes());
2297
2298 desc.m_Begin = begin;
2299 desc.m_End = end;
2300 desc.m_Stride = stride;
2301
James Ward58dec6b2020-09-11 17:32:44 +01002302 auto layerName = fmt::format("StridedSlice:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002303 IConnectableLayer* layer = m_Network->AddStridedSliceLayer(desc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002304 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002305
Mike Kelly377fb212023-01-10 15:55:28 +00002306 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002307 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2308
2309 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2310 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2311
2312 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2313 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2314}
2315
Kevin May7d96b162021-02-03 17:38:41 +00002316void TfLiteParserImpl::ParseSub(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002317{
2318 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2319
Mike Kelly0d77ae12022-01-07 17:42:27 +00002320 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2321 const auto* options = operatorPtr->builtin_options.AsSubOptions();
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002322
2323 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2324 CHECK_VALID_SIZE(inputs.size(), 2);
2325
2326 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2327 CHECK_VALID_SIZE(outputs.size(), 1);
2328
Mike Kelly377fb212023-01-10 15:55:28 +00002329 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2330 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002331
James Ward58dec6b2020-09-11 17:32:44 +01002332 auto layerName = fmt::format("Sub:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002333 IConnectableLayer* layer = m_Network->AddSubtractionLayer(layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002334 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002335
Mike Kelly377fb212023-01-10 15:55:28 +00002336 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002337 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2338
2339 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002340 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002341
2342 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2343
2344 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2345 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2346}
2347
Kevin May7d96b162021-02-03 17:38:41 +00002348void TfLiteParserImpl::ParseDiv(size_t subgraphIndex, size_t operatorIndex)
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302349{
2350 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2351
Mike Kelly0d77ae12022-01-07 17:42:27 +00002352 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2353 const auto* options = operatorPtr->builtin_options.AsDivOptions();
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302354
2355 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2356 CHECK_VALID_SIZE(inputs.size(), 2);
2357
2358 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2359 CHECK_VALID_SIZE(outputs.size(), 1);
2360
Mike Kelly377fb212023-01-10 15:55:28 +00002361 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2362 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302363
James Ward58dec6b2020-09-11 17:32:44 +01002364 auto layerName = fmt::format("Div:{}:{}", subgraphIndex, operatorIndex);
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302365 IConnectableLayer* layer = m_Network->AddDivisionLayer(layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002366 ARMNN_ASSERT(layer != nullptr);
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302367
Mike Kelly377fb212023-01-10 15:55:28 +00002368 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302369 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2370
2371 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002372 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302373 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2374
2375 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2376 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2377}
2378
Teresa Charlincdbd40b2022-02-25 13:21:55 +00002379void TfLiteParserImpl::ParseFloorDiv(size_t subgraphIndex, size_t operatorIndex)
2380{
2381 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2382
2383 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2384 CHECK_VALID_SIZE(inputs.size(), 2);
2385
2386 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2387 CHECK_VALID_SIZE(outputs.size(), 1);
2388
Mike Kelly377fb212023-01-10 15:55:28 +00002389 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2390 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Teresa Charlincdbd40b2022-02-25 13:21:55 +00002391
2392 auto layerName = fmt::format("Div:{}:{}", subgraphIndex, operatorIndex);
2393 IConnectableLayer* layer = m_Network->AddDivisionLayer(layerName.c_str());
2394 ARMNN_ASSERT(layer != nullptr);
2395
Mike Kelly377fb212023-01-10 15:55:28 +00002396 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Teresa Charlincdbd40b2022-02-25 13:21:55 +00002397 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2398
2399 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2400 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
2401 layer = AddFusedFloorLayer(layer, 0);
2402
2403 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2404 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2405}
2406
Kevin May7d96b162021-02-03 17:38:41 +00002407void TfLiteParserImpl::ParseAdd(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002408{
2409 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2410
Mike Kelly0d77ae12022-01-07 17:42:27 +00002411 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2412 const auto* options = operatorPtr->builtin_options.AsAddOptions();
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002413
2414 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2415 CHECK_VALID_SIZE(inputs.size(), 2);
2416
2417 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2418 CHECK_VALID_SIZE(outputs.size(), 1);
2419
Mike Kelly377fb212023-01-10 15:55:28 +00002420 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2421 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves9c761a62018-12-27 14:20:35 -02002422
James Ward58dec6b2020-09-11 17:32:44 +01002423 auto layerName = fmt::format("Add:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002424 IConnectableLayer* layer = m_Network->AddAdditionLayer(layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002425 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002426
Mike Kelly377fb212023-01-10 15:55:28 +00002427 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002428 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2429
2430 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002431 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002432 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2433
2434 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2435 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2436}
2437
Kevin May7d96b162021-02-03 17:38:41 +00002438void TfLiteParserImpl::ParseMul(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002439{
2440 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2441
Mike Kelly0d77ae12022-01-07 17:42:27 +00002442 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2443 const auto* options = operatorPtr->builtin_options.AsMulOptions();
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002444
2445 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2446 CHECK_VALID_SIZE(inputs.size(), 2);
2447
2448 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2449 CHECK_VALID_SIZE(outputs.size(), 1);
2450
Mike Kelly377fb212023-01-10 15:55:28 +00002451 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2452 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves9c761a62018-12-27 14:20:35 -02002453
James Ward58dec6b2020-09-11 17:32:44 +01002454 auto layerName = fmt::format("Mul:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002455 IConnectableLayer* layer = m_Network->AddMultiplicationLayer(layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002456 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002457
Mike Kelly377fb212023-01-10 15:55:28 +00002458 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002459 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2460
2461 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002462 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002463 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2464
2465 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2466 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2467}
2468
Kevin May7d96b162021-02-03 17:38:41 +00002469void TfLiteParserImpl::ParseMean(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002470{
2471 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2472
2473 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2474
2475 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2476 CHECK_VALID_SIZE(outputs.size(), 1);
2477
Mike Kelly377fb212023-01-10 15:55:28 +00002478 armnn::TensorInfo dimTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002479 BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2480
2481 armnn::MeanDescriptor desc;
2482 std::vector<unsigned int> axis(dimTensorInfo.GetNumElements());
2483 ::memcpy(axis.data(), bufferPtr->data.data(), dimTensorInfo.GetNumBytes());
2484 desc.m_Axis = axis;
2485
Mike Kelly377fb212023-01-10 15:55:28 +00002486 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Sadik Armagand109a4d2020-07-28 10:42:13 +01002487 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002488
2489 desc.m_KeepDims =
Mike Kelly377fb212023-01-10 15:55:28 +00002490 inputTensorInfo.GetNumDimensions() == outputTensorInfo.GetNumDimensions() ?
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002491 true : false;
2492
James Ward58dec6b2020-09-11 17:32:44 +01002493 auto layerName = fmt::format("Mean:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002494 IConnectableLayer* layer = m_Network->AddMeanLayer(desc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002495 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002496
Mike Kelly377fb212023-01-10 15:55:28 +00002497 outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002498 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2499
2500 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2501 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2502
2503 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2504 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2505}
2506
Kevin May7d96b162021-02-03 17:38:41 +00002507void TfLiteParserImpl::ParsePad(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002508{
2509 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2510
Kevin May7d96b162021-02-03 17:38:41 +00002511 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002512
Kevin May7d96b162021-02-03 17:38:41 +00002513 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002514 CHECK_VALID_SIZE(outputs.size(), 1);
2515
Mike Kelly377fb212023-01-10 15:55:28 +00002516 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2517 armnn::TensorInfo padTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002518
Mike Kelly0d77ae12022-01-07 17:42:27 +00002519 std::vector<unsigned int> padBuffer = GetUIntBuffer(padTensorInfo, m_Model, inputs[1]->buffer);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002520
2521 size_t step = 2;
2522 armnn::PadDescriptor desc;
Mike Kelly0d77ae12022-01-07 17:42:27 +00002523 auto opcode = GetOpCode(m_Model, subgraphIndex, operatorIndex);
2524
2525 if (opcode == tflite::BuiltinOperator_PAD)
Narumol Prangnawarat8719d222020-11-27 16:57:56 +00002526 {
Mike Kelly0d77ae12022-01-07 17:42:27 +00002527 CHECK_VALID_SIZE(inputs.size(), 2);
2528
2529 if (inputTensorInfo.IsQuantized())
2530 {
2531 desc.m_PadValue = static_cast<float>(inputTensorInfo.GetQuantizationOffset());
2532 }
Narumol Prangnawarat8719d222020-11-27 16:57:56 +00002533 }
Mike Kelly0d77ae12022-01-07 17:42:27 +00002534 else if (opcode == tflite::BuiltinOperator_PADV2)
2535 {
2536 CHECK_VALID_SIZE(inputs.size(), 3);
2537
Mike Kelly377fb212023-01-10 15:55:28 +00002538 armnn::TensorInfo padValueTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Mike Kelly0d77ae12022-01-07 17:42:27 +00002539
2540 if (padValueTensorInfo.GetNumElements() != 1)
2541 {
2542 ARMNN_THROW_PARSE_EXCEPTION("Multiple padding values are not supported in PADV2");
2543 }
2544 BufferRawPtr padValueBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
2545
2546 // Get the pad value from the input tensor
2547 if (padValueBufferPtr->data.size() > 0)
2548 {
2549 switch (padValueTensorInfo.GetDataType())
2550 {
2551 case armnn::DataType::Float32:
2552 {
2553 std::vector<float> padValueBuffer(padValueTensorInfo.GetNumElements());
2554 ::memcpy(padValueBuffer.data(), padValueBufferPtr->data.data(), padValueBufferPtr->data.size());
2555 desc.m_PadValue = padValueBuffer[0];
2556 break;
2557 }
2558 case armnn::DataType::QAsymmU8:
2559 {
2560 std::vector<uint8_t> padValueBuffer(padValueTensorInfo.GetNumElements());
2561 ::memcpy(padValueBuffer.data(), padValueBufferPtr->data.data(), padValueBufferPtr->data.size());
2562 desc.m_PadValue = armnn::Dequantize<uint8_t>(padValueBuffer[0],
2563 padValueTensorInfo.GetQuantizationScale(),
2564 padValueTensorInfo.GetQuantizationOffset());
2565 break;
2566 }
2567 case armnn::DataType::QAsymmS8:
2568 case armnn::DataType::QSymmS8:
2569 {
2570 std::vector<int8_t> padValueBuffer(padValueTensorInfo.GetNumElements());
2571 ::memcpy(padValueBuffer.data(), padValueBufferPtr->data.data(), padValueBufferPtr->data.size());
2572 desc.m_PadValue = armnn::Dequantize<int8_t>(padValueBuffer[0],
2573 padValueTensorInfo.GetQuantizationScale(),
2574 padValueTensorInfo.GetQuantizationOffset());
2575 break;
2576 }
2577 default: ARMNN_THROW_PARSE_EXCEPTION("Unsupported DataType");
2578 }
2579 }
2580 else if (inputTensorInfo.IsQuantized())
2581 {
2582 desc.m_PadValue = static_cast<float>(inputTensorInfo.GetQuantizationOffset());
2583 }
2584 }
2585
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002586 for (unsigned int i = 0; i < padTensorInfo.GetNumElements() / step; ++i)
2587 {
2588 desc.m_PadList.emplace_back(padBuffer[i * step], padBuffer[i * step + 1]);
2589 }
2590
Mike Kelly0d77ae12022-01-07 17:42:27 +00002591 auto layerName = (opcode == tflite::BuiltinOperator_PAD) ? fmt::format("Pad:{}:{}", subgraphIndex, operatorIndex)
2592 : fmt::format("PadV2:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01002593
2594 IConnectableLayer* layer = m_Network->AddPadLayer(desc, layerName.c_str());
2595 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00002596 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002597 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2598
2599 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2600 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2601
2602 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2603 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2604}
2605
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002606void TfLiteParserImpl::ParseMirrorPad(size_t subgraphIndex, size_t operatorIndex)
2607{
2608 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2609
2610 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2611 CHECK_VALID_SIZE(inputs.size(), 2);
2612
2613 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2614 CHECK_VALID_SIZE(outputs.size(), 1);
2615
Mike Kelly377fb212023-01-10 15:55:28 +00002616 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002617
Mike Kelly377fb212023-01-10 15:55:28 +00002618 armnn::TensorInfo padTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002619 BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2620
2621 std::vector<unsigned int> padBuffer(padTensorInfo.GetNumElements());
2622 ::memcpy(padBuffer.data(), bufferPtr->data.data(), padTensorInfo.GetNumBytes());
2623
2624 size_t step = 2;
2625 armnn::PadDescriptor desc;
2626 for (unsigned int i = 0; i < padTensorInfo.GetNumElements() / step; ++i)
2627 {
2628 desc.m_PadList.emplace_back(padBuffer[i * step], padBuffer[i * step + 1]);
2629 }
2630
2631 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2632 const auto* options = operatorPtr->builtin_options.AsMirrorPadOptions();
2633
2634 if (options->mode == tflite::MirrorPadMode_REFLECT)
2635 {
2636 desc.m_PaddingMode = PaddingMode::Reflect;
2637 }
2638 else if (options->mode == tflite::MirrorPadMode_SYMMETRIC)
2639 {
2640 desc.m_PaddingMode = PaddingMode::Symmetric;
2641 }
2642 else
2643 {
2644 ARMNN_THROW_PARSE_EXCEPTION("PaddingMode must be either REFLECT or SYMMETRIC");
2645 }
2646
2647 // If padding mode is Reflect then both paddings must be no greater than inputShape(i) - 1.
2648 // If padding mode is Symmetric then both paddings must be no greater than inputShape(i).
2649 auto inputShape = inputTensorInfo.GetShape();
2650 auto padList = desc.m_PadList;
2651
2652 const unsigned int isReflect = static_cast<unsigned int>(desc.m_PaddingMode == PaddingMode::Reflect);
2653 for(unsigned int i = 0; i < padList.size(); ++i)
2654 {
2655 if(padList.at(i).first > (inputShape[i] - isReflect) ||
2656 padList.at(i).second > (inputShape[i] - isReflect))
2657 {
2658 ARMNN_THROW_PARSE_EXCEPTION("Padding values must be less (Reflect) or "
2659 "equal (Symmetric) to the dimension size.");
2660 }
2661 }
2662
2663 auto layerName = fmt::format("MirrorPad:{}:{}", subgraphIndex, operatorIndex);
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002664
2665 IConnectableLayer* layer = m_Network->AddPadLayer(desc, layerName.c_str());
2666 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00002667 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002668 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2669
2670 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2671 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2672
2673 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2674 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2675}
2676
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002677void TfLiteParserImpl::ParsePrelu(size_t subgraphIndex, size_t operatorIndex)
2678{
2679 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2680
2681 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2682 CHECK_VALID_SIZE(inputs.size(), 2);
2683
2684 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2685 CHECK_VALID_SIZE(outputs.size(), 1);
2686
2687 auto layerName = fmt::format("Prelu:{}:{}", subgraphIndex, operatorIndex);
2688
Mike Kelly377fb212023-01-10 15:55:28 +00002689 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
2690 armnn::TensorInfo alphaTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002691
2692 IConnectableLayer* layer = m_Network->AddPreluLayer(layerName.c_str());
2693 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00002694
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002695
2696 if (IsConstTensor(inputs[1]))
2697 {
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002698 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawaratbf99b5f2021-05-27 09:55:43 +01002699 armnn::IInputSlot* slot = &(layer->GetInputSlot(0));
2700 RegisterConsumerOfTensor(subgraphIndex, inputTensorIndexes[0], slot);
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002701
Mike Kelly5880b912022-01-28 16:18:54 +00002702 auto alphaTensorAndData = CreateConstTensorNonPermuted(inputs[1], alphaTensorInfo,
2703 inputTensorInfo.GetDataType());
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002704 std::string constLayerName = fmt::format("Constant:{}", inputs[1]->name);
2705 IConnectableLayer* constLayer =
Mike Kelly5880b912022-01-28 16:18:54 +00002706 m_Network->AddConstantLayer(alphaTensorAndData.first, constLayerName.c_str());
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002707 ARMNN_ASSERT(constLayer != nullptr);
2708
2709 constLayer->GetOutputSlot(0).SetTensorInfo(alphaTensorInfo);
2710 constLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1));
2711 RegisterOutputSlots(subgraphIndex,
2712 VIRTUAL_OPERATOR_ID,
2713 constLayer,
2714 { inputTensorIndexes[1] });
2715 }
2716 else
2717 {
2718 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2719 RegisterInputSlots(subgraphIndex, operatorIndex, layer, inputTensorIndexes);
2720 }
2721
Mike Kelly377fb212023-01-10 15:55:28 +00002722 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
2723 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
2724 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2725
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002726 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2727 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2728}
2729
Kevin May7d96b162021-02-03 17:38:41 +00002730void TfLiteParserImpl::ParseQuantize(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan66dedc72019-12-10 16:32:07 +00002731{
2732 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2733
2734 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2735 CHECK_VALID_SIZE(inputs.size(), 1);
2736
2737 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2738 CHECK_VALID_SIZE(outputs.size(), 1);
2739
James Ward58dec6b2020-09-11 17:32:44 +01002740 auto layerName = fmt::format("Quantize:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan66dedc72019-12-10 16:32:07 +00002741
2742 IConnectableLayer* layer = m_Network->AddQuantizeLayer(layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01002743 ARMNN_ASSERT(layer != nullptr);
Sadik Armagan66dedc72019-12-10 16:32:07 +00002744
Mike Kelly377fb212023-01-10 15:55:28 +00002745 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Sadik Armagan66dedc72019-12-10 16:32:07 +00002746 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2747
2748 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2749 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2750
2751 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2752 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2753}
Finn Williamsc42c3842019-01-22 14:18:11 +00002754
Kevin May7d96b162021-02-03 17:38:41 +00002755void TfLiteParserImpl::ParseRelu(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan58f39192018-09-17 14:14:39 +01002756{
Finn Williamsc42c3842019-01-22 14:18:11 +00002757 ParseActivation(subgraphIndex,operatorIndex, ActivationFunction::ReLu);
Sadik Armagan58f39192018-09-17 14:14:39 +01002758}
2759
Kevin May7d96b162021-02-03 17:38:41 +00002760void TfLiteParserImpl::ParseRelu6(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan58f39192018-09-17 14:14:39 +01002761{
Finn Williamsc42c3842019-01-22 14:18:11 +00002762 ParseActivation(subgraphIndex,operatorIndex, ActivationFunction::BoundedReLu);
2763}
Sadik Armagan58f39192018-09-17 14:14:39 +01002764
Kevin May7d96b162021-02-03 17:38:41 +00002765void TfLiteParserImpl::ParseLeakyRelu(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan12239e72020-05-27 11:06:17 +01002766{
Jan Eilers2f746b32020-07-28 14:00:06 +01002767 ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::LeakyReLu);
Sadik Armagan12239e72020-05-27 11:06:17 +01002768}
2769
Kevin May7d96b162021-02-03 17:38:41 +00002770void TfLiteParserImpl::ParseLogistic(size_t subgraphIndex, size_t operatorIndex)
Finn Williamsc42c3842019-01-22 14:18:11 +00002771{
2772 ParseActivation(subgraphIndex,operatorIndex,ActivationFunction::Sigmoid);
2773}
2774
Kevin May7d96b162021-02-03 17:38:41 +00002775void TfLiteParserImpl::ParseTanH(size_t subgraphIndex, size_t operatorIndex)
Nina Drozd99851762019-04-09 09:37:38 +01002776{
2777 ParseActivation(subgraphIndex,operatorIndex,ActivationFunction::TanH);
2778}
2779
Kevin May7d96b162021-02-03 17:38:41 +00002780void TfLiteParserImpl::ParseElu(size_t subgraphIndex, size_t operatorIndex)
Matthew Sloyan7515d072020-12-16 12:50:01 +00002781{
2782 ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::Elu);
2783}
2784
Kevin May7d96b162021-02-03 17:38:41 +00002785void TfLiteParserImpl::ParseHardSwish(size_t subgraphIndex, size_t operatorIndex)
Jan Eilers2f746b32020-07-28 14:00:06 +01002786{
2787 ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::HardSwish);
2788}
Finn Williamsc42c3842019-01-22 14:18:11 +00002789
Kevin May7d96b162021-02-03 17:38:41 +00002790void TfLiteParserImpl::ParseActivation(size_t subgraphIndex, size_t operatorIndex, ActivationFunction activationType)
Finn Williamsc42c3842019-01-22 14:18:11 +00002791{
2792 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00002793 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
Jan Eilers8eb25602020-03-09 12:13:48 +00002794 IgnoreUnused(operatorPtr);
Sadik Armagan58f39192018-09-17 14:14:39 +01002795
2796 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2797 CHECK_VALID_SIZE(inputs.size(), 1);
2798
2799 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2800 CHECK_VALID_SIZE(outputs.size(), 1);
2801
James Ward58dec6b2020-09-11 17:32:44 +01002802 auto layerName = fmt::format("Activation:");
Sadik Armagan58f39192018-09-17 14:14:39 +01002803 ActivationDescriptor activationDesc;
Finn Williamsc42c3842019-01-22 14:18:11 +00002804 activationDesc.m_Function = activationType;
2805
2806 switch (activationType)
2807 {
2808 case ActivationFunction::ReLu:
2809 {
James Ward58dec6b2020-09-11 17:32:44 +01002810 layerName += fmt::format("RELU:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsc42c3842019-01-22 14:18:11 +00002811 break;
2812 }
2813 case ActivationFunction::BoundedReLu:
2814 {
James Ward58dec6b2020-09-11 17:32:44 +01002815 layerName += fmt::format("RELU6:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsc42c3842019-01-22 14:18:11 +00002816 activationDesc.m_A = 6.0f;
2817 activationDesc.m_B = 0.0f;
2818 break;
2819 }
2820 case ActivationFunction::Sigmoid:
2821 {
James Ward58dec6b2020-09-11 17:32:44 +01002822 layerName += fmt::format("SIGMOID:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsc42c3842019-01-22 14:18:11 +00002823 break;
2824 }
Nina Drozd99851762019-04-09 09:37:38 +01002825 case ActivationFunction::TanH:
2826 {
James Ward58dec6b2020-09-11 17:32:44 +01002827 layerName += fmt::format("TANH:{}:{}", subgraphIndex, operatorIndex);
Nina Drozd99851762019-04-09 09:37:38 +01002828 activationDesc.m_A = 1.0f;
2829 activationDesc.m_B = 1.0f;
2830 break;
2831 }
Sadik Armagan12239e72020-05-27 11:06:17 +01002832 case ActivationFunction::LeakyReLu:
2833 {
James Ward58dec6b2020-09-11 17:32:44 +01002834 layerName += fmt::format("LEAKYRELU:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00002835 const auto* options = operatorPtr->builtin_options.AsLeakyReluOptions();
Sadik Armagan12239e72020-05-27 11:06:17 +01002836 activationDesc.m_A = options->alpha;
2837 break;
2838 }
Matthew Sloyan7515d072020-12-16 12:50:01 +00002839 case ActivationFunction::Elu:
2840 {
2841 layerName += fmt::format("ELU:{}:{}", subgraphIndex, operatorIndex);
2842 activationDesc.m_A = 1.0f;
2843 break;
2844 }
Jan Eilers2f746b32020-07-28 14:00:06 +01002845 case ActivationFunction::HardSwish:
Matthew Sloyan7515d072020-12-16 12:50:01 +00002846 {
James Ward58dec6b2020-09-11 17:32:44 +01002847 layerName += fmt::format("HARDSWISH:{}:{}", subgraphIndex, operatorIndex);
Jan Eilers2f746b32020-07-28 14:00:06 +01002848 break;
Matthew Sloyan7515d072020-12-16 12:50:01 +00002849 }
Finn Williamsc42c3842019-01-22 14:18:11 +00002850 default:
2851 {
2852 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01002853 fmt::format("Unexpected ActivationFunction[{}] when creating layerName {} ",
2854 static_cast<int>(activationType), CHECK_LOCATION().AsString()));
Finn Williamsc42c3842019-01-22 14:18:11 +00002855 }
2856 }
2857
2858 IConnectableLayer* const layer = m_Network->AddActivationLayer(activationDesc, layerName.c_str());
Sadik Armagan58f39192018-09-17 14:14:39 +01002859
Mike Kelly377fb212023-01-10 15:55:28 +00002860 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Sadik Armagan58f39192018-09-17 14:14:39 +01002861 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2862
2863 // register the input connection slots for the layer, connections are made after all layers have been created
2864 // only the tensors for the inputs are relevant, exclude the const tensors
2865 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2866 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2867
2868 // register the output connection slots for the layer, connections are made after all layers have been created
2869 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2870 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2871}
Mike Kelly0d77ae12022-01-07 17:42:27 +00002872armnn::TensorInfo TfLiteParserImpl::OutputShapeOfReshape(const armnn::TensorInfo& inputTensorInfo,
2873 const std::vector<int32_t>& targetDimsIn)
Sadikb94967b2018-09-19 15:30:00 +01002874{
2875 std::vector<unsigned int> outputDims(targetDimsIn.begin(), targetDimsIn.end());
2876 const auto stretchDim = std::find(targetDimsIn.begin(), targetDimsIn.end(), -1);
2877
2878 if (stretchDim != targetDimsIn.end())
2879 {
2880 if (std::find(std::next(stretchDim), targetDimsIn.end(), -1) != targetDimsIn.end())
2881 {
2882 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01002883 fmt::format("At most one component of shape can be -1 {}", CHECK_LOCATION().AsString()));
Sadikb94967b2018-09-19 15:30:00 +01002884 }
2885
2886 auto targetNumElements =
Matthew Sloyan589e3e82020-09-11 16:17:48 +01002887 armnn::numeric_cast<unsigned int>(
Sadikb94967b2018-09-19 15:30:00 +01002888 std::accumulate(targetDimsIn.begin(), targetDimsIn.end(), -1, std::multiplies<int32_t>()));
2889
2890 auto stretchIndex = static_cast<size_t>(std::distance(targetDimsIn.begin(), stretchDim));
2891 outputDims[stretchIndex] = inputTensorInfo.GetNumElements() / targetNumElements;
2892 }
2893
2894 TensorShape outputShape = TensorShape(static_cast<unsigned int>(outputDims.size()), outputDims.data());
2895
2896 TensorInfo reshapeInfo = inputTensorInfo;
2897 reshapeInfo.SetShape(outputShape);
2898
2899 return reshapeInfo;
2900}
2901
Kevin May7d96b162021-02-03 17:38:41 +00002902void TfLiteParserImpl::ParseReshape(size_t subgraphIndex, size_t operatorIndex)
Sadikb94967b2018-09-19 15:30:00 +01002903{
2904 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2905
2906 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Sadikb94967b2018-09-19 15:30:00 +01002907
2908 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2909 CHECK_VALID_SIZE(outputs.size(), 1);
2910
Mike Kelly0d77ae12022-01-07 17:42:27 +00002911 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2912 const auto* options = operatorPtr->builtin_options.AsReshapeOptions();
James Ward58dec6b2020-09-11 17:32:44 +01002913 auto layerName = fmt::format("Reshape:{}:{}", subgraphIndex, operatorIndex);
Sadikb94967b2018-09-19 15:30:00 +01002914
Mike Kelly377fb212023-01-10 15:55:28 +00002915 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
kevmay0171972a82018-12-17 14:28:03 +00002916 armnn::TensorInfo actualOutputTensorInfo = ToTensorInfo(outputs[0]);
James Conroy05102392020-06-24 15:39:55 +01002917 CheckMatchingQuantization(inputTensorInfo, actualOutputTensorInfo, layerName, "Input 0", "Output 0");
Derek Lambertic9e52792020-03-11 11:42:26 +00002918
Jan Eilersbac9b352020-07-13 13:40:24 +01002919 // Extracting new shape for the output
2920 // There are two ways it can be passed
2921 // * First is to define the target shape in the operator built-in options
2922 // * Second is to pass it as a second input tensor
Derek Lambertic9e52792020-03-11 11:42:26 +00002923 std::vector<int32_t> targetShape;
Jan Eilersbac9b352020-07-13 13:40:24 +01002924 bool targetShapeFound = false;
2925 // Check if built-in options were given
2926 if (options != nullptr)
Derek Lambertic9e52792020-03-11 11:42:26 +00002927 {
Jan Eilersbac9b352020-07-13 13:40:24 +01002928 // make sure the parameter is given
2929 if (options->new_shape.empty() == false)
Derek Lambertic9e52792020-03-11 11:42:26 +00002930 {
Jan Eilersbac9b352020-07-13 13:40:24 +01002931 targetShape = options->new_shape;
2932 targetShapeFound = true;
Derek Lambertif4a953f2020-03-17 14:25:57 +00002933 }
Derek Lambertic9e52792020-03-11 11:42:26 +00002934 }
Jan Eilersbac9b352020-07-13 13:40:24 +01002935
2936 // If there is no built-in option given or if the built-in new_shape parameter was empty
2937 if (!targetShapeFound)
Derek Lambertic9e52792020-03-11 11:42:26 +00002938 {
Teresa Charlin6a056a42021-12-01 10:25:43 +00002939 // Check for a second input tensor
2940 if (inputs.size() > 1 && inputs[1] != nullptr)
Jan Eilersbac9b352020-07-13 13:40:24 +01002941 {
2942 if (inputs[1]->is_variable)
2943 {
2944 ARMNN_THROW_PARSE_EXCEPTION( "Target shapes defined in non-const input tensors is not supported");
2945 }
2946
2947 if (inputs[1]->shape.size() != 1)
2948 {
2949 ARMNN_THROW_PARSE_EXCEPTION("Target 'shape' input is not a 1D tensor");
2950 }
2951
2952 if (inputs[1]->type != tflite::TensorType_INT32)
2953 {
2954 ARMNN_THROW_PARSE_EXCEPTION("Target 'shape' input is not an int32 type");
2955 }
2956
Teresa Charlin6a056a42021-12-01 10:25:43 +00002957 // Extract target shape from input
2958 auto bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2959 auto values = reinterpret_cast<const int32_t*>(bufferPtr->data.data());
Cathal Corbettd2f73232021-12-10 13:38:52 +00002960 if (values)
Sadik Armagan19a1c032021-01-20 12:17:00 +00002961 {
Cathal Corbettd2f73232021-12-10 13:38:52 +00002962 for (int i = 0; i < inputs[1]->shape[0]; ++i)
2963 {
2964 targetShape.push_back(values[i]);
2965 }
Sadik Armagan19a1c032021-01-20 12:17:00 +00002966 }
Cathal Corbettd2f73232021-12-10 13:38:52 +00002967 else
Jan Eilersbac9b352020-07-13 13:40:24 +01002968 {
Cathal Corbettd2f73232021-12-10 13:38:52 +00002969 try
2970 {
2971 // We attempt to infer during Runtime.
Mike Kelly377fb212023-01-10 15:55:28 +00002972 TensorShape reshapeShapes =ToTensorInfo(inputs[1]).GetShape();
2973 reshapeShapes = InputTensorInfo(subgraphIndex, operatorIndex, 1).GetShape();
Cathal Corbettd2f73232021-12-10 13:38:52 +00002974 // The parser only supports shape (batch, -1) or (-1) for non-constant shape input.
2975 if (reshapeShapes[0] > 2)
2976 {
2977 throw ParseException(fmt::format("Invalid input shape '{}' in Reshape layer '{}' {}. "
2978 "When inferring during runtime, the parser only supports "
2979 "shape (batch, -1) or (-1) for target shape input.",
2980 reshapeShapes[0],
2981 layerName,
2982 CHECK_LOCATION().AsString()));
2983 }
2984
2985 const int32_t numInputElements = inputTensorInfo.GetNumElements();
2986 const int32_t inputTensorShape = inputTensorInfo.GetShape()[0];
2987 if (reshapeShapes[0] == 1)
2988 {
2989 targetShape = {numInputElements};
2990 }
2991 else if (reshapeShapes[0] == 2)
2992 {
2993 targetShape = {inputTensorShape, numInputElements / inputTensorShape};
2994 }
2995 }
2996 catch (const std::exception& exc)
2997 {
2998 ARMNN_THROW_PARSE_EXCEPTION("Failed attempt to infer during runtime the target shape input for "
2999 "Reshape operation. Reshape operator target shape input buffer data "
3000 "is null. " << exc.what());
3001 }
Jan Eilersbac9b352020-07-13 13:40:24 +01003002 }
3003 }
3004 else
Derek Lambertic9e52792020-03-11 11:42:26 +00003005 {
3006 ARMNN_THROW_PARSE_EXCEPTION("Target shape not defined in reshape parameters or input tensor. "
3007 "At least one method required");
3008 }
Derek Lambertic9e52792020-03-11 11:42:26 +00003009 }
3010
kevmay0171972a82018-12-17 14:28:03 +00003011 armnn::TensorInfo reshapeOutputTensorInfo =
Kevin May7d96b162021-02-03 17:38:41 +00003012 TfLiteParserImpl::OutputShapeOfReshape(inputTensorInfo, targetShape);
Sadikb94967b2018-09-19 15:30:00 +01003013
kevmay0171972a82018-12-17 14:28:03 +00003014 // Check for valid input size and that reshape parameters equal output shape
Cathal Corbett2b922e22022-09-23 15:49:24 +01003015 // The output shape can be provided to us in 2 ways:
3016 // 1. through the normal 'shape' parameter given by outputs[indx]->shape
3017 // 2. through additional parameter 'shape_signature' given by outputs[indx]->buffer.
3018 // This parameter can sometimes contain -1 value not visible in the 'shape' parameter.
Aron Virginas-Tar70672f62019-01-23 14:00:00 +00003019 const armnn::TensorShape& reshapeOutputTensorShape = reshapeOutputTensorInfo.GetShape();
3020 if (inputs.size() > 1 && !CheckShape(reshapeOutputTensorShape, outputs[0]->shape))
kevmay0171972a82018-12-17 14:28:03 +00003021 {
Cathal Corbett2b922e22022-09-23 15:49:24 +01003022 // Attempt to extract output shape from secondary 'shape_signature'
3023 // parameter and try to CheckShape() with this param.
3024 std::vector<int32_t> secondaryOutputTargetShape = outputs[0]->shape_signature;
3025
3026 // if outputs[0]->shape_signature contain a -1 value, we need to compute its actual value
3027 // from reshape input in order to correctly verify reshape parameters equal output shape
3028 armnn::TensorInfo secondaryReshapeOutputTensorInfo =
3029 TfLiteParserImpl::OutputShapeOfReshape(inputTensorInfo, secondaryOutputTargetShape);
3030
3031 if (!CheckShape(reshapeOutputTensorShape, secondaryReshapeOutputTensorInfo.GetShape()))
3032 {
3033 std::stringstream ss;
3034 ss << "New shape defined in reshape parameters "
3035 << reshapeOutputTensorShape
3036 << " does not equal output shape "
3037 << actualOutputTensorInfo.GetShape()
3038 << ": "
3039 << CHECK_LOCATION().AsString();
3040 throw ParseException(ss.str());
3041 }
kevmay0171972a82018-12-17 14:28:03 +00003042 }
Mike Kelly377fb212023-01-10 15:55:28 +00003043 auto outputTensorIds = GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex);
kevmay0171972a82018-12-17 14:28:03 +00003044
Sadikb94967b2018-09-19 15:30:00 +01003045 ReshapeDescriptor reshapeDesc;
kevmay0171972a82018-12-17 14:28:03 +00003046 reshapeDesc.m_TargetShape = reshapeOutputTensorInfo.GetShape();
Mike Kelly377fb212023-01-10 15:55:28 +00003047 m_TensorInfos[outputTensorIds[0]] = reshapeOutputTensorInfo;
Sadikb94967b2018-09-19 15:30:00 +01003048
Sadikb94967b2018-09-19 15:30:00 +01003049 IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01003050 ARMNN_ASSERT(layer != nullptr);
kevmay0171972a82018-12-17 14:28:03 +00003051 layer->GetOutputSlot(0).SetTensorInfo(reshapeOutputTensorInfo);
Sadikb94967b2018-09-19 15:30:00 +01003052
3053 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3054 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3055
3056 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3057 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3058}
3059
Kevin May7d96b162021-02-03 17:38:41 +00003060void TfLiteParserImpl::ParseResizeBilinear(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003061{
Sadik Armagana3b31f02019-12-05 09:08:53 +00003062 ParseResize(subgraphIndex, operatorIndex, ResizeMethod::Bilinear);
3063}
3064
Kevin May7d96b162021-02-03 17:38:41 +00003065void TfLiteParserImpl::ParseResizeNearestNeighbor(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagana3b31f02019-12-05 09:08:53 +00003066{
3067 ParseResize(subgraphIndex, operatorIndex, ResizeMethod::NearestNeighbor);
3068}
3069
Kevin May7d96b162021-02-03 17:38:41 +00003070void TfLiteParserImpl::ParseResize(size_t subgraphIndex, size_t operatorIndex, ResizeMethod resizeMethod)
Sadik Armagana3b31f02019-12-05 09:08:53 +00003071{
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003072 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3073
3074 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3075 CHECK_VALID_SIZE(inputs.size(), 2);
3076
3077 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3078 CHECK_VALID_SIZE(outputs.size(), 1);
3079
Mike Kelly377fb212023-01-10 15:55:28 +00003080 armnn::TensorInfo sizeTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003081
3082 // Data for the parsed tensor args (size) must be stored locally.
3083 std::vector<int32_t> sizeTensorData(sizeTensorInfo.GetNumElements());
3084
3085 BufferRawPtr sizeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
3086 ::memcpy(sizeTensorData.data(), sizeBufferPtr->data.data(), sizeTensorInfo.GetNumBytes());
3087
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01003088 ResizeDescriptor desc;
Sadik Armagana3b31f02019-12-05 09:08:53 +00003089 desc.m_Method = resizeMethod;
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003090 desc.m_TargetHeight = static_cast<uint32_t> (sizeTensorData[0]);
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01003091 desc.m_TargetWidth = static_cast<uint32_t> (sizeTensorData[1]);
3092 desc.m_DataLayout = armnn::DataLayout::NHWC;
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003093
James Ward58dec6b2020-09-11 17:32:44 +01003094 auto layerName = fmt::format("Resize:");
Sadik Armagana3b31f02019-12-05 09:08:53 +00003095
3096 switch (resizeMethod)
3097 {
3098 case ResizeMethod::Bilinear:
3099 {
James Ward58dec6b2020-09-11 17:32:44 +01003100 layerName += fmt::format("BILINEAR:{}:{}", subgraphIndex, operatorIndex);
Sang-Hoon Park820eb142020-01-08 10:25:24 +00003101
3102 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3103 const auto * options = operatorPtr->builtin_options.AsResizeBilinearOptions();
3104
David Monahan4a0c9b92020-05-30 09:48:39 +01003105 desc.m_AlignCorners = options->align_corners;
Sadik Armagana3b31f02019-12-05 09:08:53 +00003106 break;
3107 }
3108 case ResizeMethod::NearestNeighbor:
3109 {
James Ward58dec6b2020-09-11 17:32:44 +01003110 layerName += fmt::format("NEARESTNEIGHBOR:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagana3b31f02019-12-05 09:08:53 +00003111 break;
3112 }
3113 default:
3114 {
3115 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003116 fmt::format("Unexpected ResizeMethod[{}] when creating layerName {} ",
3117 static_cast<int>(resizeMethod), CHECK_LOCATION().AsString()));
Sadik Armagana3b31f02019-12-05 09:08:53 +00003118 }
3119 }
3120
Mike Kelly377fb212023-01-10 15:55:28 +00003121 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
James Conroy05102392020-06-24 15:39:55 +01003122
3123 IConnectableLayer* layer = m_Network->AddResizeLayer(desc, layerName.c_str());
3124 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00003125 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
3126 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02003127 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3128
3129 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3130 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3131
3132 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3133 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
3134}
3135
Kevin May7d96b162021-02-03 17:38:41 +00003136void TfLiteParserImpl::ParseConcatenation(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan479045b2018-10-01 11:51:37 +01003137{
3138 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3139
Mike Kelly0d77ae12022-01-07 17:42:27 +00003140 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3141 const auto* options = operatorPtr->builtin_options.AsConcatenationOptions();
Sadik Armagan479045b2018-10-01 11:51:37 +01003142
3143 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
3144
3145 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3146 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Mike Kelly377fb212023-01-10 15:55:28 +00003147 auto inputTensorIds = GetInputTensorIds(m_Model, subgraphIndex, operatorIndex);
3148
Sadik Armagan479045b2018-10-01 11:51:37 +01003149 CHECK_VALID_SIZE(outputs.size(), 1);
3150
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003151 unsigned int numConcatView = static_cast<unsigned int>(inputs.size());
Mike Kelly377fb212023-01-10 15:55:28 +00003152 uint32_t inputRank = InputTensorInfo(subgraphIndex, operatorIndex, 0).GetNumDimensions();
Sadik Armagan479045b2018-10-01 11:51:37 +01003153
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003154 const unsigned int concatDimInput = static_cast<unsigned int>(
Mike Kelly377fb212023-01-10 15:55:28 +00003155 (static_cast<int>(inputRank) + options->axis) % static_cast<int>(inputRank));
Sadik Armagan479045b2018-10-01 11:51:37 +01003156
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003157 OriginsDescriptor concatDescriptor(static_cast<uint32_t>(numConcatView), inputRank);
3158 concatDescriptor.SetConcatAxis(concatDimInput);
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003159 unsigned int mergeDimOrigin = 0;
Sadik Armagan479045b2018-10-01 11:51:37 +01003160
3161 for (unsigned int viewIndex = 0; viewIndex < numConcatView; ++viewIndex)
3162 {
Mike Kelly377fb212023-01-10 15:55:28 +00003163 TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, viewIndex);
Sadik Armagan479045b2018-10-01 11:51:37 +01003164
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003165 // This set up concatDescriptor view origin
3166 armnnUtils::ProcessConcatInputTensorInfo(
Mike Kelly377fb212023-01-10 15:55:28 +00003167 inputTensorInfo, concatDescriptor, concatDimInput, viewIndex, mergeDimOrigin);
Sadik Armagan479045b2018-10-01 11:51:37 +01003168 }
3169
James Ward58dec6b2020-09-11 17:32:44 +01003170 auto layerName = fmt::format("Concatenation:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01003171
Jim Flynn906f9462019-05-10 13:55:21 +01003172 IConnectableLayer* layer = m_Network->AddConcatLayer(concatDescriptor, layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01003173 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00003174 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {});
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003175 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
Sadik Armagan479045b2018-10-01 11:51:37 +01003176
James Conroy05102392020-06-24 15:39:55 +01003177 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003178 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes});
Sadik Armagan479045b2018-10-01 11:51:37 +01003179
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00003180 // add fused activation layer
3181 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
Sadik Armagan479045b2018-10-01 11:51:37 +01003182
Sadik Armagan479045b2018-10-01 11:51:37 +01003183 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3184 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3185}
3186
Kevin May7d96b162021-02-03 17:38:41 +00003187void TfLiteParserImpl::ParseFullyConnected(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003188{
3189 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3190
Mike Kelly0d77ae12022-01-07 17:42:27 +00003191 const auto& operatorRfr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003192 const auto options = operatorRfr->builtin_options.AsFullyConnectedOptions();
3193
3194 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
3195
3196 FullyConnectedDescriptor desc;
3197 desc.m_BiasEnabled = false;
Nattapat Chaimanowongd8eee592018-10-26 10:24:14 +01003198 desc.m_TransposeWeightMatrix = true;
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003199
3200 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3201 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3202 CHECK_VALID_SIZE(outputs.size(), 1);
3203
Mike Kelly377fb212023-01-10 15:55:28 +00003204 armnn::TensorInfo filterTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003205
3206 // Fully Connected Layer accepts two dimensional weights input
3207 int32_t weightsDimension = static_cast<int32_t>(filterTensorInfo.GetNumDimensions());
3208 if (weightsDimension != 2)
3209 {
3210 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003211 fmt::format("Dimension {} for Fully Connected weights is not supported by Armnn. "
3212 "Node {}",
3213 weightsDimension,
3214 CHECK_LOCATION().AsString()));
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003215 }
3216
Matthew Jackson74bf7da2019-08-16 16:51:42 +01003217 armnn::IConnectableLayer* layer = nullptr;
James Ward58dec6b2020-09-11 17:32:44 +01003218 auto layerName = fmt::format("FullyConnected:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003219
Matthew Sloyan81beae32021-07-13 19:46:11 +01003220 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3221 // Add the first input tensor to the registration list
3222 std::vector<unsigned int> tensorIndexesToRegister = {inputTensorIndexes[0]};
3223 std::vector<unsigned int> ignoreInputWhenRegister = {};
Mike Kelly377fb212023-01-10 15:55:28 +00003224 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Finn Williamsd4fa5452021-03-01 12:31:41 +00003225
3226 desc.m_ConstantWeights = IsConstTensor(inputs[1]);
3227
Matthew Sloyan81beae32021-07-13 19:46:11 +01003228 // Add the weights input to the registration list, constant layers will be added by SetupConstantLayers if constant.
3229 tensorIndexesToRegister.emplace_back(inputTensorIndexes[1]);
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003230
Mike Kelly0506ef02023-01-03 16:29:44 +00003231 if (ShouldConstantTensorBeConverted(inputs[1], inputTensorInfo.GetDataType(), filterTensorInfo.GetDataType()))
Mike Kelly5880b912022-01-28 16:18:54 +00003232 {
3233 m_ConstantsToDequantize.emplace_back(inputs[1]->buffer);
3234 }
3235
Finn Williamsd4fa5452021-03-01 12:31:41 +00003236 if (inputs.size() == 3)
3237 {
3238 desc.m_BiasEnabled = true;
Mike Kelly377fb212023-01-10 15:55:28 +00003239 armnn::TensorInfo biasTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Matthew Sloyan81beae32021-07-13 19:46:11 +01003240
3241 // Add the biases input to the registration list, constant layer will be added by SetupConstantLayers.
3242 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
Mike Kelly5880b912022-01-28 16:18:54 +00003243
Mike Kelly0506ef02023-01-03 16:29:44 +00003244 if (ShouldConstantTensorBeConverted(inputs[2], inputTensorInfo.GetDataType(), biasTensorInfo.GetDataType()))
Mike Kelly5880b912022-01-28 16:18:54 +00003245 {
3246 m_ConstantsToDequantize.emplace_back(inputs[2]->buffer);
3247 }
Finn Williamsd4fa5452021-03-01 12:31:41 +00003248 }
3249
Matthew Sloyan81beae32021-07-13 19:46:11 +01003250 // Filters and biases are always passed to fully connected as inputs
3251 layer = m_Network->AddFullyConnectedLayer(desc, layerName.c_str());
Finn Williamsd4fa5452021-03-01 12:31:41 +00003252
3253 ARMNN_ASSERT(layer != nullptr);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003254
Finn Williamsd4fa5452021-03-01 12:31:41 +00003255 unsigned int startingSlotIndex = 0;
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003256 if (inputTensorInfo.GetNumDimensions() > 2)
3257 {
3258 // Add reshape to flatten to 2D [batch_size, input_size],
3259 // where "input_size" corresponds to the number of inputs to the layer,
3260 // matching the second dimension of weights,
3261 // and "batch_size" is calculated by dividing the number of elements by "input_size".
3262 std::vector<unsigned int> reshapedDimensions(2);
3263 reshapedDimensions[1] = filterTensorInfo.GetShape()[1];
3264 reshapedDimensions[0] = inputTensorInfo.GetNumElements() / reshapedDimensions[1];
3265
3266 if (inputTensorInfo.GetNumElements() % reshapedDimensions[1] != 0)
3267 {
3268 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003269 fmt::format("Failed to deduce input tensor shape from filter size {} {}",
3270 reshapedDimensions[1],
3271 CHECK_LOCATION().AsString()));
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003272 }
3273
Mike Kelly377fb212023-01-10 15:55:28 +00003274 armnn::TensorInfo reshapedTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003275 reshapedTensorInfo.SetShape(armnn::TensorShape{ 2, reshapedDimensions.data() });
Mike Kelly377fb212023-01-10 15:55:28 +00003276 inputTensorInfo = reshapedTensorInfo;
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003277
James Ward58dec6b2020-09-11 17:32:44 +01003278 std::string reshapeLayerName = fmt::format("Reshape_for:{}", layer->GetName());
Finn Williamsd4fa5452021-03-01 12:31:41 +00003279 armnn::ReshapeDescriptor reshapeDescriptor;
3280 reshapeDescriptor.m_TargetShape = reshapedTensorInfo.GetShape();
3281 armnn::IConnectableLayer* reshapeLayer = m_Network->AddReshapeLayer(reshapeDescriptor, layerName.c_str());
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003282
3283 reshapeLayer->GetOutputSlot(0).SetTensorInfo(reshapedTensorInfo);
3284 reshapeLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
3285
Mike Kelly377fb212023-01-10 15:55:28 +00003286 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3287 m_TensorInfos[outputTensorIndexes[0]] = reshapedTensorInfo;
3288
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003289 RegisterInputSlots(subgraphIndex, operatorIndex, reshapeLayer, {inputTensorIndexes[0]});
Finn Williamsd4fa5452021-03-01 12:31:41 +00003290 // Fc layer connects to the reshape layer, so we skip the first input slot when registering fc's input slots
3291 tensorIndexesToRegister.erase(tensorIndexesToRegister.begin());
3292 startingSlotIndex = 1;
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003293 }
Finn Williamsd4fa5452021-03-01 12:31:41 +00003294
3295 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister, startingSlotIndex);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003296
Mike Kelly377fb212023-01-10 15:55:28 +00003297 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromShapes(subgraphIndex, operatorIndex, layer, 0,
3298 { inputTensorInfo.GetShape(),
3299 filterTensorInfo.GetShape() });
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003300 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3301
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003302 // we need to add the activation layer and fortunately we don't need to care about the data layout
3303 armnn::IConnectableLayer* fusedActivationLayer = AddFusedActivationLayer(layer, 0,
3304 options->fused_activation_function);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01003305
Sadik Armagan8853c1f2018-10-22 09:04:18 +01003306 // register the output connection slots for the layer, connections are made after all layers have been created
3307 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3308 RegisterOutputSlots(subgraphIndex, operatorIndex, fusedActivationLayer, {outputTensorIndexes[0]});
3309}
3310
Kevin May7d96b162021-02-03 17:38:41 +00003311void TfLiteParserImpl::ParseDetectionPostProcess(size_t subgraphIndex, size_t operatorIndex)
keidav011b3e2ea2019-02-21 10:07:37 +00003312{
3313 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3314
Mike Kelly0d77ae12022-01-07 17:42:27 +00003315 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
keidav011b3e2ea2019-02-21 10:07:37 +00003316
3317 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3318 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3319 CHECK_VALID_SIZE(outputs.size(), 4);
3320
3321 // Obtain custom options from flexbuffers
3322 auto custom_options = operatorPtr->custom_options;
3323 const flexbuffers::Map& m = flexbuffers::GetRoot(custom_options.data(), custom_options.size()).AsMap();
3324
3325 // Obtain descriptor information from tf lite
3326 DetectionPostProcessDescriptor desc;
3327 desc.m_MaxDetections = m["max_detections"].AsUInt32();
3328 desc.m_MaxClassesPerDetection = m["max_classes_per_detection"].AsUInt32();
3329 desc.m_NmsScoreThreshold = m["nms_score_threshold"].AsFloat();
3330 desc.m_NmsIouThreshold = m["nms_iou_threshold"].AsFloat();
3331 desc.m_NumClasses = m["num_classes"].AsUInt32();
3332 desc.m_ScaleH = m["h_scale"].AsFloat();
3333 desc.m_ScaleW = m["w_scale"].AsFloat();
3334 desc.m_ScaleX = m["x_scale"].AsFloat();
3335 desc.m_ScaleY = m["y_scale"].AsFloat();
3336
keidav0107d58c72019-02-26 11:57:39 +00003337 if (!(m["use_regular_nms"].IsNull()))
keidav011b3e2ea2019-02-21 10:07:37 +00003338 {
keidav0107d58c72019-02-26 11:57:39 +00003339 desc.m_UseRegularNms = m["use_regular_nms"].AsBool();
keidav011b3e2ea2019-02-21 10:07:37 +00003340 }
3341 if (!(m["detections_per_class"].IsNull()))
3342 {
3343 desc.m_DetectionsPerClass = m["detections_per_class"].AsUInt32();
3344 }
3345
3346 if (desc.m_NmsIouThreshold <= 0.0f || desc.m_NmsIouThreshold > 1.0f)
3347 {
3348 throw InvalidArgumentException("DetectionPostProcessTFLiteParser: Intersection over union threshold "
3349 "must be positive and less than or equal to 1.");
3350 }
3351
Mike Kelly377fb212023-01-10 15:55:28 +00003352 armnn::TensorInfo anchorTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2);
Finn Williamsd4fa5452021-03-01 12:31:41 +00003353 auto anchorTensorAndData = CreateConstTensorNonPermuted(inputs[2], anchorTensorInfo);
keidav011b3e2ea2019-02-21 10:07:37 +00003354
James Ward58dec6b2020-09-11 17:32:44 +01003355 auto layerName = fmt::format("DetectionPostProcess:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsd4fa5452021-03-01 12:31:41 +00003356 IConnectableLayer* layer = m_Network->AddDetectionPostProcessLayer(desc, anchorTensorAndData,
keidav011b3e2ea2019-02-21 10:07:37 +00003357 layerName.c_str());
3358
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01003359 ARMNN_ASSERT(layer != nullptr);
keidav011b3e2ea2019-02-21 10:07:37 +00003360
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00003361 // The model does not specify the output shapes.
3362 // The output shapes are calculated from the max_detection and max_classes_per_detection.
3363 unsigned int numDetectedBox = desc.m_MaxDetections * desc.m_MaxClassesPerDetection;
Mike Kelly377fb212023-01-10 15:55:28 +00003364 m_OverriddenOutputShapes.push_back({ 1, numDetectedBox, 4 });
3365 m_OverriddenOutputShapes.push_back({ 1, numDetectedBox });
3366 m_OverriddenOutputShapes.push_back({ 1, numDetectedBox });
3367 m_OverriddenOutputShapes.push_back({ 1 });
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00003368
keidav011b3e2ea2019-02-21 10:07:37 +00003369 for (unsigned int i = 0 ; i < outputs.size() ; ++i)
3370 {
Mike Kelly377fb212023-01-10 15:55:28 +00003371 armnn::TensorInfo detectionBoxOutputTensorInfo = ToTensorInfo(outputs[i], m_OverriddenOutputShapes[i]);
keidav011b3e2ea2019-02-21 10:07:37 +00003372 layer->GetOutputSlot(i).SetTensorInfo(detectionBoxOutputTensorInfo);
3373 }
3374
3375 // Register the input connection slots for the layer, connections are made after all layers have been created
3376 // only the tensors for the inputs are relevant, exclude the const tensors
3377 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3378 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
3379
3380 // Register the output connection slots for the layer, connections are made after all layers have been created
3381 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3382 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0],
3383 outputTensorIndexes[1],
3384 outputTensorIndexes[2],
3385 outputTensorIndexes[3]});
3386}
3387
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003388/// The TfLite Pack operator is equivalent to the ArmNN Stack operator
Kevin May7d96b162021-02-03 17:38:41 +00003389void TfLiteParserImpl::ParsePack(size_t subgraphIndex, size_t operatorIndex)
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003390{
3391 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3392
3393 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3394 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3395 CHECK_VALID_SIZE(outputs.size(), 1);
3396
3397 if (inputs.size() < 1)
3398 {
3399 throw ParseException("Pack must have at least one input.");
3400 }
3401
3402 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3403 const auto* options = operatorPtr->builtin_options.AsPackOptions();
3404
3405 StackDescriptor desc;
3406 desc.m_Axis = static_cast<uint32_t>(options->axis);
3407 desc.m_NumInputs = static_cast<uint32_t>(inputs.size());
3408
3409 // Use the tensor shape of the first input as the "correct" input shape in the descriptor
Mike Kelly377fb212023-01-10 15:55:28 +00003410 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003411 desc.m_InputShape = inputTensorInfo.GetShape();
3412
James Ward58dec6b2020-09-11 17:32:44 +01003413 auto layerName = fmt::format("Pack:{}:{}", subgraphIndex, operatorIndex);
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003414 IConnectableLayer* layer = m_Network->AddStackLayer(desc, layerName.c_str());
3415
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01003416 ARMNN_ASSERT(layer != nullptr);
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003417
Mike Kelly377fb212023-01-10 15:55:28 +00003418 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {});
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01003419 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3420
3421 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3422 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes});
3423
3424 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3425 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3426}
3427
Mike Kelly5880b912022-01-28 16:18:54 +00003428void TfLiteParserImpl::ParseUnidirectionalSequenceLSTM(size_t subgraphIndex, size_t operatorIndex)
3429{
3430 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3431
3432 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3433 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3434
3435 if (inputs.size() < 2)
3436 {
3437 throw ParseException("UnidirectionalSequenceLSTM must have at least 2 input.");
3438 }
3439
3440 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3441 const auto& subgraphPtr = m_Model->subgraphs[subgraphIndex];
3442 const auto nodeParams = operatorPtr->builtin_options.AsUnidirectionalSequenceLSTMOptions();
3443 CHECK_SUPPORTED_FUSED_ACTIVATION(nodeParams, subgraphIndex, operatorIndex);
Mike Kelly377fb212023-01-10 15:55:28 +00003444 auto inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Mike Kelly5880b912022-01-28 16:18:54 +00003445 auto outputTensorInfo = ToTensorInfo(outputs[0]);
3446
3447 // Set the params structure for the AddUnidirectionalSequenceLstmLayer call
3448 // Please refer to each operand at
3449 // https://www.tensorflow.org/mlir/tfl_ops#tflunidirectional_sequence_lstm_tflunidirectionalsequencelstmop
3450 armnn::LstmInputParams params;
3451
3452 if (IsOptionalOperandPresent(operatorPtr->inputs[1]))
3453 {
3454 params.m_InputToInputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[1]].get(),
3455 inputTensorInfo).first;
3456 }
3457
3458 params.m_InputToForgetWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[2]].get(),
3459 inputTensorInfo).first;
3460 params.m_InputToCellWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[3]].get(),
3461 inputTensorInfo).first;
3462 params.m_InputToOutputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[4]].get(),
3463 inputTensorInfo).first;
3464
3465 // Recurrent weight tensors of size {n_cell, n_output}
3466 if (IsOptionalOperandPresent(operatorPtr->inputs[5]))
3467 {
3468 params.m_RecurrentToInputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[5]].get(),
3469 inputTensorInfo).first;
3470 }
3471
3472 params.m_RecurrentToForgetWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[6]].get(),
3473 inputTensorInfo).first;
3474 params.m_RecurrentToCellWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[7]].get(),
3475 inputTensorInfo).first;
3476 params.m_RecurrentToOutputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[8]].get(),
3477 inputTensorInfo).first;
3478
3479 // Peephole weights tensors of size {n_cell}, representing a diagonal matrix.
3480 if (IsOptionalOperandPresent(operatorPtr->inputs[9]))
3481 {
3482 params.m_CellToInputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[9]].get(),
3483 inputTensorInfo).first;
3484 }
3485
3486 if (IsOptionalOperandPresent(operatorPtr->inputs[10]))
3487 {
3488 params.m_CellToForgetWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[10]].get(),
3489 inputTensorInfo).first;
3490 }
3491
3492 if (IsOptionalOperandPresent(operatorPtr->inputs[11]))
3493 {
3494 params.m_CellToOutputWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[11]].get(),
3495 inputTensorInfo).first;
3496 }
3497
3498 // Gates bias tensors of size {n_cell}
3499 if (IsOptionalOperandPresent(operatorPtr->inputs[12]))
3500 {
3501 params.m_InputGateBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[12]].get(),
3502 inputTensorInfo).first;
3503 }
3504
3505 params.m_ForgetGateBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[13]].get(),
3506 inputTensorInfo).first;
3507 params.m_CellBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[14]].get(),
3508 inputTensorInfo).first;
3509 params.m_OutputGateBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[15]].get(),
3510 inputTensorInfo).first;
3511
3512 // Projection weight tensor of size {n_output, n_cell}
3513 if (IsOptionalOperandPresent(operatorPtr->inputs[16]))
3514 {
3515 params.m_ProjectionWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[16]].get(),
3516 inputTensorInfo).first;
3517 }
3518 // Projection bias tensor of size {n_output}
3519 if (IsOptionalOperandPresent(operatorPtr->inputs[17]))
3520 {
3521 params.m_ProjectionBias = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[17]].get(),
3522 inputTensorInfo).first;
3523 }
3524
3525 // These state tensors are defined as variable tensors, and will be modified by this op.
3526 armnn::TensorInfo outputStateInInfo = ToTensorInfo(subgraphPtr->tensors[operatorPtr->inputs[18]].get());
3527 m_ConstantsToBeCreated.push_back(operatorPtr->inputs[18]);
3528 armnn::TensorInfo cellStateInInfo = ToTensorInfo(subgraphPtr->tensors[operatorPtr->inputs[19]].get());
3529 m_ConstantsToBeCreated.push_back(operatorPtr->inputs[19]);
3530
3531 // Layer norm coefficient tensors of size {n_cell}, representing a diagonal matrix.
3532 if (inputs.size() >= 21 && IsOptionalOperandPresent(operatorPtr->inputs[20]))
3533 {
3534 params.m_InputLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[20]].get(),
3535 inputTensorInfo).first;
3536 }
3537
3538 if (inputs.size() >= 22 && IsOptionalOperandPresent(operatorPtr->inputs[21]))
3539 {
3540 params.m_ForgetLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[21]].get(),
3541 inputTensorInfo).first;
3542 }
3543
3544 if (inputs.size() >= 23 && IsOptionalOperandPresent(operatorPtr->inputs[22]))
3545 {
3546 params.m_CellLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[22]].get(),
3547 inputTensorInfo).first;
3548 }
3549
3550 if (inputs.size() >= 24 && IsOptionalOperandPresent(operatorPtr->inputs[23]))
3551 {
3552 params.m_OutputLayerNormWeights = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->inputs[23]].get(),
3553 inputTensorInfo).first;
3554 }
3555
3556 // set the layer descriptor
3557 armnn::UnidirectionalSequenceLstmDescriptor desc;
3558 desc.m_ActivationFunc = nodeParams->fused_activation_function;
3559 desc.m_ClippingThresCell = nodeParams->cell_clip;
3560 desc.m_ClippingThresProj = nodeParams->proj_clip;
3561 desc.m_CifgEnabled = (params.m_InputToInputWeights == nullptr
3562 || params.m_RecurrentToInputWeights == nullptr
3563 || params.m_InputGateBias == nullptr);
3564 desc.m_PeepholeEnabled = (params.m_CellToForgetWeights != nullptr || params.m_CellToOutputWeights != nullptr);
3565 desc.m_ProjectionEnabled = (params.m_ProjectionWeights != nullptr);
3566 desc.m_LayerNormEnabled = (params.m_InputLayerNormWeights != nullptr
3567 || params.m_ForgetLayerNormWeights != nullptr
3568 || params.m_CellLayerNormWeights != nullptr
3569 || params.m_OutputLayerNormWeights != nullptr);
3570 desc.m_TimeMajor = nodeParams->time_major;
3571
Mike Kellyc0800a32022-06-15 10:57:52 +01003572 if (operatorPtr->intermediates.size() > 3 && desc.m_LayerNormEnabled)
Mike Kelly5880b912022-01-28 16:18:54 +00003573 {
3574 auto inputIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[0]].get(),
3575 inputTensorInfo).first;
3576 auto inputIntermediateTensorInfo = inputIntermediate->GetInfo();
3577 desc.m_InputIntermediateScale = inputIntermediateTensorInfo.GetQuantizationScale();
3578
3579 auto forgetIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[1]].get(),
3580 inputTensorInfo).first;
3581 auto forgetIntermediateTensorInfo = forgetIntermediate->GetInfo();
3582 desc.m_ForgetIntermediateScale = forgetIntermediateTensorInfo.GetQuantizationScale();
3583
3584 auto cellIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[2]].get(),
3585 inputTensorInfo).first;
3586 auto cellIntermediateTensorInfo = cellIntermediate->GetInfo();
3587 desc.m_CellIntermediateScale = cellIntermediateTensorInfo.GetQuantizationScale();
3588
3589 auto outputIntermediate = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[3]].get(),
3590 inputTensorInfo).first;
3591 auto outputIntermediateTensorInfo = outputIntermediate->GetInfo();
3592 desc.m_OutputIntermediateScale = outputIntermediateTensorInfo.GetQuantizationScale();
3593 }
3594 else
3595 {
3596 float defaultIntermediate = std::pow(2, -12);
3597 desc.m_InputIntermediateScale = defaultIntermediate;
3598 desc.m_ForgetIntermediateScale = defaultIntermediate;
3599 desc.m_CellIntermediateScale = defaultIntermediate;
3600 desc.m_OutputIntermediateScale = defaultIntermediate;
3601 }
3602
Mike Kellyc0800a32022-06-15 10:57:52 +01003603 if (operatorPtr->intermediates.size() > 4)
3604 {
3605 auto hiddentensor = CreateConstTensorPtr(subgraphPtr->tensors[operatorPtr->intermediates[4]].get(),
3606 inputTensorInfo).first;
Mike Kelly5880b912022-01-28 16:18:54 +00003607
Mike Kellyc0800a32022-06-15 10:57:52 +01003608 desc.m_HiddenStateScale = hiddentensor->GetInfo().GetQuantizationScale();
3609 desc.m_HiddenStateZeroPoint = hiddentensor->GetInfo().GetQuantizationOffset();
3610 }
Mike Kelly5880b912022-01-28 16:18:54 +00003611 unsigned int batchSize = inputTensorInfo.GetShape()[0];
3612 unsigned int outputSize = outputTensorInfo.GetShape()[2];
3613 unsigned int numUnits = cellStateInInfo.GetShape()[1];
3614
3615 armnn::DataType dataType = inputTensorInfo.GetDataType();
3616 float qScale = inputTensorInfo.GetQuantizationScale();
3617 float qOffset = inputTensorInfo.GetQuantizationOffset();
3618
3619 armnn::TensorInfo scratchBufferTensorInfo({batchSize, numUnits * 3}, dataType, qScale, qOffset);
3620 if (!desc.m_CifgEnabled)
3621 {
3622 scratchBufferTensorInfo = armnn::TensorInfo({batchSize, numUnits * 4}, dataType, qScale, qOffset);
3623 }
3624 armnn::TensorInfo cellStateOutTensorInfo({batchSize, numUnits},
3625 cellStateInInfo.GetDataType(),
3626 cellStateInInfo.GetQuantizationScale(),
3627 cellStateInInfo.GetQuantizationOffset());
3628 armnn::TensorInfo outputStateOutTensorInfo({batchSize, outputSize}, dataType, qScale, qOffset);
3629
3630 armnn::LstmInputParamsInfo paramsInfo;
3631 paramsInfo.m_InputToForgetWeights = &(params.m_InputToForgetWeights->GetInfo());
3632 paramsInfo.m_InputToCellWeights = &(params.m_InputToCellWeights->GetInfo());
3633 paramsInfo.m_InputToOutputWeights = &(params.m_InputToOutputWeights->GetInfo());
3634 paramsInfo.m_RecurrentToForgetWeights = &(params.m_RecurrentToForgetWeights->GetInfo());
3635 paramsInfo.m_RecurrentToCellWeights = &(params.m_RecurrentToCellWeights->GetInfo());
3636 paramsInfo.m_RecurrentToOutputWeights = &(params.m_RecurrentToOutputWeights->GetInfo());
3637 paramsInfo.m_ForgetGateBias = &(params.m_ForgetGateBias->GetInfo());
3638 paramsInfo.m_CellBias = &(params.m_CellBias->GetInfo());
3639 paramsInfo.m_OutputGateBias = &(params.m_OutputGateBias->GetInfo());
3640
3641 if (!desc.m_CifgEnabled)
3642 {
3643 paramsInfo.m_InputToInputWeights = &(params.m_InputToInputWeights->GetInfo());
3644 paramsInfo.m_RecurrentToInputWeights = &(params.m_RecurrentToInputWeights->GetInfo());
3645 if (params.m_CellToInputWeights != nullptr)
3646 {
3647 paramsInfo.m_CellToInputWeights = &(params.m_CellToInputWeights->GetInfo());
3648 }
3649 paramsInfo.m_InputGateBias = &(params.m_InputGateBias->GetInfo());
3650 }
3651
3652 if (desc.m_ProjectionEnabled)
3653 {
3654 paramsInfo.m_ProjectionWeights = &(params.m_ProjectionWeights->GetInfo());
3655 if (params.m_ProjectionBias != nullptr)
3656 {
3657 paramsInfo.m_ProjectionBias = &(params.m_ProjectionBias->GetInfo());
3658 }
3659 }
3660
3661 if (desc.m_PeepholeEnabled)
3662 {
3663 paramsInfo.m_CellToForgetWeights = &(params.m_CellToForgetWeights->GetInfo());
3664 paramsInfo.m_CellToOutputWeights = &(params.m_CellToOutputWeights->GetInfo());
3665 }
3666
3667 if (desc.m_LayerNormEnabled)
3668 {
3669 if(!desc.m_CifgEnabled)
3670 {
3671 paramsInfo.m_InputLayerNormWeights = &(params.m_InputLayerNormWeights->GetInfo());
3672 }
3673 paramsInfo.m_ForgetLayerNormWeights = &(params.m_ForgetLayerNormWeights->GetInfo());
3674 paramsInfo.m_CellLayerNormWeights = &(params.m_CellLayerNormWeights->GetInfo());
3675 paramsInfo.m_OutputLayerNormWeights = &(params.m_OutputLayerNormWeights->GetInfo());
3676 }
3677
3678 auto layerName = fmt::format("UnidirectionalSequenceLSTM:{}:{}", subgraphIndex, operatorIndex);
3679 armnn::IConnectableLayer* layer = m_Network->AddUnidirectionalSequenceLstmLayer(desc, params);
3680 ARMNN_ASSERT(layer != nullptr);
3681
3682 // register the input connection slots for the layer, connections are made after all layers have been created
3683 // only the tensors for the inputs are relevant, exclude the const tensors
3684 auto inputTensorIndexes = AsUnsignedVector({operatorPtr->inputs[0],
3685 operatorPtr->inputs[18],
3686 operatorPtr->inputs[19]});
3687 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0],
3688 inputTensorIndexes[1],
3689 inputTensorIndexes[2]});
3690
3691 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3692
3693 layer->GetOutputSlot(0).SetTensorInfo(outputStateOutTensorInfo);
3694 layer->GetOutputSlot(1).SetTensorInfo(cellStateOutTensorInfo);
3695 layer->GetOutputSlot(2).SetTensorInfo(outputTensorInfo);
3696
3697 unsigned int tensorIndex = outputTensorIndexes[0];
3698 armnn::IOutputSlot* slot = &(layer->GetOutputSlot(2));
3699 RegisterProducerOfTensor(subgraphIndex, tensorIndex, slot);
3700}
3701
Kevin May7d96b162021-02-03 17:38:41 +00003702void TfLiteParserImpl::ParseUnpack(size_t subgraphIndex, size_t operatorIndex)
Nina Drozd200e3802019-04-15 09:47:39 +01003703{
3704 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3705
Mike Kelly0d77ae12022-01-07 17:42:27 +00003706 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3707 const auto* options = operatorPtr->builtin_options.AsUnpackOptions();
Nina Drozd200e3802019-04-15 09:47:39 +01003708
3709 // This unpackAxis indicates the axis to unpack
3710 const unsigned int unpackAxis = CHECKED_NON_NEGATIVE(options->axis);
3711
3712 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3713 CHECK_VALID_SIZE(inputs.size(), 1);
3714
Mike Kelly377fb212023-01-10 15:55:28 +00003715 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003716
3717 if (unpackAxis >= inputTensorInfo.GetNumDimensions())
3718 {
3719 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003720 fmt::format("The unpack axis: {} cannot be greater than or equal to "
3721 "the number of input dimension {} {}",
3722 unpackAxis,
3723 inputTensorInfo.GetNumDimensions(),
3724 CHECK_LOCATION().AsString()));
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003725 }
3726
Nina Drozd200e3802019-04-15 09:47:39 +01003727 unsigned int unpackNum = CHECKED_NON_NEGATIVE(options->num);
3728 // If num is not defined, automatically infer from the length of the dimension axis.
3729 if(unpackNum == 0)
3730 {
3731 unpackNum = inputTensorInfo.GetShape()[unpackAxis];
3732 }
3733
3734 // If unpack number cannot be inferred and is still zero, throw ParseException.
3735 if(unpackNum == 0)
3736 {
3737 throw ParseException("Number to unpack must greater than zero.");
3738 }
3739
3740 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3741 CHECK_VALID_SIZE(outputs.size(), unpackNum);
3742
3743 auto inputDimSize = inputTensorInfo.GetNumDimensions();
3744 std::vector<unsigned int> unpackDimSizes(inputDimSize);
3745
3746 // Add current input shape to unpackDimSizes
3747 for (unsigned int i = 0; i < inputDimSize; ++i)
3748 {
3749 unpackDimSizes[i] = inputTensorInfo.GetShape()[i];
3750 }
3751
3752 if (unpackDimSizes[unpackAxis] != unpackNum)
3753 {
3754 throw ParseException("Number to unpack must be the same as length of the dimension to "
3755 "unpack along.");
3756 }
3757
3758 unpackDimSizes[unpackAxis] /= unpackNum;
3759
3760 SplitterDescriptor splitDesc(unpackNum, static_cast<unsigned int>(unpackDimSizes.size()));
3761 for (unsigned int j = 0; j < unpackNum; ++j)
3762 {
3763 // Set the size of the views.
3764 for (unsigned int dimIdx = 0; dimIdx < unpackDimSizes.size(); ++dimIdx)
3765 {
3766 splitDesc.SetViewSize(j, dimIdx, unpackDimSizes[dimIdx]);
3767 }
3768 splitDesc.SetViewOriginCoord(j, unpackAxis, unpackDimSizes[unpackAxis] * j);
3769 }
3770
James Ward58dec6b2020-09-11 17:32:44 +01003771 auto layerName = fmt::format("Unpack:{}:{}", subgraphIndex, operatorIndex);
Nina Drozd200e3802019-04-15 09:47:39 +01003772 IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01003773 ARMNN_ASSERT(layer != nullptr);
Nina Drozd200e3802019-04-15 09:47:39 +01003774
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003775 TensorShape splitOutShape = TensorShape(static_cast<unsigned int>(unpackDimSizes.size()),
3776 unpackDimSizes.data());
3777
Nina Drozd200e3802019-04-15 09:47:39 +01003778 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3779 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3780
Finn Williamsb49ed182021-06-29 15:50:08 +01003781 std::vector<unsigned int> reshapeDims;
3782 for (unsigned int axis = 0; axis < splitOutShape.GetNumDimensions(); ++axis)
3783 {
3784 if (axis != unpackAxis)
3785 {
3786 reshapeDims.push_back(splitOutShape[axis]);
3787 }
3788 }
3789
3790 TensorShape reshapeOutputShape(splitOutShape.GetNumDimensions() -1, reshapeDims.data());
3791
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003792 // Create reshape to remove the unpacked dimension for unpack operator of each output from Splitter.
3793 for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
3794 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01003795 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[k], true);
James Ward58dec6b2020-09-11 17:32:44 +01003796 std::string reshapeLayerName = fmt::format("Reshape_for:{}", layer->GetName());
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003797 armnn::ReshapeDescriptor desc;
Finn Williamsb49ed182021-06-29 15:50:08 +01003798 desc.m_TargetShape = reshapeOutputShape;
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003799 armnn::IConnectableLayer* reshapeLayer = m_Network->AddReshapeLayer(desc, layerName.c_str());
3800
Narumol Prangnawarat2c526462019-10-21 14:58:26 +01003801 layer->GetOutputSlot(k).SetTensorInfo(armnn::TensorInfo(splitOutShape,
3802 outputTensorInfo.GetDataType(),
3803 outputTensorInfo.GetQuantizationScale(),
3804 outputTensorInfo.GetQuantizationOffset()));
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003805 layer->GetOutputSlot(k).Connect(reshapeLayer->GetInputSlot(0));
3806
Narumol Prangnawarat2c526462019-10-21 14:58:26 +01003807 reshapeLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003808
3809 uint32_t reshapedOutputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[k]);
3810 armnn::IOutputSlot* slot = &(reshapeLayer->GetOutputSlot(0));
3811 RegisterProducerOfTensor(subgraphIndex, reshapedOutputId, slot);
3812 }
Nina Drozd200e3802019-04-15 09:47:39 +01003813}
3814
Kevin May7d96b162021-02-03 17:38:41 +00003815void TfLiteParserImpl::ParseSplit(size_t subgraphIndex, size_t operatorIndex)
Nina Drozd0324f482019-04-08 10:52:10 +01003816{
3817 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3818
Mike Kelly0d77ae12022-01-07 17:42:27 +00003819 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3820 const auto* options = operatorPtr->builtin_options.AsSplitOptions();
Nina Drozd0324f482019-04-08 10:52:10 +01003821
3822 const unsigned int numSplits = CHECKED_NON_NEGATIVE(options->num_splits);
3823
Nina Drozd200e3802019-04-15 09:47:39 +01003824 // If number of splits cannot be inferred and is zero, throw ParseException.
3825 if(numSplits == 0)
3826 {
3827 throw ParseException("Number to splits must greater than zero.");
3828 }
3829
Nina Drozd0324f482019-04-08 10:52:10 +01003830 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3831 CHECK_VALID_SIZE(inputs.size(), 2);
3832 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3833 CHECK_VALID_SIZE(outputs.size(), numSplits);
3834
Mike Kelly377fb212023-01-10 15:55:28 +00003835 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
3836 armnn::TensorInfo axisTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01003837 ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
Nina Drozd0324f482019-04-08 10:52:10 +01003838
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01003839 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[0]->buffer);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01003840 if (axisBufferPtr == nullptr)
3841 {
3842 throw ParseException(
3843 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
3844 CHECK_LOCATION().AsString()));
3845 }
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01003846
Matthew Sloyaned7fce42021-04-15 20:46:24 +01003847 std::vector<int32_t> axisData(axisTensorInfo.GetNumElements());
3848 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
3849 int32_t axis = axisData[0];
3850
3851 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
3852 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
3853 {
3854 // Square bracket denotes inclusive n while parenthesis denotes exclusive n
3855 // E.g. Rank 4 tensor can have axis in range [-4, 3)
3856 // -1 == 3, -2 == 2, -3 == 1, -4 == 0
3857 throw ParseException(
3858 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
3859 axis,
3860 CHECK_LOCATION().AsString()));
3861 }
3862
3863 const unsigned int splitDim = armnnUtils::GetUnsignedAxis(inputTensorInfo.GetNumDimensions(), axis);
Nina Drozd0324f482019-04-08 10:52:10 +01003864
Nina Drozd0324f482019-04-08 10:52:10 +01003865 auto inputDimSize = inputTensorInfo.GetNumDimensions();
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01003866 if (inputDimSize > MaxNumOfTensorDimensions)
Nina Drozd0324f482019-04-08 10:52:10 +01003867 {
3868 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003869 fmt::format("The number of dimensions: {} for input tensors of the split op cannot be greater than {} {}",
3870 inputTensorInfo.GetNumDimensions(),
3871 MaxNumOfTensorDimensions,
3872 CHECK_LOCATION().AsString()));
Nina Drozd0324f482019-04-08 10:52:10 +01003873 }
3874
3875 std::vector<unsigned int> splitterDimSizes(inputDimSize);
3876
3877 // Add current input shape to splitterDimSizes
3878 for (unsigned int i = 0; i < inputDimSize; ++i)
3879 {
3880 splitterDimSizes[i] = inputTensorInfo.GetShape()[i];
3881 }
3882
3883 if (splitterDimSizes[splitDim] % numSplits != 0)
3884 {
3885 throw ParseException("Number of splits must evenly divide the dimension");
3886 }
3887 splitterDimSizes[splitDim] /= numSplits;
3888
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01003889 SplitterDescriptor splitDesc(numSplits, inputDimSize);
Nina Drozd0324f482019-04-08 10:52:10 +01003890 for (unsigned int j = 0; j < numSplits; ++j)
3891 {
3892 // Set the size of the views.
3893 for (unsigned int dimIdx = 0; dimIdx < splitterDimSizes.size(); ++dimIdx)
3894 {
3895 splitDesc.SetViewSize(j, dimIdx, splitterDimSizes[dimIdx]);
3896 }
3897 splitDesc.SetViewOriginCoord(j, splitDim, splitterDimSizes[splitDim] * j);
3898 }
3899
James Ward58dec6b2020-09-11 17:32:44 +01003900 auto layerName = fmt::format("Split:{}:{}", subgraphIndex, operatorIndex);
Nina Drozd0324f482019-04-08 10:52:10 +01003901 IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01003902 ARMNN_ASSERT(layer != nullptr);
Nina Drozd0324f482019-04-08 10:52:10 +01003903
3904 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01003905 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[1]});
Nina Drozd0324f482019-04-08 10:52:10 +01003906
Nina Drozd0324f482019-04-08 10:52:10 +01003907 for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
3908 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01003909 armnn::TensorInfo tensorInfo = ToTensorInfo(outputs[k], true);
Francis Murtagh98d6b3d2019-10-21 10:52:54 +01003910 layer->GetOutputSlot(k).SetTensorInfo(tensorInfo);
Nina Drozd0324f482019-04-08 10:52:10 +01003911 }
3912
3913 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3914 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
3915}
3916
Derek Lambertif0176992020-04-28 13:37:49 +01003917unsigned int ComputeWrappedIndex(int idx, unsigned int numDimsIn)
3918{
3919 int numDims = armnn::numeric_cast<int>(numDimsIn);
3920 int v = idx < 0 ? numDims + idx : idx;
3921 ARMNN_ASSERT(v >= 0);
3922 ARMNN_ASSERT(v < numDims);
3923
3924 return static_cast<unsigned int>(v);
3925}
3926
Kevin May7d96b162021-02-03 17:38:41 +00003927void TfLiteParserImpl::ParseSplitV(size_t subgraphIndex, size_t operatorIndex)
Derek Lambertif0176992020-04-28 13:37:49 +01003928{
3929 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3930
Mike Kelly0d77ae12022-01-07 17:42:27 +00003931 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3932 const auto* options = operatorPtr->builtin_options.AsSplitVOptions();
Derek Lambertif0176992020-04-28 13:37:49 +01003933
3934 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3935 CHECK_VALID_SIZE(inputs.size(), 3);
3936
3937 auto& inputTensor = inputs[0];
3938 auto& splitsTensor = inputs[1];
3939 auto& axisTensor = inputs[2];
3940
3941 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputTensor);
3942 armnn::TensorInfo splitsInfo = ToTensorInfo(splitsTensor);
3943 armnn::TensorInfo axisTensorInfo = ToTensorInfo(axisTensor);
3944 ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
3945
3946 // Inputs
3947 auto inputDimSize = inputTensorInfo.GetNumDimensions();
3948 if (inputDimSize > MaxNumOfTensorDimensions)
3949 {
3950 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003951 fmt::format("The number of dimensions: {} for input tensors of the "
3952 "SplitV op cannot be greater than {} {}",
3953 inputTensorInfo.GetNumDimensions(),
3954 MaxNumOfTensorDimensions,
3955 CHECK_LOCATION().AsString()));
Derek Lambertif0176992020-04-28 13:37:49 +01003956 }
3957
3958 // Get split axis
3959 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, axisTensor->buffer);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01003960 if (axisBufferPtr == nullptr)
3961 {
3962 throw ParseException(
3963 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
3964 CHECK_LOCATION().AsString()));
3965 }
3966
Derek Lambertif0176992020-04-28 13:37:49 +01003967 std::vector<int> axisData(axisTensorInfo.GetNumElements());
3968 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
Matthew Sloyaned7fce42021-04-15 20:46:24 +01003969 int32_t axis = axisData[0];
3970
3971 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
3972 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
3973 {
3974 // Square bracket denotes inclusive n while parenthesis denotes exclusive n
3975 // E.g. Rank 4 tensor can have axis in range [-4, 3)
3976 // -1 == 3, -2 == 2, -3 == 1, -4 == 0
3977 throw ParseException(
3978 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
3979 axis,
3980 CHECK_LOCATION().AsString()));
3981 }
3982 const unsigned int splitDim = ComputeWrappedIndex(axis, inputTensorInfo.GetNumDimensions());
Derek Lambertif0176992020-04-28 13:37:49 +01003983
Derek Lambertif0176992020-04-28 13:37:49 +01003984 // Set split sizes
Derek Lambertif0176992020-04-28 13:37:49 +01003985 CHECK_VALID_SIZE(splitsInfo.GetNumDimensions(), 1);
Ryan OShea86704732020-05-26 11:41:04 +01003986 unsigned int numSplits{0};
3987
3988 if(options)
Derek Lambertif0176992020-04-28 13:37:49 +01003989 {
3990 numSplits = CHECKED_NON_NEGATIVE(options->num_splits);
Derek Lambertif0176992020-04-28 13:37:49 +01003991 }
3992 else
3993 {
Ryan OShea86704732020-05-26 11:41:04 +01003994 numSplits = splitsInfo.GetNumElements();
Derek Lambertif0176992020-04-28 13:37:49 +01003995 }
3996
3997 if (numSplits <=0)
3998 {
3999 throw ParseException("SplitV has invalid number of splits");
4000 }
4001
Jan Eilersc0761e92020-06-29 16:48:44 +01004002 std::vector<int> splitsData(numSplits);
Ryan OShea86704732020-05-26 11:41:04 +01004003 BufferRawPtr splitsBufferPtr = GetBuffer(m_Model, splitsTensor->buffer);
Jan Eilersc0761e92020-06-29 16:48:44 +01004004 ::memcpy(splitsData.data(), splitsBufferPtr->data.data(), splitsInfo.GetNumBytes());
Ryan OShea86704732020-05-26 11:41:04 +01004005
Jan Eilersc0761e92020-06-29 16:48:44 +01004006 unsigned int idx = 0;
Ryan OShea86704732020-05-26 11:41:04 +01004007 int numInferred{0};
4008 unsigned int inferIdx{0};
4009 int splitSum{0};
4010 for (auto split : splitsData)
4011 {
4012 if (split < 0)
4013 {
4014 numInferred++;
4015 inferIdx = idx;
4016 }
4017 else
4018 {
4019 splitSum += split;
4020 }
4021 idx++;
4022 }
4023 // Check for inferred Axis
4024 if (numInferred == 0)
4025 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +01004026 if (splitSum != armnn::numeric_cast<int>(inputTensorInfo.GetShape()[splitDim]))
Ryan OShea86704732020-05-26 11:41:04 +01004027 {
4028 throw ParseException("SplitV split_sizes does not sum to the dimension of value along split_dim.");
4029 }
4030 }
4031 else if (numInferred == 1)
4032 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +01004033 splitsData[inferIdx] = armnn::numeric_cast<int>(inputTensorInfo.GetShape()[splitDim]) - splitSum;
Ryan OShea86704732020-05-26 11:41:04 +01004034 }
4035 else
4036 {
4037 throw ParseException("Cannot infer split size for more than one split");
4038 }
4039
Derek Lambertif0176992020-04-28 13:37:49 +01004040 //Ouput size validation
4041 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4042 CHECK_VALID_SIZE(outputs.size(), numSplits);
4043
4044 // Setup Armnn descriptor
4045 SplitterDescriptor splitDesc(numSplits, inputDimSize);
4046 unsigned int accumSplit = 0;
4047 for (unsigned int j = 0; j < numSplits; ++j)
4048 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +01004049 unsigned int splitSize = armnn::numeric_cast<unsigned int>(splitsData[j]);
Derek Lambertif0176992020-04-28 13:37:49 +01004050
4051 // Set the size of the views.
4052 for (unsigned int dimIdx = 0; dimIdx < inputTensorInfo.GetNumDimensions(); ++dimIdx)
4053 {
4054 unsigned int dimSize = inputTensorInfo.GetShape()[dimIdx];
4055 if (dimIdx == splitDim)
4056 {
4057 dimSize = splitSize;
4058 }
4059 splitDesc.SetViewSize(j, dimIdx, dimSize);
4060 }
4061
4062 splitDesc.SetViewOriginCoord(j, splitDim, accumSplit);
4063 accumSplit += splitSize;
4064 }
4065
James Ward58dec6b2020-09-11 17:32:44 +01004066 auto layerName = fmt::format("SplitV:{}:{}", subgraphIndex, operatorIndex);
Derek Lambertif0176992020-04-28 13:37:49 +01004067 IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01004068 ARMNN_ASSERT(layer != nullptr);
Derek Lambertif0176992020-04-28 13:37:49 +01004069
4070 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4071 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4072
4073 for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
4074 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01004075 armnn::TensorInfo tensorInfo = ToTensorInfo(outputs[k], true);
Derek Lambertif0176992020-04-28 13:37:49 +01004076 layer->GetOutputSlot(k).SetTensorInfo(tensorInfo);
4077 }
4078
4079 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4080 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4081}
4082
Matthew Sloyan28f177c2021-04-09 14:38:52 +01004083void TfLiteParserImpl::ParseArgMin(size_t subgraphIndex, size_t operatorIndex)
4084{
4085 ParseArgMinMax(subgraphIndex, operatorIndex, armnn::ArgMinMaxFunction::Min);
4086}
4087
Kevin May7d96b162021-02-03 17:38:41 +00004088void TfLiteParserImpl::ParseArgMax(size_t subgraphIndex, size_t operatorIndex)
Inki Daed4619e22020-09-10 15:33:54 +09004089{
Matthew Sloyan28f177c2021-04-09 14:38:52 +01004090 ParseArgMinMax(subgraphIndex, operatorIndex, armnn::ArgMinMaxFunction::Max);
4091}
4092
4093void TfLiteParserImpl::ParseArgMinMax(size_t subgraphIndex, size_t operatorIndex, ArgMinMaxFunction argMinMaxFunction)
4094{
Inki Daed4619e22020-09-10 15:33:54 +09004095 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4096 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4097 CHECK_VALID_SIZE(inputs.size(), 2);
4098
4099 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4100 CHECK_VALID_SIZE(outputs.size(), 1);
4101
Mike Kelly377fb212023-01-10 15:55:28 +00004102 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4103 armnn::TensorInfo axisTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Inki Daed4619e22020-09-10 15:33:54 +09004104 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004105 ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
Matthew Sloyan28f177c2021-04-09 14:38:52 +01004106
4107 // Check if output tensor type is Signed32 or Signed64
Mike Kelly1f140f72021-04-06 12:25:55 +01004108 if (outputTensorInfo.GetDataType() != armnn::DataType::Signed32 &&
4109 outputTensorInfo.GetDataType() != armnn::DataType::Signed64)
4110 {
4111 throw ParseException(
4112 fmt::format(
4113 "Output tensor data type is not supported. (Supported types: Signed32 & Signed64) {}",
4114 CHECK_LOCATION().AsString()));
4115 }
Matthew Sloyan28f177c2021-04-09 14:38:52 +01004116
4117 // Get const axis value from model and set it to descriptor.
4118 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
4119 if (axisBufferPtr == nullptr)
4120 {
4121 throw ParseException(
4122 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
4123 CHECK_LOCATION().AsString()));
4124 }
4125
4126 std::vector<int32_t> axisData(axisTensorInfo.GetNumElements());
4127 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
4128 int32_t axis = axisData.front();
4129
4130 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
4131 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
4132 {
4133 // Square bracket denotes inclusive n while parenthesis denotes exclusive n
4134 // E.g. Rank 4 tensor can have axis in range [-4, 3)
4135 // -1 == 3, -2 == 2, -3 == 1, -4 == 0
4136 throw ParseException(
4137 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
4138 axis,
4139 CHECK_LOCATION().AsString()));
4140 }
4141
4142 ArgMinMaxDescriptor desc;
4143 desc.m_Axis = axis;
4144 desc.m_Function = argMinMaxFunction;
4145
4146 // Register a ArgMin/ArgMax layer.
4147 auto layerName = argMinMaxFunction == ArgMinMaxFunction::Max ? "ArgMax:{}:{}" : "ArgMin:{}:{}";
4148 auto layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4149 IConnectableLayer *layer = m_Network->AddArgMinMaxLayer(desc, layerNameFormatted.c_str());
4150 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00004151 outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Inki Daed4619e22020-09-10 15:33:54 +09004152 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4153
4154 // Register input tensor to the layer.
4155 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4156 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4157
4158 // Register output tensor to the layer.
4159 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4160 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4161}
4162
Kevin May7d96b162021-02-03 17:38:41 +00004163void TfLiteParserImpl::ParseGather(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan26868492021-01-22 14:25:31 +00004164{
4165 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4166
Kevin May7d96b162021-02-03 17:38:41 +00004167 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00004168 CHECK_VALID_SIZE(inputs.size(), 2);
Kevin May7d96b162021-02-03 17:38:41 +00004169 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00004170 CHECK_VALID_SIZE(outputs.size(), 1);
4171
Mike Kelly377fb212023-01-10 15:55:28 +00004172 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4173 armnn::TensorInfo indicesTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
4174 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
Sadik Armagan26868492021-01-22 14:25:31 +00004175
4176 armnn::GatherDescriptor gatherDescriptor;
4177
Mike Kelly0d77ae12022-01-07 17:42:27 +00004178 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4179 const auto* options = operatorPtr->builtin_options.AsGatherOptions();
Sadik Armagan26868492021-01-22 14:25:31 +00004180 auto axis = options->axis;
4181
Mike Kelly377fb212023-01-10 15:55:28 +00004182 auto layerName = fmt::format("Gather:{}:{}", subgraphIndex, operatorIndex);
4183
Sadik Armagan26868492021-01-22 14:25:31 +00004184 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
4185 auto indicesDimensions = indicesTensorInfo.GetNumDimensions();
4186 auto outputDimensions = outputTensorInfo.GetNumDimensions();
4187 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
4188 {
4189 throw ParseException(
4190 fmt::format("Operation has invalid axis: {} It is out of bounds [ -{}, {} ) {}",
4191 axis,
4192 inputDimensions, inputDimensions,
4193 CHECK_LOCATION().AsString()));
4194 }
4195 if (outputDimensions != static_cast<unsigned int>(inputDimensions) + indicesDimensions - 1)
4196 {
4197 throw ParseException(
4198 fmt::format("Operation has invalid output dimensions: {} Output must be an ({} + {} - 1) -D tensor {}",
4199 outputDimensions,
4200 inputDimensions, indicesDimensions,
4201 CHECK_LOCATION().AsString()));
4202 }
4203
4204 gatherDescriptor.m_Axis = axis;
4205
Sadik Armagan26868492021-01-22 14:25:31 +00004206 IConnectableLayer* layer = m_Network->AddGatherLayer(gatherDescriptor, layerName.c_str());
4207 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00004208 outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Sadik Armagan26868492021-01-22 14:25:31 +00004209 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4210
4211 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4212 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4213
4214 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4215 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4216}
4217
Teresa Charlin91a53ea2022-04-25 15:47:29 +01004218void TfLiteParserImpl::ParseGatherNd(size_t subgraphIndex, size_t operatorIndex)
4219{
4220 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4221
4222 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4223 CHECK_VALID_SIZE(inputs.size(), 2);
4224 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4225 CHECK_VALID_SIZE(outputs.size(), 1);
4226
Mike Kelly377fb212023-01-10 15:55:28 +00004227 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4228 armnn::TensorInfo indicesTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Teresa Charlin91a53ea2022-04-25 15:47:29 +01004229
4230 auto layerName = fmt::format("GatherNd:{}:{}", subgraphIndex, operatorIndex);
4231 IConnectableLayer* layer = m_Network->AddGatherNdLayer(layerName.c_str());
4232 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00004233 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Teresa Charlin91a53ea2022-04-25 15:47:29 +01004234 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4235
4236 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4237 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4238
4239 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4240 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4241}
4242
Kevin May7d96b162021-02-03 17:38:41 +00004243void TfLiteParserImpl::ParseDepthToSpace(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan26868492021-01-22 14:25:31 +00004244{
4245 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4246
Kevin May7d96b162021-02-03 17:38:41 +00004247 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00004248 CHECK_VALID_SIZE(inputs.size(), 1);
Kevin May7d96b162021-02-03 17:38:41 +00004249 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00004250 CHECK_VALID_SIZE(outputs.size(), 1);
4251
4252 armnn::DepthToSpaceDescriptor descriptor;
4253
Mike Kelly0d77ae12022-01-07 17:42:27 +00004254 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4255 const auto* options = operatorPtr->builtin_options.AsDepthToSpaceOptions();
Sadik Armagan26868492021-01-22 14:25:31 +00004256 auto blockSize = options->block_size;
4257 if (blockSize < 2)
4258 {
4259 throw ParseException(
4260 fmt::format("Operation has invalid block size: {} Block size should be >= 2 {}",
4261 blockSize,
4262 CHECK_LOCATION().AsString()));
4263 }
4264 descriptor.m_BlockSize = armnn::numeric_cast<uint32_t>(blockSize);
4265
4266 auto layerName = fmt::format("DepthToSpace:{}:{}", subgraphIndex, operatorIndex);
4267 IConnectableLayer* layer = m_Network->AddDepthToSpaceLayer(descriptor, layerName.c_str());
4268 ARMNN_ASSERT(layer != nullptr);
Mike Kelly377fb212023-01-10 15:55:28 +00004269 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Sadik Armagan26868492021-01-22 14:25:31 +00004270 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4271
4272 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4273 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4274
4275 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4276 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4277}
4278
Kevin May7d96b162021-02-03 17:38:41 +00004279void TfLiteParserImpl::ParseSum(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004280{
Sadik Armagana2747482021-02-09 10:28:54 +00004281 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Sum);
4282}
4283
Teresa Charlin4e3e8312021-08-05 12:34:37 +01004284void TfLiteParserImpl::ParseReduceProd(size_t subgraphIndex, size_t operatorIndex)
4285{
4286 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Prod);
4287}
4288
Sadik Armagana2747482021-02-09 10:28:54 +00004289void TfLiteParserImpl::ParseReduceMax(size_t subgraphIndex, size_t operatorIndex)
4290{
4291 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Max);
4292}
4293
4294void TfLiteParserImpl::ParseReduceMin(size_t subgraphIndex, size_t operatorIndex)
4295{
4296 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Min);
4297}
4298
4299void TfLiteParserImpl::ParseReduce(size_t subgraphIndex, size_t operatorIndex, ReduceOperation reduceOperation)
4300{
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004301 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4302
Mike Kelly0d77ae12022-01-07 17:42:27 +00004303 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4304 const auto* options = operatorPtr->builtin_options.AsReducerOptions();
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004305
4306 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4307 CHECK_VALID_SIZE(inputs.size(), 2);
4308
4309 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4310 CHECK_VALID_SIZE(outputs.size(), 1);
4311
Sadik Armagana2747482021-02-09 10:28:54 +00004312 auto layerName = fmt::format("Reduce:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004313
Mike Kelly377fb212023-01-10 15:55:28 +00004314 armnn::TensorInfo inputTensorInfo0 = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4315 armnn::TensorInfo inputTensorInfo1 = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004316
4317 ReduceDescriptor desc;
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004318 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
4319 // Get const axis value from model and set it to descriptor.
4320 if (axisBufferPtr != nullptr)
4321 {
Sadik Armagan49bdb792021-02-11 13:57:07 +00004322 std::vector<int32_t> axisData(inputTensorInfo1.GetNumElements());
4323 ::memcpy(axisData.data(), axisBufferPtr->data.data(), inputTensorInfo1.GetNumBytes());
4324
4325 // Convert the axis to unsigned int and remove duplicates.
4326 auto rank = static_cast<int32_t>(inputTensorInfo0.GetNumDimensions());
4327 std::set<unsigned int> uniqueAxis;
4328 std::transform(axisData.begin(),
4329 axisData.end(),
4330 std::inserter(uniqueAxis, uniqueAxis.begin()),
4331 [rank](int i)->unsigned int{
4332 return static_cast<uint32_t>(((i + rank) % rank)); });
4333 desc.m_vAxis.assign(uniqueAxis.begin(), uniqueAxis.end());
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004334 }
Sadik Armagana2747482021-02-09 10:28:54 +00004335 else
4336 {
4337 for (uint32_t i = 0; i < inputTensorInfo0.GetNumDimensions(); ++i)
4338 {
4339 desc.m_vAxis.push_back(i);
4340 }
4341 }
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004342
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004343 desc.m_KeepDims = options->keep_dims;
Sadik Armagana2747482021-02-09 10:28:54 +00004344 desc.m_ReduceOperation = reduceOperation;
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004345
4346 // Register a new layer object, Sum.
Mike Kelly0d77ae12022-01-07 17:42:27 +00004347 IConnectableLayer* layer = m_Network->AddReduceLayer(desc, layerName.c_str());
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004348
Mike Kelly377fb212023-01-10 15:55:28 +00004349 armnn::TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004350 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4351
4352 // Register input tensor to the layer.
4353 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4354 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4355
4356 // Register output tensor to the layer.
4357 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4358 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4359}
4360
Mike Kelly31dce2b2021-09-01 21:22:37 +01004361void TfLiteParserImpl::ParseLocalResponseNormalization(size_t subgraphIndex, size_t operatorIndex)
4362{
4363 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4364
4365 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4366 CHECK_VALID_SIZE(inputs.size(), 1);
4367
4368 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4369 CHECK_VALID_SIZE(outputs.size(), 1);
4370
4371 auto layerName = fmt::format("LRN:{}:{}", subgraphIndex, operatorIndex);
4372 std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4373
Mike Kelly377fb212023-01-10 15:55:28 +00004374 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
Mike Kelly31dce2b2021-09-01 21:22:37 +01004375
4376 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
4377 const auto* options = operatorPtr->builtin_options.AsLocalResponseNormalizationOptions();
4378
4379 armnn::NormalizationDescriptor descriptor;
4380 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
4381 descriptor.m_NormChannelType = armnn::NormalizationAlgorithmChannel::Across;
4382 descriptor.m_NormMethodType = armnn::NormalizationAlgorithmMethod::LocalBrightness;
4383 descriptor.m_NormSize = static_cast<uint32_t>(options->radius);
4384 descriptor.m_K = options->bias;
4385 descriptor.m_Alpha = options->alpha;
4386 descriptor.m_Beta = options->beta;
4387
4388 // ArmNN expects normSize to be the full size of the normalization
4389 // window rather than the radius as in TfLite.
4390 descriptor.m_NormSize = 1 + (2 * descriptor.m_NormSize);
4391
4392 IConnectableLayer* layer = m_Network->AddNormalizationLayer(descriptor, layerNameFormatted.c_str());
4393 ARMNN_ASSERT(layer != nullptr);
4394
Mike Kelly377fb212023-01-10 15:55:28 +00004395 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Mike Kelly31dce2b2021-09-01 21:22:37 +01004396 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4397
4398 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4399 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4400
4401 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4402 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4403}
4404
Teresa Charlin28aa6692022-07-12 11:18:44 +01004405void TfLiteParserImpl::ParseAbs(size_t subgraphIndex, size_t operatorIndex)
4406{
4407 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Abs);
4408}
4409
4410void TfLiteParserImpl::ParseExp(size_t subgraphIndex, size_t operatorIndex)
4411{
4412 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Exp);
4413}
4414
4415void TfLiteParserImpl::ParseLog(size_t subgraphIndex, size_t operatorIndex)
4416{
4417 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Log);
4418}
4419
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004420void TfLiteParserImpl::ParseLogicalNot(size_t subgraphIndex, size_t operatorIndex)
4421{
4422 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::LogicalNot);
4423}
4424
4425void TfLiteParserImpl::ParseNeg(size_t subgraphIndex, size_t operatorIndex)
4426{
4427 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Neg);
4428}
4429
4430void TfLiteParserImpl::ParseRsqrt(size_t subgraphIndex, size_t operatorIndex)
4431{
4432 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Rsqrt);
4433}
4434
Teresa Charlin28aa6692022-07-12 11:18:44 +01004435void TfLiteParserImpl::ParseSin(size_t subgraphIndex, size_t operatorIndex)
4436{
4437 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Sin);
4438}
4439
Teresa Charlinf0fce5b2022-05-04 17:24:43 +01004440void TfLiteParserImpl::ParseSqrt(size_t subgraphIndex, size_t operatorIndex)
4441{
4442 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Sqrt);
4443}
4444
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004445void TfLiteParserImpl::ParseElementwiseUnary(size_t subgraphIndex, size_t operatorIndex, UnaryOperation unaryOperation)
4446{
4447 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4448
4449 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4450 CHECK_VALID_SIZE(inputs.size(), 1);
4451
4452 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4453 CHECK_VALID_SIZE(outputs.size(), 1);
4454
4455 std::string layerName = std::string(GetUnaryOperationAsCString(unaryOperation)) + ":{}:{}";
4456 std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4457
4458 ElementwiseUnaryDescriptor desc;
4459 desc.m_Operation = unaryOperation;
4460 IConnectableLayer* layer = m_Network->AddElementwiseUnaryLayer(desc, layerNameFormatted.c_str());
4461 ARMNN_ASSERT(layer != nullptr);
4462
Mike Kelly377fb212023-01-10 15:55:28 +00004463 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0});
Matthew Sloyaned7fce42021-04-15 20:46:24 +01004464 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4465
4466 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4467 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
4468
4469 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4470 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
4471}
4472
Bruno Goncalves2d0eb862021-07-11 14:10:15 -03004473void TfLiteParserImpl::ParseEqual(size_t subgraphIndex, size_t operatorIndex)
4474{
4475 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::Equal);
4476}
4477
4478void TfLiteParserImpl::ParseNotEqual(size_t subgraphIndex, size_t operatorIndex)
4479{
4480 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::NotEqual);
4481}
4482
4483void TfLiteParserImpl::ParseGreater(size_t subgraphIndex, size_t operatorIndex)
4484{
4485 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::Greater);
4486}
4487
4488void TfLiteParserImpl::ParseGreaterOrEqual(size_t subgraphIndex, size_t operatorIndex)
4489{
4490 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::GreaterOrEqual);
4491}
4492
4493void TfLiteParserImpl::ParseLess(size_t subgraphIndex, size_t operatorIndex)
4494{
4495 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::Less);
4496}
4497
4498void TfLiteParserImpl::ParseLessOrEqual(size_t subgraphIndex, size_t operatorIndex)
4499{
4500 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::LessOrEqual);
4501}
4502
4503void TfLiteParserImpl::ParseComparison(size_t subgraphIndex, size_t operatorIndex,
4504 ComparisonOperation comparisonOperation)
4505{
4506 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
4507
4508 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
4509 CHECK_VALID_SIZE(inputs.size(), 2);
4510
4511 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
4512 CHECK_VALID_SIZE(outputs.size(), 1);
4513
4514 auto layerName = std::string(GetComparisonOperationAsCString(comparisonOperation)) + ":{}:{}";
4515 std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
4516
Mike Kelly377fb212023-01-10 15:55:28 +00004517 armnn::TensorInfo inputTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 0);
4518 armnn::TensorInfo input1TensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 1);
Bruno Goncalves2d0eb862021-07-11 14:10:15 -03004519 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerNameFormatted, "Input 0", "Input 1");
4520
4521 ComparisonDescriptor desc;
4522 desc.m_Operation = comparisonOperation;
4523 IConnectableLayer* layer = m_Network->AddComparisonLayer(desc, layerNameFormatted.c_str());
4524 ARMNN_ASSERT(layer != nullptr);
4525
Mike Kelly377fb212023-01-10 15:55:28 +00004526 TensorInfo outputTensorInfo = OutputTensorInfoFromInputs(subgraphIndex, operatorIndex, layer, 0, {0, 1});
Bruno Goncalves2d0eb862021-07-11 14:10:15 -03004527 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
4528
4529 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
4530 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
4531
4532 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
4533 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
4534}
4535
Kevin May7d96b162021-02-03 17:38:41 +00004536armnn::IConnectableLayer* TfLiteParserImpl::AddFusedActivationLayer(armnn::IConnectableLayer* prevLayer,
4537 unsigned int outputSlot,
4538 tflite::ActivationFunctionType activationType)
telsoa01c577f2c2018-08-31 09:22:23 +01004539{
4540 ActivationDescriptor activationDesc;
4541 std::string layerName = prevLayer->GetName();
4542
4543 switch(activationType)
4544 {
4545 case tflite::ActivationFunctionType_NONE:
4546 {
4547 // this is a no-op: return previous layer
4548 return prevLayer;
4549 }
4550 case tflite::ActivationFunctionType_RELU:
4551 {
4552 activationDesc.m_Function = ActivationFunction::ReLu;
4553 layerName += ":RELU";
4554 break;
4555 }
4556 case tflite::ActivationFunctionType_RELU6:
4557 {
4558 activationDesc.m_Function = ActivationFunction::BoundedReLu;
4559 activationDesc.m_A = 6.0f;
4560 activationDesc.m_B = 0.0f;
4561 layerName += ":RELU6";
4562 break;
4563 }
4564 case tflite::ActivationFunctionType_TANH:
4565 {
4566 activationDesc.m_Function = ActivationFunction::TanH;
4567 activationDesc.m_A = 1.0f;
4568 activationDesc.m_B = 1.0f;
4569 layerName += ":TANH";
4570 break;
4571 }
4572
4573 // I only put these here as a reminder what others we could support
4574 case tflite::ActivationFunctionType_RELU_N1_TO_1:
4575 case tflite::ActivationFunctionType_SIGN_BIT:
4576 default:
4577 {
4578 throw ParseException(
Mike Kelly377fb212023-01-10 15:55:28 +00004579 fmt::format("TfLite parser doesn't support fused activation: "
James Ward58dec6b2020-09-11 17:32:44 +01004580 "{}/{} {} ",
4581 activationType,
4582 tflite::EnumNameActivationFunctionType(activationType),
4583 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01004584
4585 }
4586 }
4587
4588 IConnectableLayer* activationLayer =
4589 m_Network->AddActivationLayer(activationDesc, layerName.c_str());
4590
4591 auto & prevOutputSlot = prevLayer->GetOutputSlot(outputSlot);
4592 prevOutputSlot.Connect(activationLayer->GetInputSlot(0));
4593 activationLayer->GetOutputSlot(0).SetTensorInfo(prevOutputSlot.GetTensorInfo());
4594 return activationLayer;
4595}
4596
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004597armnn::IConnectableLayer* TfLiteParserImpl::AddFusedFloorLayer(armnn::IConnectableLayer* prevLayer,
4598 unsigned int outputSlot)
4599{
Teresa Charlin725728e2022-05-05 13:33:33 +01004600
4601 auto& prevOutputSlot = prevLayer->GetOutputSlot(outputSlot);
4602 DataType dataType = prevOutputSlot.GetTensorInfo().GetDataType();
4603
4604 if (dataType == DataType::Signed32)
4605 {
4606 return prevLayer;
4607 }
4608
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004609 std::string layerName = prevLayer->GetName();
4610 IConnectableLayer* floorLayer = m_Network->AddFloorLayer(layerName.c_str());
4611
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004612 prevOutputSlot.Connect(floorLayer->GetInputSlot(0));
4613 floorLayer->GetOutputSlot(0).SetTensorInfo(prevOutputSlot.GetTensorInfo());
Teresa Charlin725728e2022-05-05 13:33:33 +01004614
Teresa Charlincdbd40b2022-02-25 13:21:55 +00004615 return floorLayer;
4616}
4617
Mike Kelly0d77ae12022-01-07 17:42:27 +00004618TfLiteParserImpl::ModelPtr TfLiteParserImpl::LoadModelFromFile(const char* fileName)
telsoa01c577f2c2018-08-31 09:22:23 +01004619{
4620 if (fileName == nullptr)
4621 {
James Ward58dec6b2020-09-11 17:32:44 +01004622 throw InvalidArgumentException(fmt::format("Invalid (null) file name {}",
telsoa01c577f2c2018-08-31 09:22:23 +01004623 CHECK_LOCATION().AsString()));
4624 }
Francis Murtagh532a29d2020-06-29 11:50:01 +01004625 std::error_code errorCode;
4626 fs::path pathToFile(fileName);
4627 if (!fs::exists(pathToFile, errorCode))
telsoa01c577f2c2018-08-31 09:22:23 +01004628 {
James Ward58dec6b2020-09-11 17:32:44 +01004629 //fmt::format() could not be used here (format error)
4630 std::stringstream msg;
4631 msg << "Cannot find the file (" << fileName << ") errorCode: " << errorCode
4632 << " " << CHECK_LOCATION().AsString();
4633
4634 throw FileNotFoundException(msg.str());
telsoa01c577f2c2018-08-31 09:22:23 +01004635 }
4636 std::ifstream file(fileName, std::ios::binary);
4637 std::string fileContent((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
4638 return LoadModelFromBinary(reinterpret_cast<const uint8_t *>(fileContent.c_str()),
4639 fileContent.size());
4640}
4641
Mike Kelly0d77ae12022-01-07 17:42:27 +00004642TfLiteParserImpl::ModelPtr TfLiteParserImpl::LoadModelFromBinary(const uint8_t* binaryContent, size_t len)
telsoa01c577f2c2018-08-31 09:22:23 +01004643{
4644 if (binaryContent == nullptr)
4645 {
James Ward58dec6b2020-09-11 17:32:44 +01004646 throw InvalidArgumentException(fmt::format("Invalid (null) binary content {}",
telsoa01c577f2c2018-08-31 09:22:23 +01004647 CHECK_LOCATION().AsString()));
4648 }
4649 flatbuffers::Verifier verifier(binaryContent, len);
4650 if (verifier.VerifyBuffer<tflite::Model>() == false)
4651 {
4652 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01004653 fmt::format("Buffer doesn't conform to the expected Tensorflow Lite "
4654 "flatbuffers format. size:{} {}",
4655 len,
4656 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01004657 }
4658 return tflite::UnPackModel(binaryContent);
4659}
4660
Mike Kelly0d77ae12022-01-07 17:42:27 +00004661TfLiteParserImpl::TensorRawPtrVector TfLiteParserImpl::GetInputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00004662 size_t subgraphIndex,
4663 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004664{
4665 CHECK_MODEL(model, subgraphIndex, operatorIndex);
4666
Mike Kelly0d77ae12022-01-07 17:42:27 +00004667 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
4668 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01004669
4670 size_t inputCount = operatorPtr->inputs.size();
mathad01c21025d2021-04-26 10:09:37 +01004671 TensorRawPtrVector result;
Mike Kelly0d77ae12022-01-07 17:42:27 +00004672 for (size_t i = 0; i < inputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01004673 {
mathad01c21025d2021-04-26 10:09:37 +01004674 // If the input location is -1 then assume input is turned off.
4675 if (operatorPtr->inputs[i] == -1)
4676 {
4677 continue;
4678 }
4679 else
4680 {
4681 uint32_t inputId = CHECKED_NON_NEGATIVE(operatorPtr->inputs[i]);
4682 result.push_back(subgraphPtr->tensors[inputId].get());
4683 }
telsoa01c577f2c2018-08-31 09:22:23 +01004684 }
4685 return result;
4686}
4687
Mike Kelly0d77ae12022-01-07 17:42:27 +00004688TfLiteParserImpl::TensorRawPtrVector TfLiteParserImpl::GetOutputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00004689 size_t subgraphIndex,
4690 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004691{
4692 CHECK_MODEL(model, subgraphIndex, operatorIndex);
4693
Mike Kelly0d77ae12022-01-07 17:42:27 +00004694 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
4695 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01004696
4697 size_t outputCount = operatorPtr->outputs.size();
4698 TensorRawPtrVector result(outputCount);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004699 for (size_t i = 0; i < outputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01004700 {
4701 uint32_t outputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[i]);
4702 CHECK_TENSOR(model, subgraphIndex, outputId);
Derek Lambertiff05cc52019-04-26 13:05:17 +01004703 result[i] = subgraphPtr->tensors[outputId].get();
telsoa01c577f2c2018-08-31 09:22:23 +01004704 }
4705 return result;
4706}
4707
Mike Kelly0d77ae12022-01-07 17:42:27 +00004708TfLiteParserImpl::TensorIdRawPtrVector TfLiteParserImpl::GetSubgraphInputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00004709 size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004710{
4711 CHECK_SUBGRAPH(model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004712 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01004713
Derek Lambertiff05cc52019-04-26 13:05:17 +01004714 size_t inputCount = subgraphPtr->inputs.size();
telsoa01c577f2c2018-08-31 09:22:23 +01004715 TensorIdRawPtrVector result(inputCount);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004716 for (size_t i = 0; i < inputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01004717 {
Derek Lambertiff05cc52019-04-26 13:05:17 +01004718 uint32_t inputId = CHECKED_NON_NEGATIVE(subgraphPtr->inputs[i]);
telsoa01c577f2c2018-08-31 09:22:23 +01004719 CHECK_TENSOR(model, subgraphIndex, inputId);
Derek Lambertiff05cc52019-04-26 13:05:17 +01004720 result[i] = std::make_pair(inputId, subgraphPtr->tensors[inputId].get());
telsoa01c577f2c2018-08-31 09:22:23 +01004721 }
4722 return result;
4723}
4724
Mike Kelly0d77ae12022-01-07 17:42:27 +00004725TfLiteParserImpl::TensorIdRawPtrVector TfLiteParserImpl::GetSubgraphOutputs(const ModelPtr& model,
Kevin May7d96b162021-02-03 17:38:41 +00004726 size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004727{
4728 CHECK_SUBGRAPH(model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004729 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01004730
Derek Lambertiff05cc52019-04-26 13:05:17 +01004731 size_t outputCount = subgraphPtr->outputs.size();
telsoa01c577f2c2018-08-31 09:22:23 +01004732 TensorIdRawPtrVector result(outputCount);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004733 for (size_t i = 0; i < outputCount; ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01004734 {
Derek Lambertiff05cc52019-04-26 13:05:17 +01004735 uint32_t outputId = CHECKED_NON_NEGATIVE(subgraphPtr->outputs[i]);
4736 result[i] = std::make_pair(outputId, subgraphPtr->tensors[outputId].get());
telsoa01c577f2c2018-08-31 09:22:23 +01004737 }
4738 return result;
4739}
4740
Kevin May7d96b162021-02-03 17:38:41 +00004741std::vector<int32_t>& TfLiteParserImpl::GetInputTensorIds(const ModelPtr& model,
4742 size_t subgraphIndex,
4743 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004744{
4745 CHECK_MODEL(model, subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004746 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
4747 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01004748 return operatorPtr->inputs;
4749}
4750
Kevin May7d96b162021-02-03 17:38:41 +00004751std::vector<int32_t>& TfLiteParserImpl::GetOutputTensorIds(const ModelPtr& model,
4752 size_t subgraphIndex,
4753 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004754{
4755 CHECK_MODEL(model, subgraphIndex, operatorIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004756 const auto& subgraphPtr = model->subgraphs[subgraphIndex];
4757 const auto& operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01004758 return operatorPtr->outputs;
4759}
4760
Kevin May7d96b162021-02-03 17:38:41 +00004761void TfLiteParserImpl::RegisterInputSlots(size_t subgraphIndex,
4762 size_t operatorIndex,
4763 IConnectableLayer* layer,
Finn Williamsd4fa5452021-03-01 12:31:41 +00004764 const std::vector<unsigned int>& tensorIndexes,
4765 unsigned int startingSlotIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004766{
4767 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01004768 ARMNN_ASSERT(layer != nullptr);
Matthew Sloyan81beae32021-07-13 19:46:11 +01004769
Finn Williamsd4fa5452021-03-01 12:31:41 +00004770 if (tensorIndexes.size() + startingSlotIndex != layer->GetNumInputSlots())
telsoa01c577f2c2018-08-31 09:22:23 +01004771 {
4772 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01004773 fmt::format("The number of tensor inputs ({}) does not match the number expected ({})"
4774 " for subgraph:{} operator index:{} {}",
4775 tensorIndexes.size(),
4776 layer->GetNumInputSlots(),
4777 subgraphIndex,
4778 operatorIndex,
4779 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01004780 }
4781
Finn Williamsd4fa5452021-03-01 12:31:41 +00004782 for (unsigned int index = 0; index < tensorIndexes.size() ; ++index)
telsoa01c577f2c2018-08-31 09:22:23 +01004783 {
Finn Williamsd4fa5452021-03-01 12:31:41 +00004784 unsigned int tensorIndex = tensorIndexes[index];
4785 armnn::IInputSlot* slot = &(layer->GetInputSlot(startingSlotIndex + index));
telsoa01c577f2c2018-08-31 09:22:23 +01004786 RegisterConsumerOfTensor(subgraphIndex, tensorIndex, slot);
4787 }
4788}
4789
Kevin May7d96b162021-02-03 17:38:41 +00004790void TfLiteParserImpl::RegisterOutputSlots(size_t subgraphIndex,
4791 size_t operatorIndex,
4792 IConnectableLayer* layer,
4793 const std::vector<unsigned int>& tensorIndexes)
telsoa01c577f2c2018-08-31 09:22:23 +01004794{
4795 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01004796 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01004797 if (tensorIndexes.size() != layer->GetNumOutputSlots())
4798 {
4799 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01004800 fmt::format("The number of tensor outputs ({}) does not match the number expected ({})"
4801 " for subgraph:{} operator index:{} {}",
4802 tensorIndexes.size(),
4803 layer->GetNumOutputSlots(),
4804 subgraphIndex,
4805 operatorIndex,
4806 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01004807 }
4808
4809 for (unsigned int slotIndex = 0; slotIndex < layer->GetNumOutputSlots(); ++slotIndex)
4810 {
4811 unsigned int tensorIndex = tensorIndexes[slotIndex];
4812 armnn::IOutputSlot* slot = &(layer->GetOutputSlot(slotIndex));
4813 RegisterProducerOfTensor(subgraphIndex, tensorIndex, slot);
4814 }
4815}
4816
Mike Kelly377fb212023-01-10 15:55:28 +00004817void TfLiteParserImpl::SetupInputLayerTensorInfos(size_t subgraphIndex)
4818{
4819 CHECK_SUBGRAPH(m_Model, subgraphIndex);
4820
4821 auto inputs = GetSubgraphInputs(m_Model, subgraphIndex);
4822 for (auto const& tensorIdAndPtr : inputs)
4823 {
4824 auto tensorInfo = ToTensorInfo(tensorIdAndPtr.second);
4825 m_TensorInfos.insert({tensorIdAndPtr.first, tensorInfo});
4826 }
4827}
4828
Kevin May7d96b162021-02-03 17:38:41 +00004829void TfLiteParserImpl::SetupInputLayers(size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004830{
4831 CHECK_SUBGRAPH(m_Model, subgraphIndex);
4832
4833 auto inputs = GetSubgraphInputs(m_Model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004834 for (auto const& tensorIdAndPtr : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01004835 {
4836 auto bindingId = GenerateLayerBindingId(subgraphIndex, tensorIdAndPtr.first);
4837 IConnectableLayer* layer =
4838 m_Network->AddInputLayer(bindingId, tensorIdAndPtr.second->name.c_str());
4839
4840 auto tensorInfo = ToTensorInfo(tensorIdAndPtr.second);
4841 layer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
4842
4843 RegisterOutputSlots(subgraphIndex,
4844 VIRTUAL_OPERATOR_ID,
4845 layer,
4846 { static_cast<uint32_t>(tensorIdAndPtr.first) });
4847 }
4848}
4849
Kevin May7d96b162021-02-03 17:38:41 +00004850void TfLiteParserImpl::SetupOutputLayers(size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004851{
4852 CHECK_SUBGRAPH(m_Model, subgraphIndex);
4853
4854 auto outputs = GetSubgraphOutputs(m_Model, subgraphIndex);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004855 for (auto const& tensorIdAndPtr : outputs)
telsoa01c577f2c2018-08-31 09:22:23 +01004856 {
4857 auto bindingId = GenerateLayerBindingId(subgraphIndex, tensorIdAndPtr.first);
4858 IConnectableLayer* layer =
4859 m_Network->AddOutputLayer(bindingId, tensorIdAndPtr.second->name.c_str());
4860
4861 RegisterInputSlots(subgraphIndex,
4862 VIRTUAL_OPERATOR_ID,
4863 layer,
4864 { static_cast<uint32_t>(tensorIdAndPtr.first) });
4865 }
4866}
4867
Mike Kelly377fb212023-01-10 15:55:28 +00004868void TfLiteParserImpl::SetupConstantLayerTensorInfos(size_t subgraph)
4869{
4870 CHECK_SUBGRAPH(m_Model, subgraph);
4871
4872 const auto & subgraphPtr = m_Model->subgraphs[subgraph];
4873 for (unsigned int subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex)
4874 {
4875 for (unsigned int tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex)
4876 {
4877 if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot == nullptr &&
4878 m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size() > 0)
4879 {
4880 TensorRawPtr tensorPtr = subgraphPtr->tensors[tensorIndex].get();
4881
4882 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
4883
4884 m_TensorInfos.insert({tensorIndex, tensorInfo});
4885 }
4886 }
4887 }
4888}
4889
Mike Kelly5880b912022-01-28 16:18:54 +00004890void TfLiteParserImpl::SetupConstantLayers(size_t subgraph)
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02004891{
Mike Kelly5880b912022-01-28 16:18:54 +00004892 CHECK_SUBGRAPH(m_Model, subgraph);
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02004893
Mike Kelly5880b912022-01-28 16:18:54 +00004894 const auto & subgraphPtr = m_Model->subgraphs[subgraph];
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02004895 for (unsigned int subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex)
4896 {
4897 for (unsigned int tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex)
4898 {
4899 if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot == nullptr &&
4900 m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size() > 0)
4901 {
Derek Lambertiff05cc52019-04-26 13:05:17 +01004902 TensorRawPtr tensorPtr = subgraphPtr->tensors[tensorIndex].get();
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02004903
Mike Kelly5880b912022-01-28 16:18:54 +00004904 if (IsConstTensor(tensorPtr))
Matthew Sloyan81beae32021-07-13 19:46:11 +01004905 {
4906 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
Mike Kelly5880b912022-01-28 16:18:54 +00004907 armnn::DataType dataType = tensorInfo.GetDataType();
4908
4909 if (std::find(m_ConstantsToDequantize.begin(), m_ConstantsToDequantize.end(), tensorPtr->buffer)
4910 != m_ConstantsToDequantize.end())
4911 {
4912 dataType = DataType::Float32;
4913 }
4914 auto tensorAndData = CreateConstTensorNonPermuted(tensorPtr, tensorInfo, dataType);
4915
4916 std::string layerName = fmt::format("Constant:{}", tensorPtr->name);
4917 IConnectableLayer *layer = m_Network->AddConstantLayer(tensorAndData.first, layerName.c_str());
4918
4919 layer->GetOutputSlot(0).SetTensorInfo(tensorAndData.first.GetInfo());
4920 RegisterOutputSlots(subgraphIndex,
4921 VIRTUAL_OPERATOR_ID,
4922 layer,
4923 { tensorIndex });
4924 }
4925 else if (ShouldConstantTensorBeCreated(tensorIndex))
4926 {
4927 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
4928 armnn::DataType dataType = tensorInfo.GetDataType();
4929
4930 if (std::find(m_ConstantsToDequantize.begin(), m_ConstantsToDequantize.end(), tensorPtr->buffer)
4931 != m_ConstantsToDequantize.end())
4932 {
4933 dataType = DataType::Float32;
4934 }
4935 // Make sure isConstant flag is set.
4936 tensorInfo.SetConstant();
4937 tensorInfo.SetDataType(dataType);
4938
4939 auto tensorAndData = ConstTensor(tensorInfo, std::vector<uint8_t>(tensorInfo.GetNumBytes()));
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02004940
Matthew Sloyan81beae32021-07-13 19:46:11 +01004941 std::string layerName = fmt::format("Constant:{}", tensorPtr->name);
Mike Kelly0d77ae12022-01-07 17:42:27 +00004942 IConnectableLayer* layer = m_Network->AddConstantLayer(tensorAndData, layerName.c_str());
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02004943
Matthew Sloyan81beae32021-07-13 19:46:11 +01004944 layer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
4945 RegisterOutputSlots(subgraphIndex,
4946 VIRTUAL_OPERATOR_ID,
4947 layer,
Mike Kelly5880b912022-01-28 16:18:54 +00004948 {tensorIndex});
Matthew Sloyan81beae32021-07-13 19:46:11 +01004949 }
4950 else
4951 {
4952 throw ParseException(
4953 fmt::format("Invalid Tensor: Tensor should be constant. {}",
4954 CHECK_LOCATION().AsString()));
4955 }
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02004956 }
4957 }
4958 }
4959}
4960
telsoa01c577f2c2018-08-31 09:22:23 +01004961// example usage: BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[0]->buffer);
Kevin May7d96b162021-02-03 17:38:41 +00004962TfLiteParserImpl::BufferRawPtr TfLiteParserImpl::GetBuffer(const ModelPtr& model, size_t bufferIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004963{
4964 CHECK_BUFFER(model, bufferIndex);
4965 return model->buffers[bufferIndex].get();
4966}
4967
Matteo Martincigh747ef822018-12-18 09:26:39 +00004968template<typename T>
Kevin May7d96b162021-02-03 17:38:41 +00004969std::pair<armnn::ConstTensor, TfLiteParserImpl::SupportedDataStorage>
4970TfLiteParserImpl::CreateConstTensorAndStoreData(TfLiteParserImpl::BufferRawPtr bufferPtr,
4971 TfLiteParserImpl::TensorRawPtr tensorPtr,
Matteo Martincigh747ef822018-12-18 09:26:39 +00004972 armnn::TensorInfo& tensorInfo,
4973 armnn::Optional<armnn::PermutationVector&> permutationVector)
4974{
Matthew Sloyan81beae32021-07-13 19:46:11 +01004975 // Make sure isConstant flag is set.
4976 tensorInfo.SetConstant();
4977
Matteo Martincigh747ef822018-12-18 09:26:39 +00004978 auto constData = CreateConstTensorImpl<T>(bufferPtr,
4979 tensorPtr,
4980 tensorInfo,
4981 permutationVector);
Kevin May7d96b162021-02-03 17:38:41 +00004982 TfLiteParserImpl::SupportedDataStorage storage(std::move(constData.second));
Matteo Martincigh747ef822018-12-18 09:26:39 +00004983 return std::make_pair(constData.first, std::move(storage));
4984}
4985
Mike Kelly5880b912022-01-28 16:18:54 +00004986bool TfLiteParserImpl::ShouldConstantTensorBeCreated(unsigned int tensorIndex)
4987{
4988 // If the TensorIndex appears in the list of ConstantsToBeCreated then return true
4989 return (std::find(m_ConstantsToBeCreated.begin(), m_ConstantsToBeCreated.end(), tensorIndex)
4990 != m_ConstantsToBeCreated.end());
4991}
4992
Finn Williamsd4fa5452021-03-01 12:31:41 +00004993bool TfLiteParserImpl::IsConstTensor(TensorRawPtr tensorPtr)
4994{
4995 CHECK_TENSOR_PTR(tensorPtr);
mathad01bf7edb62021-04-20 16:12:45 +01004996 bool isConst = true;
4997
4998 auto buffer = GetBuffer(m_Model, tensorPtr->buffer);
4999 if (buffer->data.size() == 0)
5000 {
5001 isConst = false;
5002 }
5003
5004 return isConst;
Finn Williamsd4fa5452021-03-01 12:31:41 +00005005}
5006
Kevin May7d96b162021-02-03 17:38:41 +00005007std::pair<armnn::ConstTensor, TfLiteParserImpl::SupportedDataStorage>
Finn Williamsd4fa5452021-03-01 12:31:41 +00005008TfLiteParserImpl::CreateConstTensorPermuted(TensorRawPtr tensorPtr,
5009 armnn::TensorInfo& tensorInfo,
5010 armnn::Optional<armnn::PermutationVector&> permutationVector)
telsoa01c577f2c2018-08-31 09:22:23 +01005011{
5012 CHECK_TENSOR_PTR(tensorPtr);
5013 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5014 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5015
Matthew Sloyan81beae32021-07-13 19:46:11 +01005016 // Make sure isConstant flag is set.
5017 tensorInfo.SetConstant();
5018
telsoa01c577f2c2018-08-31 09:22:23 +01005019 switch (tensorInfo.GetDataType())
5020 {
5021 case armnn::DataType::Float32:
Matteo Martincigh747ef822018-12-18 09:26:39 +00005022 return CreateConstTensorAndStoreData<float>(bufferPtr,
5023 tensorPtr,
5024 tensorInfo,
5025 permutationVector);
Derek Lambertif90c56d2020-01-10 17:14:08 +00005026 case armnn::DataType::QAsymmU8:
Matteo Martincigh747ef822018-12-18 09:26:39 +00005027 return CreateConstTensorAndStoreData<uint8_t>(bufferPtr,
5028 tensorPtr,
5029 tensorInfo,
5030 permutationVector);
Keith Davisd305e1a2020-01-22 11:57:54 +00005031 case armnn::DataType::QSymmS8:
5032 return CreateConstTensorAndStoreData<int8_t>(bufferPtr,
5033 tensorPtr,
5034 tensorInfo,
5035 permutationVector);
Keith Davis67e6c542020-02-19 10:08:33 +00005036 case armnn::DataType::QAsymmS8:
5037 return CreateConstTensorAndStoreData<int8_t>(bufferPtr,
5038 tensorPtr,
5039 tensorInfo,
5040 permutationVector);
telsoa01c577f2c2018-08-31 09:22:23 +01005041 case armnn::DataType::Signed32:
Matteo Martincigh747ef822018-12-18 09:26:39 +00005042 return CreateConstTensorAndStoreData<int32_t>(bufferPtr,
5043 tensorPtr,
5044 tensorInfo,
5045 permutationVector);
telsoa01c577f2c2018-08-31 09:22:23 +01005046 default:
5047 {
5048 std::stringstream errString;
5049 errString << "Unexpected datatype when creating const tensor: "
5050 << armnn::GetDataTypeName(tensorInfo.GetDataType())
5051 << " shape:" << tensorInfo.GetShape()
5052 << CHECK_LOCATION().AsString();
5053 throw ParseException(errString.str());
5054 }
5055 }
5056}
5057
Finn Williamsd4fa5452021-03-01 12:31:41 +00005058armnn::ConstTensor TfLiteParserImpl::CreateConstTensorNonPermuted(TensorRawPtr tensorPtr,
5059 armnn::TensorInfo& tensorInfo)
5060{
5061 CHECK_TENSOR_PTR(tensorPtr);
5062 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5063 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5064
Matthew Sloyan81beae32021-07-13 19:46:11 +01005065 // Make sure isConstant flag is set.
5066 tensorInfo.SetConstant();
5067
Finn Williamsd4fa5452021-03-01 12:31:41 +00005068 return ConstTensor(tensorInfo, bufferPtr->data.data());
5069}
5070
Mike Kelly5880b912022-01-28 16:18:54 +00005071std::pair<armnn::ConstTensor, std::unique_ptr<float[]>>
5072TfLiteParserImpl::CreateConstTensorNonPermuted(TensorRawPtr tensorPtr,
5073 armnn::TensorInfo& tensorInfo,
5074 armnn::DataType inputDataType)
5075{
5076 CHECK_TENSOR_PTR(tensorPtr);
5077 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5078 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5079
5080 // Make sure isConstant flag is set.
5081 tensorInfo.SetConstant();
5082
Mike Kelly0506ef02023-01-03 16:29:44 +00005083 if (inputDataType == DataType::Float32 && tensorInfo.GetDataType() != DataType::Float32)
Mike Kelly5880b912022-01-28 16:18:54 +00005084 {
Mike Kelly0506ef02023-01-03 16:29:44 +00005085 try
5086 {
5087 TensorInfo constTensorInfo(tensorInfo.GetShape(), DataType::Float32, 0.0f, 0, true);
5088 std::unique_ptr<float[]> data = armnnUtils::ToFloatArray(bufferPtr->data, tensorInfo);
5089 return std::make_pair(ConstTensor(constTensorInfo, data.get()), std::move(data));
5090 }
Cathal Corbett9c843c32023-01-09 17:51:37 +00005091 catch (InvalidArgumentException&)
Mike Kelly0506ef02023-01-03 16:29:44 +00005092 {
5093 throw ParseException(
5094 fmt::format("Unsupported input/weights combination: Input {} not supported with Weights {}",
5095 GetDataTypeName(DataType::Float32),
5096 GetDataTypeName(tensorInfo.GetDataType()),
5097 CHECK_LOCATION().AsString()));
5098 }
Mike Kelly5880b912022-01-28 16:18:54 +00005099 }
5100 else
5101 {
5102 return std::make_pair(ConstTensor(tensorInfo, bufferPtr->data.data()), std::unique_ptr<float[]>());
5103 }
5104}
5105
5106std::pair<armnn::ConstTensor*, std::unique_ptr<float[]>>
5107TfLiteParserImpl::CreateConstTensorPtr(TensorRawPtr tensorPtr, armnn::TensorInfo& inputTensorInfo)
5108{
5109 CHECK_TENSOR_PTR(tensorPtr);
5110 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
5111 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
5112 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
5113
5114 // Make sure isConstant flag is set.
5115 tensorInfo.SetConstant();
5116
5117 if (inputTensorInfo.GetDataType() == DataType::Float32 && tensorInfo.GetDataType() != DataType::Float32)
5118 {
Mike Kelly0506ef02023-01-03 16:29:44 +00005119 try
5120 {
5121 TensorInfo constTensorInfo(tensorInfo.GetShape(), DataType::Float32, 0.0f, 0, true);
5122 std::unique_ptr<float[]> data = armnnUtils::ToFloatArray(bufferPtr->data, tensorInfo);
5123 return std::make_pair(new ConstTensor(constTensorInfo, data.get()), std::move(data));
5124 }
Cathal Corbett9c843c32023-01-09 17:51:37 +00005125 catch (InvalidArgumentException&)
Mike Kelly0506ef02023-01-03 16:29:44 +00005126 {
5127 throw ParseException(
5128 fmt::format("Unsupported input/weights combination: Input {} not supported with Weights {}",
5129 GetDataTypeName(DataType::Float32),
5130 GetDataTypeName(tensorInfo.GetDataType()),
5131 CHECK_LOCATION().AsString()));
5132 }
Mike Kelly5880b912022-01-28 16:18:54 +00005133 }
5134 else
5135 {
5136 return std::make_pair(new ConstTensor(tensorInfo, bufferPtr->data.data()), std::unique_ptr<float[]>());
5137 }
5138}
5139
Kevin May7d96b162021-02-03 17:38:41 +00005140BindingPointInfo TfLiteParserImpl::GetNetworkInputBindingInfo(size_t subgraphId,
5141 const std::string& name) const
telsoa01c577f2c2018-08-31 09:22:23 +01005142{
5143 CHECK_SUBGRAPH(m_Model, subgraphId);
5144 auto inputs = GetSubgraphInputs(m_Model, subgraphId);
Mike Kelly0d77ae12022-01-07 17:42:27 +00005145 for (auto const& input : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005146 {
5147 if (input.second->name == name)
5148 {
5149 auto bindingId = GenerateLayerBindingId(subgraphId, input.first);
Colm Donelan4bc993b2021-11-09 20:39:10 +00005150 auto inputTensorInfo = ToTensorInfo(input.second);
5151 // Input tensors are always treated as constant tensors during network execution.
5152 inputTensorInfo.SetConstant(true);
5153 return std::make_pair(bindingId, inputTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +01005154 }
5155 }
5156
5157 std::stringstream bindings;
Mike Kelly0d77ae12022-01-07 17:42:27 +00005158 for (auto const& input : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005159 {
5160 bindings << "'" << input.second->name << "' ";
5161 }
5162
5163 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01005164 fmt::format("No input binding found for subgraph:{} and name:{}. "
5165 "Possible inputs are: [{}] {}",
5166 subgraphId,
5167 name,
5168 bindings.str(),
5169 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01005170}
5171
Kevin May7d96b162021-02-03 17:38:41 +00005172BindingPointInfo TfLiteParserImpl::GetNetworkOutputBindingInfo(size_t subgraphId,
5173 const std::string& name) const
telsoa01c577f2c2018-08-31 09:22:23 +01005174{
5175 CHECK_SUBGRAPH(m_Model, subgraphId);
5176 auto outputs = GetSubgraphOutputs(m_Model, subgraphId);
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00005177 for (unsigned int i = 0; i < outputs.size(); ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01005178 {
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00005179 auto const output = outputs[i];
telsoa01c577f2c2018-08-31 09:22:23 +01005180 if (output.second->name == name)
5181 {
5182 auto bindingId = GenerateLayerBindingId(subgraphId, output.first);
Mike Kelly377fb212023-01-10 15:55:28 +00005183 std::vector<unsigned int> shape = m_OverriddenOutputShapes.size() > 0 ?
5184 m_OverriddenOutputShapes[i] : AsUnsignedVector(output.second->shape);
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00005185 return std::make_pair(bindingId, ToTensorInfo(output.second, shape));
telsoa01c577f2c2018-08-31 09:22:23 +01005186 }
5187 }
5188
5189 std::stringstream bindings;
Mike Kelly0d77ae12022-01-07 17:42:27 +00005190 for (auto const& output : outputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005191 {
5192 bindings << "'" << output.second->name << "' ";
5193 }
5194
5195 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01005196 fmt::format("No output binding found for subgraph:{} and name:{}. "
5197 "Possible outputs are: [{}] {}",
5198 subgraphId,
5199 name,
5200 bindings.str(),
5201 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01005202}
5203
Kevin May7d96b162021-02-03 17:38:41 +00005204size_t TfLiteParserImpl::GetSubgraphCount() const
telsoa01c577f2c2018-08-31 09:22:23 +01005205{
5206 return m_Model->subgraphs.size();
5207}
5208
Kevin May7d96b162021-02-03 17:38:41 +00005209std::vector<std::string> TfLiteParserImpl::GetSubgraphInputTensorNames(size_t subgraphId) const
telsoa01c577f2c2018-08-31 09:22:23 +01005210{
5211 CHECK_SUBGRAPH(m_Model, subgraphId);
5212 auto inputs = GetSubgraphInputs(m_Model, subgraphId);
5213 std::vector<std::string> result;
5214 result.reserve(inputs.size());
Mike Kelly0d77ae12022-01-07 17:42:27 +00005215 for (auto const& input : inputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005216 {
5217 result.push_back(input.second->name);
5218 }
5219 return result;
5220}
5221
Kevin May7d96b162021-02-03 17:38:41 +00005222std::vector<std::string> TfLiteParserImpl::GetSubgraphOutputTensorNames(size_t subgraphId) const
telsoa01c577f2c2018-08-31 09:22:23 +01005223{
5224 CHECK_SUBGRAPH(m_Model, subgraphId);
5225 auto outputs = GetSubgraphOutputs(m_Model, subgraphId);
5226 std::vector<std::string> result;
5227 result.reserve(outputs.size());
Mike Kelly0d77ae12022-01-07 17:42:27 +00005228 for (auto const& output : outputs)
telsoa01c577f2c2018-08-31 09:22:23 +01005229 {
5230 result.push_back(output.second->name);
5231 }
5232 return result;
5233}
5234
Matthew Sloyanac001ee2021-02-03 10:43:04 +00005235const std::string TfLiteParserImpl::GetVersion()
5236{
5237 return TFLITE_PARSER_VERSION;
5238}
5239
Mike Kelly0d77ae12022-01-07 17:42:27 +00005240TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<float[]>&& data)
telsoa01c577f2c2018-08-31 09:22:23 +01005241: m_FloatData(std::move(data))
5242, m_Uint8Data(nullptr)
Keith Davisd305e1a2020-01-22 11:57:54 +00005243, m_Int8Data(nullptr)
telsoa01c577f2c2018-08-31 09:22:23 +01005244, m_Int32Data(nullptr)
5245{
5246}
5247
Mike Kelly0d77ae12022-01-07 17:42:27 +00005248TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<uint8_t[]>&& data)
telsoa01c577f2c2018-08-31 09:22:23 +01005249: m_FloatData(nullptr)
5250, m_Uint8Data(std::move(data))
Keith Davisd305e1a2020-01-22 11:57:54 +00005251, m_Int8Data(nullptr)
5252, m_Int32Data(nullptr)
5253{
5254}
5255
Mike Kelly0d77ae12022-01-07 17:42:27 +00005256TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<int8_t[]>&& data)
Keith Davisd305e1a2020-01-22 11:57:54 +00005257: m_FloatData(nullptr)
5258, m_Uint8Data(nullptr)
5259, m_Int8Data(std::move(data))
telsoa01c577f2c2018-08-31 09:22:23 +01005260, m_Int32Data(nullptr)
5261{
5262}
5263
Mike Kelly0d77ae12022-01-07 17:42:27 +00005264TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<int32_t[]>&& data)
telsoa01c577f2c2018-08-31 09:22:23 +01005265: m_FloatData(nullptr)
5266, m_Uint8Data(nullptr)
Keith Davisd305e1a2020-01-22 11:57:54 +00005267, m_Int8Data(nullptr)
telsoa01c577f2c2018-08-31 09:22:23 +01005268, m_Int32Data(std::move(data))
5269{
5270}
5271
5272} // armnnTfLiteParser