blob: 15ca36d90688a5c46c7e4659b05849013a05b021 [file] [log] [blame]
telsoa01c577f2c2018-08-31 09:22:23 +01001//
Mike Kellyc5789ca2020-07-06 19:24:15 +01002// Copyright © 2017 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"
9
Sadik Armagand109a4d2020-07-28 10:42:13 +010010#include <armnn/BackendOptions.hpp>
Matthew Bentham39ef3e52020-01-20 10:09:09 +000011#include <armnn/Descriptors.hpp>
telsoa01c577f2c2018-08-31 09:22:23 +010012#include <armnn/Exceptions.hpp>
Derek Lamberti08446972019-11-26 16:38:31 +000013#include <armnn/Logging.hpp>
James Conroy05102392020-06-24 15:39:55 +010014#include <armnn/Tensor.hpp>
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +000015#include <armnnUtils/TensorUtils.hpp>
telsoa01c577f2c2018-08-31 09:22:23 +010016#include <armnn/TypesUtils.hpp>
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +010017#include <armnn/utility/Assert.hpp>
Jan Eilers8eb25602020-03-09 12:13:48 +000018#include <armnn/utility/IgnoreUnused.hpp>
Derek Lambertif0176992020-04-28 13:37:49 +010019#include <armnn/utility/NumericCast.hpp>
telsoa01c577f2c2018-08-31 09:22:23 +010020
21// armnnUtils:
Matteo Martincighe011d202019-11-28 11:35:47 +000022#include <armnnUtils/Permute.hpp>
Rob Hughes9542f902021-07-14 09:48:54 +010023#include <armnnUtils/Filesystem.hpp>
Matteo Martincighe011d202019-11-28 11:35:47 +000024
Sadik Armagan479045b2018-10-01 11:51:37 +010025#include <ParserHelper.hpp>
telsoa01c577f2c2018-08-31 09:22:23 +010026#include <VerificationHelpers.hpp>
27
28// The generated code based on the Tf Lite schema:
29#include <schema_generated.h>
30
Matteo Martincighe011d202019-11-28 11:35:47 +000031#include <flatbuffers/flexbuffers.h>
32
James Ward58dec6b2020-09-11 17:32:44 +010033#include <fmt/format.h>
telsoa01c577f2c2018-08-31 09:22:23 +010034
telsoa01c577f2c2018-08-31 09:22:23 +010035#include <algorithm>
Matthew Sloyanac001ee2021-02-03 10:43:04 +000036#include <fstream>
37#include <iostream>
telsoa01c577f2c2018-08-31 09:22:23 +010038#include <limits>
Sadikb94967b2018-09-19 15:30:00 +010039#include <numeric>
Derek Lambertic9e52792020-03-11 11:42:26 +000040#include <sstream>
41
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
79armnn::INetworkPtr ITfLiteParser::CreateNetworkFromBinary(const std::vector<uint8_t> & binaryContent)
80{
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
Kevin May7d96b162021-02-03 17:38:41 +0000116void CheckSubgraph(const TfLiteParserImpl::ModelPtr & model,
telsoa01c577f2c2018-08-31 09:22:23 +0100117 size_t subgraphIndex,
118 const CheckLocation & location)
119{
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
Kevin May7d96b162021-02-03 17:38:41 +0000144void CheckModel(const TfLiteParserImpl::ModelPtr & model,
telsoa01c577f2c2018-08-31 09:22:23 +0100145 size_t subgraphIndex,
146 size_t operatorIndex,
147 const CheckLocation & location)
148{
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
Kevin May7d96b162021-02-03 17:38:41 +0000186void CheckTensor(const TfLiteParserImpl::ModelPtr & model,
telsoa01c577f2c2018-08-31 09:22:23 +0100187 size_t subgraphIndex,
188 size_t tensorIndex,
189 const CheckLocation & location)
190{
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,
telsoa01c577f2c2018-08-31 09:22:23 +0100216 const CheckLocation & location)
217{
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
Kevin May7d96b162021-02-03 17:38:41 +0000228void CheckBuffer(const TfLiteParserImpl::ModelPtr & model,
telsoa01c577f2c2018-08-31 09:22:23 +0100229 size_t bufferIndex,
230 const CheckLocation & location)
231{
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,
telsoa01c577f2c2018-08-31 09:22:23 +0100264 const armnn::TensorInfo & tensorInfo,
265 uint32_t bufferId,
266 const CheckLocation & location)
267{
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
287#define CHECK_BUFFER_SIZE(BUFFER_PTR, TENSOR_INFO, BUFFER_ID) \
288 CheckBufferSize(BUFFER_PTR, TENSOR_INFO, BUFFER_ID, CHECK_LOCATION())
289
290bool IsActivationSupported(tflite::ActivationFunctionType activationType)
291{
292 switch(activationType)
293 {
294 case tflite::ActivationFunctionType_NONE:
295 case tflite::ActivationFunctionType_RELU:
296 case tflite::ActivationFunctionType_RELU6:
297 case tflite::ActivationFunctionType_TANH:
298 {
299 return true;
300 }
301 default:
302 {
303 return false;
304 }
305 }
306}
307
308#define CHECK_SUPPORTED_FUSED_ACTIVATION(OPTION, SUBGRAPH_INDEX, OPERATOR_INDEX) \
309 do { \
310 if (IsActivationSupported(OPTION->fused_activation_function) == false) \
311 { \
312 throw ParseException( \
James Ward58dec6b2020-09-11 17:32:44 +0100313 fmt::format("TfLite parser doesn't suppport fused activation: " \
314 "{}/{} in {} subgraph:{} operator:{} at {}", \
315 OPTION->fused_activation_function, \
316 tflite::EnumNameActivationFunctionType(\
317 OPTION->fused_activation_function), \
318 __func__, \
319 SUBGRAPH_INDEX, \
320 OPERATOR_INDEX, \
321 CHECK_LOCATION().FileLine())); \
telsoa01c577f2c2018-08-31 09:22:23 +0100322 } \
323 } while(false)
324
325
326std::vector<unsigned int> AsUnsignedVector(const std::vector<int32_t> & in)
327{
328 std::vector<unsigned int> result;
329 result.reserve(in.size());
330 for (auto & i : in)
331 {
mathad01c21025d2021-04-26 10:09:37 +0100332 // If the location of the input data is -1 then the input should be ignored.
333 if (i == -1)
334 {
335 continue;
336 }
telsoa01c577f2c2018-08-31 09:22:23 +0100337 result.push_back(CHECKED_NON_NEGATIVE(i));
338 }
339 return result;
340}
341
342void CalcPadding(uint32_t inputSize,
343 uint32_t filterSize,
344 uint32_t stride,
Pablo Tellof0bd6832019-04-26 17:58:13 +0100345 uint32_t dilation,
telsoa01c577f2c2018-08-31 09:22:23 +0100346 uint32_t& paddingFront,
347 uint32_t& paddingBack,
348 tflite::Padding padding)
349{
350 paddingFront = 0;
351 paddingBack = 0;
352 if (padding == tflite::Padding_SAME)
353 {
354 uint32_t outputSize = (inputSize + stride - 1) / stride;
Pablo Tellof0bd6832019-04-26 17:58:13 +0100355 uint32_t dilatedSize = filterSize + (dilation - 1) * (filterSize - 1);
356 uint32_t temp = (outputSize - 1) * stride + dilatedSize;
telsoa01c577f2c2018-08-31 09:22:23 +0100357 if (temp > inputSize)
358 {
359 paddingFront = (temp - inputSize) / 2;
360 paddingBack = (temp - inputSize) - paddingFront;
361 }
362 }
363}
364
Kevin May7d96b162021-02-03 17:38:41 +0000365armnn::TensorInfo ToTensorInfo(TfLiteParserImpl::TensorRawPtr tensorPtr,
Finn Williamsb49ed182021-06-29 15:50:08 +0100366 const std::vector<unsigned int>& shape,
Sadik Armagand109a4d2020-07-28 10:42:13 +0100367 const bool outputTensor = false)
telsoa01c577f2c2018-08-31 09:22:23 +0100368{
369 armnn::DataType type;
370 CHECK_TENSOR_PTR(tensorPtr);
371
372 switch (tensorPtr->type)
373 {
374 case tflite::TensorType_UINT8:
Derek Lambertif90c56d2020-01-10 17:14:08 +0000375 type = armnn::DataType::QAsymmU8;
telsoa01c577f2c2018-08-31 09:22:23 +0100376 break;
377 case tflite::TensorType_FLOAT32:
378 type = armnn::DataType::Float32;
379 break;
Finn Williamsed66d142019-12-06 09:55:55 +0000380 case tflite::TensorType_INT8:
Keith Davis67e6c542020-02-19 10:08:33 +0000381 if (tensorPtr->quantization->zero_point.size() == 1)
Ryan OShea03181ff2020-02-07 17:22:22 +0000382 {
Keith Davis0c2eeac2020-02-11 16:51:50 +0000383 // Per-tensor
Ryan OShea03181ff2020-02-07 17:22:22 +0000384 type = armnn::DataType::QAsymmS8;
385 }
386 else
387 {
Keith Davis0c2eeac2020-02-11 16:51:50 +0000388 // Per-channel
Ryan OShea03181ff2020-02-07 17:22:22 +0000389 type = armnn::DataType::QSymmS8;
390 }
Finn Williamsed66d142019-12-06 09:55:55 +0000391 break;
392 case tflite::TensorType_INT16:
Derek Lambertif90c56d2020-01-10 17:14:08 +0000393 type = armnn::DataType::QSymmS16;
Finn Williamsed66d142019-12-06 09:55:55 +0000394 break;
telsoa01c577f2c2018-08-31 09:22:23 +0100395 case tflite::TensorType_INT32:
396 type = armnn::DataType::Signed32;
397 break;
Inki Daed4619e22020-09-10 15:33:54 +0900398 case tflite::TensorType_INT64:
399 type = armnn::DataType::Signed64;
400 break;
Matthew Sloyaned7fce42021-04-15 20:46:24 +0100401 case tflite::TensorType_BOOL:
402 type = armnn::DataType::Boolean;
403 break;
telsoa01c577f2c2018-08-31 09:22:23 +0100404 default:
405 {
406 CheckLocation location = CHECK_LOCATION();
407 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100408 fmt::format("Unsupported data type {} = {} for tensor: {}. {}",
409 tensorPtr->type,
410 tflite::EnumNameTensorType(tensorPtr->type),
411 tensorPtr->name,
412 location.AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +0100413 }
414 }
Finn Williamsb49ed182021-06-29 15:50:08 +0100415 TensorShape tensorShape;
416
417 std::vector<unsigned int> safeShape = shape;
418 if (shape.size() == 0)
Narumol Prangnawarat4818d462019-04-17 11:22:38 +0100419 {
420 safeShape.push_back(1);
Finn Williamsb49ed182021-06-29 15:50:08 +0100421 }
422
423 if (!outputTensor)
424 {
425 tensorShape = TensorShape(armnn::numeric_cast<unsigned int>(safeShape.size()), safeShape.data());
426 }
427 else
428 {
Rob Hughesd812a312021-08-06 13:10:53 +0100429 size_t shapeSignatureSize = tensorPtr->shape_signature.size();
Finn Williamsb49ed182021-06-29 15:50:08 +0100430
431 // If a shape signature exists we will use that to infer dynamic tensors
432 if (shapeSignatureSize != 0)
Sadik Armagand109a4d2020-07-28 10:42:13 +0100433 {
Finn Williamsb49ed182021-06-29 15:50:08 +0100434 // If the shape is incompatible with the shape signature override the shape
435 if (shapeSignatureSize != shape.size())
436 {
437 safeShape = {};
438
439 for (unsigned int i = 0; i < shapeSignatureSize; ++i)
440 {
441 unsigned int dim = tensorPtr->shape_signature[i] > -1 ?
442 static_cast<unsigned int>(tensorPtr->shape_signature[i]) : 0;
443 safeShape.push_back(dim);
444 }
445 }
446
Rob Hughesd812a312021-08-06 13:10:53 +0100447 std::unique_ptr<bool[]> dimMask = std::make_unique<bool[]>(tensorPtr->shape_signature.size());
Finn Williamsb49ed182021-06-29 15:50:08 +0100448 for (unsigned int i = 0; i < tensorPtr->shape_signature.size(); ++i)
449 {
450 dimMask[i] = tensorPtr->shape_signature[i] == -1 ? false : true;
451 }
Rob Hughesd812a312021-08-06 13:10:53 +0100452 tensorShape = TensorShape(static_cast<unsigned int>(safeShape.size()), safeShape.data(), dimMask.get());
Finn Williamsb49ed182021-06-29 15:50:08 +0100453 }
454 // If there is no shape signature treat the tensor as dynamic if the shape has a size of zero
455 else if (shape.size() == 0)
456 {
457 tensorShape = TensorShape(1, false);
458 }
459 else
460 {
461 tensorShape = TensorShape(armnn::numeric_cast<unsigned int>(shape.size()), shape.data());
Sadik Armagand109a4d2020-07-28 10:42:13 +0100462 }
Narumol Prangnawarat4818d462019-04-17 11:22:38 +0100463 }
464
Keith Davisd305e1a2020-01-22 11:57:54 +0000465 float quantizationScale = 0.0f;
466 int32_t quantizationOffset = 0;
467
468 if (tensorPtr->quantization.get())
469 {
470 if (tensorPtr->quantization->scale.size() <= 1)
471 {
472 CHECK_VALID_SIZE(tensorPtr->quantization->zero_point.size(), 0, 1);
473 CHECK_VALID_SIZE(tensorPtr->quantization->zero_point.size(), 0, 1);
474
475 if (tensorPtr->quantization->scale.size() == 1)
476 {
477 quantizationScale = tensorPtr->quantization->scale[0];
478 }
479 if (tensorPtr->quantization->zero_point.size() == 1)
480 {
481 // NOTE: we lose precision here when converting from 64 bit to 32
Ryan OShea03181ff2020-02-07 17:22:22 +0000482 // but this is what we support at the moment in ArmNN
Matthew Sloyan589e3e82020-09-11 16:17:48 +0100483 quantizationOffset = armnn::numeric_cast<int32_t>(tensorPtr->quantization->zero_point[0]);
Keith Davisd305e1a2020-01-22 11:57:54 +0000484 }
485
Sadik Armagand109a4d2020-07-28 10:42:13 +0100486 armnn::TensorInfo result(tensorShape,
487 type,
488 quantizationScale,
489 quantizationOffset);
Keith Davisd305e1a2020-01-22 11:57:54 +0000490 return result;
491 }
492 else
493 {
494 std::vector<float> quantizationScales;
495 std::vector<int32_t> quantizationOffsets;
496
497 // Scale
498 std::copy(tensorPtr->quantization->scale.begin(),
499 tensorPtr->quantization->scale.end(),
500 std::back_inserter(quantizationScales));
501
Keith Davis0c2eeac2020-02-11 16:51:50 +0000502 // QSymmS8 Per-axis
Sadik Armagand109a4d2020-07-28 10:42:13 +0100503 armnn::TensorInfo result(tensorShape,
504 type,
505 quantizationScales,
Jan Eilers7612bd62021-04-06 17:29:03 +0100506 armnn::numeric_cast<unsigned int>(tensorPtr->quantization->quantized_dimension));
Keith Davisd305e1a2020-01-22 11:57:54 +0000507 return result;
508 }
509 }
510 else
511 {
Sadik Armagand109a4d2020-07-28 10:42:13 +0100512 armnn::TensorInfo result(tensorShape,
Keith Davisd305e1a2020-01-22 11:57:54 +0000513 type,
514 quantizationScale,
515 quantizationOffset);
516 return result;
517 }
telsoa01c577f2c2018-08-31 09:22:23 +0100518}
519
Jan Eilers7612bd62021-04-06 17:29:03 +0100520armnn::TensorInfo ToTensorInfo(TfLiteParserImpl::TensorRawPtr tensorPtr)
Narumol Prangnawarat4628d052019-02-25 17:26:05 +0000521{
522 auto const & dimensions = AsUnsignedVector(tensorPtr->shape);
Jan Eilers7612bd62021-04-06 17:29:03 +0100523 return ToTensorInfo(tensorPtr, dimensions);
Narumol Prangnawarat4628d052019-02-25 17:26:05 +0000524}
525
Kevin May7d96b162021-02-03 17:38:41 +0000526armnn::TensorInfo ToTensorInfo(TfLiteParserImpl::TensorRawPtr tensorPtr,
Sadik Armagand109a4d2020-07-28 10:42:13 +0100527 const bool outputTensor)
528{
529 auto const & dimensions = AsUnsignedVector(tensorPtr->shape);
Jan Eilers7612bd62021-04-06 17:29:03 +0100530 return ToTensorInfo(tensorPtr, dimensions, outputTensor);
Sadik Armagand109a4d2020-07-28 10:42:13 +0100531}
532
telsoa01c577f2c2018-08-31 09:22:23 +0100533template<typename T>
534std::pair<armnn::ConstTensor, std::unique_ptr<T[]>>
Kevin May7d96b162021-02-03 17:38:41 +0000535CreateConstTensorImpl(TfLiteParserImpl::BufferRawPtr bufferPtr,
536 TfLiteParserImpl::TensorRawPtr tensorPtr,
Matteo Martincigh747ef822018-12-18 09:26:39 +0000537 armnn::TensorInfo& tensorInfo,
538 armnn::Optional<armnn::PermutationVector&> permutationVector)
telsoa01c577f2c2018-08-31 09:22:23 +0100539{
Jan Eilers8eb25602020-03-09 12:13:48 +0000540 IgnoreUnused(tensorPtr);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100541 ARMNN_ASSERT_MSG(tensorPtr != nullptr, "tensorPtr is null");
542 ARMNN_ASSERT_MSG(bufferPtr != nullptr,
James Ward58dec6b2020-09-11 17:32:44 +0100543 fmt::format("Buffer for buffer:{} is null", tensorPtr->buffer).c_str());
telsoa01c577f2c2018-08-31 09:22:23 +0100544
545 std::unique_ptr<T[]> data(new T[tensorInfo.GetNumElements()]);
Matteo Martincigh747ef822018-12-18 09:26:39 +0000546
547 if (permutationVector.has_value() && permutationVector.value().GetSize() > 0)
548 {
549 tensorInfo = armnnUtils::Permuted(tensorInfo, permutationVector.value());
Matteo Martincighd5b9e642019-01-04 18:01:21 +0000550 armnnUtils::Permute(tensorInfo.GetShape(), permutationVector.value(),
551 reinterpret_cast<const T*>(bufferPtr->data.data()), data.get(), sizeof(T));
Matteo Martincigh747ef822018-12-18 09:26:39 +0000552 }
553 else
554 {
555 ::memcpy(data.get(), bufferPtr->data.data(), tensorInfo.GetNumBytes());
556 }
557
Matthew Sloyan81beae32021-07-13 19:46:11 +0100558 // Make sure isConstant flag is set.
559 tensorInfo.SetConstant();
560
telsoa01c577f2c2018-08-31 09:22:23 +0100561 return std::make_pair(ConstTensor(tensorInfo, data.get()), std::move(data));
562}
563
telsoa01c577f2c2018-08-31 09:22:23 +0100564armnn::LayerBindingId GenerateLayerBindingId(size_t subgraphIndex, size_t tensorIndex)
565{
566 // generate the binding id by shifting the tensor id by 8 bit
567 // and add the subgraph id, which allows 256 subgraphs
568 return static_cast<armnn::LayerBindingId>((tensorIndex<<8)+subgraphIndex);
569}
570
Aron Virginas-Tar70672f62019-01-23 14:00:00 +0000571bool CheckShape(const armnn::TensorShape& actual, const std::vector<int32_t>& expected)
572{
573 const unsigned int actualSize = actual.GetNumDimensions();
574 if (actualSize != expected.size())
575 {
576 return false;
577 }
578
579 for (unsigned int i = 0u; i < actualSize; i++)
580 {
581 if (expected[i] < 0 ||
582 actual[i] != static_cast<unsigned int>(expected[i]))
583 {
584 return false;
585 }
586 }
587
588 return true;
589}
590
James Conroy05102392020-06-24 15:39:55 +0100591void CheckMatchingQuantization(const TensorInfo& first,
592 const TensorInfo& second,
593 const std::string& descName,
594 std::string const& firstName,
595 std::string const& secondName)
596{
597 if (!first.IsQuantized() ||
598 !second.IsQuantized())
599 {
600 // Not a quantized type, ignore the validation
601 return;
602 }
603
604 DataType firstDataType = first.GetDataType();
605 DataType secondDataType = second.GetDataType();
606
607 if (firstDataType != secondDataType)
608 {
609 throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
610 " must be of the same quantized type, " +
611 firstName + " is " + GetDataTypeName(firstDataType) + ", " +
612 secondName + " is " + GetDataTypeName(secondDataType));
613 }
614
615 if (!first.IsTypeSpaceMatch(second))
616 {
617 throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
618 " must have the same quantization space, " +
619 firstName + " has offset " + std::to_string(first.GetQuantizationOffset()) +
620 " and scale " + std::to_string(first.GetQuantizationScale()) + ", " +
621 secondName + " has offset " + std::to_string(second.GetQuantizationOffset()) +
622 " and scale " + std::to_string(second.GetQuantizationScale()));
623 }
624}
625
telsoa01c577f2c2018-08-31 09:22:23 +0100626} // <anonymous>
627
Kevin May7d96b162021-02-03 17:38:41 +0000628TfLiteParserImpl::TfLiteParserImpl(const Optional<ITfLiteParser::TfLiteParserOptions>& options)
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100629: m_Options(options)
630, m_Network(nullptr, nullptr)
Kevin May7d96b162021-02-03 17:38:41 +0000631, m_ParserFunctions(tflite::BuiltinOperator_MAX+1, &TfLiteParserImpl::ParseUnsupportedOperator)
telsoa01c577f2c2018-08-31 09:22:23 +0100632{
633 // register supported operators
Matthew Sloyaned7fce42021-04-15 20:46:24 +0100634 m_ParserFunctions[tflite::BuiltinOperator_ABS] = &TfLiteParserImpl::ParseAbs;
Kevin May7d96b162021-02-03 17:38:41 +0000635 m_ParserFunctions[tflite::BuiltinOperator_ADD] = &TfLiteParserImpl::ParseAdd;
Matthew Sloyan28f177c2021-04-09 14:38:52 +0100636 m_ParserFunctions[tflite::BuiltinOperator_ARG_MIN] = &TfLiteParserImpl::ParseArgMin;
637 m_ParserFunctions[tflite::BuiltinOperator_ARG_MAX] = &TfLiteParserImpl::ParseArgMax;
Kevin May7d96b162021-02-03 17:38:41 +0000638 m_ParserFunctions[tflite::BuiltinOperator_AVERAGE_POOL_2D] = &TfLiteParserImpl::ParseAveragePool2D;
639 m_ParserFunctions[tflite::BuiltinOperator_BATCH_TO_SPACE_ND] = &TfLiteParserImpl::ParseBatchToSpaceND;
mathad01b392e982021-04-07 12:07:30 +0100640 m_ParserFunctions[tflite::BuiltinOperator_CAST] = &TfLiteParserImpl::ParseCast;
Kevin May7d96b162021-02-03 17:38:41 +0000641 m_ParserFunctions[tflite::BuiltinOperator_CONCATENATION] = &TfLiteParserImpl::ParseConcatenation;
642 m_ParserFunctions[tflite::BuiltinOperator_CONV_2D] = &TfLiteParserImpl::ParseConv2D;
Matthew Sloyan4d217c02021-10-07 11:48:58 +0100643 // Conv3D support was added in TF 2.5, so for backwards compatibility a hash define is needed.
644 #if defined(ARMNN_POST_TFLITE_2_3)
Matthew Sloyaneb5f8102021-10-05 17:31:42 +0100645 m_ParserFunctions[tflite::BuiltinOperator_CONV_3D] = &TfLiteParserImpl::ParseConv3D;
Matthew Sloyan4d217c02021-10-07 11:48:58 +0100646 #endif
Kevin May7d96b162021-02-03 17:38:41 +0000647 m_ParserFunctions[tflite::BuiltinOperator_CUSTOM] = &TfLiteParserImpl::ParseCustomOperator;
648 m_ParserFunctions[tflite::BuiltinOperator_DEPTH_TO_SPACE] = &TfLiteParserImpl::ParseDepthToSpace;
649 m_ParserFunctions[tflite::BuiltinOperator_DEPTHWISE_CONV_2D] = &TfLiteParserImpl::ParseDepthwiseConv2D;
650 m_ParserFunctions[tflite::BuiltinOperator_DEQUANTIZE] = &TfLiteParserImpl::ParseDequantize;
Matthew Sloyan28f177c2021-04-09 14:38:52 +0100651 m_ParserFunctions[tflite::BuiltinOperator_DIV] = &TfLiteParserImpl::ParseDiv;
Kevin May7d96b162021-02-03 17:38:41 +0000652 m_ParserFunctions[tflite::BuiltinOperator_ELU] = &TfLiteParserImpl::ParseElu;
Bruno Goncalves2d0eb862021-07-11 14:10:15 -0300653 m_ParserFunctions[tflite::BuiltinOperator_EQUAL] = &TfLiteParserImpl::ParseEqual;
Kevin May7d96b162021-02-03 17:38:41 +0000654 m_ParserFunctions[tflite::BuiltinOperator_EXP] = &TfLiteParserImpl::ParseExp;
Teresa Charlin3ab85482021-06-08 16:59:29 +0100655 m_ParserFunctions[tflite::BuiltinOperator_EXPAND_DIMS] = &TfLiteParserImpl::ParseExpandDims;
Kevin May7d96b162021-02-03 17:38:41 +0000656 m_ParserFunctions[tflite::BuiltinOperator_FULLY_CONNECTED] = &TfLiteParserImpl::ParseFullyConnected;
657 m_ParserFunctions[tflite::BuiltinOperator_GATHER] = &TfLiteParserImpl::ParseGather;
Bruno Goncalves2d0eb862021-07-11 14:10:15 -0300658 m_ParserFunctions[tflite::BuiltinOperator_GREATER] = &TfLiteParserImpl::ParseGreater;
659 m_ParserFunctions[tflite::BuiltinOperator_GREATER_EQUAL] = &TfLiteParserImpl::ParseGreaterOrEqual;
Kevin May7d96b162021-02-03 17:38:41 +0000660 m_ParserFunctions[tflite::BuiltinOperator_HARD_SWISH] = &TfLiteParserImpl::ParseHardSwish;
661 m_ParserFunctions[tflite::BuiltinOperator_LEAKY_RELU] = &TfLiteParserImpl::ParseLeakyRelu;
Bruno Goncalves2d0eb862021-07-11 14:10:15 -0300662 m_ParserFunctions[tflite::BuiltinOperator_LESS] = &TfLiteParserImpl::ParseLess;
663 m_ParserFunctions[tflite::BuiltinOperator_LESS_EQUAL] = &TfLiteParserImpl::ParseLessOrEqual;
Mike Kelly31dce2b2021-09-01 21:22:37 +0100664 m_ParserFunctions[tflite::BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION]
665 = &TfLiteParserImpl::ParseLocalResponseNormalization;
Matthew Sloyaned7fce42021-04-15 20:46:24 +0100666 m_ParserFunctions[tflite::BuiltinOperator_LOGICAL_NOT] = &TfLiteParserImpl::ParseLogicalNot;
Kevin May7d96b162021-02-03 17:38:41 +0000667 m_ParserFunctions[tflite::BuiltinOperator_LOGISTIC] = &TfLiteParserImpl::ParseLogistic;
668 m_ParserFunctions[tflite::BuiltinOperator_L2_NORMALIZATION] = &TfLiteParserImpl::ParseL2Normalization;
669 m_ParserFunctions[tflite::BuiltinOperator_MAX_POOL_2D] = &TfLiteParserImpl::ParseMaxPool2D;
670 m_ParserFunctions[tflite::BuiltinOperator_MAXIMUM] = &TfLiteParserImpl::ParseMaximum;
671 m_ParserFunctions[tflite::BuiltinOperator_MEAN] = &TfLiteParserImpl::ParseMean;
672 m_ParserFunctions[tflite::BuiltinOperator_MINIMUM] = &TfLiteParserImpl::ParseMinimum;
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +0100673 m_ParserFunctions[tflite::BuiltinOperator_MIRROR_PAD] = &TfLiteParserImpl::ParseMirrorPad;
Kevin May7d96b162021-02-03 17:38:41 +0000674 m_ParserFunctions[tflite::BuiltinOperator_MUL] = &TfLiteParserImpl::ParseMul;
675 m_ParserFunctions[tflite::BuiltinOperator_NEG] = &TfLiteParserImpl::ParseNeg;
Bruno Goncalves2d0eb862021-07-11 14:10:15 -0300676 m_ParserFunctions[tflite::BuiltinOperator_NOT_EQUAL] = &TfLiteParserImpl::ParseNotEqual;
Kevin May7d96b162021-02-03 17:38:41 +0000677 m_ParserFunctions[tflite::BuiltinOperator_PACK] = &TfLiteParserImpl::ParsePack;
678 m_ParserFunctions[tflite::BuiltinOperator_PAD] = &TfLiteParserImpl::ParsePad;
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +0100679 m_ParserFunctions[tflite::BuiltinOperator_PRELU] = &TfLiteParserImpl::ParsePrelu;
Kevin May7d96b162021-02-03 17:38:41 +0000680 m_ParserFunctions[tflite::BuiltinOperator_QUANTIZE] = &TfLiteParserImpl::ParseQuantize;
681 m_ParserFunctions[tflite::BuiltinOperator_RELU] = &TfLiteParserImpl::ParseRelu;
682 m_ParserFunctions[tflite::BuiltinOperator_RELU6] = &TfLiteParserImpl::ParseRelu6;
Sadik Armagana2747482021-02-09 10:28:54 +0000683 m_ParserFunctions[tflite::BuiltinOperator_REDUCE_MAX] = &TfLiteParserImpl::ParseReduceMax;
684 m_ParserFunctions[tflite::BuiltinOperator_REDUCE_MIN] = &TfLiteParserImpl::ParseReduceMin;
Teresa Charlin4e3e8312021-08-05 12:34:37 +0100685 m_ParserFunctions[tflite::BuiltinOperator_REDUCE_PROD] = &TfLiteParserImpl::ParseReduceProd;
Kevin May7d96b162021-02-03 17:38:41 +0000686 m_ParserFunctions[tflite::BuiltinOperator_RESHAPE] = &TfLiteParserImpl::ParseReshape;
687 m_ParserFunctions[tflite::BuiltinOperator_RESIZE_BILINEAR] = &TfLiteParserImpl::ParseResizeBilinear;
688 m_ParserFunctions[tflite::BuiltinOperator_RESIZE_NEAREST_NEIGHBOR] = &TfLiteParserImpl::ParseResizeNearestNeighbor;
Matthew Sloyaned7fce42021-04-15 20:46:24 +0100689 m_ParserFunctions[tflite::BuiltinOperator_RSQRT] = &TfLiteParserImpl::ParseRsqrt;
Keith Davis0176fd82021-06-01 17:36:32 +0100690 m_ParserFunctions[tflite::BuiltinOperator_SHAPE] = &TfLiteParserImpl::ParseShape;
Kevin May7d96b162021-02-03 17:38:41 +0000691 m_ParserFunctions[tflite::BuiltinOperator_SLICE] = &TfLiteParserImpl::ParseSlice;
692 m_ParserFunctions[tflite::BuiltinOperator_SOFTMAX] = &TfLiteParserImpl::ParseSoftmax;
693 m_ParserFunctions[tflite::BuiltinOperator_SPACE_TO_BATCH_ND] = &TfLiteParserImpl::ParseSpaceToBatchND;
694 m_ParserFunctions[tflite::BuiltinOperator_SPLIT] = &TfLiteParserImpl::ParseSplit;
695 m_ParserFunctions[tflite::BuiltinOperator_SPLIT_V] = &TfLiteParserImpl::ParseSplitV;
696 m_ParserFunctions[tflite::BuiltinOperator_SQUEEZE] = &TfLiteParserImpl::ParseSqueeze;
697 m_ParserFunctions[tflite::BuiltinOperator_STRIDED_SLICE] = &TfLiteParserImpl::ParseStridedSlice;
698 m_ParserFunctions[tflite::BuiltinOperator_SUB] = &TfLiteParserImpl::ParseSub;
699 m_ParserFunctions[tflite::BuiltinOperator_SUM] = &TfLiteParserImpl::ParseSum;
700 m_ParserFunctions[tflite::BuiltinOperator_TANH] = &TfLiteParserImpl::ParseTanH;
701 m_ParserFunctions[tflite::BuiltinOperator_TRANSPOSE] = &TfLiteParserImpl::ParseTranspose;
702 m_ParserFunctions[tflite::BuiltinOperator_TRANSPOSE_CONV] = &TfLiteParserImpl::ParseTransposeConv;
703 m_ParserFunctions[tflite::BuiltinOperator_UNPACK] = &TfLiteParserImpl::ParseUnpack;
Matthew Sloyan28f177c2021-04-09 14:38:52 +0100704
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100705 // register supported custom operators
Kevin May7d96b162021-02-03 17:38:41 +0000706 m_CustomParserFunctions["TFLite_Detection_PostProcess"] = &TfLiteParserImpl::ParseDetectionPostProcess;
telsoa01c577f2c2018-08-31 09:22:23 +0100707}
708
Kevin May7d96b162021-02-03 17:38:41 +0000709void TfLiteParserImpl::ResetParser()
telsoa01c577f2c2018-08-31 09:22:23 +0100710{
711 m_Network = armnn::INetworkPtr(nullptr, nullptr);
712 m_Model = nullptr;
713 m_SubgraphConnections.clear();
714}
715
Kevin May7d96b162021-02-03 17:38:41 +0000716INetworkPtr TfLiteParserImpl::CreateNetworkFromBinaryFile(const char* graphFile)
telsoa01c577f2c2018-08-31 09:22:23 +0100717{
718 ResetParser();
719 m_Model = LoadModelFromFile(graphFile);
720 return CreateNetworkFromModel();
721}
722
Kevin May7d96b162021-02-03 17:38:41 +0000723INetworkPtr TfLiteParserImpl::CreateNetworkFromBinary(const std::vector<uint8_t> & binaryContent)
telsoa01c577f2c2018-08-31 09:22:23 +0100724{
725 ResetParser();
726 m_Model = LoadModelFromBinary(binaryContent.data(), binaryContent.size());
727 return CreateNetworkFromModel();
728}
729
Finn Williamsb49ed182021-06-29 15:50:08 +0100730
731armnn::INetworkPtr TfLiteParserImpl::LoadModel(std::unique_ptr<tflite::ModelT> model)
732{
733 ResetParser();
734 m_Model = std::move(model);
735
736 return CreateNetworkFromModel();
737}
738
Kevin May7d96b162021-02-03 17:38:41 +0000739INetworkPtr TfLiteParserImpl::CreateNetworkFromModel()
telsoa01c577f2c2018-08-31 09:22:23 +0100740{
Sadik Armagand109a4d2020-07-28 10:42:13 +0100741
742 using NetworkOptions = std::vector<BackendOptions>;
743 NetworkOptions networkOptions = {};
744 if (m_Options && m_Options.value().m_InferAndValidate)
745 {
746 BackendOptions shapeInferenceMethodOption("ShapeInferenceMethod",
747 {
748 { "InferAndValidate", true }
749 });
750
751 networkOptions.push_back(shapeInferenceMethodOption);
752 }
753
754 m_Network = INetwork::Create(networkOptions);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100755 ARMNN_ASSERT(m_Model.get() != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +0100756
telsoa01c577f2c2018-08-31 09:22:23 +0100757 if (m_Model->subgraphs.size() != 1)
758 {
759 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100760 fmt::format("Current TfLite parser only supports 1 subgraph. Current one has: {} {}",
761 m_Model->subgraphs.size(),
762 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +0100763 }
764
765 size_t subgraphIndex = 0;
Colm Donelan6350d272020-06-09 16:56:25 +0100766 size_t operatorIndex = 0;
767 try
telsoa01c577f2c2018-08-31 09:22:23 +0100768 {
Colm Donelan6350d272020-06-09 16:56:25 +0100769 for (SubgraphPtr const& subgraph : m_Model->subgraphs)
telsoa01c577f2c2018-08-31 09:22:23 +0100770 {
Colm Donelan6350d272020-06-09 16:56:25 +0100771 m_SubgraphConnections.emplace_back(subgraph->tensors.size());
772 for (OperatorPtr const& op : subgraph->operators)
telsoa01c577f2c2018-08-31 09:22:23 +0100773 {
Colm Donelan6350d272020-06-09 16:56:25 +0100774 auto const& opCodePtr = m_Model->operator_codes[op->opcode_index];
Jim Flynnfca233e2021-09-23 12:16:53 +0100775
776// 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 +0100777#if defined(ARMNN_POST_TFLITE_2_3)
Jim Flynnfca233e2021-09-23 12:16:53 +0100778 auto builtinCode = std::max(opCodePtr->builtin_code,
779 static_cast<tflite::BuiltinOperator>(opCodePtr->deprecated_builtin_code));
780#else
telsoa01c577f2c2018-08-31 09:22:23 +0100781 auto builtinCode = opCodePtr->builtin_code;
Jim Flynnfca233e2021-09-23 12:16:53 +0100782#endif
telsoa01c577f2c2018-08-31 09:22:23 +0100783
784 if (builtinCode > tflite::BuiltinOperator_MAX)
785 {
James Ward58dec6b2020-09-11 17:32:44 +0100786 throw ParseException(fmt::format("Operator code {} is out of range 0-{}. "
787 "subgraph:{} operator idx:{}. {}",
788 builtinCode, tflite::BuiltinOperator_MAX, subgraphIndex,
789 operatorIndex, CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +0100790 }
791
792 // lookup and call the parser function
Colm Donelan6350d272020-06-09 16:56:25 +0100793 auto& parserFunction = m_ParserFunctions[builtinCode];
telsoa01c577f2c2018-08-31 09:22:23 +0100794 (this->*parserFunction)(subgraphIndex, operatorIndex);
Colm Donelan6350d272020-06-09 16:56:25 +0100795 ++operatorIndex;
telsoa01c577f2c2018-08-31 09:22:23 +0100796 }
telsoa01c577f2c2018-08-31 09:22:23 +0100797
Colm Donelan6350d272020-06-09 16:56:25 +0100798 SetupInputLayers(subgraphIndex);
799 SetupOutputLayers(subgraphIndex);
800 SetupConstantLayers(subgraphIndex);
telsoa01c577f2c2018-08-31 09:22:23 +0100801
Colm Donelan6350d272020-06-09 16:56:25 +0100802 ++subgraphIndex;
803 operatorIndex = 0;
telsoa01c577f2c2018-08-31 09:22:23 +0100804 }
telsoa01c577f2c2018-08-31 09:22:23 +0100805 }
Colm Donelan6350d272020-06-09 16:56:25 +0100806 catch (const ParseException& e)
telsoa01c577f2c2018-08-31 09:22:23 +0100807 {
Colm Donelan6350d272020-06-09 16:56:25 +0100808 std::stringstream errorString;
809 errorString << "Failed to parse operator #" << operatorIndex << " within subgraph #"
810 << subgraphIndex << " error: " << e.what();
811 ARMNN_LOG(error) << errorString.str();
812 std::stringstream errors;
813 errors << errorString.str() << "\n";
telsoa01c577f2c2018-08-31 09:22:23 +0100814 throw ParseException(errors.str());
815 }
816
817 // establish the connections from the layer outputs to the inputs of the subsequent layers
Colm Donelan6350d272020-06-09 16:56:25 +0100818 for (subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +0100819 {
820 for (size_t tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex)
821 {
822 if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot != nullptr)
823 {
824 for (size_t inputSlotIdx = 0;
825 inputSlotIdx < m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size();
826 ++inputSlotIdx)
827 {
828 m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot->Connect(
829 *(m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots[inputSlotIdx]));
830 }
831 }
832 }
833 }
834
835 return std::move(m_Network);
836}
837
Kevin May7d96b162021-02-03 17:38:41 +0000838void TfLiteParserImpl::RegisterProducerOfTensor(size_t subgraphIndex,
839 size_t tensorIndex,
840 armnn::IOutputSlot* slot)
telsoa01c577f2c2018-08-31 09:22:23 +0100841{
842 CHECK_TENSOR(m_Model, subgraphIndex, tensorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100843 ARMNN_ASSERT(m_SubgraphConnections.size() > subgraphIndex);
844 ARMNN_ASSERT(m_SubgraphConnections[subgraphIndex].size() > tensorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +0100845
846 TensorSlots & tensorSlots = m_SubgraphConnections[subgraphIndex][tensorIndex];
847
848 // assuming there is only one producer for that tensor
849 if (tensorSlots.outputSlot != nullptr)
850 {
James Ward58dec6b2020-09-11 17:32:44 +0100851 throw ParseException(fmt::format("Another layer has already registered itself as the producer of "
852 "subgraph:{} tensor:{} {}",
853 subgraphIndex,
854 tensorIndex,
855 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +0100856 }
857
858 tensorSlots.outputSlot = slot;
859}
860
Kevin May7d96b162021-02-03 17:38:41 +0000861void TfLiteParserImpl::RegisterConsumerOfTensor(size_t subgraphIndex,
862 size_t tensorIndex,
863 armnn::IInputSlot* slot)
telsoa01c577f2c2018-08-31 09:22:23 +0100864{
865 CHECK_TENSOR(m_Model, subgraphIndex, tensorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100866 ARMNN_ASSERT(m_SubgraphConnections.size() > subgraphIndex);
867 ARMNN_ASSERT(m_SubgraphConnections[subgraphIndex].size() > tensorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +0100868
Finn Williamsd4fa5452021-03-01 12:31:41 +0000869 TensorSlots& tensorSlots = m_SubgraphConnections[subgraphIndex][tensorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +0100870 tensorSlots.inputSlots.push_back(slot);
871}
872
Kevin May7d96b162021-02-03 17:38:41 +0000873void TfLiteParserImpl::ParseCustomOperator(size_t subgraphIndex, size_t operatorIndex)
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100874{
875 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
876
877 // NOTE: By default we presume the custom operator is not supported
Kevin May7d96b162021-02-03 17:38:41 +0000878 auto customParserFunction = &TfLiteParserImpl::ParseUnsupportedOperator;
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100879
880 // Identify custom code defined for custom operator
881 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
882 const auto& customCode = m_Model->operator_codes[operatorPtr->opcode_index]->custom_code;
883
884 // Find parser function that correspondes to custom code (if any)
885 auto iterator = m_CustomParserFunctions.find(customCode);
886 if (iterator != m_CustomParserFunctions.end())
887 {
888 customParserFunction = iterator->second;
889 }
890
891 // Run parser function
892 (this->*customParserFunction)(subgraphIndex, operatorIndex);
893}
894
Kevin May7d96b162021-02-03 17:38:41 +0000895void TfLiteParserImpl::ParseUnsupportedOperator(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +0100896{
897 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +0100898
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100899 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
900
901 auto opcodeIndex = operatorPtr->opcode_index;
Jim Flynnfca233e2021-09-23 12:16:53 +0100902
903// 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 +0100904#if defined(ARMNN_POST_TFLITE_2_3)
Jim Flynnfca233e2021-09-23 12:16:53 +0100905 auto opcode = std::max(m_Model->operator_codes[opcodeIndex]->builtin_code,
906 static_cast<tflite::BuiltinOperator>(m_Model->operator_codes[opcodeIndex]->deprecated_builtin_code));
907#else
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100908 auto opcode = m_Model->operator_codes[opcodeIndex]->builtin_code;
Jim Flynnfca233e2021-09-23 12:16:53 +0100909#endif
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100910
911 if (!m_Options || !m_Options.value().m_StandInLayerForUnsupported)
912 {
913 // Do not add StandInLayer, throw ParseException instead
914 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100915 fmt::format("Operator not supported. "
916 "subgraph:{} operator:{} "
917 "opcode_index:{} opcode:{} / {} {}",
918 subgraphIndex,
919 operatorIndex,
920 opcodeIndex,
921 opcode,
922 tflite::EnumNameBuiltinOperator(opcode),
923 CHECK_LOCATION().AsString()));
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100924 }
925
926 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
927 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
928
Matthew Sloyan589e3e82020-09-11 16:17:48 +0100929 const unsigned int numInputs = armnn::numeric_cast<unsigned int>(inputs.size());
930 const unsigned int numOutputs = armnn::numeric_cast<unsigned int>(outputs.size());
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100931
932 StandInDescriptor descriptor(numInputs, numOutputs);
James Ward58dec6b2020-09-11 17:32:44 +0100933 auto layerName = fmt::format("StandIn:{}:{}:{}", subgraphIndex, operatorIndex, opcode);
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100934
935 // Add a non-executable StandInLayer as a placeholder for any unsupported operator
936 IConnectableLayer* layer = m_Network->AddStandInLayer(descriptor, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +0100937 ARMNN_ASSERT(layer != nullptr);
938
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100939 for (unsigned int i = 0u; i < numOutputs; ++i)
940 {
Sadik Armagand109a4d2020-07-28 10:42:13 +0100941 layer->GetOutputSlot(i).SetTensorInfo(ToTensorInfo(outputs[i], true));
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100942 }
943
944 auto inputTensorIds = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
945 auto outputTensorIds = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
946
947 RegisterInputSlots(subgraphIndex, operatorIndex, layer, inputTensorIds);
948 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIds);
telsoa01c577f2c2018-08-31 09:22:23 +0100949}
950
mathad01b392e982021-04-07 12:07:30 +0100951void TfLiteParserImpl::ParseCast(size_t subgraphIndex, size_t operatorIndex)
952{
953 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
954
955 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
956 CHECK_VALID_SIZE(inputs.size(), 1);
957 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
958 CHECK_VALID_SIZE(outputs.size(), 1);
959
960 auto layerName = fmt::format("Cast:{}:{}", subgraphIndex, operatorIndex);
961
962 IConnectableLayer* layer = m_Network->AddCastLayer(layerName.c_str());
963 ARMNN_ASSERT(layer != nullptr);
964
965 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
966 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
967
968 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
969 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
970
971 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
972 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
973}
974
Kevin May7d96b162021-02-03 17:38:41 +0000975void TfLiteParserImpl::ParseConv2D(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +0100976{
977 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
978
979 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
980 const auto * options = operatorPtr->builtin_options.AsConv2DOptions();
981
982 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
983
984 Convolution2dDescriptor desc;
985 desc.m_BiasEnabled = false;
986 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
987 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
jimfly01c25411c2018-11-14 17:47:22 +0000988 desc.m_DataLayout = armnn::DataLayout::NHWC;
Pablo Tellof0bd6832019-04-26 17:58:13 +0100989 desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
990 desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
Kevin May83add212019-03-26 11:39:19 +0000991
telsoa01c577f2c2018-08-31 09:22:23 +0100992 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
993 CHECK_VALID_SIZE(inputs.size(), 2, 3);
994
995 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
996 CHECK_VALID_SIZE(outputs.size(), 1);
997
998 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
999 armnn::TensorInfo filterTensorInfo = ToTensorInfo(inputs[1]);
1000
1001 // assuming input is NHWC
1002 unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1003 unsigned int inputWidth = inputTensorInfo.GetShape()[2];
1004
1005 // assuming the filter is OHWI : Output, H, W, Input
1006 // which is essentially the same as NHWC
1007 unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1008 unsigned int filterWidth = filterTensorInfo.GetShape()[2];
1009
Pablo Tellof0bd6832019-04-26 17:58:13 +01001010 CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
1011 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
1012 CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
1013 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
telsoa01c577f2c2018-08-31 09:22:23 +01001014
Finn Williamsd4fa5452021-03-01 12:31:41 +00001015 auto filterTensorAndData = CreateConstTensorNonPermuted(inputs[1], filterTensorInfo);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001016 armnn::IConnectableLayer* layer = nullptr;
telsoa01c577f2c2018-08-31 09:22:23 +01001017
James Ward58dec6b2020-09-11 17:32:44 +01001018 auto layerName = fmt::format("Conv2D:{}:{}", subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001019
1020 if (inputs.size() == 3)
1021 {
1022 desc.m_BiasEnabled = true;
1023 armnn::TensorInfo biasTensorInfo = ToTensorInfo(inputs[2]);
Finn Williamsd4fa5452021-03-01 12:31:41 +00001024 auto biasTensorAndData = CreateConstTensorNonPermuted(inputs[2], biasTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +01001025 layer = m_Network->AddConvolution2dLayer(desc,
Finn Williamsd4fa5452021-03-01 12:31:41 +00001026 filterTensorAndData,
1027 Optional<ConstTensor>(biasTensorAndData),
telsoa01c577f2c2018-08-31 09:22:23 +01001028 layerName.c_str());
1029 }
1030 else
1031 {
1032 layer = m_Network->AddConvolution2dLayer(desc,
Finn Williamsd4fa5452021-03-01 12:31:41 +00001033 filterTensorAndData,
Matteo Martincighfc598e12019-05-14 10:36:13 +01001034 EmptyOptional(),
telsoa01c577f2c2018-08-31 09:22:23 +01001035 layerName.c_str());
1036 }
1037
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001038 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01001039
Sadik Armagand109a4d2020-07-28 10:42:13 +01001040 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
jimfly01c25411c2018-11-14 17:47:22 +00001041 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +01001042
1043 // register the input connection slots for the layer, connections are made after all layers have been created
1044 // only the tensors for the inputs are relevant, exclude the const tensors
1045 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
jimfly01c25411c2018-11-14 17:47:22 +00001046 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
telsoa01c577f2c2018-08-31 09:22:23 +01001047
jimfly01c25411c2018-11-14 17:47:22 +00001048 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
telsoa01c577f2c2018-08-31 09:22:23 +01001049 // register the output connection slots for the layer, connections are made after all layers have been created
1050 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1051 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1052}
1053
Matthew Sloyan4d217c02021-10-07 11:48:58 +01001054// Conv3D support was added in TF 2.5, so for backwards compatibility a hash define is needed.
1055#if defined(ARMNN_POST_TFLITE_2_3)
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001056void TfLiteParserImpl::ParseConv3D(size_t subgraphIndex, size_t operatorIndex)
1057{
1058 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1059
1060 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1061 const auto* options = operatorPtr->builtin_options.AsConv3DOptions();
1062
1063 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1064
1065 Convolution3dDescriptor desc;
1066 desc.m_BiasEnabled = false;
1067 desc.m_DataLayout = armnn::DataLayout::NDHWC;
1068 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1069 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1070 desc.m_StrideZ = CHECKED_NON_NEGATIVE(options->stride_d);
1071 desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
1072 desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
1073 desc.m_DilationZ = CHECKED_NON_NEGATIVE(options->dilation_d_factor);
1074
1075 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1076 CHECK_VALID_SIZE(inputs.size(), 2, 3);
1077
1078 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1079 CHECK_VALID_SIZE(outputs.size(), 1);
1080
1081 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
1082 armnn::TensorInfo filterTensorInfo = ToTensorInfo(inputs[1]);
1083
1084 // Assuming input is NDHWC
1085 unsigned int inputDepth = inputTensorInfo.GetShape()[1];
1086 unsigned int inputHeight = inputTensorInfo.GetShape()[2];
1087 unsigned int inputWidth = inputTensorInfo.GetShape()[3];
1088
1089 // Assuming the filter is DHWIO : Depth, Height, Width, OutputChannels, InputChannels
1090 unsigned int filterDepth = filterTensorInfo.GetShape()[0];
1091 unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1092 unsigned int filterWidth = filterTensorInfo.GetShape()[2];
1093
1094 CalcPadding(inputDepth, filterDepth, desc.m_StrideZ,
1095 desc.m_DilationY, desc.m_PadFront, desc.m_PadBack, options->padding);
1096 CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
1097 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
1098 CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
1099 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
1100
1101 auto filterTensorAndData = CreateConstTensorNonPermuted(inputs[1], filterTensorInfo);
1102
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001103 auto layerName = fmt::format("Conv3D:{}:{}", subgraphIndex, operatorIndex);
1104
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001105 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1106 // Add the first input and weights tensor to the registration list.
1107 // The constant weights will be added by SetupConstantLayers.
1108 std::vector<unsigned int> tensorIndexesToRegister = {inputTensorIndexes[0], inputTensorIndexes[1]};
1109
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001110 if (inputs.size() == 3)
1111 {
1112 desc.m_BiasEnabled = true;
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001113
1114 // Add the biases input to the registration list, a constant layer will be added by SetupConstantLayers.
1115 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001116 }
1117
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001118 armnn::IConnectableLayer* layer = m_Network->AddConvolution3dLayer(desc, layerName.c_str());
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001119 ARMNN_ASSERT(layer != nullptr);
1120
1121 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1122 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1123
1124 // Register the input connection slots for the layer, connections are made after all layers have been created
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +01001125 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister);
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001126
1127 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
1128 // Register the output connection slots for the layer, connections are made after all layers have been created
1129 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1130 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1131}
Matthew Sloyan4d217c02021-10-07 11:48:58 +01001132#endif
Matthew Sloyaneb5f8102021-10-05 17:31:42 +01001133
Kevin May7d96b162021-02-03 17:38:41 +00001134void TfLiteParserImpl::ParseDepthwiseConv2D(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001135{
1136 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1137
1138 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1139 const auto * options = operatorPtr->builtin_options.AsDepthwiseConv2DOptions();
1140
1141 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1142
1143 DepthwiseConvolution2dDescriptor desc;
1144 desc.m_BiasEnabled = false;
1145 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1146 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
jimfly01c25411c2018-11-14 17:47:22 +00001147 desc.m_DataLayout = armnn::DataLayout::NHWC;
Matthew Jacksond6a9dee2019-07-22 13:53:24 +01001148 CHECKED_NON_NEGATIVE(options->depth_multiplier);
telsoa01c577f2c2018-08-31 09:22:23 +01001149
1150 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1151 CHECK_VALID_SIZE(inputs.size(), 2, 3);
1152 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1153 CHECK_VALID_SIZE(outputs.size(), 1);
Pablo Tellof0bd6832019-04-26 17:58:13 +01001154 desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
1155 desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
Kevin May83add212019-03-26 11:39:19 +00001156
telsoa01c577f2c2018-08-31 09:22:23 +01001157 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
Jan Eilers7612bd62021-04-06 17:29:03 +01001158 armnn::TensorInfo filterTensorInfo = ToTensorInfo(inputs[1]);
telsoa01c577f2c2018-08-31 09:22:23 +01001159
Matteo Martincigh747ef822018-12-18 09:26:39 +00001160 // Assuming input is NHWC
telsoa01c577f2c2018-08-31 09:22:23 +01001161 unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1162 unsigned int inputWidth = inputTensorInfo.GetShape()[2];
Matteo Martincigh747ef822018-12-18 09:26:39 +00001163
1164 // TensorflowLite weights come in the format [1, H, W, I * M]
telsoa01c577f2c2018-08-31 09:22:23 +01001165 unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1166 unsigned int filterWidth = filterTensorInfo.GetShape()[2];
1167
Pablo Tellof0bd6832019-04-26 17:58:13 +01001168 CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
1169 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
1170 CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
1171 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
telsoa01c577f2c2018-08-31 09:22:23 +01001172
Jan Eilers53ef7952021-06-02 12:01:25 +01001173 // ArmNN uses the same filter tensor layout at TfLite [1, H, W, O] no need for any permutation
1174 auto filterTensor = CreateConstTensorNonPermuted(inputs[1], filterTensorInfo);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001175 armnn::IConnectableLayer* layer = nullptr;
James Ward58dec6b2020-09-11 17:32:44 +01001176 auto layerName = fmt::format("DepthwiseConv2D:{}:{}", subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001177
1178 if (inputs.size() == 3)
1179 {
1180 desc.m_BiasEnabled = true;
1181 TensorInfo biasTensorInfo = ToTensorInfo(inputs[2]);
Finn Williamsd4fa5452021-03-01 12:31:41 +00001182 auto biasTensorAndData = CreateConstTensorNonPermuted(inputs[2], biasTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +01001183 layer = m_Network->AddDepthwiseConvolution2dLayer(desc,
Jan Eilers53ef7952021-06-02 12:01:25 +01001184 filterTensor,
Finn Williamsd4fa5452021-03-01 12:31:41 +00001185 Optional<ConstTensor>(biasTensorAndData),
telsoa01c577f2c2018-08-31 09:22:23 +01001186 layerName.c_str());
1187 }
1188 else
1189 {
1190 layer = m_Network->AddDepthwiseConvolution2dLayer(desc,
Jan Eilers53ef7952021-06-02 12:01:25 +01001191 filterTensor,
Matteo Martincighfc598e12019-05-14 10:36:13 +01001192 EmptyOptional(),
telsoa01c577f2c2018-08-31 09:22:23 +01001193 layerName.c_str());
1194 }
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001195 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01001196
Sadik Armagand109a4d2020-07-28 10:42:13 +01001197 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
jimfly01c25411c2018-11-14 17:47:22 +00001198 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +01001199
1200 // register the input connection slots for the layer, connections are made after all layers have been created
1201 // only the tensors for the inputs are relevant, exclude the const tensors
1202 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
jimfly01c25411c2018-11-14 17:47:22 +00001203 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
telsoa01c577f2c2018-08-31 09:22:23 +01001204
jimfly01c25411c2018-11-14 17:47:22 +00001205 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
telsoa01c577f2c2018-08-31 09:22:23 +01001206 // register the output connection slots for the layer, connections are made after all layers have been created
1207 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1208 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1209}
1210
Kevin May7d96b162021-02-03 17:38:41 +00001211void TfLiteParserImpl::ParseDequantize(size_t subgraphIndex, size_t operatorIndex)
Finn Williamsed66d142019-12-06 09:55:55 +00001212{
1213 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1214
1215 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1216 CHECK_VALID_SIZE(inputs.size(), 1);
1217
1218 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1219 CHECK_VALID_SIZE(outputs.size(), 1);
1220
James Ward58dec6b2020-09-11 17:32:44 +01001221 auto layerName = fmt::format("Dequantize:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsed66d142019-12-06 09:55:55 +00001222
1223 IConnectableLayer* layer = m_Network->AddDequantizeLayer(layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001224 ARMNN_ASSERT(layer != nullptr);
Finn Williamsed66d142019-12-06 09:55:55 +00001225
Sadik Armagand109a4d2020-07-28 10:42:13 +01001226 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Finn Williamsed66d142019-12-06 09:55:55 +00001227 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1228
1229 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1230 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1231
1232 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1233 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
1234}
1235
Teresa Charlin3ab85482021-06-08 16:59:29 +01001236void TfLiteParserImpl::ParseExpandDims(size_t subgraphIndex, size_t operatorIndex)
1237{
1238 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1239
1240 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1241 CHECK_VALID_SIZE(inputs.size(), 2);
1242
1243 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1244 CHECK_VALID_SIZE(outputs.size(), 1);
1245
1246 auto layerName = fmt::format("ExpandDims:{}:{}", subgraphIndex, operatorIndex);
1247
1248 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
1249 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1250
1251 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1252
1253 ReshapeDescriptor reshapeDesc;
Finn Williamsb49ed182021-06-29 15:50:08 +01001254
1255 if (outputTensorInfo.GetShape().AreAllDimensionsSpecified())
1256 {
1257 reshapeDesc.m_TargetShape = outputTensorInfo.GetShape();
1258 }
1259 else
1260 {
1261 int32_t axis = inputs[1]->shape[0];
1262
1263 int32_t inputDimSize = static_cast<int32_t>(inputTensorInfo.GetShape().GetNumDimensions());
1264
1265 if (axis > inputDimSize || axis < 0 - (inputDimSize + 1))
1266 {
1267 throw ParseException("axis must be in range [0 - (inputDimSize + 1), inputDimSize] inclusive");
1268 }
1269
1270 if(axis < 0)
1271 {
1272 axis = inputDimSize + axis + 1;
1273 }
1274
Rob Hughesd812a312021-08-06 13:10:53 +01001275 std::vector<unsigned int> shape(static_cast<unsigned int>(inputDimSize) + 1);
Finn Williamsb49ed182021-06-29 15:50:08 +01001276 unsigned int inputShapeIndex = 0;
1277 for (unsigned int i = 0; i < static_cast<unsigned int>(inputDimSize + 1); ++i)
1278 {
1279 if (i == static_cast<unsigned int>(axis))
1280 {
1281 shape[i] = 1;
1282 }
1283 else
1284 {
1285 shape[i] = inputTensorInfo.GetShape()[inputShapeIndex];
1286 ++inputShapeIndex;
1287 }
1288 }
1289
Rob Hughesd812a312021-08-06 13:10:53 +01001290 reshapeDesc.m_TargetShape = TensorShape(static_cast<unsigned int>(inputDimSize + 1), shape.data());
Finn Williamsb49ed182021-06-29 15:50:08 +01001291 }
Teresa Charlin3ab85482021-06-08 16:59:29 +01001292
1293 IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
1294 ARMNN_ASSERT(layer != nullptr);
1295 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1296
1297 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1298 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1299
1300 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1301 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1302}
1303
Kevin May7d96b162021-02-03 17:38:41 +00001304void TfLiteParserImpl::ParseTranspose(size_t subgraphIndex, size_t operatorIndex)
Keith Davis4cd29a02019-09-09 14:49:20 +01001305{
1306 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1307
1308 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Kevin May85d92602019-09-27 17:21:06 +01001309 CHECK_VALID_SIZE(inputs.size(), 1, 2);
Keith Davis4cd29a02019-09-09 14:49:20 +01001310
1311 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1312 CHECK_VALID_SIZE(outputs.size(), 1);
1313
James Ward58dec6b2020-09-11 17:32:44 +01001314 auto layerName = fmt::format("Transpose:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly08759e22020-03-02 11:41:31 +00001315 TransposeDescriptor desc;
Keith Davis4cd29a02019-09-09 14:49:20 +01001316
josh minorba424d22019-11-13 10:55:17 -06001317 if (inputs.size() == 2)
Kevin May85d92602019-09-27 17:21:06 +01001318 {
1319 armnn::TensorInfo permuteTensorInfo = ToTensorInfo(inputs[1]);
1320 BufferRawPtr permuteBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
josh minorba424d22019-11-13 10:55:17 -06001321 auto numPermVecElements = permuteTensorInfo.GetNumElements();
1322 std::vector<unsigned int> permuteShape(numPermVecElements);
Kevin May85d92602019-09-27 17:21:06 +01001323 ::memcpy(permuteShape.data(), permuteBufferPtr->data.data(), permuteTensorInfo.GetNumBytes());
Mike Kelly08759e22020-03-02 11:41:31 +00001324 PermutationVector permutationVector(permuteShape.data(), permuteTensorInfo.GetNumElements());
Kevin May85d92602019-09-27 17:21:06 +01001325
Mike Kelly08759e22020-03-02 11:41:31 +00001326 desc = TransposeDescriptor(permutationVector);
Kevin May85d92602019-09-27 17:21:06 +01001327 }
1328
James Conroy05102392020-06-24 15:39:55 +01001329 TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
Sadik Armagand109a4d2020-07-28 10:42:13 +01001330 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01001331 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Keith Davis4cd29a02019-09-09 14:49:20 +01001332
James Conroy05102392020-06-24 15:39:55 +01001333 IConnectableLayer* layer = m_Network->AddTransposeLayer(desc, layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001334 ARMNN_ASSERT(layer != nullptr);
Keith Davis4cd29a02019-09-09 14:49:20 +01001335 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1336
1337 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1338 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1339
1340 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1341 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1342}
1343
Kevin May7d96b162021-02-03 17:38:41 +00001344void TfLiteParserImpl::ParseTransposeConv(size_t subgraphIndex, size_t operatorIndex)
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001345{
1346 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1347
1348 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1349 const auto * options = operatorPtr->builtin_options.AsTransposeConvOptions();
1350
1351 TransposeConvolution2dDescriptor desc;
1352 desc.m_BiasEnabled = false;
1353 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1354 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1355 desc.m_DataLayout = armnn::DataLayout::NHWC;
1356
1357 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
David Monahan61683802021-01-12 09:11:07 +00001358 if (inputs.size() == 4)
1359 {
1360 desc.m_BiasEnabled = true;
1361 }
1362 else
1363 {
1364 CHECK_VALID_SIZE(inputs.size(), 3);
1365 }
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001366
1367 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1368 CHECK_VALID_SIZE(outputs.size(), 1);
1369
Colm Donelan0ad3ef12020-07-03 15:54:28 +01001370 if (inputs[0])
1371 {
1372 armnn::TensorInfo tensorInfo = ToTensorInfo(inputs[0]);
1373 std::vector<int> output_shape(tensorInfo.GetNumElements());
1374 if (tensorInfo.GetDataType() == DataType::Signed32)
1375 {
1376 ::memcpy(output_shape.data(), GetBuffer(m_Model, inputs[0]->buffer)->data.data(), tensorInfo.GetNumBytes());
1377 }
1378 if (tensorInfo.GetDataType() == DataType::QAsymmU8)
1379 {
1380 for(unsigned int i=0; i < tensorInfo.GetNumElements(); i++)
1381 {
1382 output_shape[i] = GetBuffer(m_Model, inputs[0]->buffer)->data.data()[i];
1383 }
1384 }
1385 // Change from signed to unsigned int to store in TransposeConvolution2dDescriptor.
1386 for (int dimension : output_shape)
1387 {
1388 desc.m_OutputShape.push_back(static_cast<unsigned int>(dimension));
1389 }
1390 desc.m_OutputShapeEnabled = true;
1391 }
Matthew Jacksonccb25ea2019-08-20 17:18:33 +01001392 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[2]);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001393 armnn::TensorInfo filterTensorInfo = ToTensorInfo(inputs[1]);
1394
1395 // TfLite uses NHWC tensors
1396 const unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1397 const unsigned int inputWidth = inputTensorInfo.GetShape()[2];
1398
1399 const unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1400 const unsigned int filterWidth = filterTensorInfo.GetShape()[2];
1401
1402 CalcPadding(inputHeight,
1403 filterHeight,
1404 desc.m_StrideY,
1405 1, // DilationY
1406 desc.m_PadTop,
1407 desc.m_PadBottom,
1408 options->padding);
1409
1410 CalcPadding(inputWidth,
1411 filterWidth,
1412 desc.m_StrideX,
1413 1, // DilationX
1414 desc.m_PadLeft,
1415 desc.m_PadRight,
1416 options->padding);
1417
Finn Williamsd4fa5452021-03-01 12:31:41 +00001418 auto filterTensorAndData = CreateConstTensorNonPermuted(inputs[1], filterTensorInfo);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001419
1420 armnn::IConnectableLayer* layer = nullptr;
James Ward58dec6b2020-09-11 17:32:44 +01001421 auto layerName = fmt::format("TransposeConv:{}:{}", subgraphIndex, operatorIndex);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001422
David Monahan61683802021-01-12 09:11:07 +00001423 if (desc.m_BiasEnabled)
1424 {
1425 auto biasTensorInfo = ToTensorInfo(inputs[3]);
Finn Williamsd4fa5452021-03-01 12:31:41 +00001426 auto biasConstTensor = CreateConstTensorNonPermuted(inputs[3], biasTensorInfo);
David Monahan61683802021-01-12 09:11:07 +00001427 layer = m_Network->AddTransposeConvolution2dLayer(desc,
Finn Williamsd4fa5452021-03-01 12:31:41 +00001428 filterTensorAndData,
1429 biasConstTensor,
David Monahan61683802021-01-12 09:11:07 +00001430 layerName.c_str());
1431 }
1432 else
1433 {
1434 layer = m_Network->AddTransposeConvolution2dLayer(desc,
Finn Williamsd4fa5452021-03-01 12:31:41 +00001435 filterTensorAndData,
David Monahan61683802021-01-12 09:11:07 +00001436 EmptyOptional(),
1437 layerName.c_str());
1438 }
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001439
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001440 ARMNN_ASSERT(layer != nullptr);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001441
Sadik Armagand109a4d2020-07-28 10:42:13 +01001442 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001443 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1444
1445 // only the tensors for the inputs are relevant, exclude the const (filter) tensor
1446 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Matthew Jacksonccb25ea2019-08-20 17:18:33 +01001447 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[2]});
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001448
1449 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1450 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1451}
1452
Kevin May7d96b162021-02-03 17:38:41 +00001453void TfLiteParserImpl::ParseAveragePool2D(size_t subgraphIndex, size_t operatorIndex)
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001454{
1455 ParsePool(subgraphIndex, operatorIndex, PoolingAlgorithm::Average);
1456}
1457
Kevin May7d96b162021-02-03 17:38:41 +00001458void TfLiteParserImpl::ParseBatchToSpaceND(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001459{
1460 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1461
1462 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1463 CHECK_VALID_SIZE(inputs.size(), 3);
1464
1465 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1466 CHECK_VALID_SIZE(outputs.size(), 1);
1467
1468 armnn::TensorInfo blockShapeTensorInfo = ToTensorInfo(inputs[1]);
1469 BufferRawPtr blockShapeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1470
1471 armnn::TensorInfo cropsTensorInfo = ToTensorInfo(inputs[2]);
1472 BufferRawPtr cropsBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
1473
1474 std::vector<unsigned int> blockShape(blockShapeTensorInfo.GetNumElements());
1475 ::memcpy(blockShape.data(), blockShapeBufferPtr->data.data(), blockShapeTensorInfo.GetNumBytes());
1476
1477 std::vector<unsigned int> cropsVector(cropsTensorInfo.GetNumElements());
1478 ::memcpy(cropsVector.data(), cropsBufferPtr->data.data(), cropsTensorInfo.GetNumBytes());
1479
1480 size_t step = 2;
1481 std::vector<std::pair<unsigned int, unsigned int>> crops;
1482 for (unsigned int i = 0; i < cropsTensorInfo.GetNumElements() / step; ++i)
1483 {
1484 crops.emplace_back(cropsVector[i * step], cropsVector[i * step + 1]);
1485 }
1486
1487 armnn::BatchToSpaceNdDescriptor desc;
1488 desc.m_BlockShape = blockShape;
1489 desc.m_Crops = crops;
1490 desc.m_DataLayout = armnn::DataLayout::NHWC;
1491
James Ward58dec6b2020-09-11 17:32:44 +01001492 auto layerName = fmt::format("BatchToSpaceND:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001493
James Conroy05102392020-06-24 15:39:55 +01001494 TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
Sadik Armagand109a4d2020-07-28 10:42:13 +01001495 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01001496 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1497
1498 IConnectableLayer* layer = m_Network->AddBatchToSpaceNdLayer(desc, layerName.c_str());
1499 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001500 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1501
1502 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1503 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1504
1505 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1506 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1507}
1508
Kevin May7d96b162021-02-03 17:38:41 +00001509void TfLiteParserImpl::ParseL2Normalization(size_t subgraphIndex, size_t operatorIndex)
Matthew Jackson28c94572019-07-18 10:47:03 +01001510{
1511 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1512
1513 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1514 CHECK_VALID_SIZE(inputs.size(), 1);
1515
1516 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1517 CHECK_VALID_SIZE(outputs.size(), 1);
1518
1519 L2NormalizationDescriptor desc;
1520 desc.m_DataLayout = armnn::DataLayout::NHWC;
James Ward58dec6b2020-09-11 17:32:44 +01001521 auto layerName = fmt::format("L2Normalization:{}:{}", subgraphIndex, operatorIndex);
Matthew Jackson28c94572019-07-18 10:47:03 +01001522 IConnectableLayer* layer = m_Network->AddL2NormalizationLayer(desc, layerName.c_str());
1523
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001524 ARMNN_ASSERT(layer != nullptr);
Matthew Jackson28c94572019-07-18 10:47:03 +01001525
Sadik Armagand109a4d2020-07-28 10:42:13 +01001526 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Matthew Jackson28c94572019-07-18 10:47:03 +01001527 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1528
1529 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1530 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1531
1532 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1533 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1534}
1535
Kevin May7d96b162021-02-03 17:38:41 +00001536void TfLiteParserImpl::ParseMaxPool2D(size_t subgraphIndex, size_t operatorIndex)
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001537{
1538 ParsePool(subgraphIndex, operatorIndex, PoolingAlgorithm::Max);
1539}
1540
Kevin May7d96b162021-02-03 17:38:41 +00001541void TfLiteParserImpl::ParseMaximum(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001542{
1543 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1544
1545 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1546 CHECK_VALID_SIZE(inputs.size(), 2);
1547
1548 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1549 CHECK_VALID_SIZE(outputs.size(), 1);
1550
James Ward58dec6b2020-09-11 17:32:44 +01001551 auto layerName = fmt::format("Maximum:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01001552
1553 TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
1554 TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]);
1555 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001556
Sadik Armagand109a4d2020-07-28 10:42:13 +01001557 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01001558 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1559
1560 IConnectableLayer* layer = m_Network->AddMaximumLayer(layerName.c_str());
1561 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001562 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1563
1564 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01001565 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001566
1567 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1568 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1569}
1570
Kevin May7d96b162021-02-03 17:38:41 +00001571void TfLiteParserImpl::ParseMinimum(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001572{
1573 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1574
1575 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1576 CHECK_VALID_SIZE(inputs.size(), 2);
1577
1578 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1579 CHECK_VALID_SIZE(outputs.size(), 1);
1580
James Ward58dec6b2020-09-11 17:32:44 +01001581 auto layerName = fmt::format("Minimum:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01001582
1583 TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
1584 TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]);
1585 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001586
Sadik Armagand109a4d2020-07-28 10:42:13 +01001587 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01001588 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1589
1590 IConnectableLayer* layer = m_Network->AddMinimumLayer(layerName.c_str());
1591 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001592 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1593
1594 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01001595 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001596
1597 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1598 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1599}
1600
Kevin May7d96b162021-02-03 17:38:41 +00001601void TfLiteParserImpl::ParsePool(size_t subgraphIndex,
1602 size_t operatorIndex,
1603 PoolingAlgorithm algorithm)
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001604{
1605 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1606
1607 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1608 const auto * options = operatorPtr->builtin_options.AsPool2DOptions();
1609
1610 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1611
1612 std::string layerName;
1613
1614 switch (algorithm)
1615 {
1616 case PoolingAlgorithm::Average:
1617 layerName =
James Ward58dec6b2020-09-11 17:32:44 +01001618 fmt::format("AveragePool2D:{}:{}", subgraphIndex, operatorIndex);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001619 break;
1620 case PoolingAlgorithm::Max:
1621 layerName =
James Ward58dec6b2020-09-11 17:32:44 +01001622 fmt::format("MaxPool2D:{}:{}", subgraphIndex, operatorIndex);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001623 break;
1624 default:
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001625 ARMNN_ASSERT_MSG(false, "Unsupported Pooling Algorithm");
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001626 }
1627
1628 Pooling2dDescriptor desc;
1629
1630 desc.m_PoolType = algorithm;
1631 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1632 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1633 desc.m_PoolWidth = CHECKED_NON_NEGATIVE(options->filter_width);
1634 desc.m_PoolHeight = CHECKED_NON_NEGATIVE(options->filter_height);
1635 desc.m_PaddingMethod = PaddingMethod::Exclude;
1636 desc.m_OutputShapeRounding = OutputShapeRounding::Floor;
jimfly01c25411c2018-11-14 17:47:22 +00001637 desc.m_DataLayout = armnn::DataLayout::NHWC;
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001638
1639 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1640 CHECK_VALID_SIZE(inputs.size(), 1);
1641 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
1642
1643 // assuming input is NHWC
1644 unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1645 unsigned int inputWidth = inputTensorInfo.GetShape()[2];
1646
Pablo Tellof0bd6832019-04-26 17:58:13 +01001647 CalcPadding(inputHeight, desc.m_PoolHeight, desc.m_StrideY, 1u,
1648 desc.m_PadTop, desc.m_PadBottom, options->padding);
1649 CalcPadding(inputWidth, desc.m_PoolWidth, desc.m_StrideX, 1u,
1650 desc.m_PadLeft, desc.m_PadRight, options->padding);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001651
1652 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1653 CHECK_VALID_SIZE(outputs.size(), 1);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001654
Sadik Armagand109a4d2020-07-28 10:42:13 +01001655 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01001656 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1657
1658 IConnectableLayer* layer = m_Network->AddPooling2dLayer(desc, layerName.c_str());
1659 ARMNN_ASSERT(layer != nullptr);
jimfly01c25411c2018-11-14 17:47:22 +00001660 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001661
1662 // register the input connection slots for the layer, connections are made after all layers have been created
1663 // only the tensors for the inputs are relevant, exclude the const tensors
1664 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
jimfly01c25411c2018-11-14 17:47:22 +00001665 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001666
jimfly01c25411c2018-11-14 17:47:22 +00001667 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001668 // register the output connection slots for the layer, connections are made after all layers have been created
1669 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1670 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1671}
1672
Kevin May7d96b162021-02-03 17:38:41 +00001673void TfLiteParserImpl::ParseSlice(size_t subgraphIndex, size_t operatorIndex)
josh minorba424d22019-11-13 10:55:17 -06001674{
1675 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1676
1677 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1678 CHECK_VALID_SIZE(inputs.size(), 3);
1679 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1680 CHECK_VALID_SIZE(outputs.size(), 1);
1681
1682 SliceDescriptor desc;
1683
1684 // set begin tensor info for slice descriptor
1685 armnn::TensorInfo beginTensorInfo = ToTensorInfo(inputs[1]);
1686 BufferRawPtr beginBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1687
1688 std::vector<unsigned int> begin(beginTensorInfo.GetNumElements());
1689 ::memcpy(begin.data(), beginBufferPtr->data.data(), beginTensorInfo.GetNumBytes());
1690
1691 // set size tensor info for slice descriptor
1692 armnn::TensorInfo sizeTensorInfo = ToTensorInfo(inputs[2]);
1693 BufferRawPtr sizeBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
1694
Mike Kelly7ba84d62021-09-10 15:27:19 +01001695 std::vector<int> signedSize(sizeTensorInfo.GetNumElements());
1696 ::memcpy(signedSize.data(), sizeBufferPtr->data.data(), sizeTensorInfo.GetNumBytes());
josh minorba424d22019-11-13 10:55:17 -06001697 std::vector<unsigned int> size(sizeTensorInfo.GetNumElements());
Mike Kelly7ba84d62021-09-10 15:27:19 +01001698 TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
1699
1700 for (unsigned int i = 0; i < signedSize.size(); ++i)
1701 {
1702 int signedValue = signedSize[i];
Jim Flynnfca233e2021-09-23 12:16:53 +01001703
Mike Kelly7ba84d62021-09-10 15:27:19 +01001704 if (signedValue < -1 || signedValue > static_cast<int>(inputTensorInfo.GetShape()[i] - begin[i]))
1705 {
1706 throw ParseException(fmt::format("Invalid value for size {} size must be in range "
1707 "[-1, inputDimSize - begin] [-1, {}] inclusive {}",
1708 signedValue,
1709 inputTensorInfo.GetShape()[i] - begin[i],
1710 CHECK_LOCATION().AsString()));
1711 }
1712
1713 if (signedValue == -1)
1714 {
1715 size[i] = inputTensorInfo.GetShape()[i] - begin[i];
1716 }
1717 else
1718 {
1719 size[i] = static_cast<unsigned int>(signedValue);
1720 }
1721 }
1722
josh minorba424d22019-11-13 10:55:17 -06001723 desc = SliceDescriptor(begin, size);
1724
James Ward58dec6b2020-09-11 17:32:44 +01001725 auto layerName = fmt::format("Slice:{}:{}", subgraphIndex, operatorIndex);
josh minorba424d22019-11-13 10:55:17 -06001726
Sadik Armagand109a4d2020-07-28 10:42:13 +01001727 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01001728 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1729
1730 IConnectableLayer* const layer = m_Network->AddSliceLayer(desc, layerName.c_str());
josh minorba424d22019-11-13 10:55:17 -06001731 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1732
1733 // register the input connection slots for the layer, connections are made after all layers have been created
1734 // only the tensors for the inputs are relevant, exclude the const tensors
1735 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1736 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1737
1738 // register the output connection slots for the layer, connections are made after all layers have been created
1739 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1740 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1741}
1742
Kevin May7d96b162021-02-03 17:38:41 +00001743void TfLiteParserImpl::ParseSoftmax(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001744{
1745 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1746 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1747 const auto * options = operatorPtr->builtin_options.AsSoftmaxOptions();
1748
1749 SoftmaxDescriptor desc;
1750 desc.m_Beta = options->beta;
1751
1752 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1753 CHECK_VALID_SIZE(inputs.size(), 1);
1754 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1755 CHECK_VALID_SIZE(outputs.size(), 1);
1756
James Ward58dec6b2020-09-11 17:32:44 +01001757 auto layerName = fmt::format("Softmax:{}:{}", subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001758 IConnectableLayer* const layer = m_Network->AddSoftmaxLayer(desc, layerName.c_str());
1759
Sadik Armagand109a4d2020-07-28 10:42:13 +01001760 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
telsoa01c577f2c2018-08-31 09:22:23 +01001761 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1762
1763 // register the input connection slots for the layer, connections are made after all layers have been created
1764 // only the tensors for the inputs are relevant, exclude the const tensors
1765 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1766 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1767
1768 // register the output connection slots for the layer, connections are made after all layers have been created
1769 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1770 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1771}
1772
Kevin May7d96b162021-02-03 17:38:41 +00001773void TfLiteParserImpl::ParseSpaceToBatchND(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesbaded142019-02-08 19:02:48 -02001774{
1775 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1776
1777 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1778 CHECK_VALID_SIZE(inputs.size(), 3);
1779
1780 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1781 CHECK_VALID_SIZE(outputs.size(), 1);
1782
1783 armnn::TensorInfo blockShapeTensorInfo = ToTensorInfo(inputs[1]);
1784 BufferRawPtr blockShapeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1785
1786 armnn::TensorInfo padListTensorInfo = ToTensorInfo(inputs[2]);
1787 BufferRawPtr padListBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
1788
1789 std::vector<unsigned int> blockShape(blockShapeTensorInfo.GetNumElements());
1790 ::memcpy(blockShape.data(), blockShapeBufferPtr->data.data(), blockShapeTensorInfo.GetNumBytes());
1791
1792 std::vector<unsigned int> padListVector(padListTensorInfo.GetNumElements());
1793 ::memcpy(padListVector.data(), padListBufferPtr->data.data(), padListTensorInfo.GetNumBytes());
1794
1795 size_t step = 2;
1796 std::vector<std::pair<unsigned int, unsigned int>> padList;
1797 for (unsigned int i = 0; i < padListTensorInfo.GetNumElements() / step; ++i)
1798 {
1799 padList.emplace_back(padListVector[i * step], padListVector[i * step + 1]);
1800 }
1801
1802 armnn::SpaceToBatchNdDescriptor desc;
1803 desc.m_BlockShape = blockShape;
1804 desc.m_PadList = padList;
1805 desc.m_DataLayout = armnn::DataLayout::NHWC;
1806
James Ward58dec6b2020-09-11 17:32:44 +01001807 auto layerName = fmt::format("SpaceToBatchND:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesbaded142019-02-08 19:02:48 -02001808
James Conroy05102392020-06-24 15:39:55 +01001809 TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
Sadik Armagand109a4d2020-07-28 10:42:13 +01001810 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01001811 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1812
1813 IConnectableLayer* layer = m_Network->AddSpaceToBatchNdLayer(desc, layerName.c_str());
1814 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesbaded142019-02-08 19:02:48 -02001815 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1816
1817 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1818 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1819
1820 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1821 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1822}
1823
Teresa Charlin3ab85482021-06-08 16:59:29 +01001824armnn::TensorInfo TfLiteParserImpl::OutputShapeOfSqueeze(std::vector<uint32_t> squeezeDims,
Kevin May7d96b162021-02-03 17:38:41 +00001825 const armnn::TensorInfo & inputTensorInfo)
telsoa01c577f2c2018-08-31 09:22:23 +01001826{
Teresa Charlin3ab85482021-06-08 16:59:29 +01001827 CHECK_VALID_SIZE(squeezeDims.size(), 0, 1, 2, 3, 4);
telsoa01c577f2c2018-08-31 09:22:23 +01001828 static const uint32_t dimensionSequence[] = { 0, 1, 2, 3 };
1829
1830 if (inputTensorInfo.GetNumDimensions() > 4)
1831 {
1832 std::stringstream ss;
1833 ss << "Input tensor has unexpected number of dimensions:" << inputTensorInfo.GetNumDimensions()
1834 << " shape:" << inputTensorInfo.GetShape() << " "
1835 << CHECK_LOCATION().AsString();
1836 throw ParseException(ss.str());
1837 }
1838
1839 if (squeezeDims.empty())
1840 {
1841 squeezeDims.assign(dimensionSequence,
1842 dimensionSequence+inputTensorInfo.GetNumDimensions());
1843 }
1844
1845 std::vector<uint32_t> outputDims;
1846 for(unsigned int i = 0; i < inputTensorInfo.GetNumDimensions(); i++)
1847 {
1848 bool skipSqueeze = (std::find(squeezeDims.begin(), squeezeDims.end(), i) == squeezeDims.end());
1849 auto currentDimension = inputTensorInfo.GetShape()[i];
1850 if (skipSqueeze || currentDimension != 1)
1851 {
1852 outputDims.push_back(currentDimension);
1853 }
1854 }
1855
1856 if (outputDims.size() > 4)
1857 {
1858 std::stringstream ss;
1859 ss << "Output tensor has unexpected number of dimensions:" << inputTensorInfo.GetNumDimensions()
1860 << " shape:" << inputTensorInfo.GetShape() << " "
1861 << CHECK_LOCATION().AsString();
1862 throw ParseException(ss.str());
1863 }
1864
1865 TensorShape outShape = TensorShape(static_cast<unsigned int>(outputDims.size()),
1866 outputDims.data());
1867
1868 // we need to preserve the tensor type and the quantization data as well
1869 TensorInfo outTensorInfo = inputTensorInfo;
1870 outTensorInfo.SetShape(outShape);
1871
1872 return outTensorInfo;
1873}
1874
Keith Davis0176fd82021-06-01 17:36:32 +01001875void TfLiteParserImpl::ParseShape(size_t subgraphIndex, size_t operatorIndex)
1876{
1877 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1878
1879 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1880 CHECK_VALID_SIZE(inputs.size(), 1);
1881 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1882 CHECK_VALID_SIZE(outputs.size(), 1);
1883
1884 auto layerName = fmt::format("Shape:{}:{}", subgraphIndex, operatorIndex);
1885
1886 IConnectableLayer* layer = m_Network->AddShapeLayer(layerName.c_str());
1887 ARMNN_ASSERT(layer != nullptr);
1888
1889
1890 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1891 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1892
1893 // Check if output tensor type is Signed32 or Signed64
1894 if (outputTensorInfo.GetDataType() != armnn::DataType::Signed32 &&
1895 outputTensorInfo.GetDataType() != armnn::DataType::Signed64)
1896 {
1897 throw ParseException(
1898 fmt::format(
1899 "Output tensor data type is not supported. (Supported types: Signed32 & Signed64) {}",
1900 CHECK_LOCATION().AsString()));
1901 }
1902
1903 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1904 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1905
1906 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1907 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
1908}
1909
Kevin May7d96b162021-02-03 17:38:41 +00001910void TfLiteParserImpl::ParseSqueeze(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001911{
1912 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1913
1914 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1915 CHECK_VALID_SIZE(inputs.size(), 1);
1916
1917 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1918 CHECK_VALID_SIZE(outputs.size(), 1);
1919
1920 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1921 const auto * options = operatorPtr->builtin_options.AsSqueezeOptions();
James Ward58dec6b2020-09-11 17:32:44 +01001922 auto layerName = fmt::format("Squeeze:{}:{}", subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001923
1924 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
Teresa Charlin3ab85482021-06-08 16:59:29 +01001925
1926 std::vector<uint32_t> squeezeDim;
1927 // A single negative dim index is interpreted as a negative index in python
1928 // Meaning the index will be the shape size plus the negative index value
1929 if (options->squeeze_dims.size() == 1 && options->squeeze_dims[0] < 0)
1930 {
1931 int32_t dim = static_cast<int32_t>(inputTensorInfo.GetShape().GetNumDimensions()) + options->squeeze_dims[0];
1932 squeezeDim.push_back(static_cast<uint32_t>(dim));
1933 }
1934 else
1935 {
1936 squeezeDim = AsUnsignedVector(options->squeeze_dims);
1937 }
1938
1939 armnn::TensorInfo outputTensorInfo = TfLiteParserImpl::OutputShapeOfSqueeze(squeezeDim, inputTensorInfo);
1940
James Conroy05102392020-06-24 15:39:55 +01001941 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
telsoa01c577f2c2018-08-31 09:22:23 +01001942
1943 ReshapeDescriptor reshapeDesc;
1944 reshapeDesc.m_TargetShape = outputTensorInfo.GetShape();
1945
telsoa01c577f2c2018-08-31 09:22:23 +01001946 IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01001947 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01001948 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1949
1950 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1951 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1952
1953 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1954 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1955}
1956
Kevin May7d96b162021-02-03 17:38:41 +00001957void TfLiteParserImpl::ParseStridedSlice(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves451d95b2019-02-12 22:59:22 -02001958{
1959 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1960
1961 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1962 CHECK_VALID_SIZE(inputs.size(), 4);
1963
1964 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1965 CHECK_VALID_SIZE(outputs.size(), 1);
1966
1967 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1968 const auto * options = operatorPtr->builtin_options.AsStridedSliceOptions();
1969
1970 StridedSliceDescriptor desc;
1971 desc.m_BeginMask = options->begin_mask;
1972 desc.m_EllipsisMask = options->ellipsis_mask;
1973 desc.m_EndMask = options->end_mask;
1974 desc.m_NewAxisMask = options->new_axis_mask;
1975 desc.m_ShrinkAxisMask = options->shrink_axis_mask;
1976 desc.m_DataLayout = armnn::DataLayout::NHWC;
1977
1978 armnn::TensorInfo beginTensorInfo = ToTensorInfo(inputs[1]);
1979 BufferRawPtr beginBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1980
1981 std::vector<int> begin(beginTensorInfo.GetNumElements());
1982 ::memcpy(begin.data(), beginBufferPtr->data.data(), beginTensorInfo.GetNumBytes());
1983
1984 armnn::TensorInfo endTensorInfo = ToTensorInfo(inputs[2]);
1985 BufferRawPtr endBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
1986
1987 std::vector<int> end(endTensorInfo.GetNumElements());
1988 ::memcpy(end.data(), endBufferPtr->data.data(), endTensorInfo.GetNumBytes());
1989
1990 armnn::TensorInfo strideTensorInfo = ToTensorInfo(inputs[3]);
1991 BufferRawPtr strideBufferPtr = GetBuffer(m_Model, inputs[3]->buffer);
1992
1993 std::vector<int> stride(strideTensorInfo.GetNumElements());
1994 ::memcpy(stride.data(), strideBufferPtr->data.data(), strideTensorInfo.GetNumBytes());
1995
1996 desc.m_Begin = begin;
1997 desc.m_End = end;
1998 desc.m_Stride = stride;
1999
James Ward58dec6b2020-09-11 17:32:44 +01002000 auto layerName = fmt::format("StridedSlice:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002001 IConnectableLayer* layer = m_Network->AddStridedSliceLayer(desc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002002 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002003
Sadik Armagand109a4d2020-07-28 10:42:13 +01002004 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02002005 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2006
2007 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2008 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2009
2010 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2011 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2012}
2013
Kevin May7d96b162021-02-03 17:38:41 +00002014void TfLiteParserImpl::ParseSub(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002015{
2016 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2017
2018 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2019 const auto * options = operatorPtr->builtin_options.AsSubOptions();
2020
2021 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2022 CHECK_VALID_SIZE(inputs.size(), 2);
2023
2024 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2025 CHECK_VALID_SIZE(outputs.size(), 1);
2026
2027 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
2028 armnn::TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]);
2029
James Ward58dec6b2020-09-11 17:32:44 +01002030 auto layerName = fmt::format("Sub:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002031 IConnectableLayer* layer = m_Network->AddSubtractionLayer(layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002032 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002033
Sadik Armagand109a4d2020-07-28 10:42:13 +01002034 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002035 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2036
2037 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002038 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02002039
2040 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2041
2042 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2043 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2044}
2045
Kevin May7d96b162021-02-03 17:38:41 +00002046void TfLiteParserImpl::ParseDiv(size_t subgraphIndex, size_t operatorIndex)
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302047{
2048 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2049
2050 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2051 const auto * options = operatorPtr->builtin_options.AsDivOptions();
2052
2053 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2054 CHECK_VALID_SIZE(inputs.size(), 2);
2055
2056 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2057 CHECK_VALID_SIZE(outputs.size(), 1);
2058
2059 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
2060 armnn::TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]);
2061
James Ward58dec6b2020-09-11 17:32:44 +01002062 auto layerName = fmt::format("Div:{}:{}", subgraphIndex, operatorIndex);
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302063 IConnectableLayer* layer = m_Network->AddDivisionLayer(layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002064 ARMNN_ASSERT(layer != nullptr);
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302065
Sadik Armagand109a4d2020-07-28 10:42:13 +01002066 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302067 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2068
2069 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002070 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Darshan Patel42b3d7d2020-05-25 22:30:07 +05302071 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2072
2073 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2074 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2075}
2076
Kevin May7d96b162021-02-03 17:38:41 +00002077void TfLiteParserImpl::ParseAdd(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002078{
2079 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2080
2081 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2082 const auto * options = operatorPtr->builtin_options.AsAddOptions();
2083
2084 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2085 CHECK_VALID_SIZE(inputs.size(), 2);
2086
2087 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2088 CHECK_VALID_SIZE(outputs.size(), 1);
2089
Bruno Goncalves9c761a62018-12-27 14:20:35 -02002090 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
2091 armnn::TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]);
2092
James Ward58dec6b2020-09-11 17:32:44 +01002093 auto layerName = fmt::format("Add:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002094 IConnectableLayer* layer = m_Network->AddAdditionLayer(layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002095 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002096
Sadik Armagand109a4d2020-07-28 10:42:13 +01002097 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002098 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2099
2100 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002101 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02002102 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2103
2104 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2105 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2106}
2107
Kevin May7d96b162021-02-03 17:38:41 +00002108void TfLiteParserImpl::ParseMul(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002109{
2110 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2111
2112 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2113 const auto * options = operatorPtr->builtin_options.AsMulOptions();
2114
2115 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2116 CHECK_VALID_SIZE(inputs.size(), 2);
2117
2118 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2119 CHECK_VALID_SIZE(outputs.size(), 1);
2120
Bruno Goncalves9c761a62018-12-27 14:20:35 -02002121 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
2122 armnn::TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]);
2123
James Ward58dec6b2020-09-11 17:32:44 +01002124 auto layerName = fmt::format("Mul:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002125 IConnectableLayer* layer = m_Network->AddMultiplicationLayer(layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002126 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002127
Sadik Armagand109a4d2020-07-28 10:42:13 +01002128 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002129 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2130
2131 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01002132 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalvesf803f782018-12-18 13:40:30 -02002133 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
2134
2135 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2136 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2137}
2138
Kevin May7d96b162021-02-03 17:38:41 +00002139void TfLiteParserImpl::ParseMean(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002140{
2141 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2142
2143 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2144
2145 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2146 CHECK_VALID_SIZE(outputs.size(), 1);
2147
2148 armnn::TensorInfo dimTensorInfo = ToTensorInfo(inputs[1]);
2149 BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2150
2151 armnn::MeanDescriptor desc;
2152 std::vector<unsigned int> axis(dimTensorInfo.GetNumElements());
2153 ::memcpy(axis.data(), bufferPtr->data.data(), dimTensorInfo.GetNumBytes());
2154 desc.m_Axis = axis;
2155
2156 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
Sadik Armagand109a4d2020-07-28 10:42:13 +01002157 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002158
2159 desc.m_KeepDims =
2160 inputTensorInfo.GetNumDimensions() == outputTensorInfo.GetNumDimensions() ?
2161 true : false;
2162
James Ward58dec6b2020-09-11 17:32:44 +01002163 auto layerName = fmt::format("Mean:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002164 IConnectableLayer* layer = m_Network->AddMeanLayer(desc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002165 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02002166
2167 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2168
2169 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2170 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2171
2172 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2173 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2174}
2175
Kevin May7d96b162021-02-03 17:38:41 +00002176void TfLiteParserImpl::ParsePad(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002177{
2178 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2179
Kevin May7d96b162021-02-03 17:38:41 +00002180 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002181
Kevin May7d96b162021-02-03 17:38:41 +00002182 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002183 CHECK_VALID_SIZE(outputs.size(), 1);
2184
Narumol Prangnawarat8719d222020-11-27 16:57:56 +00002185 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
2186
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002187 armnn::TensorInfo padTensorInfo = ToTensorInfo(inputs[1]);
2188 BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2189
2190 std::vector<unsigned int> padBuffer(padTensorInfo.GetNumElements());
2191 ::memcpy(padBuffer.data(), bufferPtr->data.data(), padTensorInfo.GetNumBytes());
2192
2193 size_t step = 2;
2194 armnn::PadDescriptor desc;
Narumol Prangnawarat8719d222020-11-27 16:57:56 +00002195 if (inputTensorInfo.IsQuantized())
2196 {
2197 desc.m_PadValue = static_cast<float>(inputTensorInfo.GetQuantizationOffset());
2198 }
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002199 for (unsigned int i = 0; i < padTensorInfo.GetNumElements() / step; ++i)
2200 {
2201 desc.m_PadList.emplace_back(padBuffer[i * step], padBuffer[i * step + 1]);
2202 }
2203
James Ward58dec6b2020-09-11 17:32:44 +01002204 auto layerName = fmt::format("Pad:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagand109a4d2020-07-28 10:42:13 +01002205 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01002206
2207 IConnectableLayer* layer = m_Network->AddPadLayer(desc, layerName.c_str());
2208 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02002209 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2210
2211 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2212 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2213
2214 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2215 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2216}
2217
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +01002218void TfLiteParserImpl::ParseMirrorPad(size_t subgraphIndex, size_t operatorIndex)
2219{
2220 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2221
2222 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2223 CHECK_VALID_SIZE(inputs.size(), 2);
2224
2225 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2226 CHECK_VALID_SIZE(outputs.size(), 1);
2227
2228 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
2229
2230 armnn::TensorInfo padTensorInfo = ToTensorInfo(inputs[1]);
2231 BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2232
2233 std::vector<unsigned int> padBuffer(padTensorInfo.GetNumElements());
2234 ::memcpy(padBuffer.data(), bufferPtr->data.data(), padTensorInfo.GetNumBytes());
2235
2236 size_t step = 2;
2237 armnn::PadDescriptor desc;
2238 for (unsigned int i = 0; i < padTensorInfo.GetNumElements() / step; ++i)
2239 {
2240 desc.m_PadList.emplace_back(padBuffer[i * step], padBuffer[i * step + 1]);
2241 }
2242
2243 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2244 const auto* options = operatorPtr->builtin_options.AsMirrorPadOptions();
2245
2246 if (options->mode == tflite::MirrorPadMode_REFLECT)
2247 {
2248 desc.m_PaddingMode = PaddingMode::Reflect;
2249 }
2250 else if (options->mode == tflite::MirrorPadMode_SYMMETRIC)
2251 {
2252 desc.m_PaddingMode = PaddingMode::Symmetric;
2253 }
2254 else
2255 {
2256 ARMNN_THROW_PARSE_EXCEPTION("PaddingMode must be either REFLECT or SYMMETRIC");
2257 }
2258
2259 // If padding mode is Reflect then both paddings must be no greater than inputShape(i) - 1.
2260 // If padding mode is Symmetric then both paddings must be no greater than inputShape(i).
2261 auto inputShape = inputTensorInfo.GetShape();
2262 auto padList = desc.m_PadList;
2263
2264 const unsigned int isReflect = static_cast<unsigned int>(desc.m_PaddingMode == PaddingMode::Reflect);
2265 for(unsigned int i = 0; i < padList.size(); ++i)
2266 {
2267 if(padList.at(i).first > (inputShape[i] - isReflect) ||
2268 padList.at(i).second > (inputShape[i] - isReflect))
2269 {
2270 ARMNN_THROW_PARSE_EXCEPTION("Padding values must be less (Reflect) or "
2271 "equal (Symmetric) to the dimension size.");
2272 }
2273 }
2274
2275 auto layerName = fmt::format("MirrorPad:{}:{}", subgraphIndex, operatorIndex);
2276 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
2277
2278 IConnectableLayer* layer = m_Network->AddPadLayer(desc, layerName.c_str());
2279 ARMNN_ASSERT(layer != nullptr);
2280 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2281
2282 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2283 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2284
2285 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2286 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2287}
2288
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002289void TfLiteParserImpl::ParsePrelu(size_t subgraphIndex, size_t operatorIndex)
2290{
2291 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2292
2293 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2294 CHECK_VALID_SIZE(inputs.size(), 2);
2295
2296 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2297 CHECK_VALID_SIZE(outputs.size(), 1);
2298
2299 auto layerName = fmt::format("Prelu:{}:{}", subgraphIndex, operatorIndex);
2300
2301 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
2302 armnn::TensorInfo alphaTensorInfo = ToTensorInfo(inputs[1]);
2303 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
2304 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
2305
2306 IConnectableLayer* layer = m_Network->AddPreluLayer(layerName.c_str());
2307 ARMNN_ASSERT(layer != nullptr);
2308 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2309
2310 if (IsConstTensor(inputs[1]))
2311 {
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002312 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawaratbf99b5f2021-05-27 09:55:43 +01002313 armnn::IInputSlot* slot = &(layer->GetInputSlot(0));
2314 RegisterConsumerOfTensor(subgraphIndex, inputTensorIndexes[0], slot);
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01002315
2316 auto alphaTensorAndData = CreateConstTensorNonPermuted(inputs[1], alphaTensorInfo);
2317 std::string constLayerName = fmt::format("Constant:{}", inputs[1]->name);
2318 IConnectableLayer* constLayer =
2319 m_Network->AddConstantLayer(alphaTensorAndData, constLayerName.c_str());
2320 ARMNN_ASSERT(constLayer != nullptr);
2321
2322 constLayer->GetOutputSlot(0).SetTensorInfo(alphaTensorInfo);
2323 constLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1));
2324 RegisterOutputSlots(subgraphIndex,
2325 VIRTUAL_OPERATOR_ID,
2326 constLayer,
2327 { inputTensorIndexes[1] });
2328 }
2329 else
2330 {
2331 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2332 RegisterInputSlots(subgraphIndex, operatorIndex, layer, inputTensorIndexes);
2333 }
2334
2335 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2336 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2337}
2338
Kevin May7d96b162021-02-03 17:38:41 +00002339void TfLiteParserImpl::ParseQuantize(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan66dedc72019-12-10 16:32:07 +00002340{
2341 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2342
2343 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2344 CHECK_VALID_SIZE(inputs.size(), 1);
2345
2346 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2347 CHECK_VALID_SIZE(outputs.size(), 1);
2348
James Ward58dec6b2020-09-11 17:32:44 +01002349 auto layerName = fmt::format("Quantize:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan66dedc72019-12-10 16:32:07 +00002350
2351 IConnectableLayer* layer = m_Network->AddQuantizeLayer(layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01002352 ARMNN_ASSERT(layer != nullptr);
Sadik Armagan66dedc72019-12-10 16:32:07 +00002353
Sadik Armagand109a4d2020-07-28 10:42:13 +01002354 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Sadik Armagan66dedc72019-12-10 16:32:07 +00002355 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2356
2357 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2358 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2359
2360 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2361 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2362}
Finn Williamsc42c3842019-01-22 14:18:11 +00002363
Kevin May7d96b162021-02-03 17:38:41 +00002364void TfLiteParserImpl::ParseRelu(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan58f39192018-09-17 14:14:39 +01002365{
Finn Williamsc42c3842019-01-22 14:18:11 +00002366 ParseActivation(subgraphIndex,operatorIndex, ActivationFunction::ReLu);
Sadik Armagan58f39192018-09-17 14:14:39 +01002367}
2368
Kevin May7d96b162021-02-03 17:38:41 +00002369void TfLiteParserImpl::ParseRelu6(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan58f39192018-09-17 14:14:39 +01002370{
Finn Williamsc42c3842019-01-22 14:18:11 +00002371 ParseActivation(subgraphIndex,operatorIndex, ActivationFunction::BoundedReLu);
2372}
Sadik Armagan58f39192018-09-17 14:14:39 +01002373
Kevin May7d96b162021-02-03 17:38:41 +00002374void TfLiteParserImpl::ParseLeakyRelu(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan12239e72020-05-27 11:06:17 +01002375{
Jan Eilers2f746b32020-07-28 14:00:06 +01002376 ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::LeakyReLu);
Sadik Armagan12239e72020-05-27 11:06:17 +01002377}
2378
Kevin May7d96b162021-02-03 17:38:41 +00002379void TfLiteParserImpl::ParseLogistic(size_t subgraphIndex, size_t operatorIndex)
Finn Williamsc42c3842019-01-22 14:18:11 +00002380{
2381 ParseActivation(subgraphIndex,operatorIndex,ActivationFunction::Sigmoid);
2382}
2383
Kevin May7d96b162021-02-03 17:38:41 +00002384void TfLiteParserImpl::ParseTanH(size_t subgraphIndex, size_t operatorIndex)
Nina Drozd99851762019-04-09 09:37:38 +01002385{
2386 ParseActivation(subgraphIndex,operatorIndex,ActivationFunction::TanH);
2387}
2388
Kevin May7d96b162021-02-03 17:38:41 +00002389void TfLiteParserImpl::ParseElu(size_t subgraphIndex, size_t operatorIndex)
Matthew Sloyan7515d072020-12-16 12:50:01 +00002390{
2391 ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::Elu);
2392}
2393
Kevin May7d96b162021-02-03 17:38:41 +00002394void TfLiteParserImpl::ParseHardSwish(size_t subgraphIndex, size_t operatorIndex)
Jan Eilers2f746b32020-07-28 14:00:06 +01002395{
2396 ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::HardSwish);
2397}
Finn Williamsc42c3842019-01-22 14:18:11 +00002398
Kevin May7d96b162021-02-03 17:38:41 +00002399void TfLiteParserImpl::ParseActivation(size_t subgraphIndex, size_t operatorIndex, ActivationFunction activationType)
Finn Williamsc42c3842019-01-22 14:18:11 +00002400{
2401 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan58f39192018-09-17 14:14:39 +01002402 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
Jan Eilers8eb25602020-03-09 12:13:48 +00002403 IgnoreUnused(operatorPtr);
Sadik Armagan58f39192018-09-17 14:14:39 +01002404
2405 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2406 CHECK_VALID_SIZE(inputs.size(), 1);
2407
2408 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2409 CHECK_VALID_SIZE(outputs.size(), 1);
2410
James Ward58dec6b2020-09-11 17:32:44 +01002411 auto layerName = fmt::format("Activation:");
Sadik Armagan58f39192018-09-17 14:14:39 +01002412 ActivationDescriptor activationDesc;
Finn Williamsc42c3842019-01-22 14:18:11 +00002413 activationDesc.m_Function = activationType;
2414
2415 switch (activationType)
2416 {
2417 case ActivationFunction::ReLu:
2418 {
James Ward58dec6b2020-09-11 17:32:44 +01002419 layerName += fmt::format("RELU:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsc42c3842019-01-22 14:18:11 +00002420 break;
2421 }
2422 case ActivationFunction::BoundedReLu:
2423 {
James Ward58dec6b2020-09-11 17:32:44 +01002424 layerName += fmt::format("RELU6:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsc42c3842019-01-22 14:18:11 +00002425 activationDesc.m_A = 6.0f;
2426 activationDesc.m_B = 0.0f;
2427 break;
2428 }
2429 case ActivationFunction::Sigmoid:
2430 {
James Ward58dec6b2020-09-11 17:32:44 +01002431 layerName += fmt::format("SIGMOID:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsc42c3842019-01-22 14:18:11 +00002432 break;
2433 }
Nina Drozd99851762019-04-09 09:37:38 +01002434 case ActivationFunction::TanH:
2435 {
James Ward58dec6b2020-09-11 17:32:44 +01002436 layerName += fmt::format("TANH:{}:{}", subgraphIndex, operatorIndex);
Nina Drozd99851762019-04-09 09:37:38 +01002437 activationDesc.m_A = 1.0f;
2438 activationDesc.m_B = 1.0f;
2439 break;
2440 }
Sadik Armagan12239e72020-05-27 11:06:17 +01002441 case ActivationFunction::LeakyReLu:
2442 {
James Ward58dec6b2020-09-11 17:32:44 +01002443 layerName += fmt::format("LEAKYRELU:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan12239e72020-05-27 11:06:17 +01002444 const auto * options = operatorPtr->builtin_options.AsLeakyReluOptions();
2445 activationDesc.m_A = options->alpha;
2446 break;
2447 }
Matthew Sloyan7515d072020-12-16 12:50:01 +00002448 case ActivationFunction::Elu:
2449 {
2450 layerName += fmt::format("ELU:{}:{}", subgraphIndex, operatorIndex);
2451 activationDesc.m_A = 1.0f;
2452 break;
2453 }
Jan Eilers2f746b32020-07-28 14:00:06 +01002454 case ActivationFunction::HardSwish:
Matthew Sloyan7515d072020-12-16 12:50:01 +00002455 {
James Ward58dec6b2020-09-11 17:32:44 +01002456 layerName += fmt::format("HARDSWISH:{}:{}", subgraphIndex, operatorIndex);
Jan Eilers2f746b32020-07-28 14:00:06 +01002457 break;
Matthew Sloyan7515d072020-12-16 12:50:01 +00002458 }
Finn Williamsc42c3842019-01-22 14:18:11 +00002459 default:
2460 {
2461 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01002462 fmt::format("Unexpected ActivationFunction[{}] when creating layerName {} ",
2463 static_cast<int>(activationType), CHECK_LOCATION().AsString()));
Finn Williamsc42c3842019-01-22 14:18:11 +00002464 }
2465 }
2466
2467 IConnectableLayer* const layer = m_Network->AddActivationLayer(activationDesc, layerName.c_str());
Sadik Armagan58f39192018-09-17 14:14:39 +01002468
Sadik Armagand109a4d2020-07-28 10:42:13 +01002469 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Sadik Armagan58f39192018-09-17 14:14:39 +01002470 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2471
2472 // register the input connection slots for the layer, connections are made after all layers have been created
2473 // only the tensors for the inputs are relevant, exclude the const tensors
2474 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2475 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2476
2477 // register the output connection slots for the layer, connections are made after all layers have been created
2478 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2479 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2480}
Kevin May7d96b162021-02-03 17:38:41 +00002481armnn::TensorInfo TfLiteParserImpl::OutputShapeOfReshape(const armnn::TensorInfo & inputTensorInfo,
2482 const std::vector<int32_t> & targetDimsIn)
Sadikb94967b2018-09-19 15:30:00 +01002483{
2484 std::vector<unsigned int> outputDims(targetDimsIn.begin(), targetDimsIn.end());
2485 const auto stretchDim = std::find(targetDimsIn.begin(), targetDimsIn.end(), -1);
2486
2487 if (stretchDim != targetDimsIn.end())
2488 {
2489 if (std::find(std::next(stretchDim), targetDimsIn.end(), -1) != targetDimsIn.end())
2490 {
2491 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01002492 fmt::format("At most one component of shape can be -1 {}", CHECK_LOCATION().AsString()));
Sadikb94967b2018-09-19 15:30:00 +01002493 }
2494
2495 auto targetNumElements =
Matthew Sloyan589e3e82020-09-11 16:17:48 +01002496 armnn::numeric_cast<unsigned int>(
Sadikb94967b2018-09-19 15:30:00 +01002497 std::accumulate(targetDimsIn.begin(), targetDimsIn.end(), -1, std::multiplies<int32_t>()));
2498
2499 auto stretchIndex = static_cast<size_t>(std::distance(targetDimsIn.begin(), stretchDim));
2500 outputDims[stretchIndex] = inputTensorInfo.GetNumElements() / targetNumElements;
2501 }
2502
2503 TensorShape outputShape = TensorShape(static_cast<unsigned int>(outputDims.size()), outputDims.data());
2504
2505 TensorInfo reshapeInfo = inputTensorInfo;
2506 reshapeInfo.SetShape(outputShape);
2507
2508 return reshapeInfo;
2509}
2510
Kevin May7d96b162021-02-03 17:38:41 +00002511void TfLiteParserImpl::ParseReshape(size_t subgraphIndex, size_t operatorIndex)
Sadikb94967b2018-09-19 15:30:00 +01002512{
2513 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2514
2515 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Sadikb94967b2018-09-19 15:30:00 +01002516
2517 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2518 CHECK_VALID_SIZE(outputs.size(), 1);
2519
2520 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2521 const auto * options = operatorPtr->builtin_options.AsReshapeOptions();
James Ward58dec6b2020-09-11 17:32:44 +01002522 auto layerName = fmt::format("Reshape:{}:{}", subgraphIndex, operatorIndex);
Sadikb94967b2018-09-19 15:30:00 +01002523
2524 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
kevmay0171972a82018-12-17 14:28:03 +00002525 armnn::TensorInfo actualOutputTensorInfo = ToTensorInfo(outputs[0]);
James Conroy05102392020-06-24 15:39:55 +01002526 CheckMatchingQuantization(inputTensorInfo, actualOutputTensorInfo, layerName, "Input 0", "Output 0");
Derek Lambertic9e52792020-03-11 11:42:26 +00002527
Jan Eilersbac9b352020-07-13 13:40:24 +01002528 // Extracting new shape for the output
2529 // There are two ways it can be passed
2530 // * First is to define the target shape in the operator built-in options
2531 // * Second is to pass it as a second input tensor
Derek Lambertic9e52792020-03-11 11:42:26 +00002532 std::vector<int32_t> targetShape;
Jan Eilersbac9b352020-07-13 13:40:24 +01002533 bool targetShapeFound = false;
2534 // Check if built-in options were given
2535 if (options != nullptr)
Derek Lambertic9e52792020-03-11 11:42:26 +00002536 {
Jan Eilersbac9b352020-07-13 13:40:24 +01002537 // make sure the parameter is given
2538 if (options->new_shape.empty() == false)
Derek Lambertic9e52792020-03-11 11:42:26 +00002539 {
Jan Eilersbac9b352020-07-13 13:40:24 +01002540 targetShape = options->new_shape;
2541 targetShapeFound = true;
Derek Lambertif4a953f2020-03-17 14:25:57 +00002542 }
Derek Lambertic9e52792020-03-11 11:42:26 +00002543 }
Jan Eilersbac9b352020-07-13 13:40:24 +01002544
2545 // If there is no built-in option given or if the built-in new_shape parameter was empty
2546 if (!targetShapeFound)
Derek Lambertic9e52792020-03-11 11:42:26 +00002547 {
Teresa Charlin6a056a42021-12-01 10:25:43 +00002548 // Check for a second input tensor
2549 if (inputs.size() > 1 && inputs[1] != nullptr)
Jan Eilersbac9b352020-07-13 13:40:24 +01002550 {
2551 if (inputs[1]->is_variable)
2552 {
2553 ARMNN_THROW_PARSE_EXCEPTION( "Target shapes defined in non-const input tensors is not supported");
2554 }
2555
2556 if (inputs[1]->shape.size() != 1)
2557 {
2558 ARMNN_THROW_PARSE_EXCEPTION("Target 'shape' input is not a 1D tensor");
2559 }
2560
2561 if (inputs[1]->type != tflite::TensorType_INT32)
2562 {
2563 ARMNN_THROW_PARSE_EXCEPTION("Target 'shape' input is not an int32 type");
2564 }
2565
Teresa Charlin6a056a42021-12-01 10:25:43 +00002566 // Extract target shape from input
2567 auto bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2568 auto values = reinterpret_cast<const int32_t*>(bufferPtr->data.data());
2569 if (!values)
Sadik Armagan19a1c032021-01-20 12:17:00 +00002570 {
Teresa Charlin6a056a42021-12-01 10:25:43 +00002571 ARMNN_THROW_PARSE_EXCEPTION("Reshape operator target shape input buffer data is null");
Sadik Armagan19a1c032021-01-20 12:17:00 +00002572 }
Teresa Charlin6a056a42021-12-01 10:25:43 +00002573 for (int i=0; i < inputs[1]->shape[0]; ++i)
Jan Eilersbac9b352020-07-13 13:40:24 +01002574 {
Teresa Charlin6a056a42021-12-01 10:25:43 +00002575 targetShape.push_back(values[i]);
Jan Eilersbac9b352020-07-13 13:40:24 +01002576 }
2577 }
2578 else
Derek Lambertic9e52792020-03-11 11:42:26 +00002579 {
2580 ARMNN_THROW_PARSE_EXCEPTION("Target shape not defined in reshape parameters or input tensor. "
2581 "At least one method required");
2582 }
Derek Lambertic9e52792020-03-11 11:42:26 +00002583 }
2584
kevmay0171972a82018-12-17 14:28:03 +00002585 armnn::TensorInfo reshapeOutputTensorInfo =
Kevin May7d96b162021-02-03 17:38:41 +00002586 TfLiteParserImpl::OutputShapeOfReshape(inputTensorInfo, targetShape);
Sadikb94967b2018-09-19 15:30:00 +01002587
kevmay0171972a82018-12-17 14:28:03 +00002588 // Check for valid input size and that reshape parameters equal output shape
Aron Virginas-Tar70672f62019-01-23 14:00:00 +00002589 const armnn::TensorShape& reshapeOutputTensorShape = reshapeOutputTensorInfo.GetShape();
2590 if (inputs.size() > 1 && !CheckShape(reshapeOutputTensorShape, outputs[0]->shape))
kevmay0171972a82018-12-17 14:28:03 +00002591 {
2592 std::stringstream ss;
2593 ss << "New shape defined in reshape parameters "
Aron Virginas-Tar70672f62019-01-23 14:00:00 +00002594 << reshapeOutputTensorShape
kevmay0171972a82018-12-17 14:28:03 +00002595 << " does not equal output shape "
2596 << actualOutputTensorInfo.GetShape()
2597 << ": "
2598 << CHECK_LOCATION().AsString();
2599 throw ParseException(ss.str());
2600 }
2601
Sadikb94967b2018-09-19 15:30:00 +01002602 ReshapeDescriptor reshapeDesc;
kevmay0171972a82018-12-17 14:28:03 +00002603 reshapeDesc.m_TargetShape = reshapeOutputTensorInfo.GetShape();
Sadikb94967b2018-09-19 15:30:00 +01002604
Sadikb94967b2018-09-19 15:30:00 +01002605 IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002606 ARMNN_ASSERT(layer != nullptr);
kevmay0171972a82018-12-17 14:28:03 +00002607 layer->GetOutputSlot(0).SetTensorInfo(reshapeOutputTensorInfo);
Sadikb94967b2018-09-19 15:30:00 +01002608
2609 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2610 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2611
2612 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2613 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2614}
2615
Kevin May7d96b162021-02-03 17:38:41 +00002616void TfLiteParserImpl::ParseResizeBilinear(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02002617{
Sadik Armagana3b31f02019-12-05 09:08:53 +00002618 ParseResize(subgraphIndex, operatorIndex, ResizeMethod::Bilinear);
2619}
2620
Kevin May7d96b162021-02-03 17:38:41 +00002621void TfLiteParserImpl::ParseResizeNearestNeighbor(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagana3b31f02019-12-05 09:08:53 +00002622{
2623 ParseResize(subgraphIndex, operatorIndex, ResizeMethod::NearestNeighbor);
2624}
2625
Kevin May7d96b162021-02-03 17:38:41 +00002626void TfLiteParserImpl::ParseResize(size_t subgraphIndex, size_t operatorIndex, ResizeMethod resizeMethod)
Sadik Armagana3b31f02019-12-05 09:08:53 +00002627{
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02002628 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2629
2630 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2631 CHECK_VALID_SIZE(inputs.size(), 2);
2632
2633 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2634 CHECK_VALID_SIZE(outputs.size(), 1);
2635
2636 armnn::TensorInfo sizeTensorInfo = ToTensorInfo(inputs[1]);
2637
2638 // Data for the parsed tensor args (size) must be stored locally.
2639 std::vector<int32_t> sizeTensorData(sizeTensorInfo.GetNumElements());
2640
2641 BufferRawPtr sizeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2642 ::memcpy(sizeTensorData.data(), sizeBufferPtr->data.data(), sizeTensorInfo.GetNumBytes());
2643
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01002644 ResizeDescriptor desc;
Sadik Armagana3b31f02019-12-05 09:08:53 +00002645 desc.m_Method = resizeMethod;
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02002646 desc.m_TargetHeight = static_cast<uint32_t> (sizeTensorData[0]);
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01002647 desc.m_TargetWidth = static_cast<uint32_t> (sizeTensorData[1]);
2648 desc.m_DataLayout = armnn::DataLayout::NHWC;
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02002649
James Ward58dec6b2020-09-11 17:32:44 +01002650 auto layerName = fmt::format("Resize:");
Sadik Armagana3b31f02019-12-05 09:08:53 +00002651
2652 switch (resizeMethod)
2653 {
2654 case ResizeMethod::Bilinear:
2655 {
James Ward58dec6b2020-09-11 17:32:44 +01002656 layerName += fmt::format("BILINEAR:{}:{}", subgraphIndex, operatorIndex);
Sang-Hoon Park820eb142020-01-08 10:25:24 +00002657
2658 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2659 const auto * options = operatorPtr->builtin_options.AsResizeBilinearOptions();
2660
David Monahan4a0c9b92020-05-30 09:48:39 +01002661 desc.m_AlignCorners = options->align_corners;
Sadik Armagana3b31f02019-12-05 09:08:53 +00002662 break;
2663 }
2664 case ResizeMethod::NearestNeighbor:
2665 {
James Ward58dec6b2020-09-11 17:32:44 +01002666 layerName += fmt::format("NEARESTNEIGHBOR:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagana3b31f02019-12-05 09:08:53 +00002667 break;
2668 }
2669 default:
2670 {
2671 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01002672 fmt::format("Unexpected ResizeMethod[{}] when creating layerName {} ",
2673 static_cast<int>(resizeMethod), CHECK_LOCATION().AsString()));
Sadik Armagana3b31f02019-12-05 09:08:53 +00002674 }
2675 }
2676
James Conroy05102392020-06-24 15:39:55 +01002677 TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
Sadik Armagand109a4d2020-07-28 10:42:13 +01002678 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01002679 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
2680
2681 IConnectableLayer* layer = m_Network->AddResizeLayer(desc, layerName.c_str());
2682 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02002683 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2684
2685 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2686 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2687
2688 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2689 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2690}
2691
Kevin May7d96b162021-02-03 17:38:41 +00002692void TfLiteParserImpl::ParseConcatenation(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan479045b2018-10-01 11:51:37 +01002693{
2694 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2695
2696 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2697 const auto * options = operatorPtr->builtin_options.AsConcatenationOptions();
2698
2699 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
2700
2701 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2702 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2703 CHECK_VALID_SIZE(outputs.size(), 1);
2704
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00002705 unsigned int numConcatView = static_cast<unsigned int>(inputs.size());
2706 uint32_t inputRank = ToTensorInfo(inputs[0]).GetNumDimensions();
Sadik Armagan479045b2018-10-01 11:51:37 +01002707
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00002708 const unsigned int concatDimInput = static_cast<unsigned int>(
2709 (static_cast<int>(inputRank) + options->axis) % static_cast<int>(inputRank));
Sadik Armagan479045b2018-10-01 11:51:37 +01002710
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00002711 OriginsDescriptor concatDescriptor(static_cast<uint32_t>(numConcatView), inputRank);
2712 concatDescriptor.SetConcatAxis(concatDimInput);
Sadik Armagan479045b2018-10-01 11:51:37 +01002713
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00002714 unsigned int mergeDimOrigin = 0;
Sadik Armagan479045b2018-10-01 11:51:37 +01002715
2716 for (unsigned int viewIndex = 0; viewIndex < numConcatView; ++viewIndex)
2717 {
2718 TensorInfo inputTensorInfo = ToTensorInfo(inputs[viewIndex]);
2719
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00002720 // This set up concatDescriptor view origin
2721 armnnUtils::ProcessConcatInputTensorInfo(
2722 inputTensorInfo, concatDescriptor, concatDimInput, viewIndex, mergeDimOrigin);
Sadik Armagan479045b2018-10-01 11:51:37 +01002723 }
2724
James Ward58dec6b2020-09-11 17:32:44 +01002725 auto layerName = fmt::format("Concatenation:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagand109a4d2020-07-28 10:42:13 +01002726 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01002727
Jim Flynn906f9462019-05-10 13:55:21 +01002728 IConnectableLayer* layer = m_Network->AddConcatLayer(concatDescriptor, layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01002729 ARMNN_ASSERT(layer != nullptr);
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00002730 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
Sadik Armagan479045b2018-10-01 11:51:37 +01002731
James Conroy05102392020-06-24 15:39:55 +01002732 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00002733 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes});
Sadik Armagan479045b2018-10-01 11:51:37 +01002734
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00002735 // add fused activation layer
2736 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
Sadik Armagan479045b2018-10-01 11:51:37 +01002737
Sadik Armagan479045b2018-10-01 11:51:37 +01002738 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2739 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2740}
2741
Kevin May7d96b162021-02-03 17:38:41 +00002742void TfLiteParserImpl::ParseFullyConnected(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan8853c1f2018-10-22 09:04:18 +01002743{
2744 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2745
2746 const auto & operatorRfr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2747 const auto options = operatorRfr->builtin_options.AsFullyConnectedOptions();
2748
2749 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
2750
2751 FullyConnectedDescriptor desc;
2752 desc.m_BiasEnabled = false;
Nattapat Chaimanowongd8eee592018-10-26 10:24:14 +01002753 desc.m_TransposeWeightMatrix = true;
Sadik Armagan8853c1f2018-10-22 09:04:18 +01002754
2755 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2756 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2757 CHECK_VALID_SIZE(outputs.size(), 1);
2758
2759 armnn::TensorInfo filterTensorInfo = ToTensorInfo(inputs[1]);
2760
2761 // Fully Connected Layer accepts two dimensional weights input
2762 int32_t weightsDimension = static_cast<int32_t>(filterTensorInfo.GetNumDimensions());
2763 if (weightsDimension != 2)
2764 {
2765 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01002766 fmt::format("Dimension {} for Fully Connected weights is not supported by Armnn. "
2767 "Node {}",
2768 weightsDimension,
2769 CHECK_LOCATION().AsString()));
Sadik Armagan8853c1f2018-10-22 09:04:18 +01002770 }
2771
Matthew Jackson74bf7da2019-08-16 16:51:42 +01002772 armnn::IConnectableLayer* layer = nullptr;
James Ward58dec6b2020-09-11 17:32:44 +01002773 auto layerName = fmt::format("FullyConnected:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan8853c1f2018-10-22 09:04:18 +01002774
Matthew Sloyan81beae32021-07-13 19:46:11 +01002775 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2776 // Add the first input tensor to the registration list
2777 std::vector<unsigned int> tensorIndexesToRegister = {inputTensorIndexes[0]};
2778 std::vector<unsigned int> ignoreInputWhenRegister = {};
Finn Williamsd4fa5452021-03-01 12:31:41 +00002779
2780 desc.m_ConstantWeights = IsConstTensor(inputs[1]);
2781
Matthew Sloyan81beae32021-07-13 19:46:11 +01002782 // Add the weights input to the registration list, constant layers will be added by SetupConstantLayers if constant.
2783 tensorIndexesToRegister.emplace_back(inputTensorIndexes[1]);
Sadik Armagan8853c1f2018-10-22 09:04:18 +01002784
Finn Williamsd4fa5452021-03-01 12:31:41 +00002785 if (inputs.size() == 3)
2786 {
2787 desc.m_BiasEnabled = true;
Matthew Sloyan81beae32021-07-13 19:46:11 +01002788
2789 // Add the biases input to the registration list, constant layer will be added by SetupConstantLayers.
2790 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
Finn Williamsd4fa5452021-03-01 12:31:41 +00002791 }
2792
Matthew Sloyan81beae32021-07-13 19:46:11 +01002793 // Filters and biases are always passed to fully connected as inputs
2794 layer = m_Network->AddFullyConnectedLayer(desc, layerName.c_str());
Finn Williamsd4fa5452021-03-01 12:31:41 +00002795
2796 ARMNN_ASSERT(layer != nullptr);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01002797 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
2798
Finn Williamsd4fa5452021-03-01 12:31:41 +00002799 unsigned int startingSlotIndex = 0;
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01002800 if (inputTensorInfo.GetNumDimensions() > 2)
2801 {
2802 // Add reshape to flatten to 2D [batch_size, input_size],
2803 // where "input_size" corresponds to the number of inputs to the layer,
2804 // matching the second dimension of weights,
2805 // and "batch_size" is calculated by dividing the number of elements by "input_size".
2806 std::vector<unsigned int> reshapedDimensions(2);
2807 reshapedDimensions[1] = filterTensorInfo.GetShape()[1];
2808 reshapedDimensions[0] = inputTensorInfo.GetNumElements() / reshapedDimensions[1];
2809
2810 if (inputTensorInfo.GetNumElements() % reshapedDimensions[1] != 0)
2811 {
2812 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01002813 fmt::format("Failed to deduce input tensor shape from filter size {} {}",
2814 reshapedDimensions[1],
2815 CHECK_LOCATION().AsString()));
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01002816 }
2817
2818 armnn::TensorInfo reshapedTensorInfo = ToTensorInfo(inputs[0]);
2819 reshapedTensorInfo.SetShape(armnn::TensorShape{ 2, reshapedDimensions.data() });
2820
James Ward58dec6b2020-09-11 17:32:44 +01002821 std::string reshapeLayerName = fmt::format("Reshape_for:{}", layer->GetName());
Finn Williamsd4fa5452021-03-01 12:31:41 +00002822 armnn::ReshapeDescriptor reshapeDescriptor;
2823 reshapeDescriptor.m_TargetShape = reshapedTensorInfo.GetShape();
2824 armnn::IConnectableLayer* reshapeLayer = m_Network->AddReshapeLayer(reshapeDescriptor, layerName.c_str());
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01002825
2826 reshapeLayer->GetOutputSlot(0).SetTensorInfo(reshapedTensorInfo);
2827 reshapeLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
2828
2829 RegisterInputSlots(subgraphIndex, operatorIndex, reshapeLayer, {inputTensorIndexes[0]});
Finn Williamsd4fa5452021-03-01 12:31:41 +00002830 // Fc layer connects to the reshape layer, so we skip the first input slot when registering fc's input slots
2831 tensorIndexesToRegister.erase(tensorIndexesToRegister.begin());
2832 startingSlotIndex = 1;
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01002833 }
Finn Williamsd4fa5452021-03-01 12:31:41 +00002834
2835 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister, startingSlotIndex);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01002836
Sadik Armagand109a4d2020-07-28 10:42:13 +01002837 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Sadik Armagan8853c1f2018-10-22 09:04:18 +01002838 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2839
Sadik Armagan8853c1f2018-10-22 09:04:18 +01002840 // we need to add the activation layer and fortunately we don't need to care about the data layout
2841 armnn::IConnectableLayer* fusedActivationLayer = AddFusedActivationLayer(layer, 0,
2842 options->fused_activation_function);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01002843
Sadik Armagan8853c1f2018-10-22 09:04:18 +01002844 // register the output connection slots for the layer, connections are made after all layers have been created
2845 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2846 RegisterOutputSlots(subgraphIndex, operatorIndex, fusedActivationLayer, {outputTensorIndexes[0]});
2847}
2848
Kevin May7d96b162021-02-03 17:38:41 +00002849void TfLiteParserImpl::ParseDetectionPostProcess(size_t subgraphIndex, size_t operatorIndex)
keidav011b3e2ea2019-02-21 10:07:37 +00002850{
2851 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2852
2853 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2854
2855 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2856 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2857 CHECK_VALID_SIZE(outputs.size(), 4);
2858
2859 // Obtain custom options from flexbuffers
2860 auto custom_options = operatorPtr->custom_options;
2861 const flexbuffers::Map& m = flexbuffers::GetRoot(custom_options.data(), custom_options.size()).AsMap();
2862
2863 // Obtain descriptor information from tf lite
2864 DetectionPostProcessDescriptor desc;
2865 desc.m_MaxDetections = m["max_detections"].AsUInt32();
2866 desc.m_MaxClassesPerDetection = m["max_classes_per_detection"].AsUInt32();
2867 desc.m_NmsScoreThreshold = m["nms_score_threshold"].AsFloat();
2868 desc.m_NmsIouThreshold = m["nms_iou_threshold"].AsFloat();
2869 desc.m_NumClasses = m["num_classes"].AsUInt32();
2870 desc.m_ScaleH = m["h_scale"].AsFloat();
2871 desc.m_ScaleW = m["w_scale"].AsFloat();
2872 desc.m_ScaleX = m["x_scale"].AsFloat();
2873 desc.m_ScaleY = m["y_scale"].AsFloat();
2874
keidav0107d58c72019-02-26 11:57:39 +00002875 if (!(m["use_regular_nms"].IsNull()))
keidav011b3e2ea2019-02-21 10:07:37 +00002876 {
keidav0107d58c72019-02-26 11:57:39 +00002877 desc.m_UseRegularNms = m["use_regular_nms"].AsBool();
keidav011b3e2ea2019-02-21 10:07:37 +00002878 }
2879 if (!(m["detections_per_class"].IsNull()))
2880 {
2881 desc.m_DetectionsPerClass = m["detections_per_class"].AsUInt32();
2882 }
2883
2884 if (desc.m_NmsIouThreshold <= 0.0f || desc.m_NmsIouThreshold > 1.0f)
2885 {
2886 throw InvalidArgumentException("DetectionPostProcessTFLiteParser: Intersection over union threshold "
2887 "must be positive and less than or equal to 1.");
2888 }
2889
2890 armnn::TensorInfo anchorTensorInfo = ToTensorInfo(inputs[2]);
Finn Williamsd4fa5452021-03-01 12:31:41 +00002891 auto anchorTensorAndData = CreateConstTensorNonPermuted(inputs[2], anchorTensorInfo);
keidav011b3e2ea2019-02-21 10:07:37 +00002892
James Ward58dec6b2020-09-11 17:32:44 +01002893 auto layerName = fmt::format("DetectionPostProcess:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsd4fa5452021-03-01 12:31:41 +00002894 IConnectableLayer* layer = m_Network->AddDetectionPostProcessLayer(desc, anchorTensorAndData,
keidav011b3e2ea2019-02-21 10:07:37 +00002895 layerName.c_str());
2896
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01002897 ARMNN_ASSERT(layer != nullptr);
keidav011b3e2ea2019-02-21 10:07:37 +00002898
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00002899 // The model does not specify the output shapes.
2900 // The output shapes are calculated from the max_detection and max_classes_per_detection.
2901 unsigned int numDetectedBox = desc.m_MaxDetections * desc.m_MaxClassesPerDetection;
2902 m_OverridenOutputShapes.push_back({ 1, numDetectedBox, 4 });
2903 m_OverridenOutputShapes.push_back({ 1, numDetectedBox });
2904 m_OverridenOutputShapes.push_back({ 1, numDetectedBox });
2905 m_OverridenOutputShapes.push_back({ 1 });
2906
keidav011b3e2ea2019-02-21 10:07:37 +00002907 for (unsigned int i = 0 ; i < outputs.size() ; ++i)
2908 {
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00002909 armnn::TensorInfo detectionBoxOutputTensorInfo = ToTensorInfo(outputs[i], m_OverridenOutputShapes[i]);
keidav011b3e2ea2019-02-21 10:07:37 +00002910 layer->GetOutputSlot(i).SetTensorInfo(detectionBoxOutputTensorInfo);
2911 }
2912
2913 // Register the input connection slots for the layer, connections are made after all layers have been created
2914 // only the tensors for the inputs are relevant, exclude the const tensors
2915 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2916 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
2917
2918 // Register the output connection slots for the layer, connections are made after all layers have been created
2919 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2920 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0],
2921 outputTensorIndexes[1],
2922 outputTensorIndexes[2],
2923 outputTensorIndexes[3]});
2924}
2925
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01002926/// The TfLite Pack operator is equivalent to the ArmNN Stack operator
Kevin May7d96b162021-02-03 17:38:41 +00002927void TfLiteParserImpl::ParsePack(size_t subgraphIndex, size_t operatorIndex)
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01002928{
2929 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2930
2931 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2932 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2933 CHECK_VALID_SIZE(outputs.size(), 1);
2934
2935 if (inputs.size() < 1)
2936 {
2937 throw ParseException("Pack must have at least one input.");
2938 }
2939
2940 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2941 const auto* options = operatorPtr->builtin_options.AsPackOptions();
2942
2943 StackDescriptor desc;
2944 desc.m_Axis = static_cast<uint32_t>(options->axis);
2945 desc.m_NumInputs = static_cast<uint32_t>(inputs.size());
2946
2947 // Use the tensor shape of the first input as the "correct" input shape in the descriptor
2948 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
2949 desc.m_InputShape = inputTensorInfo.GetShape();
2950
James Ward58dec6b2020-09-11 17:32:44 +01002951 auto layerName = fmt::format("Pack:{}:{}", subgraphIndex, operatorIndex);
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01002952 IConnectableLayer* layer = m_Network->AddStackLayer(desc, layerName.c_str());
2953
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01002954 ARMNN_ASSERT(layer != nullptr);
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01002955
Sadik Armagand109a4d2020-07-28 10:42:13 +01002956 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01002957 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2958
2959 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2960 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes});
2961
2962 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2963 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2964}
2965
Kevin May7d96b162021-02-03 17:38:41 +00002966void TfLiteParserImpl::ParseUnpack(size_t subgraphIndex, size_t operatorIndex)
Nina Drozd200e3802019-04-15 09:47:39 +01002967{
2968 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2969
2970 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2971 const auto * options = operatorPtr->builtin_options.AsUnpackOptions();
2972
2973 // This unpackAxis indicates the axis to unpack
2974 const unsigned int unpackAxis = CHECKED_NON_NEGATIVE(options->axis);
2975
2976 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2977 CHECK_VALID_SIZE(inputs.size(), 1);
2978
2979 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
Narumol Prangnawarat672de572019-04-23 15:28:06 +01002980
2981 if (unpackAxis >= inputTensorInfo.GetNumDimensions())
2982 {
2983 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01002984 fmt::format("The unpack axis: {} cannot be greater than or equal to "
2985 "the number of input dimension {} {}",
2986 unpackAxis,
2987 inputTensorInfo.GetNumDimensions(),
2988 CHECK_LOCATION().AsString()));
Narumol Prangnawarat672de572019-04-23 15:28:06 +01002989 }
2990
Nina Drozd200e3802019-04-15 09:47:39 +01002991 unsigned int unpackNum = CHECKED_NON_NEGATIVE(options->num);
2992 // If num is not defined, automatically infer from the length of the dimension axis.
2993 if(unpackNum == 0)
2994 {
2995 unpackNum = inputTensorInfo.GetShape()[unpackAxis];
2996 }
2997
2998 // If unpack number cannot be inferred and is still zero, throw ParseException.
2999 if(unpackNum == 0)
3000 {
3001 throw ParseException("Number to unpack must greater than zero.");
3002 }
3003
3004 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3005 CHECK_VALID_SIZE(outputs.size(), unpackNum);
3006
3007 auto inputDimSize = inputTensorInfo.GetNumDimensions();
3008 std::vector<unsigned int> unpackDimSizes(inputDimSize);
3009
3010 // Add current input shape to unpackDimSizes
3011 for (unsigned int i = 0; i < inputDimSize; ++i)
3012 {
3013 unpackDimSizes[i] = inputTensorInfo.GetShape()[i];
3014 }
3015
3016 if (unpackDimSizes[unpackAxis] != unpackNum)
3017 {
3018 throw ParseException("Number to unpack must be the same as length of the dimension to "
3019 "unpack along.");
3020 }
3021
3022 unpackDimSizes[unpackAxis] /= unpackNum;
3023
3024 SplitterDescriptor splitDesc(unpackNum, static_cast<unsigned int>(unpackDimSizes.size()));
3025 for (unsigned int j = 0; j < unpackNum; ++j)
3026 {
3027 // Set the size of the views.
3028 for (unsigned int dimIdx = 0; dimIdx < unpackDimSizes.size(); ++dimIdx)
3029 {
3030 splitDesc.SetViewSize(j, dimIdx, unpackDimSizes[dimIdx]);
3031 }
3032 splitDesc.SetViewOriginCoord(j, unpackAxis, unpackDimSizes[unpackAxis] * j);
3033 }
3034
James Ward58dec6b2020-09-11 17:32:44 +01003035 auto layerName = fmt::format("Unpack:{}:{}", subgraphIndex, operatorIndex);
Nina Drozd200e3802019-04-15 09:47:39 +01003036 IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01003037 ARMNN_ASSERT(layer != nullptr);
Nina Drozd200e3802019-04-15 09:47:39 +01003038
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003039 TensorShape splitOutShape = TensorShape(static_cast<unsigned int>(unpackDimSizes.size()),
3040 unpackDimSizes.data());
3041
Nina Drozd200e3802019-04-15 09:47:39 +01003042 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3043 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3044
Finn Williamsb49ed182021-06-29 15:50:08 +01003045 std::vector<unsigned int> reshapeDims;
3046 for (unsigned int axis = 0; axis < splitOutShape.GetNumDimensions(); ++axis)
3047 {
3048 if (axis != unpackAxis)
3049 {
3050 reshapeDims.push_back(splitOutShape[axis]);
3051 }
3052 }
3053
3054 TensorShape reshapeOutputShape(splitOutShape.GetNumDimensions() -1, reshapeDims.data());
3055
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003056 // Create reshape to remove the unpacked dimension for unpack operator of each output from Splitter.
3057 for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
3058 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01003059 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[k], true);
James Ward58dec6b2020-09-11 17:32:44 +01003060 std::string reshapeLayerName = fmt::format("Reshape_for:{}", layer->GetName());
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003061 armnn::ReshapeDescriptor desc;
Finn Williamsb49ed182021-06-29 15:50:08 +01003062 desc.m_TargetShape = reshapeOutputShape;
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003063 armnn::IConnectableLayer* reshapeLayer = m_Network->AddReshapeLayer(desc, layerName.c_str());
3064
Narumol Prangnawarat2c526462019-10-21 14:58:26 +01003065 layer->GetOutputSlot(k).SetTensorInfo(armnn::TensorInfo(splitOutShape,
3066 outputTensorInfo.GetDataType(),
3067 outputTensorInfo.GetQuantizationScale(),
3068 outputTensorInfo.GetQuantizationOffset()));
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003069 layer->GetOutputSlot(k).Connect(reshapeLayer->GetInputSlot(0));
3070
Narumol Prangnawarat2c526462019-10-21 14:58:26 +01003071 reshapeLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
Narumol Prangnawarat672de572019-04-23 15:28:06 +01003072
3073 uint32_t reshapedOutputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[k]);
3074 armnn::IOutputSlot* slot = &(reshapeLayer->GetOutputSlot(0));
3075 RegisterProducerOfTensor(subgraphIndex, reshapedOutputId, slot);
3076 }
Nina Drozd200e3802019-04-15 09:47:39 +01003077}
3078
Kevin May7d96b162021-02-03 17:38:41 +00003079void TfLiteParserImpl::ParseSplit(size_t subgraphIndex, size_t operatorIndex)
Nina Drozd0324f482019-04-08 10:52:10 +01003080{
3081 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3082
3083 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3084 const auto * options = operatorPtr->builtin_options.AsSplitOptions();
3085
3086 const unsigned int numSplits = CHECKED_NON_NEGATIVE(options->num_splits);
3087
Nina Drozd200e3802019-04-15 09:47:39 +01003088 // If number of splits cannot be inferred and is zero, throw ParseException.
3089 if(numSplits == 0)
3090 {
3091 throw ParseException("Number to splits must greater than zero.");
3092 }
3093
Nina Drozd0324f482019-04-08 10:52:10 +01003094 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3095 CHECK_VALID_SIZE(inputs.size(), 2);
3096 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3097 CHECK_VALID_SIZE(outputs.size(), numSplits);
3098
Matthew Sloyaned7fce42021-04-15 20:46:24 +01003099 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[1]);
3100 armnn::TensorInfo axisTensorInfo = ToTensorInfo(inputs[0]);
3101 ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
Nina Drozd0324f482019-04-08 10:52:10 +01003102
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01003103 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[0]->buffer);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01003104 if (axisBufferPtr == nullptr)
3105 {
3106 throw ParseException(
3107 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
3108 CHECK_LOCATION().AsString()));
3109 }
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01003110
Matthew Sloyaned7fce42021-04-15 20:46:24 +01003111 std::vector<int32_t> axisData(axisTensorInfo.GetNumElements());
3112 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
3113 int32_t axis = axisData[0];
3114
3115 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
3116 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
3117 {
3118 // Square bracket denotes inclusive n while parenthesis denotes exclusive n
3119 // E.g. Rank 4 tensor can have axis in range [-4, 3)
3120 // -1 == 3, -2 == 2, -3 == 1, -4 == 0
3121 throw ParseException(
3122 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
3123 axis,
3124 CHECK_LOCATION().AsString()));
3125 }
3126
3127 const unsigned int splitDim = armnnUtils::GetUnsignedAxis(inputTensorInfo.GetNumDimensions(), axis);
Nina Drozd0324f482019-04-08 10:52:10 +01003128
Nina Drozd0324f482019-04-08 10:52:10 +01003129 auto inputDimSize = inputTensorInfo.GetNumDimensions();
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01003130 if (inputDimSize > MaxNumOfTensorDimensions)
Nina Drozd0324f482019-04-08 10:52:10 +01003131 {
3132 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003133 fmt::format("The number of dimensions: {} for input tensors of the split op cannot be greater than {} {}",
3134 inputTensorInfo.GetNumDimensions(),
3135 MaxNumOfTensorDimensions,
3136 CHECK_LOCATION().AsString()));
Nina Drozd0324f482019-04-08 10:52:10 +01003137 }
3138
3139 std::vector<unsigned int> splitterDimSizes(inputDimSize);
3140
3141 // Add current input shape to splitterDimSizes
3142 for (unsigned int i = 0; i < inputDimSize; ++i)
3143 {
3144 splitterDimSizes[i] = inputTensorInfo.GetShape()[i];
3145 }
3146
3147 if (splitterDimSizes[splitDim] % numSplits != 0)
3148 {
3149 throw ParseException("Number of splits must evenly divide the dimension");
3150 }
3151 splitterDimSizes[splitDim] /= numSplits;
3152
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01003153 SplitterDescriptor splitDesc(numSplits, inputDimSize);
Nina Drozd0324f482019-04-08 10:52:10 +01003154 for (unsigned int j = 0; j < numSplits; ++j)
3155 {
3156 // Set the size of the views.
3157 for (unsigned int dimIdx = 0; dimIdx < splitterDimSizes.size(); ++dimIdx)
3158 {
3159 splitDesc.SetViewSize(j, dimIdx, splitterDimSizes[dimIdx]);
3160 }
3161 splitDesc.SetViewOriginCoord(j, splitDim, splitterDimSizes[splitDim] * j);
3162 }
3163
James Ward58dec6b2020-09-11 17:32:44 +01003164 auto layerName = fmt::format("Split:{}:{}", subgraphIndex, operatorIndex);
Nina Drozd0324f482019-04-08 10:52:10 +01003165 IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01003166 ARMNN_ASSERT(layer != nullptr);
Nina Drozd0324f482019-04-08 10:52:10 +01003167
3168 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01003169 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[1]});
Nina Drozd0324f482019-04-08 10:52:10 +01003170
Nina Drozd0324f482019-04-08 10:52:10 +01003171 for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
3172 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01003173 armnn::TensorInfo tensorInfo = ToTensorInfo(outputs[k], true);
Francis Murtagh98d6b3d2019-10-21 10:52:54 +01003174 layer->GetOutputSlot(k).SetTensorInfo(tensorInfo);
Nina Drozd0324f482019-04-08 10:52:10 +01003175 }
3176
3177 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3178 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
3179}
3180
Derek Lambertif0176992020-04-28 13:37:49 +01003181unsigned int ComputeWrappedIndex(int idx, unsigned int numDimsIn)
3182{
3183 int numDims = armnn::numeric_cast<int>(numDimsIn);
3184 int v = idx < 0 ? numDims + idx : idx;
3185 ARMNN_ASSERT(v >= 0);
3186 ARMNN_ASSERT(v < numDims);
3187
3188 return static_cast<unsigned int>(v);
3189}
3190
Kevin May7d96b162021-02-03 17:38:41 +00003191void TfLiteParserImpl::ParseSplitV(size_t subgraphIndex, size_t operatorIndex)
Derek Lambertif0176992020-04-28 13:37:49 +01003192{
3193 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3194
3195 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
Ryan OShea86704732020-05-26 11:41:04 +01003196 const auto * options = operatorPtr->builtin_options.AsSplitVOptions();
Derek Lambertif0176992020-04-28 13:37:49 +01003197
3198 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3199 CHECK_VALID_SIZE(inputs.size(), 3);
3200
3201 auto& inputTensor = inputs[0];
3202 auto& splitsTensor = inputs[1];
3203 auto& axisTensor = inputs[2];
3204
3205 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputTensor);
3206 armnn::TensorInfo splitsInfo = ToTensorInfo(splitsTensor);
3207 armnn::TensorInfo axisTensorInfo = ToTensorInfo(axisTensor);
3208 ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
3209
3210 // Inputs
3211 auto inputDimSize = inputTensorInfo.GetNumDimensions();
3212 if (inputDimSize > MaxNumOfTensorDimensions)
3213 {
3214 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003215 fmt::format("The number of dimensions: {} for input tensors of the "
3216 "SplitV op cannot be greater than {} {}",
3217 inputTensorInfo.GetNumDimensions(),
3218 MaxNumOfTensorDimensions,
3219 CHECK_LOCATION().AsString()));
Derek Lambertif0176992020-04-28 13:37:49 +01003220 }
3221
3222 // Get split axis
3223 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, axisTensor->buffer);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01003224 if (axisBufferPtr == nullptr)
3225 {
3226 throw ParseException(
3227 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
3228 CHECK_LOCATION().AsString()));
3229 }
3230
Derek Lambertif0176992020-04-28 13:37:49 +01003231 std::vector<int> axisData(axisTensorInfo.GetNumElements());
3232 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
Matthew Sloyaned7fce42021-04-15 20:46:24 +01003233 int32_t axis = axisData[0];
3234
3235 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
3236 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
3237 {
3238 // Square bracket denotes inclusive n while parenthesis denotes exclusive n
3239 // E.g. Rank 4 tensor can have axis in range [-4, 3)
3240 // -1 == 3, -2 == 2, -3 == 1, -4 == 0
3241 throw ParseException(
3242 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
3243 axis,
3244 CHECK_LOCATION().AsString()));
3245 }
3246 const unsigned int splitDim = ComputeWrappedIndex(axis, inputTensorInfo.GetNumDimensions());
Derek Lambertif0176992020-04-28 13:37:49 +01003247
Derek Lambertif0176992020-04-28 13:37:49 +01003248 // Set split sizes
Derek Lambertif0176992020-04-28 13:37:49 +01003249 CHECK_VALID_SIZE(splitsInfo.GetNumDimensions(), 1);
Ryan OShea86704732020-05-26 11:41:04 +01003250 unsigned int numSplits{0};
3251
3252 if(options)
Derek Lambertif0176992020-04-28 13:37:49 +01003253 {
3254 numSplits = CHECKED_NON_NEGATIVE(options->num_splits);
Derek Lambertif0176992020-04-28 13:37:49 +01003255 }
3256 else
3257 {
Ryan OShea86704732020-05-26 11:41:04 +01003258 numSplits = splitsInfo.GetNumElements();
Derek Lambertif0176992020-04-28 13:37:49 +01003259 }
3260
3261 if (numSplits <=0)
3262 {
3263 throw ParseException("SplitV has invalid number of splits");
3264 }
3265
Jan Eilersc0761e92020-06-29 16:48:44 +01003266 std::vector<int> splitsData(numSplits);
Ryan OShea86704732020-05-26 11:41:04 +01003267 BufferRawPtr splitsBufferPtr = GetBuffer(m_Model, splitsTensor->buffer);
Jan Eilersc0761e92020-06-29 16:48:44 +01003268 ::memcpy(splitsData.data(), splitsBufferPtr->data.data(), splitsInfo.GetNumBytes());
Ryan OShea86704732020-05-26 11:41:04 +01003269
Jan Eilersc0761e92020-06-29 16:48:44 +01003270 unsigned int idx = 0;
Ryan OShea86704732020-05-26 11:41:04 +01003271 int numInferred{0};
3272 unsigned int inferIdx{0};
3273 int splitSum{0};
3274 for (auto split : splitsData)
3275 {
3276 if (split < 0)
3277 {
3278 numInferred++;
3279 inferIdx = idx;
3280 }
3281 else
3282 {
3283 splitSum += split;
3284 }
3285 idx++;
3286 }
3287 // Check for inferred Axis
3288 if (numInferred == 0)
3289 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +01003290 if (splitSum != armnn::numeric_cast<int>(inputTensorInfo.GetShape()[splitDim]))
Ryan OShea86704732020-05-26 11:41:04 +01003291 {
3292 throw ParseException("SplitV split_sizes does not sum to the dimension of value along split_dim.");
3293 }
3294 }
3295 else if (numInferred == 1)
3296 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +01003297 splitsData[inferIdx] = armnn::numeric_cast<int>(inputTensorInfo.GetShape()[splitDim]) - splitSum;
Ryan OShea86704732020-05-26 11:41:04 +01003298 }
3299 else
3300 {
3301 throw ParseException("Cannot infer split size for more than one split");
3302 }
3303
Derek Lambertif0176992020-04-28 13:37:49 +01003304 //Ouput size validation
3305 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3306 CHECK_VALID_SIZE(outputs.size(), numSplits);
3307
3308 // Setup Armnn descriptor
3309 SplitterDescriptor splitDesc(numSplits, inputDimSize);
3310 unsigned int accumSplit = 0;
3311 for (unsigned int j = 0; j < numSplits; ++j)
3312 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +01003313 unsigned int splitSize = armnn::numeric_cast<unsigned int>(splitsData[j]);
Derek Lambertif0176992020-04-28 13:37:49 +01003314
3315 // Set the size of the views.
3316 for (unsigned int dimIdx = 0; dimIdx < inputTensorInfo.GetNumDimensions(); ++dimIdx)
3317 {
3318 unsigned int dimSize = inputTensorInfo.GetShape()[dimIdx];
3319 if (dimIdx == splitDim)
3320 {
3321 dimSize = splitSize;
3322 }
3323 splitDesc.SetViewSize(j, dimIdx, dimSize);
3324 }
3325
3326 splitDesc.SetViewOriginCoord(j, splitDim, accumSplit);
3327 accumSplit += splitSize;
3328 }
3329
James Ward58dec6b2020-09-11 17:32:44 +01003330 auto layerName = fmt::format("SplitV:{}:{}", subgraphIndex, operatorIndex);
Derek Lambertif0176992020-04-28 13:37:49 +01003331 IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01003332 ARMNN_ASSERT(layer != nullptr);
Derek Lambertif0176992020-04-28 13:37:49 +01003333
3334 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3335 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3336
3337 for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
3338 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01003339 armnn::TensorInfo tensorInfo = ToTensorInfo(outputs[k], true);
Derek Lambertif0176992020-04-28 13:37:49 +01003340 layer->GetOutputSlot(k).SetTensorInfo(tensorInfo);
3341 }
3342
3343 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3344 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
3345}
3346
Matthew Sloyan28f177c2021-04-09 14:38:52 +01003347void TfLiteParserImpl::ParseArgMin(size_t subgraphIndex, size_t operatorIndex)
3348{
3349 ParseArgMinMax(subgraphIndex, operatorIndex, armnn::ArgMinMaxFunction::Min);
3350}
3351
Kevin May7d96b162021-02-03 17:38:41 +00003352void TfLiteParserImpl::ParseArgMax(size_t subgraphIndex, size_t operatorIndex)
Inki Daed4619e22020-09-10 15:33:54 +09003353{
Matthew Sloyan28f177c2021-04-09 14:38:52 +01003354 ParseArgMinMax(subgraphIndex, operatorIndex, armnn::ArgMinMaxFunction::Max);
3355}
3356
3357void TfLiteParserImpl::ParseArgMinMax(size_t subgraphIndex, size_t operatorIndex, ArgMinMaxFunction argMinMaxFunction)
3358{
Inki Daed4619e22020-09-10 15:33:54 +09003359 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3360 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3361 CHECK_VALID_SIZE(inputs.size(), 2);
3362
3363 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3364 CHECK_VALID_SIZE(outputs.size(), 1);
3365
Matthew Sloyan28f177c2021-04-09 14:38:52 +01003366 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
3367 armnn::TensorInfo axisTensorInfo = ToTensorInfo(inputs[1]);
Inki Daed4619e22020-09-10 15:33:54 +09003368 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01003369 ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
Matthew Sloyan28f177c2021-04-09 14:38:52 +01003370
3371 // Check if output tensor type is Signed32 or Signed64
Mike Kelly1f140f72021-04-06 12:25:55 +01003372 if (outputTensorInfo.GetDataType() != armnn::DataType::Signed32 &&
3373 outputTensorInfo.GetDataType() != armnn::DataType::Signed64)
3374 {
3375 throw ParseException(
3376 fmt::format(
3377 "Output tensor data type is not supported. (Supported types: Signed32 & Signed64) {}",
3378 CHECK_LOCATION().AsString()));
3379 }
Matthew Sloyan28f177c2021-04-09 14:38:52 +01003380
3381 // Get const axis value from model and set it to descriptor.
3382 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
3383 if (axisBufferPtr == nullptr)
3384 {
3385 throw ParseException(
3386 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
3387 CHECK_LOCATION().AsString()));
3388 }
3389
3390 std::vector<int32_t> axisData(axisTensorInfo.GetNumElements());
3391 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
3392 int32_t axis = axisData.front();
3393
3394 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
3395 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
3396 {
3397 // Square bracket denotes inclusive n while parenthesis denotes exclusive n
3398 // E.g. Rank 4 tensor can have axis in range [-4, 3)
3399 // -1 == 3, -2 == 2, -3 == 1, -4 == 0
3400 throw ParseException(
3401 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
3402 axis,
3403 CHECK_LOCATION().AsString()));
3404 }
3405
3406 ArgMinMaxDescriptor desc;
3407 desc.m_Axis = axis;
3408 desc.m_Function = argMinMaxFunction;
3409
3410 // Register a ArgMin/ArgMax layer.
3411 auto layerName = argMinMaxFunction == ArgMinMaxFunction::Max ? "ArgMax:{}:{}" : "ArgMin:{}:{}";
3412 auto layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
3413 IConnectableLayer *layer = m_Network->AddArgMinMaxLayer(desc, layerNameFormatted.c_str());
3414 ARMNN_ASSERT(layer != nullptr);
Inki Daed4619e22020-09-10 15:33:54 +09003415 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3416
3417 // Register input tensor to the layer.
3418 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3419 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3420
3421 // Register output tensor to the layer.
3422 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3423 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
3424}
3425
Kevin May7d96b162021-02-03 17:38:41 +00003426void TfLiteParserImpl::ParseGather(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan26868492021-01-22 14:25:31 +00003427{
3428 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3429
Kevin May7d96b162021-02-03 17:38:41 +00003430 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00003431 CHECK_VALID_SIZE(inputs.size(), 2);
Kevin May7d96b162021-02-03 17:38:41 +00003432 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00003433 CHECK_VALID_SIZE(outputs.size(), 1);
3434
3435 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
3436 armnn::TensorInfo indicesTensorInfo = ToTensorInfo(inputs[1]);
3437 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
3438
3439 armnn::GatherDescriptor gatherDescriptor;
3440
3441 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3442 const auto * options = operatorPtr->builtin_options.AsGatherOptions();
3443 auto axis = options->axis;
3444
3445 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
3446 auto indicesDimensions = indicesTensorInfo.GetNumDimensions();
3447 auto outputDimensions = outputTensorInfo.GetNumDimensions();
3448 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
3449 {
3450 throw ParseException(
3451 fmt::format("Operation has invalid axis: {} It is out of bounds [ -{}, {} ) {}",
3452 axis,
3453 inputDimensions, inputDimensions,
3454 CHECK_LOCATION().AsString()));
3455 }
3456 if (outputDimensions != static_cast<unsigned int>(inputDimensions) + indicesDimensions - 1)
3457 {
3458 throw ParseException(
3459 fmt::format("Operation has invalid output dimensions: {} Output must be an ({} + {} - 1) -D tensor {}",
3460 outputDimensions,
3461 inputDimensions, indicesDimensions,
3462 CHECK_LOCATION().AsString()));
3463 }
3464
3465 gatherDescriptor.m_Axis = axis;
3466
3467 auto layerName = fmt::format("Gather:{}:{}", subgraphIndex, operatorIndex);
3468 IConnectableLayer* layer = m_Network->AddGatherLayer(gatherDescriptor, layerName.c_str());
3469 ARMNN_ASSERT(layer != nullptr);
3470 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3471
3472 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3473 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
3474
3475 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3476 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3477}
3478
Kevin May7d96b162021-02-03 17:38:41 +00003479void TfLiteParserImpl::ParseDepthToSpace(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan26868492021-01-22 14:25:31 +00003480{
3481 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3482
Kevin May7d96b162021-02-03 17:38:41 +00003483 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00003484 CHECK_VALID_SIZE(inputs.size(), 1);
Kevin May7d96b162021-02-03 17:38:41 +00003485 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00003486 CHECK_VALID_SIZE(outputs.size(), 1);
3487
3488 armnn::DepthToSpaceDescriptor descriptor;
3489
3490 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3491 const auto * options = operatorPtr->builtin_options.AsDepthToSpaceOptions();
3492 auto blockSize = options->block_size;
3493 if (blockSize < 2)
3494 {
3495 throw ParseException(
3496 fmt::format("Operation has invalid block size: {} Block size should be >= 2 {}",
3497 blockSize,
3498 CHECK_LOCATION().AsString()));
3499 }
3500 descriptor.m_BlockSize = armnn::numeric_cast<uint32_t>(blockSize);
3501
3502 auto layerName = fmt::format("DepthToSpace:{}:{}", subgraphIndex, operatorIndex);
3503 IConnectableLayer* layer = m_Network->AddDepthToSpaceLayer(descriptor, layerName.c_str());
3504 ARMNN_ASSERT(layer != nullptr);
3505 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
3506 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3507
3508 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3509 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3510
3511 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3512 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3513}
3514
Kevin May7d96b162021-02-03 17:38:41 +00003515void TfLiteParserImpl::ParseSum(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00003516{
Sadik Armagana2747482021-02-09 10:28:54 +00003517 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Sum);
3518}
3519
Teresa Charlin4e3e8312021-08-05 12:34:37 +01003520void TfLiteParserImpl::ParseReduceProd(size_t subgraphIndex, size_t operatorIndex)
3521{
3522 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Prod);
3523}
3524
Sadik Armagana2747482021-02-09 10:28:54 +00003525void TfLiteParserImpl::ParseReduceMax(size_t subgraphIndex, size_t operatorIndex)
3526{
3527 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Max);
3528}
3529
3530void TfLiteParserImpl::ParseReduceMin(size_t subgraphIndex, size_t operatorIndex)
3531{
3532 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Min);
3533}
3534
3535void TfLiteParserImpl::ParseReduce(size_t subgraphIndex, size_t operatorIndex, ReduceOperation reduceOperation)
3536{
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00003537 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3538
3539 const auto &operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3540 const auto *options = operatorPtr->builtin_options.AsReducerOptions();
3541
3542 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3543 CHECK_VALID_SIZE(inputs.size(), 2);
3544
3545 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3546 CHECK_VALID_SIZE(outputs.size(), 1);
3547
Sadik Armagana2747482021-02-09 10:28:54 +00003548 auto layerName = fmt::format("Reduce:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00003549
3550 armnn::TensorInfo inputTensorInfo0 = ToTensorInfo(inputs[0]);
3551 armnn::TensorInfo inputTensorInfo1 = ToTensorInfo(inputs[1]);
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00003552
3553 ReduceDescriptor desc;
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00003554 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
3555 // Get const axis value from model and set it to descriptor.
3556 if (axisBufferPtr != nullptr)
3557 {
Sadik Armagan49bdb792021-02-11 13:57:07 +00003558 std::vector<int32_t> axisData(inputTensorInfo1.GetNumElements());
3559 ::memcpy(axisData.data(), axisBufferPtr->data.data(), inputTensorInfo1.GetNumBytes());
3560
3561 // Convert the axis to unsigned int and remove duplicates.
3562 auto rank = static_cast<int32_t>(inputTensorInfo0.GetNumDimensions());
3563 std::set<unsigned int> uniqueAxis;
3564 std::transform(axisData.begin(),
3565 axisData.end(),
3566 std::inserter(uniqueAxis, uniqueAxis.begin()),
3567 [rank](int i)->unsigned int{
3568 return static_cast<uint32_t>(((i + rank) % rank)); });
3569 desc.m_vAxis.assign(uniqueAxis.begin(), uniqueAxis.end());
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00003570 }
Sadik Armagana2747482021-02-09 10:28:54 +00003571 else
3572 {
3573 for (uint32_t i = 0; i < inputTensorInfo0.GetNumDimensions(); ++i)
3574 {
3575 desc.m_vAxis.push_back(i);
3576 }
3577 }
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00003578
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00003579 desc.m_KeepDims = options->keep_dims;
Sadik Armagana2747482021-02-09 10:28:54 +00003580 desc.m_ReduceOperation = reduceOperation;
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00003581
3582 // Register a new layer object, Sum.
3583 IConnectableLayer *layer = m_Network->AddReduceLayer(desc, layerName.c_str());
3584
3585 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
3586 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3587
3588 // Register input tensor to the layer.
3589 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3590 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3591
3592 // Register output tensor to the layer.
3593 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3594 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
3595}
3596
Matthew Sloyaned7fce42021-04-15 20:46:24 +01003597void TfLiteParserImpl::ParseAbs(size_t subgraphIndex, size_t operatorIndex)
3598{
3599 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Abs);
3600}
3601
3602void TfLiteParserImpl::ParseExp(size_t subgraphIndex, size_t operatorIndex)
3603{
3604 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Exp);
3605}
3606
Mike Kelly31dce2b2021-09-01 21:22:37 +01003607void TfLiteParserImpl::ParseLocalResponseNormalization(size_t subgraphIndex, size_t operatorIndex)
3608{
3609 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3610
3611 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3612 CHECK_VALID_SIZE(inputs.size(), 1);
3613
3614 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3615 CHECK_VALID_SIZE(outputs.size(), 1);
3616
3617 auto layerName = fmt::format("LRN:{}:{}", subgraphIndex, operatorIndex);
3618 std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
3619
3620 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
3621
3622 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3623 const auto* options = operatorPtr->builtin_options.AsLocalResponseNormalizationOptions();
3624
3625 armnn::NormalizationDescriptor descriptor;
3626 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
3627 descriptor.m_NormChannelType = armnn::NormalizationAlgorithmChannel::Across;
3628 descriptor.m_NormMethodType = armnn::NormalizationAlgorithmMethod::LocalBrightness;
3629 descriptor.m_NormSize = static_cast<uint32_t>(options->radius);
3630 descriptor.m_K = options->bias;
3631 descriptor.m_Alpha = options->alpha;
3632 descriptor.m_Beta = options->beta;
3633
3634 // ArmNN expects normSize to be the full size of the normalization
3635 // window rather than the radius as in TfLite.
3636 descriptor.m_NormSize = 1 + (2 * descriptor.m_NormSize);
3637
3638 IConnectableLayer* layer = m_Network->AddNormalizationLayer(descriptor, layerNameFormatted.c_str());
3639 ARMNN_ASSERT(layer != nullptr);
3640
3641 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
3642 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3643
3644 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3645 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3646
3647 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3648 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3649}
3650
Matthew Sloyaned7fce42021-04-15 20:46:24 +01003651void TfLiteParserImpl::ParseLogicalNot(size_t subgraphIndex, size_t operatorIndex)
3652{
3653 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::LogicalNot);
3654}
3655
3656void TfLiteParserImpl::ParseNeg(size_t subgraphIndex, size_t operatorIndex)
3657{
3658 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Neg);
3659}
3660
3661void TfLiteParserImpl::ParseRsqrt(size_t subgraphIndex, size_t operatorIndex)
3662{
3663 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Rsqrt);
3664}
3665
3666void TfLiteParserImpl::ParseElementwiseUnary(size_t subgraphIndex, size_t operatorIndex, UnaryOperation unaryOperation)
3667{
3668 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3669
3670 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3671 CHECK_VALID_SIZE(inputs.size(), 1);
3672
3673 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3674 CHECK_VALID_SIZE(outputs.size(), 1);
3675
3676 std::string layerName = std::string(GetUnaryOperationAsCString(unaryOperation)) + ":{}:{}";
3677 std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
3678
3679 ElementwiseUnaryDescriptor desc;
3680 desc.m_Operation = unaryOperation;
3681 IConnectableLayer* layer = m_Network->AddElementwiseUnaryLayer(desc, layerNameFormatted.c_str());
3682 ARMNN_ASSERT(layer != nullptr);
3683
3684 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
3685 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3686
3687 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3688 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3689
3690 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3691 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
3692}
3693
Bruno Goncalves2d0eb862021-07-11 14:10:15 -03003694void TfLiteParserImpl::ParseEqual(size_t subgraphIndex, size_t operatorIndex)
3695{
3696 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::Equal);
3697}
3698
3699void TfLiteParserImpl::ParseNotEqual(size_t subgraphIndex, size_t operatorIndex)
3700{
3701 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::NotEqual);
3702}
3703
3704void TfLiteParserImpl::ParseGreater(size_t subgraphIndex, size_t operatorIndex)
3705{
3706 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::Greater);
3707}
3708
3709void TfLiteParserImpl::ParseGreaterOrEqual(size_t subgraphIndex, size_t operatorIndex)
3710{
3711 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::GreaterOrEqual);
3712}
3713
3714void TfLiteParserImpl::ParseLess(size_t subgraphIndex, size_t operatorIndex)
3715{
3716 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::Less);
3717}
3718
3719void TfLiteParserImpl::ParseLessOrEqual(size_t subgraphIndex, size_t operatorIndex)
3720{
3721 ParseComparison(subgraphIndex, operatorIndex, armnn::ComparisonOperation::LessOrEqual);
3722}
3723
3724void TfLiteParserImpl::ParseComparison(size_t subgraphIndex, size_t operatorIndex,
3725 ComparisonOperation comparisonOperation)
3726{
3727 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3728
3729 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3730 CHECK_VALID_SIZE(inputs.size(), 2);
3731
3732 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3733 CHECK_VALID_SIZE(outputs.size(), 1);
3734
3735 auto layerName = std::string(GetComparisonOperationAsCString(comparisonOperation)) + ":{}:{}";
3736 std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
3737
3738 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
3739 armnn::TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]);
3740 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerNameFormatted, "Input 0", "Input 1");
3741
3742 ComparisonDescriptor desc;
3743 desc.m_Operation = comparisonOperation;
3744 IConnectableLayer* layer = m_Network->AddComparisonLayer(desc, layerNameFormatted.c_str());
3745 ARMNN_ASSERT(layer != nullptr);
3746
3747 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
3748 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3749
3750 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3751 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
3752
3753 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3754 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3755}
3756
Kevin May7d96b162021-02-03 17:38:41 +00003757armnn::IConnectableLayer* TfLiteParserImpl::AddFusedActivationLayer(armnn::IConnectableLayer* prevLayer,
3758 unsigned int outputSlot,
3759 tflite::ActivationFunctionType activationType)
telsoa01c577f2c2018-08-31 09:22:23 +01003760{
3761 ActivationDescriptor activationDesc;
3762 std::string layerName = prevLayer->GetName();
3763
3764 switch(activationType)
3765 {
3766 case tflite::ActivationFunctionType_NONE:
3767 {
3768 // this is a no-op: return previous layer
3769 return prevLayer;
3770 }
3771 case tflite::ActivationFunctionType_RELU:
3772 {
3773 activationDesc.m_Function = ActivationFunction::ReLu;
3774 layerName += ":RELU";
3775 break;
3776 }
3777 case tflite::ActivationFunctionType_RELU6:
3778 {
3779 activationDesc.m_Function = ActivationFunction::BoundedReLu;
3780 activationDesc.m_A = 6.0f;
3781 activationDesc.m_B = 0.0f;
3782 layerName += ":RELU6";
3783 break;
3784 }
3785 case tflite::ActivationFunctionType_TANH:
3786 {
3787 activationDesc.m_Function = ActivationFunction::TanH;
3788 activationDesc.m_A = 1.0f;
3789 activationDesc.m_B = 1.0f;
3790 layerName += ":TANH";
3791 break;
3792 }
3793
3794 // I only put these here as a reminder what others we could support
3795 case tflite::ActivationFunctionType_RELU_N1_TO_1:
3796 case tflite::ActivationFunctionType_SIGN_BIT:
3797 default:
3798 {
3799 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003800 fmt::format("TfLite parser doesn't suppport fused activation: "
3801 "{}/{} {} ",
3802 activationType,
3803 tflite::EnumNameActivationFunctionType(activationType),
3804 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01003805
3806 }
3807 }
3808
3809 IConnectableLayer* activationLayer =
3810 m_Network->AddActivationLayer(activationDesc, layerName.c_str());
3811
3812 auto & prevOutputSlot = prevLayer->GetOutputSlot(outputSlot);
3813 prevOutputSlot.Connect(activationLayer->GetInputSlot(0));
3814 activationLayer->GetOutputSlot(0).SetTensorInfo(prevOutputSlot.GetTensorInfo());
3815 return activationLayer;
3816}
3817
Kevin May7d96b162021-02-03 17:38:41 +00003818TfLiteParserImpl::ModelPtr TfLiteParserImpl::LoadModelFromFile(const char * fileName)
telsoa01c577f2c2018-08-31 09:22:23 +01003819{
3820 if (fileName == nullptr)
3821 {
James Ward58dec6b2020-09-11 17:32:44 +01003822 throw InvalidArgumentException(fmt::format("Invalid (null) file name {}",
telsoa01c577f2c2018-08-31 09:22:23 +01003823 CHECK_LOCATION().AsString()));
3824 }
Francis Murtagh532a29d2020-06-29 11:50:01 +01003825 std::error_code errorCode;
3826 fs::path pathToFile(fileName);
3827 if (!fs::exists(pathToFile, errorCode))
telsoa01c577f2c2018-08-31 09:22:23 +01003828 {
James Ward58dec6b2020-09-11 17:32:44 +01003829 //fmt::format() could not be used here (format error)
3830 std::stringstream msg;
3831 msg << "Cannot find the file (" << fileName << ") errorCode: " << errorCode
3832 << " " << CHECK_LOCATION().AsString();
3833
3834 throw FileNotFoundException(msg.str());
telsoa01c577f2c2018-08-31 09:22:23 +01003835 }
3836 std::ifstream file(fileName, std::ios::binary);
3837 std::string fileContent((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
3838 return LoadModelFromBinary(reinterpret_cast<const uint8_t *>(fileContent.c_str()),
3839 fileContent.size());
3840}
3841
Kevin May7d96b162021-02-03 17:38:41 +00003842TfLiteParserImpl::ModelPtr TfLiteParserImpl::LoadModelFromBinary(const uint8_t * binaryContent, size_t len)
telsoa01c577f2c2018-08-31 09:22:23 +01003843{
3844 if (binaryContent == nullptr)
3845 {
James Ward58dec6b2020-09-11 17:32:44 +01003846 throw InvalidArgumentException(fmt::format("Invalid (null) binary content {}",
telsoa01c577f2c2018-08-31 09:22:23 +01003847 CHECK_LOCATION().AsString()));
3848 }
3849 flatbuffers::Verifier verifier(binaryContent, len);
3850 if (verifier.VerifyBuffer<tflite::Model>() == false)
3851 {
3852 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003853 fmt::format("Buffer doesn't conform to the expected Tensorflow Lite "
3854 "flatbuffers format. size:{} {}",
3855 len,
3856 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01003857 }
3858 return tflite::UnPackModel(binaryContent);
3859}
3860
Kevin May7d96b162021-02-03 17:38:41 +00003861TfLiteParserImpl::TensorRawPtrVector TfLiteParserImpl::GetInputs(const ModelPtr & model,
3862 size_t subgraphIndex,
3863 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01003864{
3865 CHECK_MODEL(model, subgraphIndex, operatorIndex);
3866
Derek Lambertiff05cc52019-04-26 13:05:17 +01003867 const auto & subgraphPtr = model->subgraphs[subgraphIndex];
3868 const auto & operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01003869
3870 size_t inputCount = operatorPtr->inputs.size();
mathad01c21025d2021-04-26 10:09:37 +01003871 TensorRawPtrVector result;
telsoa01c577f2c2018-08-31 09:22:23 +01003872 for (size_t i=0; i<inputCount; ++i)
3873 {
mathad01c21025d2021-04-26 10:09:37 +01003874 // If the input location is -1 then assume input is turned off.
3875 if (operatorPtr->inputs[i] == -1)
3876 {
3877 continue;
3878 }
3879 else
3880 {
3881 uint32_t inputId = CHECKED_NON_NEGATIVE(operatorPtr->inputs[i]);
3882 result.push_back(subgraphPtr->tensors[inputId].get());
3883 }
telsoa01c577f2c2018-08-31 09:22:23 +01003884 }
3885 return result;
3886}
3887
Kevin May7d96b162021-02-03 17:38:41 +00003888TfLiteParserImpl::TensorRawPtrVector TfLiteParserImpl::GetOutputs(const ModelPtr & model,
3889 size_t subgraphIndex,
3890 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01003891{
3892 CHECK_MODEL(model, subgraphIndex, operatorIndex);
3893
Derek Lambertiff05cc52019-04-26 13:05:17 +01003894 const auto & subgraphPtr = model->subgraphs[subgraphIndex];
3895 const auto & operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01003896
3897 size_t outputCount = operatorPtr->outputs.size();
3898 TensorRawPtrVector result(outputCount);
3899 for (size_t i=0; i<outputCount; ++i)
3900 {
3901 uint32_t outputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[i]);
3902 CHECK_TENSOR(model, subgraphIndex, outputId);
Derek Lambertiff05cc52019-04-26 13:05:17 +01003903 result[i] = subgraphPtr->tensors[outputId].get();
telsoa01c577f2c2018-08-31 09:22:23 +01003904 }
3905 return result;
3906}
3907
Kevin May7d96b162021-02-03 17:38:41 +00003908TfLiteParserImpl::TensorIdRawPtrVector TfLiteParserImpl::GetSubgraphInputs(const ModelPtr & model,
3909 size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01003910{
3911 CHECK_SUBGRAPH(model, subgraphIndex);
Derek Lambertiff05cc52019-04-26 13:05:17 +01003912 const auto & subgraphPtr = model->subgraphs[subgraphIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01003913
Derek Lambertiff05cc52019-04-26 13:05:17 +01003914 size_t inputCount = subgraphPtr->inputs.size();
telsoa01c577f2c2018-08-31 09:22:23 +01003915 TensorIdRawPtrVector result(inputCount);
3916 for (size_t i=0; i<inputCount; ++i)
3917 {
Derek Lambertiff05cc52019-04-26 13:05:17 +01003918 uint32_t inputId = CHECKED_NON_NEGATIVE(subgraphPtr->inputs[i]);
telsoa01c577f2c2018-08-31 09:22:23 +01003919 CHECK_TENSOR(model, subgraphIndex, inputId);
Derek Lambertiff05cc52019-04-26 13:05:17 +01003920 result[i] = std::make_pair(inputId, subgraphPtr->tensors[inputId].get());
telsoa01c577f2c2018-08-31 09:22:23 +01003921 }
3922 return result;
3923}
3924
Kevin May7d96b162021-02-03 17:38:41 +00003925TfLiteParserImpl::TensorIdRawPtrVector TfLiteParserImpl::GetSubgraphOutputs(const ModelPtr & model,
3926 size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01003927{
3928 CHECK_SUBGRAPH(model, subgraphIndex);
Derek Lambertiff05cc52019-04-26 13:05:17 +01003929 const auto & subgraphPtr = model->subgraphs[subgraphIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01003930
Derek Lambertiff05cc52019-04-26 13:05:17 +01003931 size_t outputCount = subgraphPtr->outputs.size();
telsoa01c577f2c2018-08-31 09:22:23 +01003932 TensorIdRawPtrVector result(outputCount);
3933 for (size_t i=0; i<outputCount; ++i)
3934 {
Derek Lambertiff05cc52019-04-26 13:05:17 +01003935 uint32_t outputId = CHECKED_NON_NEGATIVE(subgraphPtr->outputs[i]);
3936 result[i] = std::make_pair(outputId, subgraphPtr->tensors[outputId].get());
telsoa01c577f2c2018-08-31 09:22:23 +01003937 }
3938 return result;
3939}
3940
Kevin May7d96b162021-02-03 17:38:41 +00003941std::vector<int32_t>& TfLiteParserImpl::GetInputTensorIds(const ModelPtr& model,
3942 size_t subgraphIndex,
3943 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01003944{
3945 CHECK_MODEL(model, subgraphIndex, operatorIndex);
Derek Lambertiff05cc52019-04-26 13:05:17 +01003946 const auto & subgraphPtr = model->subgraphs[subgraphIndex];
3947 const auto & operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01003948 return operatorPtr->inputs;
3949}
3950
Kevin May7d96b162021-02-03 17:38:41 +00003951std::vector<int32_t>& TfLiteParserImpl::GetOutputTensorIds(const ModelPtr& model,
3952 size_t subgraphIndex,
3953 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01003954{
3955 CHECK_MODEL(model, subgraphIndex, operatorIndex);
Derek Lambertiff05cc52019-04-26 13:05:17 +01003956 const auto & subgraphPtr = model->subgraphs[subgraphIndex];
3957 const auto & operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01003958 return operatorPtr->outputs;
3959}
3960
Kevin May7d96b162021-02-03 17:38:41 +00003961void TfLiteParserImpl::RegisterInputSlots(size_t subgraphIndex,
3962 size_t operatorIndex,
3963 IConnectableLayer* layer,
Finn Williamsd4fa5452021-03-01 12:31:41 +00003964 const std::vector<unsigned int>& tensorIndexes,
3965 unsigned int startingSlotIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01003966{
3967 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01003968 ARMNN_ASSERT(layer != nullptr);
Matthew Sloyan81beae32021-07-13 19:46:11 +01003969
Finn Williamsd4fa5452021-03-01 12:31:41 +00003970 if (tensorIndexes.size() + startingSlotIndex != layer->GetNumInputSlots())
telsoa01c577f2c2018-08-31 09:22:23 +01003971 {
3972 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003973 fmt::format("The number of tensor inputs ({}) does not match the number expected ({})"
3974 " for subgraph:{} operator index:{} {}",
3975 tensorIndexes.size(),
3976 layer->GetNumInputSlots(),
3977 subgraphIndex,
3978 operatorIndex,
3979 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01003980 }
3981
Finn Williamsd4fa5452021-03-01 12:31:41 +00003982 for (unsigned int index = 0; index < tensorIndexes.size() ; ++index)
telsoa01c577f2c2018-08-31 09:22:23 +01003983 {
Finn Williamsd4fa5452021-03-01 12:31:41 +00003984 unsigned int tensorIndex = tensorIndexes[index];
3985 armnn::IInputSlot* slot = &(layer->GetInputSlot(startingSlotIndex + index));
telsoa01c577f2c2018-08-31 09:22:23 +01003986 RegisterConsumerOfTensor(subgraphIndex, tensorIndex, slot);
3987 }
3988}
3989
Kevin May7d96b162021-02-03 17:38:41 +00003990void TfLiteParserImpl::RegisterOutputSlots(size_t subgraphIndex,
3991 size_t operatorIndex,
3992 IConnectableLayer* layer,
3993 const std::vector<unsigned int>& tensorIndexes)
telsoa01c577f2c2018-08-31 09:22:23 +01003994{
3995 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01003996 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01003997 if (tensorIndexes.size() != layer->GetNumOutputSlots())
3998 {
3999 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01004000 fmt::format("The number of tensor outputs ({}) does not match the number expected ({})"
4001 " for subgraph:{} operator index:{} {}",
4002 tensorIndexes.size(),
4003 layer->GetNumOutputSlots(),
4004 subgraphIndex,
4005 operatorIndex,
4006 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01004007 }
4008
4009 for (unsigned int slotIndex = 0; slotIndex < layer->GetNumOutputSlots(); ++slotIndex)
4010 {
4011 unsigned int tensorIndex = tensorIndexes[slotIndex];
4012 armnn::IOutputSlot* slot = &(layer->GetOutputSlot(slotIndex));
4013 RegisterProducerOfTensor(subgraphIndex, tensorIndex, slot);
4014 }
4015}
4016
Kevin May7d96b162021-02-03 17:38:41 +00004017void TfLiteParserImpl::SetupInputLayers(size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004018{
4019 CHECK_SUBGRAPH(m_Model, subgraphIndex);
4020
4021 auto inputs = GetSubgraphInputs(m_Model, subgraphIndex);
4022 for (auto const & tensorIdAndPtr : inputs)
4023 {
4024 auto bindingId = GenerateLayerBindingId(subgraphIndex, tensorIdAndPtr.first);
4025 IConnectableLayer* layer =
4026 m_Network->AddInputLayer(bindingId, tensorIdAndPtr.second->name.c_str());
4027
4028 auto tensorInfo = ToTensorInfo(tensorIdAndPtr.second);
4029 layer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
4030
4031 RegisterOutputSlots(subgraphIndex,
4032 VIRTUAL_OPERATOR_ID,
4033 layer,
4034 { static_cast<uint32_t>(tensorIdAndPtr.first) });
4035 }
4036}
4037
Kevin May7d96b162021-02-03 17:38:41 +00004038void TfLiteParserImpl::SetupOutputLayers(size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004039{
4040 CHECK_SUBGRAPH(m_Model, subgraphIndex);
4041
4042 auto outputs = GetSubgraphOutputs(m_Model, subgraphIndex);
4043 for (auto const & tensorIdAndPtr : outputs)
4044 {
4045 auto bindingId = GenerateLayerBindingId(subgraphIndex, tensorIdAndPtr.first);
4046 IConnectableLayer* layer =
4047 m_Network->AddOutputLayer(bindingId, tensorIdAndPtr.second->name.c_str());
4048
4049 RegisterInputSlots(subgraphIndex,
4050 VIRTUAL_OPERATOR_ID,
4051 layer,
4052 { static_cast<uint32_t>(tensorIdAndPtr.first) });
4053 }
4054}
4055
Kevin May7d96b162021-02-03 17:38:41 +00004056void TfLiteParserImpl::SetupConstantLayers(size_t subgraphIndex)
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02004057{
4058 CHECK_SUBGRAPH(m_Model, subgraphIndex);
4059
Derek Lambertiff05cc52019-04-26 13:05:17 +01004060 const auto & subgraphPtr = m_Model->subgraphs[subgraphIndex];
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02004061 for (unsigned int subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex)
4062 {
4063 for (unsigned int tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex)
4064 {
4065 if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot == nullptr &&
4066 m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size() > 0)
4067 {
Derek Lambertiff05cc52019-04-26 13:05:17 +01004068 TensorRawPtr tensorPtr = subgraphPtr->tensors[tensorIndex].get();
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02004069
Matthew Sloyan81beae32021-07-13 19:46:11 +01004070 if(IsConstTensor(tensorPtr))
4071 {
4072 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
4073 auto tensorAndData = CreateConstTensorNonPermuted(tensorPtr, tensorInfo);
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02004074
Matthew Sloyan81beae32021-07-13 19:46:11 +01004075 std::string layerName = fmt::format("Constant:{}", tensorPtr->name);
4076 IConnectableLayer *layer = m_Network->AddConstantLayer(tensorAndData, layerName.c_str());
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02004077
Matthew Sloyan81beae32021-07-13 19:46:11 +01004078 layer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
4079 RegisterOutputSlots(subgraphIndex,
4080 VIRTUAL_OPERATOR_ID,
4081 layer,
4082 { tensorIndex });
4083 }
4084 else
4085 {
4086 throw ParseException(
4087 fmt::format("Invalid Tensor: Tensor should be constant. {}",
4088 CHECK_LOCATION().AsString()));
4089 }
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02004090 }
4091 }
4092 }
4093}
4094
telsoa01c577f2c2018-08-31 09:22:23 +01004095// example usage: BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[0]->buffer);
Kevin May7d96b162021-02-03 17:38:41 +00004096TfLiteParserImpl::BufferRawPtr TfLiteParserImpl::GetBuffer(const ModelPtr& model, size_t bufferIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01004097{
4098 CHECK_BUFFER(model, bufferIndex);
4099 return model->buffers[bufferIndex].get();
4100}
4101
Matteo Martincigh747ef822018-12-18 09:26:39 +00004102template<typename T>
Kevin May7d96b162021-02-03 17:38:41 +00004103std::pair<armnn::ConstTensor, TfLiteParserImpl::SupportedDataStorage>
4104TfLiteParserImpl::CreateConstTensorAndStoreData(TfLiteParserImpl::BufferRawPtr bufferPtr,
4105 TfLiteParserImpl::TensorRawPtr tensorPtr,
Matteo Martincigh747ef822018-12-18 09:26:39 +00004106 armnn::TensorInfo& tensorInfo,
4107 armnn::Optional<armnn::PermutationVector&> permutationVector)
4108{
Matthew Sloyan81beae32021-07-13 19:46:11 +01004109 // Make sure isConstant flag is set.
4110 tensorInfo.SetConstant();
4111
Matteo Martincigh747ef822018-12-18 09:26:39 +00004112 auto constData = CreateConstTensorImpl<T>(bufferPtr,
4113 tensorPtr,
4114 tensorInfo,
4115 permutationVector);
Kevin May7d96b162021-02-03 17:38:41 +00004116 TfLiteParserImpl::SupportedDataStorage storage(std::move(constData.second));
Matteo Martincigh747ef822018-12-18 09:26:39 +00004117 return std::make_pair(constData.first, std::move(storage));
4118}
4119
Finn Williamsd4fa5452021-03-01 12:31:41 +00004120bool TfLiteParserImpl::IsConstTensor(TensorRawPtr tensorPtr)
4121{
4122 CHECK_TENSOR_PTR(tensorPtr);
mathad01bf7edb62021-04-20 16:12:45 +01004123 bool isConst = true;
4124
4125 auto buffer = GetBuffer(m_Model, tensorPtr->buffer);
4126 if (buffer->data.size() == 0)
4127 {
4128 isConst = false;
4129 }
4130
4131 return isConst;
Finn Williamsd4fa5452021-03-01 12:31:41 +00004132}
4133
Kevin May7d96b162021-02-03 17:38:41 +00004134std::pair<armnn::ConstTensor, TfLiteParserImpl::SupportedDataStorage>
Finn Williamsd4fa5452021-03-01 12:31:41 +00004135TfLiteParserImpl::CreateConstTensorPermuted(TensorRawPtr tensorPtr,
4136 armnn::TensorInfo& tensorInfo,
4137 armnn::Optional<armnn::PermutationVector&> permutationVector)
telsoa01c577f2c2018-08-31 09:22:23 +01004138{
4139 CHECK_TENSOR_PTR(tensorPtr);
4140 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
4141 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
4142
Matthew Sloyan81beae32021-07-13 19:46:11 +01004143 // Make sure isConstant flag is set.
4144 tensorInfo.SetConstant();
4145
telsoa01c577f2c2018-08-31 09:22:23 +01004146 switch (tensorInfo.GetDataType())
4147 {
4148 case armnn::DataType::Float32:
Matteo Martincigh747ef822018-12-18 09:26:39 +00004149 return CreateConstTensorAndStoreData<float>(bufferPtr,
4150 tensorPtr,
4151 tensorInfo,
4152 permutationVector);
Derek Lambertif90c56d2020-01-10 17:14:08 +00004153 case armnn::DataType::QAsymmU8:
Matteo Martincigh747ef822018-12-18 09:26:39 +00004154 return CreateConstTensorAndStoreData<uint8_t>(bufferPtr,
4155 tensorPtr,
4156 tensorInfo,
4157 permutationVector);
Keith Davisd305e1a2020-01-22 11:57:54 +00004158 case armnn::DataType::QSymmS8:
4159 return CreateConstTensorAndStoreData<int8_t>(bufferPtr,
4160 tensorPtr,
4161 tensorInfo,
4162 permutationVector);
Keith Davis67e6c542020-02-19 10:08:33 +00004163 case armnn::DataType::QAsymmS8:
4164 return CreateConstTensorAndStoreData<int8_t>(bufferPtr,
4165 tensorPtr,
4166 tensorInfo,
4167 permutationVector);
telsoa01c577f2c2018-08-31 09:22:23 +01004168 case armnn::DataType::Signed32:
Matteo Martincigh747ef822018-12-18 09:26:39 +00004169 return CreateConstTensorAndStoreData<int32_t>(bufferPtr,
4170 tensorPtr,
4171 tensorInfo,
4172 permutationVector);
telsoa01c577f2c2018-08-31 09:22:23 +01004173 default:
4174 {
4175 std::stringstream errString;
4176 errString << "Unexpected datatype when creating const tensor: "
4177 << armnn::GetDataTypeName(tensorInfo.GetDataType())
4178 << " shape:" << tensorInfo.GetShape()
4179 << CHECK_LOCATION().AsString();
4180 throw ParseException(errString.str());
4181 }
4182 }
4183}
4184
Finn Williamsd4fa5452021-03-01 12:31:41 +00004185armnn::ConstTensor TfLiteParserImpl::CreateConstTensorNonPermuted(TensorRawPtr tensorPtr,
4186 armnn::TensorInfo& tensorInfo)
4187{
4188 CHECK_TENSOR_PTR(tensorPtr);
4189 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
4190 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
4191
Matthew Sloyan81beae32021-07-13 19:46:11 +01004192 // Make sure isConstant flag is set.
4193 tensorInfo.SetConstant();
4194
Finn Williamsd4fa5452021-03-01 12:31:41 +00004195 return ConstTensor(tensorInfo, bufferPtr->data.data());
4196}
4197
Kevin May7d96b162021-02-03 17:38:41 +00004198BindingPointInfo TfLiteParserImpl::GetNetworkInputBindingInfo(size_t subgraphId,
4199 const std::string& name) const
telsoa01c577f2c2018-08-31 09:22:23 +01004200{
4201 CHECK_SUBGRAPH(m_Model, subgraphId);
4202 auto inputs = GetSubgraphInputs(m_Model, subgraphId);
4203 for (auto const & input : inputs)
4204 {
4205 if (input.second->name == name)
4206 {
4207 auto bindingId = GenerateLayerBindingId(subgraphId, input.first);
Colm Donelan4bc993b2021-11-09 20:39:10 +00004208 auto inputTensorInfo = ToTensorInfo(input.second);
4209 // Input tensors are always treated as constant tensors during network execution.
4210 inputTensorInfo.SetConstant(true);
4211 return std::make_pair(bindingId, inputTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +01004212 }
4213 }
4214
4215 std::stringstream bindings;
4216 for (auto const & input : inputs)
4217 {
4218 bindings << "'" << input.second->name << "' ";
4219 }
4220
4221 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01004222 fmt::format("No input binding found for subgraph:{} and name:{}. "
4223 "Possible inputs are: [{}] {}",
4224 subgraphId,
4225 name,
4226 bindings.str(),
4227 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01004228}
4229
Kevin May7d96b162021-02-03 17:38:41 +00004230BindingPointInfo TfLiteParserImpl::GetNetworkOutputBindingInfo(size_t subgraphId,
4231 const std::string& name) const
telsoa01c577f2c2018-08-31 09:22:23 +01004232{
4233 CHECK_SUBGRAPH(m_Model, subgraphId);
4234 auto outputs = GetSubgraphOutputs(m_Model, subgraphId);
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00004235 for (unsigned int i = 0; i < outputs.size(); ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01004236 {
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00004237 auto const output = outputs[i];
telsoa01c577f2c2018-08-31 09:22:23 +01004238 if (output.second->name == name)
4239 {
4240 auto bindingId = GenerateLayerBindingId(subgraphId, output.first);
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00004241 std::vector<unsigned int> shape = m_OverridenOutputShapes.size() > 0 ?
4242 m_OverridenOutputShapes[i] : AsUnsignedVector(output.second->shape);
4243 return std::make_pair(bindingId, ToTensorInfo(output.second, shape));
telsoa01c577f2c2018-08-31 09:22:23 +01004244 }
4245 }
4246
4247 std::stringstream bindings;
4248 for (auto const & output : outputs)
4249 {
4250 bindings << "'" << output.second->name << "' ";
4251 }
4252
4253 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01004254 fmt::format("No output binding found for subgraph:{} and name:{}. "
4255 "Possible outputs are: [{}] {}",
4256 subgraphId,
4257 name,
4258 bindings.str(),
4259 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01004260}
4261
Kevin May7d96b162021-02-03 17:38:41 +00004262size_t TfLiteParserImpl::GetSubgraphCount() const
telsoa01c577f2c2018-08-31 09:22:23 +01004263{
4264 return m_Model->subgraphs.size();
4265}
4266
Kevin May7d96b162021-02-03 17:38:41 +00004267std::vector<std::string> TfLiteParserImpl::GetSubgraphInputTensorNames(size_t subgraphId) const
telsoa01c577f2c2018-08-31 09:22:23 +01004268{
4269 CHECK_SUBGRAPH(m_Model, subgraphId);
4270 auto inputs = GetSubgraphInputs(m_Model, subgraphId);
4271 std::vector<std::string> result;
4272 result.reserve(inputs.size());
4273 for (auto const & input : inputs)
4274 {
4275 result.push_back(input.second->name);
4276 }
4277 return result;
4278}
4279
Kevin May7d96b162021-02-03 17:38:41 +00004280std::vector<std::string> TfLiteParserImpl::GetSubgraphOutputTensorNames(size_t subgraphId) const
telsoa01c577f2c2018-08-31 09:22:23 +01004281{
4282 CHECK_SUBGRAPH(m_Model, subgraphId);
4283 auto outputs = GetSubgraphOutputs(m_Model, subgraphId);
4284 std::vector<std::string> result;
4285 result.reserve(outputs.size());
4286 for (auto const & output : outputs)
4287 {
4288 result.push_back(output.second->name);
4289 }
4290 return result;
4291}
4292
Matthew Sloyanac001ee2021-02-03 10:43:04 +00004293const std::string TfLiteParserImpl::GetVersion()
4294{
4295 return TFLITE_PARSER_VERSION;
4296}
4297
Kevin May7d96b162021-02-03 17:38:41 +00004298TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<float[]> && data)
telsoa01c577f2c2018-08-31 09:22:23 +01004299: m_FloatData(std::move(data))
4300, m_Uint8Data(nullptr)
Keith Davisd305e1a2020-01-22 11:57:54 +00004301, m_Int8Data(nullptr)
telsoa01c577f2c2018-08-31 09:22:23 +01004302, m_Int32Data(nullptr)
4303{
4304}
4305
Kevin May7d96b162021-02-03 17:38:41 +00004306TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<uint8_t[]> && data)
telsoa01c577f2c2018-08-31 09:22:23 +01004307: m_FloatData(nullptr)
4308, m_Uint8Data(std::move(data))
Keith Davisd305e1a2020-01-22 11:57:54 +00004309, m_Int8Data(nullptr)
4310, m_Int32Data(nullptr)
4311{
4312}
4313
Kevin May7d96b162021-02-03 17:38:41 +00004314TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<int8_t[]> && data)
Keith Davisd305e1a2020-01-22 11:57:54 +00004315: m_FloatData(nullptr)
4316, m_Uint8Data(nullptr)
4317, m_Int8Data(std::move(data))
telsoa01c577f2c2018-08-31 09:22:23 +01004318, m_Int32Data(nullptr)
4319{
4320}
4321
Kevin May7d96b162021-02-03 17:38:41 +00004322TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<int32_t[]> && data)
telsoa01c577f2c2018-08-31 09:22:23 +01004323: m_FloatData(nullptr)
4324, m_Uint8Data(nullptr)
Keith Davisd305e1a2020-01-22 11:57:54 +00004325, m_Int8Data(nullptr)
telsoa01c577f2c2018-08-31 09:22:23 +01004326, m_Int32Data(std::move(data))
4327{
4328}
4329
4330} // armnnTfLiteParser