blob: d4a0a6e865d66ba8e7a9eec0caa5756149622883 [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>
Francis Murtagh532a29d2020-06-29 11:50:01 +010023#include <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,
Sadik Armagand109a4d2020-07-28 10:42:13 +0100366 const std::vector<unsigned int>& shapes,
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 }
Narumol Prangnawarat4818d462019-04-17 11:22:38 +0100415 std::vector<unsigned int> safeShape = shapes;
Sadik Armagand109a4d2020-07-28 10:42:13 +0100416 bool isDynamic = false;
Narumol Prangnawarat4818d462019-04-17 11:22:38 +0100417 if (safeShape.size() == 0)
418 {
419 safeShape.push_back(1);
Sadik Armagand109a4d2020-07-28 10:42:13 +0100420 if (outputTensor)
421 {
422 isDynamic = true;
423 }
Narumol Prangnawarat4818d462019-04-17 11:22:38 +0100424 }
425
Keith Davisd305e1a2020-01-22 11:57:54 +0000426 float quantizationScale = 0.0f;
427 int32_t quantizationOffset = 0;
428
429 if (tensorPtr->quantization.get())
430 {
431 if (tensorPtr->quantization->scale.size() <= 1)
432 {
433 CHECK_VALID_SIZE(tensorPtr->quantization->zero_point.size(), 0, 1);
434 CHECK_VALID_SIZE(tensorPtr->quantization->zero_point.size(), 0, 1);
435
436 if (tensorPtr->quantization->scale.size() == 1)
437 {
438 quantizationScale = tensorPtr->quantization->scale[0];
439 }
440 if (tensorPtr->quantization->zero_point.size() == 1)
441 {
442 // NOTE: we lose precision here when converting from 64 bit to 32
Ryan OShea03181ff2020-02-07 17:22:22 +0000443 // but this is what we support at the moment in ArmNN
Matthew Sloyan589e3e82020-09-11 16:17:48 +0100444 quantizationOffset = armnn::numeric_cast<int32_t>(tensorPtr->quantization->zero_point[0]);
Keith Davisd305e1a2020-01-22 11:57:54 +0000445 }
446
Matthew Sloyan589e3e82020-09-11 16:17:48 +0100447 TensorShape tensorShape(armnn::numeric_cast<unsigned int>(safeShape.size()),
Sadik Armagand109a4d2020-07-28 10:42:13 +0100448 safeShape.data());
449 if (isDynamic)
450 {
451 tensorShape = TensorShape(1, false);
452 }
453 armnn::TensorInfo result(tensorShape,
454 type,
455 quantizationScale,
456 quantizationOffset);
Keith Davisd305e1a2020-01-22 11:57:54 +0000457 return result;
458 }
459 else
460 {
461 std::vector<float> quantizationScales;
462 std::vector<int32_t> quantizationOffsets;
463
464 // Scale
465 std::copy(tensorPtr->quantization->scale.begin(),
466 tensorPtr->quantization->scale.end(),
467 std::back_inserter(quantizationScales));
468
Keith Davis0c2eeac2020-02-11 16:51:50 +0000469 // QSymmS8 Per-axis
Matthew Sloyan589e3e82020-09-11 16:17:48 +0100470 TensorShape tensorShape(armnn::numeric_cast<unsigned int>(safeShape.size()),
Sadik Armagand109a4d2020-07-28 10:42:13 +0100471 safeShape.data());
472 if (isDynamic)
473 {
474 tensorShape = TensorShape(1, false);
475 }
476 armnn::TensorInfo result(tensorShape,
477 type,
478 quantizationScales,
Jan Eilers7612bd62021-04-06 17:29:03 +0100479 armnn::numeric_cast<unsigned int>(tensorPtr->quantization->quantized_dimension));
Keith Davisd305e1a2020-01-22 11:57:54 +0000480 return result;
481 }
482 }
483 else
484 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +0100485 TensorShape tensorShape(armnn::numeric_cast<unsigned int>(safeShape.size()),
Sadik Armagand109a4d2020-07-28 10:42:13 +0100486 safeShape.data());
487 if (isDynamic)
488 {
489 tensorShape = TensorShape(1, false);
490 }
491 armnn::TensorInfo result(tensorShape,
Keith Davisd305e1a2020-01-22 11:57:54 +0000492 type,
493 quantizationScale,
494 quantizationOffset);
495 return result;
496 }
telsoa01c577f2c2018-08-31 09:22:23 +0100497}
498
Jan Eilers7612bd62021-04-06 17:29:03 +0100499armnn::TensorInfo ToTensorInfo(TfLiteParserImpl::TensorRawPtr tensorPtr)
Narumol Prangnawarat4628d052019-02-25 17:26:05 +0000500{
501 auto const & dimensions = AsUnsignedVector(tensorPtr->shape);
Jan Eilers7612bd62021-04-06 17:29:03 +0100502 return ToTensorInfo(tensorPtr, dimensions);
Narumol Prangnawarat4628d052019-02-25 17:26:05 +0000503}
504
Kevin May7d96b162021-02-03 17:38:41 +0000505armnn::TensorInfo ToTensorInfo(TfLiteParserImpl::TensorRawPtr tensorPtr,
Sadik Armagand109a4d2020-07-28 10:42:13 +0100506 const bool outputTensor)
507{
508 auto const & dimensions = AsUnsignedVector(tensorPtr->shape);
Jan Eilers7612bd62021-04-06 17:29:03 +0100509 return ToTensorInfo(tensorPtr, dimensions, outputTensor);
Sadik Armagand109a4d2020-07-28 10:42:13 +0100510}
511
telsoa01c577f2c2018-08-31 09:22:23 +0100512template<typename T>
513std::pair<armnn::ConstTensor, std::unique_ptr<T[]>>
Kevin May7d96b162021-02-03 17:38:41 +0000514CreateConstTensorImpl(TfLiteParserImpl::BufferRawPtr bufferPtr,
515 TfLiteParserImpl::TensorRawPtr tensorPtr,
Matteo Martincigh747ef822018-12-18 09:26:39 +0000516 armnn::TensorInfo& tensorInfo,
517 armnn::Optional<armnn::PermutationVector&> permutationVector)
telsoa01c577f2c2018-08-31 09:22:23 +0100518{
Jan Eilers8eb25602020-03-09 12:13:48 +0000519 IgnoreUnused(tensorPtr);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100520 ARMNN_ASSERT_MSG(tensorPtr != nullptr, "tensorPtr is null");
521 ARMNN_ASSERT_MSG(bufferPtr != nullptr,
James Ward58dec6b2020-09-11 17:32:44 +0100522 fmt::format("Buffer for buffer:{} is null", tensorPtr->buffer).c_str());
telsoa01c577f2c2018-08-31 09:22:23 +0100523
524 std::unique_ptr<T[]> data(new T[tensorInfo.GetNumElements()]);
Matteo Martincigh747ef822018-12-18 09:26:39 +0000525
526 if (permutationVector.has_value() && permutationVector.value().GetSize() > 0)
527 {
528 tensorInfo = armnnUtils::Permuted(tensorInfo, permutationVector.value());
Matteo Martincighd5b9e642019-01-04 18:01:21 +0000529 armnnUtils::Permute(tensorInfo.GetShape(), permutationVector.value(),
530 reinterpret_cast<const T*>(bufferPtr->data.data()), data.get(), sizeof(T));
Matteo Martincigh747ef822018-12-18 09:26:39 +0000531 }
532 else
533 {
534 ::memcpy(data.get(), bufferPtr->data.data(), tensorInfo.GetNumBytes());
535 }
536
telsoa01c577f2c2018-08-31 09:22:23 +0100537 return std::make_pair(ConstTensor(tensorInfo, data.get()), std::move(data));
538}
539
telsoa01c577f2c2018-08-31 09:22:23 +0100540armnn::LayerBindingId GenerateLayerBindingId(size_t subgraphIndex, size_t tensorIndex)
541{
542 // generate the binding id by shifting the tensor id by 8 bit
543 // and add the subgraph id, which allows 256 subgraphs
544 return static_cast<armnn::LayerBindingId>((tensorIndex<<8)+subgraphIndex);
545}
546
Aron Virginas-Tar70672f62019-01-23 14:00:00 +0000547bool CheckShape(const armnn::TensorShape& actual, const std::vector<int32_t>& expected)
548{
549 const unsigned int actualSize = actual.GetNumDimensions();
550 if (actualSize != expected.size())
551 {
552 return false;
553 }
554
555 for (unsigned int i = 0u; i < actualSize; i++)
556 {
557 if (expected[i] < 0 ||
558 actual[i] != static_cast<unsigned int>(expected[i]))
559 {
560 return false;
561 }
562 }
563
564 return true;
565}
566
James Conroy05102392020-06-24 15:39:55 +0100567void CheckMatchingQuantization(const TensorInfo& first,
568 const TensorInfo& second,
569 const std::string& descName,
570 std::string const& firstName,
571 std::string const& secondName)
572{
573 if (!first.IsQuantized() ||
574 !second.IsQuantized())
575 {
576 // Not a quantized type, ignore the validation
577 return;
578 }
579
580 DataType firstDataType = first.GetDataType();
581 DataType secondDataType = second.GetDataType();
582
583 if (firstDataType != secondDataType)
584 {
585 throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
586 " must be of the same quantized type, " +
587 firstName + " is " + GetDataTypeName(firstDataType) + ", " +
588 secondName + " is " + GetDataTypeName(secondDataType));
589 }
590
591 if (!first.IsTypeSpaceMatch(second))
592 {
593 throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
594 " must have the same quantization space, " +
595 firstName + " has offset " + std::to_string(first.GetQuantizationOffset()) +
596 " and scale " + std::to_string(first.GetQuantizationScale()) + ", " +
597 secondName + " has offset " + std::to_string(second.GetQuantizationOffset()) +
598 " and scale " + std::to_string(second.GetQuantizationScale()));
599 }
600}
601
telsoa01c577f2c2018-08-31 09:22:23 +0100602} // <anonymous>
603
Kevin May7d96b162021-02-03 17:38:41 +0000604TfLiteParserImpl::TfLiteParserImpl(const Optional<ITfLiteParser::TfLiteParserOptions>& options)
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100605: m_Options(options)
606, m_Network(nullptr, nullptr)
Kevin May7d96b162021-02-03 17:38:41 +0000607, m_ParserFunctions(tflite::BuiltinOperator_MAX+1, &TfLiteParserImpl::ParseUnsupportedOperator)
telsoa01c577f2c2018-08-31 09:22:23 +0100608{
609 // register supported operators
Matthew Sloyaned7fce42021-04-15 20:46:24 +0100610 m_ParserFunctions[tflite::BuiltinOperator_ABS] = &TfLiteParserImpl::ParseAbs;
Kevin May7d96b162021-02-03 17:38:41 +0000611 m_ParserFunctions[tflite::BuiltinOperator_ADD] = &TfLiteParserImpl::ParseAdd;
Matthew Sloyan28f177c2021-04-09 14:38:52 +0100612 m_ParserFunctions[tflite::BuiltinOperator_ARG_MIN] = &TfLiteParserImpl::ParseArgMin;
613 m_ParserFunctions[tflite::BuiltinOperator_ARG_MAX] = &TfLiteParserImpl::ParseArgMax;
Kevin May7d96b162021-02-03 17:38:41 +0000614 m_ParserFunctions[tflite::BuiltinOperator_AVERAGE_POOL_2D] = &TfLiteParserImpl::ParseAveragePool2D;
615 m_ParserFunctions[tflite::BuiltinOperator_BATCH_TO_SPACE_ND] = &TfLiteParserImpl::ParseBatchToSpaceND;
mathad01b392e982021-04-07 12:07:30 +0100616 m_ParserFunctions[tflite::BuiltinOperator_CAST] = &TfLiteParserImpl::ParseCast;
Kevin May7d96b162021-02-03 17:38:41 +0000617 m_ParserFunctions[tflite::BuiltinOperator_CONCATENATION] = &TfLiteParserImpl::ParseConcatenation;
618 m_ParserFunctions[tflite::BuiltinOperator_CONV_2D] = &TfLiteParserImpl::ParseConv2D;
619 m_ParserFunctions[tflite::BuiltinOperator_CUSTOM] = &TfLiteParserImpl::ParseCustomOperator;
620 m_ParserFunctions[tflite::BuiltinOperator_DEPTH_TO_SPACE] = &TfLiteParserImpl::ParseDepthToSpace;
621 m_ParserFunctions[tflite::BuiltinOperator_DEPTHWISE_CONV_2D] = &TfLiteParserImpl::ParseDepthwiseConv2D;
622 m_ParserFunctions[tflite::BuiltinOperator_DEQUANTIZE] = &TfLiteParserImpl::ParseDequantize;
Matthew Sloyan28f177c2021-04-09 14:38:52 +0100623 m_ParserFunctions[tflite::BuiltinOperator_DIV] = &TfLiteParserImpl::ParseDiv;
Kevin May7d96b162021-02-03 17:38:41 +0000624 m_ParserFunctions[tflite::BuiltinOperator_ELU] = &TfLiteParserImpl::ParseElu;
625 m_ParserFunctions[tflite::BuiltinOperator_EXP] = &TfLiteParserImpl::ParseExp;
626 m_ParserFunctions[tflite::BuiltinOperator_FULLY_CONNECTED] = &TfLiteParserImpl::ParseFullyConnected;
627 m_ParserFunctions[tflite::BuiltinOperator_GATHER] = &TfLiteParserImpl::ParseGather;
628 m_ParserFunctions[tflite::BuiltinOperator_HARD_SWISH] = &TfLiteParserImpl::ParseHardSwish;
629 m_ParserFunctions[tflite::BuiltinOperator_LEAKY_RELU] = &TfLiteParserImpl::ParseLeakyRelu;
Matthew Sloyaned7fce42021-04-15 20:46:24 +0100630 m_ParserFunctions[tflite::BuiltinOperator_LOGICAL_NOT] = &TfLiteParserImpl::ParseLogicalNot;
Kevin May7d96b162021-02-03 17:38:41 +0000631 m_ParserFunctions[tflite::BuiltinOperator_LOGISTIC] = &TfLiteParserImpl::ParseLogistic;
632 m_ParserFunctions[tflite::BuiltinOperator_L2_NORMALIZATION] = &TfLiteParserImpl::ParseL2Normalization;
633 m_ParserFunctions[tflite::BuiltinOperator_MAX_POOL_2D] = &TfLiteParserImpl::ParseMaxPool2D;
634 m_ParserFunctions[tflite::BuiltinOperator_MAXIMUM] = &TfLiteParserImpl::ParseMaximum;
635 m_ParserFunctions[tflite::BuiltinOperator_MEAN] = &TfLiteParserImpl::ParseMean;
636 m_ParserFunctions[tflite::BuiltinOperator_MINIMUM] = &TfLiteParserImpl::ParseMinimum;
637 m_ParserFunctions[tflite::BuiltinOperator_MUL] = &TfLiteParserImpl::ParseMul;
638 m_ParserFunctions[tflite::BuiltinOperator_NEG] = &TfLiteParserImpl::ParseNeg;
639 m_ParserFunctions[tflite::BuiltinOperator_PACK] = &TfLiteParserImpl::ParsePack;
640 m_ParserFunctions[tflite::BuiltinOperator_PAD] = &TfLiteParserImpl::ParsePad;
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +0100641 m_ParserFunctions[tflite::BuiltinOperator_PRELU] = &TfLiteParserImpl::ParsePrelu;
Kevin May7d96b162021-02-03 17:38:41 +0000642 m_ParserFunctions[tflite::BuiltinOperator_QUANTIZE] = &TfLiteParserImpl::ParseQuantize;
643 m_ParserFunctions[tflite::BuiltinOperator_RELU] = &TfLiteParserImpl::ParseRelu;
644 m_ParserFunctions[tflite::BuiltinOperator_RELU6] = &TfLiteParserImpl::ParseRelu6;
Sadik Armagana2747482021-02-09 10:28:54 +0000645 m_ParserFunctions[tflite::BuiltinOperator_REDUCE_MAX] = &TfLiteParserImpl::ParseReduceMax;
646 m_ParserFunctions[tflite::BuiltinOperator_REDUCE_MIN] = &TfLiteParserImpl::ParseReduceMin;
Kevin May7d96b162021-02-03 17:38:41 +0000647 m_ParserFunctions[tflite::BuiltinOperator_RESHAPE] = &TfLiteParserImpl::ParseReshape;
648 m_ParserFunctions[tflite::BuiltinOperator_RESIZE_BILINEAR] = &TfLiteParserImpl::ParseResizeBilinear;
649 m_ParserFunctions[tflite::BuiltinOperator_RESIZE_NEAREST_NEIGHBOR] = &TfLiteParserImpl::ParseResizeNearestNeighbor;
Matthew Sloyaned7fce42021-04-15 20:46:24 +0100650 m_ParserFunctions[tflite::BuiltinOperator_RSQRT] = &TfLiteParserImpl::ParseRsqrt;
Kevin May7d96b162021-02-03 17:38:41 +0000651 m_ParserFunctions[tflite::BuiltinOperator_SLICE] = &TfLiteParserImpl::ParseSlice;
652 m_ParserFunctions[tflite::BuiltinOperator_SOFTMAX] = &TfLiteParserImpl::ParseSoftmax;
653 m_ParserFunctions[tflite::BuiltinOperator_SPACE_TO_BATCH_ND] = &TfLiteParserImpl::ParseSpaceToBatchND;
654 m_ParserFunctions[tflite::BuiltinOperator_SPLIT] = &TfLiteParserImpl::ParseSplit;
655 m_ParserFunctions[tflite::BuiltinOperator_SPLIT_V] = &TfLiteParserImpl::ParseSplitV;
656 m_ParserFunctions[tflite::BuiltinOperator_SQUEEZE] = &TfLiteParserImpl::ParseSqueeze;
657 m_ParserFunctions[tflite::BuiltinOperator_STRIDED_SLICE] = &TfLiteParserImpl::ParseStridedSlice;
658 m_ParserFunctions[tflite::BuiltinOperator_SUB] = &TfLiteParserImpl::ParseSub;
659 m_ParserFunctions[tflite::BuiltinOperator_SUM] = &TfLiteParserImpl::ParseSum;
660 m_ParserFunctions[tflite::BuiltinOperator_TANH] = &TfLiteParserImpl::ParseTanH;
661 m_ParserFunctions[tflite::BuiltinOperator_TRANSPOSE] = &TfLiteParserImpl::ParseTranspose;
662 m_ParserFunctions[tflite::BuiltinOperator_TRANSPOSE_CONV] = &TfLiteParserImpl::ParseTransposeConv;
663 m_ParserFunctions[tflite::BuiltinOperator_UNPACK] = &TfLiteParserImpl::ParseUnpack;
Matthew Sloyan28f177c2021-04-09 14:38:52 +0100664
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100665 // register supported custom operators
Kevin May7d96b162021-02-03 17:38:41 +0000666 m_CustomParserFunctions["TFLite_Detection_PostProcess"] = &TfLiteParserImpl::ParseDetectionPostProcess;
telsoa01c577f2c2018-08-31 09:22:23 +0100667}
668
Kevin May7d96b162021-02-03 17:38:41 +0000669void TfLiteParserImpl::ResetParser()
telsoa01c577f2c2018-08-31 09:22:23 +0100670{
671 m_Network = armnn::INetworkPtr(nullptr, nullptr);
672 m_Model = nullptr;
673 m_SubgraphConnections.clear();
674}
675
Kevin May7d96b162021-02-03 17:38:41 +0000676INetworkPtr TfLiteParserImpl::CreateNetworkFromBinaryFile(const char* graphFile)
telsoa01c577f2c2018-08-31 09:22:23 +0100677{
678 ResetParser();
679 m_Model = LoadModelFromFile(graphFile);
680 return CreateNetworkFromModel();
681}
682
Kevin May7d96b162021-02-03 17:38:41 +0000683INetworkPtr TfLiteParserImpl::CreateNetworkFromBinary(const std::vector<uint8_t> & binaryContent)
telsoa01c577f2c2018-08-31 09:22:23 +0100684{
685 ResetParser();
686 m_Model = LoadModelFromBinary(binaryContent.data(), binaryContent.size());
687 return CreateNetworkFromModel();
688}
689
Kevin May7d96b162021-02-03 17:38:41 +0000690INetworkPtr TfLiteParserImpl::CreateNetworkFromModel()
telsoa01c577f2c2018-08-31 09:22:23 +0100691{
Sadik Armagand109a4d2020-07-28 10:42:13 +0100692
693 using NetworkOptions = std::vector<BackendOptions>;
694 NetworkOptions networkOptions = {};
695 if (m_Options && m_Options.value().m_InferAndValidate)
696 {
697 BackendOptions shapeInferenceMethodOption("ShapeInferenceMethod",
698 {
699 { "InferAndValidate", true }
700 });
701
702 networkOptions.push_back(shapeInferenceMethodOption);
703 }
704
705 m_Network = INetwork::Create(networkOptions);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100706 ARMNN_ASSERT(m_Model.get() != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +0100707
telsoa01c577f2c2018-08-31 09:22:23 +0100708 if (m_Model->subgraphs.size() != 1)
709 {
710 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100711 fmt::format("Current TfLite parser only supports 1 subgraph. Current one has: {} {}",
712 m_Model->subgraphs.size(),
713 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +0100714 }
715
716 size_t subgraphIndex = 0;
Colm Donelan6350d272020-06-09 16:56:25 +0100717 size_t operatorIndex = 0;
718 try
telsoa01c577f2c2018-08-31 09:22:23 +0100719 {
Colm Donelan6350d272020-06-09 16:56:25 +0100720 for (SubgraphPtr const& subgraph : m_Model->subgraphs)
telsoa01c577f2c2018-08-31 09:22:23 +0100721 {
Colm Donelan6350d272020-06-09 16:56:25 +0100722 m_SubgraphConnections.emplace_back(subgraph->tensors.size());
723 for (OperatorPtr const& op : subgraph->operators)
telsoa01c577f2c2018-08-31 09:22:23 +0100724 {
Colm Donelan6350d272020-06-09 16:56:25 +0100725 auto const& opCodePtr = m_Model->operator_codes[op->opcode_index];
telsoa01c577f2c2018-08-31 09:22:23 +0100726 auto builtinCode = opCodePtr->builtin_code;
727
728 if (builtinCode > tflite::BuiltinOperator_MAX)
729 {
James Ward58dec6b2020-09-11 17:32:44 +0100730 throw ParseException(fmt::format("Operator code {} is out of range 0-{}. "
731 "subgraph:{} operator idx:{}. {}",
732 builtinCode, tflite::BuiltinOperator_MAX, subgraphIndex,
733 operatorIndex, CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +0100734 }
735
736 // lookup and call the parser function
Colm Donelan6350d272020-06-09 16:56:25 +0100737 auto& parserFunction = m_ParserFunctions[builtinCode];
telsoa01c577f2c2018-08-31 09:22:23 +0100738 (this->*parserFunction)(subgraphIndex, operatorIndex);
Colm Donelan6350d272020-06-09 16:56:25 +0100739 ++operatorIndex;
telsoa01c577f2c2018-08-31 09:22:23 +0100740 }
telsoa01c577f2c2018-08-31 09:22:23 +0100741
Colm Donelan6350d272020-06-09 16:56:25 +0100742 SetupInputLayers(subgraphIndex);
743 SetupOutputLayers(subgraphIndex);
744 SetupConstantLayers(subgraphIndex);
telsoa01c577f2c2018-08-31 09:22:23 +0100745
Colm Donelan6350d272020-06-09 16:56:25 +0100746 ++subgraphIndex;
747 operatorIndex = 0;
telsoa01c577f2c2018-08-31 09:22:23 +0100748 }
telsoa01c577f2c2018-08-31 09:22:23 +0100749 }
Colm Donelan6350d272020-06-09 16:56:25 +0100750 catch (const ParseException& e)
telsoa01c577f2c2018-08-31 09:22:23 +0100751 {
Colm Donelan6350d272020-06-09 16:56:25 +0100752 std::stringstream errorString;
753 errorString << "Failed to parse operator #" << operatorIndex << " within subgraph #"
754 << subgraphIndex << " error: " << e.what();
755 ARMNN_LOG(error) << errorString.str();
756 std::stringstream errors;
757 errors << errorString.str() << "\n";
telsoa01c577f2c2018-08-31 09:22:23 +0100758 throw ParseException(errors.str());
759 }
760
761 // establish the connections from the layer outputs to the inputs of the subsequent layers
Colm Donelan6350d272020-06-09 16:56:25 +0100762 for (subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +0100763 {
764 for (size_t tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex)
765 {
766 if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot != nullptr)
767 {
768 for (size_t inputSlotIdx = 0;
769 inputSlotIdx < m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size();
770 ++inputSlotIdx)
771 {
772 m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot->Connect(
773 *(m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots[inputSlotIdx]));
774 }
775 }
776 }
777 }
778
779 return std::move(m_Network);
780}
781
Kevin May7d96b162021-02-03 17:38:41 +0000782void TfLiteParserImpl::RegisterProducerOfTensor(size_t subgraphIndex,
783 size_t tensorIndex,
784 armnn::IOutputSlot* slot)
telsoa01c577f2c2018-08-31 09:22:23 +0100785{
786 CHECK_TENSOR(m_Model, subgraphIndex, tensorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100787 ARMNN_ASSERT(m_SubgraphConnections.size() > subgraphIndex);
788 ARMNN_ASSERT(m_SubgraphConnections[subgraphIndex].size() > tensorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +0100789
790 TensorSlots & tensorSlots = m_SubgraphConnections[subgraphIndex][tensorIndex];
791
792 // assuming there is only one producer for that tensor
793 if (tensorSlots.outputSlot != nullptr)
794 {
James Ward58dec6b2020-09-11 17:32:44 +0100795 throw ParseException(fmt::format("Another layer has already registered itself as the producer of "
796 "subgraph:{} tensor:{} {}",
797 subgraphIndex,
798 tensorIndex,
799 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +0100800 }
801
802 tensorSlots.outputSlot = slot;
803}
804
Kevin May7d96b162021-02-03 17:38:41 +0000805void TfLiteParserImpl::RegisterConsumerOfTensor(size_t subgraphIndex,
806 size_t tensorIndex,
807 armnn::IInputSlot* slot)
telsoa01c577f2c2018-08-31 09:22:23 +0100808{
809 CHECK_TENSOR(m_Model, subgraphIndex, tensorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100810 ARMNN_ASSERT(m_SubgraphConnections.size() > subgraphIndex);
811 ARMNN_ASSERT(m_SubgraphConnections[subgraphIndex].size() > tensorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +0100812
Finn Williamsd4fa5452021-03-01 12:31:41 +0000813 TensorSlots& tensorSlots = m_SubgraphConnections[subgraphIndex][tensorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +0100814 tensorSlots.inputSlots.push_back(slot);
815}
816
Kevin May7d96b162021-02-03 17:38:41 +0000817void TfLiteParserImpl::ParseCustomOperator(size_t subgraphIndex, size_t operatorIndex)
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100818{
819 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
820
821 // NOTE: By default we presume the custom operator is not supported
Kevin May7d96b162021-02-03 17:38:41 +0000822 auto customParserFunction = &TfLiteParserImpl::ParseUnsupportedOperator;
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100823
824 // Identify custom code defined for custom operator
825 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
826 const auto& customCode = m_Model->operator_codes[operatorPtr->opcode_index]->custom_code;
827
828 // Find parser function that correspondes to custom code (if any)
829 auto iterator = m_CustomParserFunctions.find(customCode);
830 if (iterator != m_CustomParserFunctions.end())
831 {
832 customParserFunction = iterator->second;
833 }
834
835 // Run parser function
836 (this->*customParserFunction)(subgraphIndex, operatorIndex);
837}
838
Kevin May7d96b162021-02-03 17:38:41 +0000839void TfLiteParserImpl::ParseUnsupportedOperator(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +0100840{
841 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +0100842
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100843 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
844
845 auto opcodeIndex = operatorPtr->opcode_index;
846 auto opcode = m_Model->operator_codes[opcodeIndex]->builtin_code;
847
848 if (!m_Options || !m_Options.value().m_StandInLayerForUnsupported)
849 {
850 // Do not add StandInLayer, throw ParseException instead
851 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +0100852 fmt::format("Operator not supported. "
853 "subgraph:{} operator:{} "
854 "opcode_index:{} opcode:{} / {} {}",
855 subgraphIndex,
856 operatorIndex,
857 opcodeIndex,
858 opcode,
859 tflite::EnumNameBuiltinOperator(opcode),
860 CHECK_LOCATION().AsString()));
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100861 }
862
863 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
864 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
865
Matthew Sloyan589e3e82020-09-11 16:17:48 +0100866 const unsigned int numInputs = armnn::numeric_cast<unsigned int>(inputs.size());
867 const unsigned int numOutputs = armnn::numeric_cast<unsigned int>(outputs.size());
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100868
869 StandInDescriptor descriptor(numInputs, numOutputs);
James Ward58dec6b2020-09-11 17:32:44 +0100870 auto layerName = fmt::format("StandIn:{}:{}:{}", subgraphIndex, operatorIndex, opcode);
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100871
872 // Add a non-executable StandInLayer as a placeholder for any unsupported operator
873 IConnectableLayer* layer = m_Network->AddStandInLayer(descriptor, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +0100874 ARMNN_ASSERT(layer != nullptr);
875
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100876 for (unsigned int i = 0u; i < numOutputs; ++i)
877 {
Sadik Armagand109a4d2020-07-28 10:42:13 +0100878 layer->GetOutputSlot(i).SetTensorInfo(ToTensorInfo(outputs[i], true));
Aron Virginas-Tarc975f922019-10-23 17:38:17 +0100879 }
880
881 auto inputTensorIds = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
882 auto outputTensorIds = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
883
884 RegisterInputSlots(subgraphIndex, operatorIndex, layer, inputTensorIds);
885 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIds);
telsoa01c577f2c2018-08-31 09:22:23 +0100886}
887
mathad01b392e982021-04-07 12:07:30 +0100888void TfLiteParserImpl::ParseCast(size_t subgraphIndex, size_t operatorIndex)
889{
890 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
891
892 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
893 CHECK_VALID_SIZE(inputs.size(), 1);
894 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
895 CHECK_VALID_SIZE(outputs.size(), 1);
896
897 auto layerName = fmt::format("Cast:{}:{}", subgraphIndex, operatorIndex);
898
899 IConnectableLayer* layer = m_Network->AddCastLayer(layerName.c_str());
900 ARMNN_ASSERT(layer != nullptr);
901
902 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
903 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
904
905 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
906 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
907
908 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
909 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
910}
911
Kevin May7d96b162021-02-03 17:38:41 +0000912void TfLiteParserImpl::ParseConv2D(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +0100913{
914 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
915
916 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
917 const auto * options = operatorPtr->builtin_options.AsConv2DOptions();
918
919 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
920
921 Convolution2dDescriptor desc;
922 desc.m_BiasEnabled = false;
923 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
924 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
jimfly01c25411c2018-11-14 17:47:22 +0000925 desc.m_DataLayout = armnn::DataLayout::NHWC;
Pablo Tellof0bd6832019-04-26 17:58:13 +0100926 desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
927 desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
Kevin May83add212019-03-26 11:39:19 +0000928
telsoa01c577f2c2018-08-31 09:22:23 +0100929 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
930 CHECK_VALID_SIZE(inputs.size(), 2, 3);
931
932 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
933 CHECK_VALID_SIZE(outputs.size(), 1);
934
935 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
936 armnn::TensorInfo filterTensorInfo = ToTensorInfo(inputs[1]);
937
938 // assuming input is NHWC
939 unsigned int inputHeight = inputTensorInfo.GetShape()[1];
940 unsigned int inputWidth = inputTensorInfo.GetShape()[2];
941
942 // assuming the filter is OHWI : Output, H, W, Input
943 // which is essentially the same as NHWC
944 unsigned int filterHeight = filterTensorInfo.GetShape()[1];
945 unsigned int filterWidth = filterTensorInfo.GetShape()[2];
946
Pablo Tellof0bd6832019-04-26 17:58:13 +0100947 CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
948 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
949 CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
950 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
telsoa01c577f2c2018-08-31 09:22:23 +0100951
Finn Williamsd4fa5452021-03-01 12:31:41 +0000952 auto filterTensorAndData = CreateConstTensorNonPermuted(inputs[1], filterTensorInfo);
Matthew Jackson74bf7da2019-08-16 16:51:42 +0100953 armnn::IConnectableLayer* layer = nullptr;
telsoa01c577f2c2018-08-31 09:22:23 +0100954
James Ward58dec6b2020-09-11 17:32:44 +0100955 auto layerName = fmt::format("Conv2D:{}:{}", subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +0100956
957 if (inputs.size() == 3)
958 {
959 desc.m_BiasEnabled = true;
960 armnn::TensorInfo biasTensorInfo = ToTensorInfo(inputs[2]);
Finn Williamsd4fa5452021-03-01 12:31:41 +0000961 auto biasTensorAndData = CreateConstTensorNonPermuted(inputs[2], biasTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +0100962 layer = m_Network->AddConvolution2dLayer(desc,
Finn Williamsd4fa5452021-03-01 12:31:41 +0000963 filterTensorAndData,
964 Optional<ConstTensor>(biasTensorAndData),
telsoa01c577f2c2018-08-31 09:22:23 +0100965 layerName.c_str());
966 }
967 else
968 {
969 layer = m_Network->AddConvolution2dLayer(desc,
Finn Williamsd4fa5452021-03-01 12:31:41 +0000970 filterTensorAndData,
Matteo Martincighfc598e12019-05-14 10:36:13 +0100971 EmptyOptional(),
telsoa01c577f2c2018-08-31 09:22:23 +0100972 layerName.c_str());
973 }
974
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100975 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +0100976
Sadik Armagand109a4d2020-07-28 10:42:13 +0100977 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
jimfly01c25411c2018-11-14 17:47:22 +0000978 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +0100979
980 // register the input connection slots for the layer, connections are made after all layers have been created
981 // only the tensors for the inputs are relevant, exclude the const tensors
982 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
jimfly01c25411c2018-11-14 17:47:22 +0000983 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
telsoa01c577f2c2018-08-31 09:22:23 +0100984
jimfly01c25411c2018-11-14 17:47:22 +0000985 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
telsoa01c577f2c2018-08-31 09:22:23 +0100986 // register the output connection slots for the layer, connections are made after all layers have been created
987 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
988 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
989}
990
Kevin May7d96b162021-02-03 17:38:41 +0000991void TfLiteParserImpl::ParseDepthwiseConv2D(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +0100992{
993 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
994
995 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
996 const auto * options = operatorPtr->builtin_options.AsDepthwiseConv2DOptions();
997
998 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
999
1000 DepthwiseConvolution2dDescriptor desc;
1001 desc.m_BiasEnabled = false;
1002 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1003 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
jimfly01c25411c2018-11-14 17:47:22 +00001004 desc.m_DataLayout = armnn::DataLayout::NHWC;
Matthew Jacksond6a9dee2019-07-22 13:53:24 +01001005 CHECKED_NON_NEGATIVE(options->depth_multiplier);
telsoa01c577f2c2018-08-31 09:22:23 +01001006
1007 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1008 CHECK_VALID_SIZE(inputs.size(), 2, 3);
1009 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1010 CHECK_VALID_SIZE(outputs.size(), 1);
Pablo Tellof0bd6832019-04-26 17:58:13 +01001011 desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
1012 desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
Kevin May83add212019-03-26 11:39:19 +00001013
Keith Davis0c2eeac2020-02-11 16:51:50 +00001014 // Mappings from TensorflowLite filter tensors to the ArmNN filter tensors (ArmNN weights have to be [M, I, H, W])
1015 PermutationVector permutationVector{ 2, 3, 1, 0 }; // [H, W, I, M] -> [M, I, H, W]
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01001016
telsoa01c577f2c2018-08-31 09:22:23 +01001017 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
Jan Eilers7612bd62021-04-06 17:29:03 +01001018 armnn::TensorInfo filterTensorInfo = ToTensorInfo(inputs[1]);
telsoa01c577f2c2018-08-31 09:22:23 +01001019
Matteo Martincigh747ef822018-12-18 09:26:39 +00001020 // Assuming input is NHWC
telsoa01c577f2c2018-08-31 09:22:23 +01001021 unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1022 unsigned int inputWidth = inputTensorInfo.GetShape()[2];
Matteo Martincigh747ef822018-12-18 09:26:39 +00001023
1024 // TensorflowLite weights come in the format [1, H, W, I * M]
telsoa01c577f2c2018-08-31 09:22:23 +01001025 unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1026 unsigned int filterWidth = filterTensorInfo.GetShape()[2];
1027
Matteo Martincigh747ef822018-12-18 09:26:39 +00001028 // Reshape weights as [ H, W, I, M ]
1029 filterTensorInfo.SetShape({ filterHeight,
1030 filterWidth,
1031 inputTensorInfo.GetShape()[3],
1032 filterTensorInfo.GetShape()[3] / inputTensorInfo.GetShape()[3] });
1033
Pablo Tellof0bd6832019-04-26 17:58:13 +01001034 CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
1035 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
1036 CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
1037 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
telsoa01c577f2c2018-08-31 09:22:23 +01001038
Finn Williamsd4fa5452021-03-01 12:31:41 +00001039 auto filterTensorAndData = CreateConstTensorPermuted(inputs[1], filterTensorInfo, permutationVector);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001040 armnn::IConnectableLayer* layer = nullptr;
James Ward58dec6b2020-09-11 17:32:44 +01001041 auto layerName = fmt::format("DepthwiseConv2D:{}:{}", subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001042
1043 if (inputs.size() == 3)
1044 {
1045 desc.m_BiasEnabled = true;
1046 TensorInfo biasTensorInfo = ToTensorInfo(inputs[2]);
Finn Williamsd4fa5452021-03-01 12:31:41 +00001047 auto biasTensorAndData = CreateConstTensorNonPermuted(inputs[2], biasTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +01001048 layer = m_Network->AddDepthwiseConvolution2dLayer(desc,
1049 filterTensorAndData.first,
Finn Williamsd4fa5452021-03-01 12:31:41 +00001050 Optional<ConstTensor>(biasTensorAndData),
telsoa01c577f2c2018-08-31 09:22:23 +01001051 layerName.c_str());
1052 }
1053 else
1054 {
1055 layer = m_Network->AddDepthwiseConvolution2dLayer(desc,
1056 filterTensorAndData.first,
Matteo Martincighfc598e12019-05-14 10:36:13 +01001057 EmptyOptional(),
telsoa01c577f2c2018-08-31 09:22:23 +01001058 layerName.c_str());
1059 }
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001060 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01001061
Sadik Armagand109a4d2020-07-28 10:42:13 +01001062 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
jimfly01c25411c2018-11-14 17:47:22 +00001063 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
telsoa01c577f2c2018-08-31 09:22:23 +01001064
1065 // register the input connection slots for the layer, connections are made after all layers have been created
1066 // only the tensors for the inputs are relevant, exclude the const tensors
1067 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
jimfly01c25411c2018-11-14 17:47:22 +00001068 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
telsoa01c577f2c2018-08-31 09:22:23 +01001069
jimfly01c25411c2018-11-14 17:47:22 +00001070 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
telsoa01c577f2c2018-08-31 09:22:23 +01001071 // register the output connection slots for the layer, connections are made after all layers have been created
1072 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1073 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1074}
1075
Kevin May7d96b162021-02-03 17:38:41 +00001076void TfLiteParserImpl::ParseDequantize(size_t subgraphIndex, size_t operatorIndex)
Finn Williamsed66d142019-12-06 09:55:55 +00001077{
1078 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1079
1080 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1081 CHECK_VALID_SIZE(inputs.size(), 1);
1082
1083 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1084 CHECK_VALID_SIZE(outputs.size(), 1);
1085
James Ward58dec6b2020-09-11 17:32:44 +01001086 auto layerName = fmt::format("Dequantize:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsed66d142019-12-06 09:55:55 +00001087
1088 IConnectableLayer* layer = m_Network->AddDequantizeLayer(layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001089 ARMNN_ASSERT(layer != nullptr);
Finn Williamsed66d142019-12-06 09:55:55 +00001090
Sadik Armagand109a4d2020-07-28 10:42:13 +01001091 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Finn Williamsed66d142019-12-06 09:55:55 +00001092 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1093
1094 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1095 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1096
1097 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1098 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
1099}
1100
Kevin May7d96b162021-02-03 17:38:41 +00001101void TfLiteParserImpl::ParseTranspose(size_t subgraphIndex, size_t operatorIndex)
Keith Davis4cd29a02019-09-09 14:49:20 +01001102{
1103 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1104
1105 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Kevin May85d92602019-09-27 17:21:06 +01001106 CHECK_VALID_SIZE(inputs.size(), 1, 2);
Keith Davis4cd29a02019-09-09 14:49:20 +01001107
1108 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1109 CHECK_VALID_SIZE(outputs.size(), 1);
1110
James Ward58dec6b2020-09-11 17:32:44 +01001111 auto layerName = fmt::format("Transpose:{}:{}", subgraphIndex, operatorIndex);
Mike Kelly08759e22020-03-02 11:41:31 +00001112 TransposeDescriptor desc;
Keith Davis4cd29a02019-09-09 14:49:20 +01001113
josh minorba424d22019-11-13 10:55:17 -06001114 if (inputs.size() == 2)
Kevin May85d92602019-09-27 17:21:06 +01001115 {
1116 armnn::TensorInfo permuteTensorInfo = ToTensorInfo(inputs[1]);
1117 BufferRawPtr permuteBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
josh minorba424d22019-11-13 10:55:17 -06001118 auto numPermVecElements = permuteTensorInfo.GetNumElements();
1119 std::vector<unsigned int> permuteShape(numPermVecElements);
Kevin May85d92602019-09-27 17:21:06 +01001120 ::memcpy(permuteShape.data(), permuteBufferPtr->data.data(), permuteTensorInfo.GetNumBytes());
Mike Kelly08759e22020-03-02 11:41:31 +00001121 PermutationVector permutationVector(permuteShape.data(), permuteTensorInfo.GetNumElements());
Kevin May85d92602019-09-27 17:21:06 +01001122
Mike Kelly08759e22020-03-02 11:41:31 +00001123 desc = TransposeDescriptor(permutationVector);
Kevin May85d92602019-09-27 17:21:06 +01001124 }
1125
James Conroy05102392020-06-24 15:39:55 +01001126 TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
Sadik Armagand109a4d2020-07-28 10:42:13 +01001127 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01001128 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
Keith Davis4cd29a02019-09-09 14:49:20 +01001129
James Conroy05102392020-06-24 15:39:55 +01001130 IConnectableLayer* layer = m_Network->AddTransposeLayer(desc, layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001131 ARMNN_ASSERT(layer != nullptr);
Keith Davis4cd29a02019-09-09 14:49:20 +01001132 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1133
1134 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1135 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1136
1137 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1138 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1139}
1140
Kevin May7d96b162021-02-03 17:38:41 +00001141void TfLiteParserImpl::ParseTransposeConv(size_t subgraphIndex, size_t operatorIndex)
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001142{
1143 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1144
1145 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1146 const auto * options = operatorPtr->builtin_options.AsTransposeConvOptions();
1147
1148 TransposeConvolution2dDescriptor desc;
1149 desc.m_BiasEnabled = false;
1150 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1151 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1152 desc.m_DataLayout = armnn::DataLayout::NHWC;
1153
1154 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
David Monahan61683802021-01-12 09:11:07 +00001155 if (inputs.size() == 4)
1156 {
1157 desc.m_BiasEnabled = true;
1158 }
1159 else
1160 {
1161 CHECK_VALID_SIZE(inputs.size(), 3);
1162 }
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001163
1164 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1165 CHECK_VALID_SIZE(outputs.size(), 1);
1166
Colm Donelan0ad3ef12020-07-03 15:54:28 +01001167 if (inputs[0])
1168 {
1169 armnn::TensorInfo tensorInfo = ToTensorInfo(inputs[0]);
1170 std::vector<int> output_shape(tensorInfo.GetNumElements());
1171 if (tensorInfo.GetDataType() == DataType::Signed32)
1172 {
1173 ::memcpy(output_shape.data(), GetBuffer(m_Model, inputs[0]->buffer)->data.data(), tensorInfo.GetNumBytes());
1174 }
1175 if (tensorInfo.GetDataType() == DataType::QAsymmU8)
1176 {
1177 for(unsigned int i=0; i < tensorInfo.GetNumElements(); i++)
1178 {
1179 output_shape[i] = GetBuffer(m_Model, inputs[0]->buffer)->data.data()[i];
1180 }
1181 }
1182 // Change from signed to unsigned int to store in TransposeConvolution2dDescriptor.
1183 for (int dimension : output_shape)
1184 {
1185 desc.m_OutputShape.push_back(static_cast<unsigned int>(dimension));
1186 }
1187 desc.m_OutputShapeEnabled = true;
1188 }
Matthew Jacksonccb25ea2019-08-20 17:18:33 +01001189 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[2]);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001190 armnn::TensorInfo filterTensorInfo = ToTensorInfo(inputs[1]);
1191
1192 // TfLite uses NHWC tensors
1193 const unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1194 const unsigned int inputWidth = inputTensorInfo.GetShape()[2];
1195
1196 const unsigned int filterHeight = filterTensorInfo.GetShape()[1];
1197 const unsigned int filterWidth = filterTensorInfo.GetShape()[2];
1198
1199 CalcPadding(inputHeight,
1200 filterHeight,
1201 desc.m_StrideY,
1202 1, // DilationY
1203 desc.m_PadTop,
1204 desc.m_PadBottom,
1205 options->padding);
1206
1207 CalcPadding(inputWidth,
1208 filterWidth,
1209 desc.m_StrideX,
1210 1, // DilationX
1211 desc.m_PadLeft,
1212 desc.m_PadRight,
1213 options->padding);
1214
Finn Williamsd4fa5452021-03-01 12:31:41 +00001215 auto filterTensorAndData = CreateConstTensorNonPermuted(inputs[1], filterTensorInfo);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001216
1217 armnn::IConnectableLayer* layer = nullptr;
James Ward58dec6b2020-09-11 17:32:44 +01001218 auto layerName = fmt::format("TransposeConv:{}:{}", subgraphIndex, operatorIndex);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001219
David Monahan61683802021-01-12 09:11:07 +00001220 if (desc.m_BiasEnabled)
1221 {
1222 auto biasTensorInfo = ToTensorInfo(inputs[3]);
Finn Williamsd4fa5452021-03-01 12:31:41 +00001223 auto biasConstTensor = CreateConstTensorNonPermuted(inputs[3], biasTensorInfo);
David Monahan61683802021-01-12 09:11:07 +00001224 layer = m_Network->AddTransposeConvolution2dLayer(desc,
Finn Williamsd4fa5452021-03-01 12:31:41 +00001225 filterTensorAndData,
1226 biasConstTensor,
David Monahan61683802021-01-12 09:11:07 +00001227 layerName.c_str());
1228 }
1229 else
1230 {
1231 layer = m_Network->AddTransposeConvolution2dLayer(desc,
Finn Williamsd4fa5452021-03-01 12:31:41 +00001232 filterTensorAndData,
David Monahan61683802021-01-12 09:11:07 +00001233 EmptyOptional(),
1234 layerName.c_str());
1235 }
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001236
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001237 ARMNN_ASSERT(layer != nullptr);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001238
Sadik Armagand109a4d2020-07-28 10:42:13 +01001239 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001240 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1241
1242 // only the tensors for the inputs are relevant, exclude the const (filter) tensor
1243 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Matthew Jacksonccb25ea2019-08-20 17:18:33 +01001244 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[2]});
Matthew Jackson74bf7da2019-08-16 16:51:42 +01001245
1246 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1247 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1248}
1249
Kevin May7d96b162021-02-03 17:38:41 +00001250void TfLiteParserImpl::ParseAveragePool2D(size_t subgraphIndex, size_t operatorIndex)
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001251{
1252 ParsePool(subgraphIndex, operatorIndex, PoolingAlgorithm::Average);
1253}
1254
Kevin May7d96b162021-02-03 17:38:41 +00001255void TfLiteParserImpl::ParseBatchToSpaceND(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001256{
1257 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1258
1259 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1260 CHECK_VALID_SIZE(inputs.size(), 3);
1261
1262 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1263 CHECK_VALID_SIZE(outputs.size(), 1);
1264
1265 armnn::TensorInfo blockShapeTensorInfo = ToTensorInfo(inputs[1]);
1266 BufferRawPtr blockShapeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1267
1268 armnn::TensorInfo cropsTensorInfo = ToTensorInfo(inputs[2]);
1269 BufferRawPtr cropsBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
1270
1271 std::vector<unsigned int> blockShape(blockShapeTensorInfo.GetNumElements());
1272 ::memcpy(blockShape.data(), blockShapeBufferPtr->data.data(), blockShapeTensorInfo.GetNumBytes());
1273
1274 std::vector<unsigned int> cropsVector(cropsTensorInfo.GetNumElements());
1275 ::memcpy(cropsVector.data(), cropsBufferPtr->data.data(), cropsTensorInfo.GetNumBytes());
1276
1277 size_t step = 2;
1278 std::vector<std::pair<unsigned int, unsigned int>> crops;
1279 for (unsigned int i = 0; i < cropsTensorInfo.GetNumElements() / step; ++i)
1280 {
1281 crops.emplace_back(cropsVector[i * step], cropsVector[i * step + 1]);
1282 }
1283
1284 armnn::BatchToSpaceNdDescriptor desc;
1285 desc.m_BlockShape = blockShape;
1286 desc.m_Crops = crops;
1287 desc.m_DataLayout = armnn::DataLayout::NHWC;
1288
James Ward58dec6b2020-09-11 17:32:44 +01001289 auto layerName = fmt::format("BatchToSpaceND:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001290
James Conroy05102392020-06-24 15:39:55 +01001291 TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
Sadik Armagand109a4d2020-07-28 10:42:13 +01001292 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01001293 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1294
1295 IConnectableLayer* layer = m_Network->AddBatchToSpaceNdLayer(desc, layerName.c_str());
1296 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesdb947e22019-02-08 18:52:21 -02001297 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1298
1299 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1300 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1301
1302 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1303 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1304}
1305
Kevin May7d96b162021-02-03 17:38:41 +00001306void TfLiteParserImpl::ParseL2Normalization(size_t subgraphIndex, size_t operatorIndex)
Matthew Jackson28c94572019-07-18 10:47:03 +01001307{
1308 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1309
1310 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1311 CHECK_VALID_SIZE(inputs.size(), 1);
1312
1313 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1314 CHECK_VALID_SIZE(outputs.size(), 1);
1315
1316 L2NormalizationDescriptor desc;
1317 desc.m_DataLayout = armnn::DataLayout::NHWC;
James Ward58dec6b2020-09-11 17:32:44 +01001318 auto layerName = fmt::format("L2Normalization:{}:{}", subgraphIndex, operatorIndex);
Matthew Jackson28c94572019-07-18 10:47:03 +01001319 IConnectableLayer* layer = m_Network->AddL2NormalizationLayer(desc, layerName.c_str());
1320
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001321 ARMNN_ASSERT(layer != nullptr);
Matthew Jackson28c94572019-07-18 10:47:03 +01001322
Sadik Armagand109a4d2020-07-28 10:42:13 +01001323 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Matthew Jackson28c94572019-07-18 10:47:03 +01001324 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1325
1326 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1327 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1328
1329 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1330 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1331}
1332
Kevin May7d96b162021-02-03 17:38:41 +00001333void TfLiteParserImpl::ParseMaxPool2D(size_t subgraphIndex, size_t operatorIndex)
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001334{
1335 ParsePool(subgraphIndex, operatorIndex, PoolingAlgorithm::Max);
1336}
1337
Kevin May7d96b162021-02-03 17:38:41 +00001338void TfLiteParserImpl::ParseMaximum(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001339{
1340 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1341
1342 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1343 CHECK_VALID_SIZE(inputs.size(), 2);
1344
1345 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1346 CHECK_VALID_SIZE(outputs.size(), 1);
1347
James Ward58dec6b2020-09-11 17:32:44 +01001348 auto layerName = fmt::format("Maximum:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01001349
1350 TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
1351 TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]);
1352 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001353
Sadik Armagand109a4d2020-07-28 10:42:13 +01001354 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01001355 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1356
1357 IConnectableLayer* layer = m_Network->AddMaximumLayer(layerName.c_str());
1358 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001359 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1360
1361 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01001362 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalvesb8d805e2019-02-12 22:57:13 -02001363
1364 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1365 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1366}
1367
Kevin May7d96b162021-02-03 17:38:41 +00001368void TfLiteParserImpl::ParseMinimum(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001369{
1370 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1371
1372 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1373 CHECK_VALID_SIZE(inputs.size(), 2);
1374
1375 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1376 CHECK_VALID_SIZE(outputs.size(), 1);
1377
James Ward58dec6b2020-09-11 17:32:44 +01001378 auto layerName = fmt::format("Minimum:{}:{}", subgraphIndex, operatorIndex);
James Conroy05102392020-06-24 15:39:55 +01001379
1380 TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
1381 TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]);
1382 CheckMatchingQuantization(inputTensorInfo, input1TensorInfo, layerName, "Input 0", "Input 1");
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001383
Sadik Armagand109a4d2020-07-28 10:42:13 +01001384 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01001385 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1386
1387 IConnectableLayer* layer = m_Network->AddMinimumLayer(layerName.c_str());
1388 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001389 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1390
1391 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01001392 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalves8f6d7a72019-02-12 22:58:18 -02001393
1394 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1395 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1396}
1397
Kevin May7d96b162021-02-03 17:38:41 +00001398void TfLiteParserImpl::ParsePool(size_t subgraphIndex,
1399 size_t operatorIndex,
1400 PoolingAlgorithm algorithm)
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001401{
1402 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1403
1404 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1405 const auto * options = operatorPtr->builtin_options.AsPool2DOptions();
1406
1407 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
1408
1409 std::string layerName;
1410
1411 switch (algorithm)
1412 {
1413 case PoolingAlgorithm::Average:
1414 layerName =
James Ward58dec6b2020-09-11 17:32:44 +01001415 fmt::format("AveragePool2D:{}:{}", subgraphIndex, operatorIndex);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001416 break;
1417 case PoolingAlgorithm::Max:
1418 layerName =
James Ward58dec6b2020-09-11 17:32:44 +01001419 fmt::format("MaxPool2D:{}:{}", subgraphIndex, operatorIndex);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001420 break;
1421 default:
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01001422 ARMNN_ASSERT_MSG(false, "Unsupported Pooling Algorithm");
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001423 }
1424
1425 Pooling2dDescriptor desc;
1426
1427 desc.m_PoolType = algorithm;
1428 desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
1429 desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
1430 desc.m_PoolWidth = CHECKED_NON_NEGATIVE(options->filter_width);
1431 desc.m_PoolHeight = CHECKED_NON_NEGATIVE(options->filter_height);
1432 desc.m_PaddingMethod = PaddingMethod::Exclude;
1433 desc.m_OutputShapeRounding = OutputShapeRounding::Floor;
jimfly01c25411c2018-11-14 17:47:22 +00001434 desc.m_DataLayout = armnn::DataLayout::NHWC;
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001435
1436 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1437 CHECK_VALID_SIZE(inputs.size(), 1);
1438 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
1439
1440 // assuming input is NHWC
1441 unsigned int inputHeight = inputTensorInfo.GetShape()[1];
1442 unsigned int inputWidth = inputTensorInfo.GetShape()[2];
1443
Pablo Tellof0bd6832019-04-26 17:58:13 +01001444 CalcPadding(inputHeight, desc.m_PoolHeight, desc.m_StrideY, 1u,
1445 desc.m_PadTop, desc.m_PadBottom, options->padding);
1446 CalcPadding(inputWidth, desc.m_PoolWidth, desc.m_StrideX, 1u,
1447 desc.m_PadLeft, desc.m_PadRight, options->padding);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001448
1449 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1450 CHECK_VALID_SIZE(outputs.size(), 1);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001451
Sadik Armagand109a4d2020-07-28 10:42:13 +01001452 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01001453 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1454
1455 IConnectableLayer* layer = m_Network->AddPooling2dLayer(desc, layerName.c_str());
1456 ARMNN_ASSERT(layer != nullptr);
jimfly01c25411c2018-11-14 17:47:22 +00001457 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001458
1459 // register the input connection slots for the layer, connections are made after all layers have been created
1460 // only the tensors for the inputs are relevant, exclude the const tensors
1461 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
jimfly01c25411c2018-11-14 17:47:22 +00001462 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001463
jimfly01c25411c2018-11-14 17:47:22 +00001464 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
Nattapat Chaimanowongb66504b2018-10-17 15:19:14 +01001465 // register the output connection slots for the layer, connections are made after all layers have been created
1466 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1467 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1468}
1469
Kevin May7d96b162021-02-03 17:38:41 +00001470void TfLiteParserImpl::ParseSlice(size_t subgraphIndex, size_t operatorIndex)
josh minorba424d22019-11-13 10:55:17 -06001471{
1472 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1473
1474 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1475 CHECK_VALID_SIZE(inputs.size(), 3);
1476 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1477 CHECK_VALID_SIZE(outputs.size(), 1);
1478
1479 SliceDescriptor desc;
1480
1481 // set begin tensor info for slice descriptor
1482 armnn::TensorInfo beginTensorInfo = ToTensorInfo(inputs[1]);
1483 BufferRawPtr beginBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1484
1485 std::vector<unsigned int> begin(beginTensorInfo.GetNumElements());
1486 ::memcpy(begin.data(), beginBufferPtr->data.data(), beginTensorInfo.GetNumBytes());
1487
1488 // set size tensor info for slice descriptor
1489 armnn::TensorInfo sizeTensorInfo = ToTensorInfo(inputs[2]);
1490 BufferRawPtr sizeBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
1491
1492 std::vector<unsigned int> size(sizeTensorInfo.GetNumElements());
1493 ::memcpy(size.data(), sizeBufferPtr->data.data(), sizeTensorInfo.GetNumBytes());
1494 desc = SliceDescriptor(begin, size);
1495
James Ward58dec6b2020-09-11 17:32:44 +01001496 auto layerName = fmt::format("Slice:{}:{}", subgraphIndex, operatorIndex);
josh minorba424d22019-11-13 10:55:17 -06001497
James Conroy05102392020-06-24 15:39:55 +01001498 TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
Sadik Armagand109a4d2020-07-28 10:42:13 +01001499 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01001500 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1501
1502 IConnectableLayer* const layer = m_Network->AddSliceLayer(desc, layerName.c_str());
josh minorba424d22019-11-13 10:55:17 -06001503 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1504
1505 // register the input connection slots for the layer, connections are made after all layers have been created
1506 // only the tensors for the inputs are relevant, exclude the const tensors
1507 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1508 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1509
1510 // register the output connection slots for the layer, connections are made after all layers have been created
1511 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1512 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1513}
1514
Kevin May7d96b162021-02-03 17:38:41 +00001515void TfLiteParserImpl::ParseSoftmax(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001516{
1517 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1518 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1519 const auto * options = operatorPtr->builtin_options.AsSoftmaxOptions();
1520
1521 SoftmaxDescriptor desc;
1522 desc.m_Beta = options->beta;
1523
1524 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1525 CHECK_VALID_SIZE(inputs.size(), 1);
1526 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1527 CHECK_VALID_SIZE(outputs.size(), 1);
1528
James Ward58dec6b2020-09-11 17:32:44 +01001529 auto layerName = fmt::format("Softmax:{}:{}", subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001530 IConnectableLayer* const layer = m_Network->AddSoftmaxLayer(desc, layerName.c_str());
1531
Sadik Armagand109a4d2020-07-28 10:42:13 +01001532 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
telsoa01c577f2c2018-08-31 09:22:23 +01001533 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1534
1535 // register the input connection slots for the layer, connections are made after all layers have been created
1536 // only the tensors for the inputs are relevant, exclude the const tensors
1537 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1538 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1539
1540 // register the output connection slots for the layer, connections are made after all layers have been created
1541 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1542 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1543}
1544
Kevin May7d96b162021-02-03 17:38:41 +00001545void TfLiteParserImpl::ParseSpaceToBatchND(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesbaded142019-02-08 19:02:48 -02001546{
1547 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1548
1549 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1550 CHECK_VALID_SIZE(inputs.size(), 3);
1551
1552 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1553 CHECK_VALID_SIZE(outputs.size(), 1);
1554
1555 armnn::TensorInfo blockShapeTensorInfo = ToTensorInfo(inputs[1]);
1556 BufferRawPtr blockShapeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1557
1558 armnn::TensorInfo padListTensorInfo = ToTensorInfo(inputs[2]);
1559 BufferRawPtr padListBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
1560
1561 std::vector<unsigned int> blockShape(blockShapeTensorInfo.GetNumElements());
1562 ::memcpy(blockShape.data(), blockShapeBufferPtr->data.data(), blockShapeTensorInfo.GetNumBytes());
1563
1564 std::vector<unsigned int> padListVector(padListTensorInfo.GetNumElements());
1565 ::memcpy(padListVector.data(), padListBufferPtr->data.data(), padListTensorInfo.GetNumBytes());
1566
1567 size_t step = 2;
1568 std::vector<std::pair<unsigned int, unsigned int>> padList;
1569 for (unsigned int i = 0; i < padListTensorInfo.GetNumElements() / step; ++i)
1570 {
1571 padList.emplace_back(padListVector[i * step], padListVector[i * step + 1]);
1572 }
1573
1574 armnn::SpaceToBatchNdDescriptor desc;
1575 desc.m_BlockShape = blockShape;
1576 desc.m_PadList = padList;
1577 desc.m_DataLayout = armnn::DataLayout::NHWC;
1578
James Ward58dec6b2020-09-11 17:32:44 +01001579 auto layerName = fmt::format("SpaceToBatchND:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesbaded142019-02-08 19:02:48 -02001580
James Conroy05102392020-06-24 15:39:55 +01001581 TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
Sadik Armagand109a4d2020-07-28 10:42:13 +01001582 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01001583 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1584
1585 IConnectableLayer* layer = m_Network->AddSpaceToBatchNdLayer(desc, layerName.c_str());
1586 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesbaded142019-02-08 19:02:48 -02001587 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1588
1589 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1590 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1591
1592 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1593 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1594}
1595
Kevin May7d96b162021-02-03 17:38:41 +00001596armnn::TensorInfo TfLiteParserImpl::OutputShapeOfSqueeze(const std::vector<uint32_t> & squeezeDimsIn,
1597 const armnn::TensorInfo & inputTensorInfo)
telsoa01c577f2c2018-08-31 09:22:23 +01001598{
1599 CHECK_VALID_SIZE(squeezeDimsIn.size(), 0, 1, 2, 3, 4);
1600 std::vector<uint32_t> squeezeDims = squeezeDimsIn;
1601 static const uint32_t dimensionSequence[] = { 0, 1, 2, 3 };
1602
1603 if (inputTensorInfo.GetNumDimensions() > 4)
1604 {
1605 std::stringstream ss;
1606 ss << "Input tensor has unexpected number of dimensions:" << inputTensorInfo.GetNumDimensions()
1607 << " shape:" << inputTensorInfo.GetShape() << " "
1608 << CHECK_LOCATION().AsString();
1609 throw ParseException(ss.str());
1610 }
1611
1612 if (squeezeDims.empty())
1613 {
1614 squeezeDims.assign(dimensionSequence,
1615 dimensionSequence+inputTensorInfo.GetNumDimensions());
1616 }
1617
1618 std::vector<uint32_t> outputDims;
1619 for(unsigned int i = 0; i < inputTensorInfo.GetNumDimensions(); i++)
1620 {
1621 bool skipSqueeze = (std::find(squeezeDims.begin(), squeezeDims.end(), i) == squeezeDims.end());
1622 auto currentDimension = inputTensorInfo.GetShape()[i];
1623 if (skipSqueeze || currentDimension != 1)
1624 {
1625 outputDims.push_back(currentDimension);
1626 }
1627 }
1628
1629 if (outputDims.size() > 4)
1630 {
1631 std::stringstream ss;
1632 ss << "Output tensor has unexpected number of dimensions:" << inputTensorInfo.GetNumDimensions()
1633 << " shape:" << inputTensorInfo.GetShape() << " "
1634 << CHECK_LOCATION().AsString();
1635 throw ParseException(ss.str());
1636 }
1637
1638 TensorShape outShape = TensorShape(static_cast<unsigned int>(outputDims.size()),
1639 outputDims.data());
1640
1641 // we need to preserve the tensor type and the quantization data as well
1642 TensorInfo outTensorInfo = inputTensorInfo;
1643 outTensorInfo.SetShape(outShape);
1644
1645 return outTensorInfo;
1646}
1647
Kevin May7d96b162021-02-03 17:38:41 +00001648void TfLiteParserImpl::ParseSqueeze(size_t subgraphIndex, size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01001649{
1650 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1651
1652 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1653 CHECK_VALID_SIZE(inputs.size(), 1);
1654
1655 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1656 CHECK_VALID_SIZE(outputs.size(), 1);
1657
1658 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1659 const auto * options = operatorPtr->builtin_options.AsSqueezeOptions();
James Ward58dec6b2020-09-11 17:32:44 +01001660 auto layerName = fmt::format("Squeeze:{}:{}", subgraphIndex, operatorIndex);
telsoa01c577f2c2018-08-31 09:22:23 +01001661
1662 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
1663 armnn::TensorInfo outputTensorInfo =
Kevin May7d96b162021-02-03 17:38:41 +00001664 TfLiteParserImpl::OutputShapeOfSqueeze(AsUnsignedVector(options->squeeze_dims),
telsoa01c577f2c2018-08-31 09:22:23 +01001665 inputTensorInfo);
James Conroy05102392020-06-24 15:39:55 +01001666 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
telsoa01c577f2c2018-08-31 09:22:23 +01001667
1668 ReshapeDescriptor reshapeDesc;
1669 reshapeDesc.m_TargetShape = outputTensorInfo.GetShape();
1670
telsoa01c577f2c2018-08-31 09:22:23 +01001671 IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01001672 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01001673 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1674
1675 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1676 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1677
1678 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1679 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1680}
1681
Kevin May7d96b162021-02-03 17:38:41 +00001682void TfLiteParserImpl::ParseStridedSlice(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves451d95b2019-02-12 22:59:22 -02001683{
1684 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1685
1686 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1687 CHECK_VALID_SIZE(inputs.size(), 4);
1688
1689 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1690 CHECK_VALID_SIZE(outputs.size(), 1);
1691
1692 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1693 const auto * options = operatorPtr->builtin_options.AsStridedSliceOptions();
1694
1695 StridedSliceDescriptor desc;
1696 desc.m_BeginMask = options->begin_mask;
1697 desc.m_EllipsisMask = options->ellipsis_mask;
1698 desc.m_EndMask = options->end_mask;
1699 desc.m_NewAxisMask = options->new_axis_mask;
1700 desc.m_ShrinkAxisMask = options->shrink_axis_mask;
1701 desc.m_DataLayout = armnn::DataLayout::NHWC;
1702
1703 armnn::TensorInfo beginTensorInfo = ToTensorInfo(inputs[1]);
1704 BufferRawPtr beginBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1705
1706 std::vector<int> begin(beginTensorInfo.GetNumElements());
1707 ::memcpy(begin.data(), beginBufferPtr->data.data(), beginTensorInfo.GetNumBytes());
1708
1709 armnn::TensorInfo endTensorInfo = ToTensorInfo(inputs[2]);
1710 BufferRawPtr endBufferPtr = GetBuffer(m_Model, inputs[2]->buffer);
1711
1712 std::vector<int> end(endTensorInfo.GetNumElements());
1713 ::memcpy(end.data(), endBufferPtr->data.data(), endTensorInfo.GetNumBytes());
1714
1715 armnn::TensorInfo strideTensorInfo = ToTensorInfo(inputs[3]);
1716 BufferRawPtr strideBufferPtr = GetBuffer(m_Model, inputs[3]->buffer);
1717
1718 std::vector<int> stride(strideTensorInfo.GetNumElements());
1719 ::memcpy(stride.data(), strideBufferPtr->data.data(), strideTensorInfo.GetNumBytes());
1720
1721 desc.m_Begin = begin;
1722 desc.m_End = end;
1723 desc.m_Stride = stride;
1724
James Ward58dec6b2020-09-11 17:32:44 +01001725 auto layerName = fmt::format("StridedSlice:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02001726 IConnectableLayer* layer = m_Network->AddStridedSliceLayer(desc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01001727 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02001728
Sadik Armagand109a4d2020-07-28 10:42:13 +01001729 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Bruno Goncalves451d95b2019-02-12 22:59:22 -02001730 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1731
1732 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1733 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1734
1735 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1736 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1737}
1738
Kevin May7d96b162021-02-03 17:38:41 +00001739void TfLiteParserImpl::ParseSub(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02001740{
1741 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1742
1743 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1744 const auto * options = operatorPtr->builtin_options.AsSubOptions();
1745
1746 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1747 CHECK_VALID_SIZE(inputs.size(), 2);
1748
1749 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1750 CHECK_VALID_SIZE(outputs.size(), 1);
1751
1752 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
1753 armnn::TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]);
1754
James Ward58dec6b2020-09-11 17:32:44 +01001755 auto layerName = fmt::format("Sub:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02001756 IConnectableLayer* layer = m_Network->AddSubtractionLayer(layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01001757 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02001758
Sadik Armagand109a4d2020-07-28 10:42:13 +01001759 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02001760 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1761
1762 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01001763 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalvesbbeae262019-02-07 18:37:39 -02001764
1765 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
1766
1767 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1768 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1769}
1770
Kevin May7d96b162021-02-03 17:38:41 +00001771void TfLiteParserImpl::ParseDiv(size_t subgraphIndex, size_t operatorIndex)
Darshan Patel42b3d7d2020-05-25 22:30:07 +05301772{
1773 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1774
1775 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1776 const auto * options = operatorPtr->builtin_options.AsDivOptions();
1777
1778 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1779 CHECK_VALID_SIZE(inputs.size(), 2);
1780
1781 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1782 CHECK_VALID_SIZE(outputs.size(), 1);
1783
1784 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
1785 armnn::TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]);
1786
James Ward58dec6b2020-09-11 17:32:44 +01001787 auto layerName = fmt::format("Div:{}:{}", subgraphIndex, operatorIndex);
Darshan Patel42b3d7d2020-05-25 22:30:07 +05301788 IConnectableLayer* layer = m_Network->AddDivisionLayer(layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01001789 ARMNN_ASSERT(layer != nullptr);
Darshan Patel42b3d7d2020-05-25 22:30:07 +05301790
Sadik Armagand109a4d2020-07-28 10:42:13 +01001791 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Darshan Patel42b3d7d2020-05-25 22:30:07 +05301792 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1793
1794 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01001795 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Darshan Patel42b3d7d2020-05-25 22:30:07 +05301796 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
1797
1798 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1799 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1800}
1801
Kevin May7d96b162021-02-03 17:38:41 +00001802void TfLiteParserImpl::ParseAdd(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02001803{
1804 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1805
1806 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1807 const auto * options = operatorPtr->builtin_options.AsAddOptions();
1808
1809 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1810 CHECK_VALID_SIZE(inputs.size(), 2);
1811
1812 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1813 CHECK_VALID_SIZE(outputs.size(), 1);
1814
Bruno Goncalves9c761a62018-12-27 14:20:35 -02001815 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
1816 armnn::TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]);
1817
James Ward58dec6b2020-09-11 17:32:44 +01001818 auto layerName = fmt::format("Add:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02001819 IConnectableLayer* layer = m_Network->AddAdditionLayer(layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01001820 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02001821
Sadik Armagand109a4d2020-07-28 10:42:13 +01001822 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02001823 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1824
1825 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01001826 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalvesd4ac6a42018-12-18 12:56:22 -02001827 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
1828
1829 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1830 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1831}
1832
Kevin May7d96b162021-02-03 17:38:41 +00001833void TfLiteParserImpl::ParseMul(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalvesf803f782018-12-18 13:40:30 -02001834{
1835 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1836
1837 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
1838 const auto * options = operatorPtr->builtin_options.AsMulOptions();
1839
1840 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1841 CHECK_VALID_SIZE(inputs.size(), 2);
1842
1843 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1844 CHECK_VALID_SIZE(outputs.size(), 1);
1845
Bruno Goncalves9c761a62018-12-27 14:20:35 -02001846 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
1847 armnn::TensorInfo input1TensorInfo = ToTensorInfo(inputs[1]);
1848
James Ward58dec6b2020-09-11 17:32:44 +01001849 auto layerName = fmt::format("Mul:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalvesf803f782018-12-18 13:40:30 -02001850 IConnectableLayer* layer = m_Network->AddMultiplicationLayer(layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01001851 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalvesf803f782018-12-18 13:40:30 -02001852
Sadik Armagand109a4d2020-07-28 10:42:13 +01001853 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Bruno Goncalvesf803f782018-12-18 13:40:30 -02001854 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1855
1856 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat16f82f92020-09-14 16:12:44 +01001857 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
Bruno Goncalvesf803f782018-12-18 13:40:30 -02001858 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
1859
1860 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1861 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1862}
1863
Kevin May7d96b162021-02-03 17:38:41 +00001864void TfLiteParserImpl::ParseMean(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves2235cee2018-12-19 12:51:45 -02001865{
1866 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1867
1868 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1869
1870 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1871 CHECK_VALID_SIZE(outputs.size(), 1);
1872
1873 armnn::TensorInfo dimTensorInfo = ToTensorInfo(inputs[1]);
1874 BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1875
1876 armnn::MeanDescriptor desc;
1877 std::vector<unsigned int> axis(dimTensorInfo.GetNumElements());
1878 ::memcpy(axis.data(), bufferPtr->data.data(), dimTensorInfo.GetNumBytes());
1879 desc.m_Axis = axis;
1880
1881 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
Sadik Armagand109a4d2020-07-28 10:42:13 +01001882 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02001883
1884 desc.m_KeepDims =
1885 inputTensorInfo.GetNumDimensions() == outputTensorInfo.GetNumDimensions() ?
1886 true : false;
1887
James Ward58dec6b2020-09-11 17:32:44 +01001888 auto layerName = fmt::format("Mean:{}:{}", subgraphIndex, operatorIndex);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02001889 IConnectableLayer* layer = m_Network->AddMeanLayer(desc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01001890 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalves2235cee2018-12-19 12:51:45 -02001891
1892 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1893
1894 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1895 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1896
1897 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1898 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1899}
1900
Kevin May7d96b162021-02-03 17:38:41 +00001901void TfLiteParserImpl::ParsePad(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02001902{
1903 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1904
Kevin May7d96b162021-02-03 17:38:41 +00001905 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02001906
Kevin May7d96b162021-02-03 17:38:41 +00001907 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02001908 CHECK_VALID_SIZE(outputs.size(), 1);
1909
Narumol Prangnawarat8719d222020-11-27 16:57:56 +00001910 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
1911
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02001912 armnn::TensorInfo padTensorInfo = ToTensorInfo(inputs[1]);
1913 BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
1914
1915 std::vector<unsigned int> padBuffer(padTensorInfo.GetNumElements());
1916 ::memcpy(padBuffer.data(), bufferPtr->data.data(), padTensorInfo.GetNumBytes());
1917
1918 size_t step = 2;
1919 armnn::PadDescriptor desc;
Narumol Prangnawarat8719d222020-11-27 16:57:56 +00001920 if (inputTensorInfo.IsQuantized())
1921 {
1922 desc.m_PadValue = static_cast<float>(inputTensorInfo.GetQuantizationOffset());
1923 }
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02001924 for (unsigned int i = 0; i < padTensorInfo.GetNumElements() / step; ++i)
1925 {
1926 desc.m_PadList.emplace_back(padBuffer[i * step], padBuffer[i * step + 1]);
1927 }
1928
James Ward58dec6b2020-09-11 17:32:44 +01001929 auto layerName = fmt::format("Pad:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagand109a4d2020-07-28 10:42:13 +01001930 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01001931
1932 IConnectableLayer* layer = m_Network->AddPadLayer(desc, layerName.c_str());
1933 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalves6c2355b2018-12-19 12:52:01 -02001934 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1935
1936 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1937 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
1938
1939 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1940 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
1941}
1942
Narumol Prangnawaratbfaee6b2021-05-24 18:50:24 +01001943void TfLiteParserImpl::ParsePrelu(size_t subgraphIndex, size_t operatorIndex)
1944{
1945 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1946
1947 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1948 CHECK_VALID_SIZE(inputs.size(), 2);
1949
1950 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
1951 CHECK_VALID_SIZE(outputs.size(), 1);
1952
1953 auto layerName = fmt::format("Prelu:{}:{}", subgraphIndex, operatorIndex);
1954
1955 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
1956 armnn::TensorInfo alphaTensorInfo = ToTensorInfo(inputs[1]);
1957 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
1958 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
1959
1960 IConnectableLayer* layer = m_Network->AddPreluLayer(layerName.c_str());
1961 ARMNN_ASSERT(layer != nullptr);
1962 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1963
1964 if (IsConstTensor(inputs[1]))
1965 {
1966 armnn::IInputSlot* slot = &(layer->GetInputSlot(0));
1967 RegisterConsumerOfTensor(subgraphIndex, 0, slot);
1968
1969 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1970
1971 auto alphaTensorAndData = CreateConstTensorNonPermuted(inputs[1], alphaTensorInfo);
1972 std::string constLayerName = fmt::format("Constant:{}", inputs[1]->name);
1973 IConnectableLayer* constLayer =
1974 m_Network->AddConstantLayer(alphaTensorAndData, constLayerName.c_str());
1975 ARMNN_ASSERT(constLayer != nullptr);
1976
1977 constLayer->GetOutputSlot(0).SetTensorInfo(alphaTensorInfo);
1978 constLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1));
1979 RegisterOutputSlots(subgraphIndex,
1980 VIRTUAL_OPERATOR_ID,
1981 constLayer,
1982 { inputTensorIndexes[1] });
1983 }
1984 else
1985 {
1986 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
1987 RegisterInputSlots(subgraphIndex, operatorIndex, layer, inputTensorIndexes);
1988 }
1989
1990 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
1991 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
1992}
1993
Kevin May7d96b162021-02-03 17:38:41 +00001994void TfLiteParserImpl::ParseQuantize(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan66dedc72019-12-10 16:32:07 +00001995{
1996 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
1997
1998 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
1999 CHECK_VALID_SIZE(inputs.size(), 1);
2000
2001 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2002 CHECK_VALID_SIZE(outputs.size(), 1);
2003
James Ward58dec6b2020-09-11 17:32:44 +01002004 auto layerName = fmt::format("Quantize:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan66dedc72019-12-10 16:32:07 +00002005
2006 IConnectableLayer* layer = m_Network->AddQuantizeLayer(layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01002007 ARMNN_ASSERT(layer != nullptr);
Sadik Armagan66dedc72019-12-10 16:32:07 +00002008
Sadik Armagand109a4d2020-07-28 10:42:13 +01002009 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Sadik Armagan66dedc72019-12-10 16:32:07 +00002010 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2011
2012 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2013 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2014
2015 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2016 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2017}
Finn Williamsc42c3842019-01-22 14:18:11 +00002018
Kevin May7d96b162021-02-03 17:38:41 +00002019void TfLiteParserImpl::ParseRelu(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan58f39192018-09-17 14:14:39 +01002020{
Finn Williamsc42c3842019-01-22 14:18:11 +00002021 ParseActivation(subgraphIndex,operatorIndex, ActivationFunction::ReLu);
Sadik Armagan58f39192018-09-17 14:14:39 +01002022}
2023
Kevin May7d96b162021-02-03 17:38:41 +00002024void TfLiteParserImpl::ParseRelu6(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan58f39192018-09-17 14:14:39 +01002025{
Finn Williamsc42c3842019-01-22 14:18:11 +00002026 ParseActivation(subgraphIndex,operatorIndex, ActivationFunction::BoundedReLu);
2027}
Sadik Armagan58f39192018-09-17 14:14:39 +01002028
Kevin May7d96b162021-02-03 17:38:41 +00002029void TfLiteParserImpl::ParseLeakyRelu(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan12239e72020-05-27 11:06:17 +01002030{
Jan Eilers2f746b32020-07-28 14:00:06 +01002031 ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::LeakyReLu);
Sadik Armagan12239e72020-05-27 11:06:17 +01002032}
2033
Kevin May7d96b162021-02-03 17:38:41 +00002034void TfLiteParserImpl::ParseLogistic(size_t subgraphIndex, size_t operatorIndex)
Finn Williamsc42c3842019-01-22 14:18:11 +00002035{
2036 ParseActivation(subgraphIndex,operatorIndex,ActivationFunction::Sigmoid);
2037}
2038
Kevin May7d96b162021-02-03 17:38:41 +00002039void TfLiteParserImpl::ParseTanH(size_t subgraphIndex, size_t operatorIndex)
Nina Drozd99851762019-04-09 09:37:38 +01002040{
2041 ParseActivation(subgraphIndex,operatorIndex,ActivationFunction::TanH);
2042}
2043
Kevin May7d96b162021-02-03 17:38:41 +00002044void TfLiteParserImpl::ParseElu(size_t subgraphIndex, size_t operatorIndex)
Matthew Sloyan7515d072020-12-16 12:50:01 +00002045{
2046 ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::Elu);
2047}
2048
Kevin May7d96b162021-02-03 17:38:41 +00002049void TfLiteParserImpl::ParseHardSwish(size_t subgraphIndex, size_t operatorIndex)
Jan Eilers2f746b32020-07-28 14:00:06 +01002050{
2051 ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::HardSwish);
2052}
Finn Williamsc42c3842019-01-22 14:18:11 +00002053
Kevin May7d96b162021-02-03 17:38:41 +00002054void TfLiteParserImpl::ParseActivation(size_t subgraphIndex, size_t operatorIndex, ActivationFunction activationType)
Finn Williamsc42c3842019-01-22 14:18:11 +00002055{
2056 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan58f39192018-09-17 14:14:39 +01002057 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
Jan Eilers8eb25602020-03-09 12:13:48 +00002058 IgnoreUnused(operatorPtr);
Sadik Armagan58f39192018-09-17 14:14:39 +01002059
2060 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2061 CHECK_VALID_SIZE(inputs.size(), 1);
2062
2063 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2064 CHECK_VALID_SIZE(outputs.size(), 1);
2065
James Ward58dec6b2020-09-11 17:32:44 +01002066 auto layerName = fmt::format("Activation:");
Sadik Armagan58f39192018-09-17 14:14:39 +01002067 ActivationDescriptor activationDesc;
Finn Williamsc42c3842019-01-22 14:18:11 +00002068 activationDesc.m_Function = activationType;
2069
2070 switch (activationType)
2071 {
2072 case ActivationFunction::ReLu:
2073 {
James Ward58dec6b2020-09-11 17:32:44 +01002074 layerName += fmt::format("RELU:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsc42c3842019-01-22 14:18:11 +00002075 break;
2076 }
2077 case ActivationFunction::BoundedReLu:
2078 {
James Ward58dec6b2020-09-11 17:32:44 +01002079 layerName += fmt::format("RELU6:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsc42c3842019-01-22 14:18:11 +00002080 activationDesc.m_A = 6.0f;
2081 activationDesc.m_B = 0.0f;
2082 break;
2083 }
2084 case ActivationFunction::Sigmoid:
2085 {
James Ward58dec6b2020-09-11 17:32:44 +01002086 layerName += fmt::format("SIGMOID:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsc42c3842019-01-22 14:18:11 +00002087 break;
2088 }
Nina Drozd99851762019-04-09 09:37:38 +01002089 case ActivationFunction::TanH:
2090 {
James Ward58dec6b2020-09-11 17:32:44 +01002091 layerName += fmt::format("TANH:{}:{}", subgraphIndex, operatorIndex);
Nina Drozd99851762019-04-09 09:37:38 +01002092 activationDesc.m_A = 1.0f;
2093 activationDesc.m_B = 1.0f;
2094 break;
2095 }
Sadik Armagan12239e72020-05-27 11:06:17 +01002096 case ActivationFunction::LeakyReLu:
2097 {
James Ward58dec6b2020-09-11 17:32:44 +01002098 layerName += fmt::format("LEAKYRELU:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan12239e72020-05-27 11:06:17 +01002099 const auto * options = operatorPtr->builtin_options.AsLeakyReluOptions();
2100 activationDesc.m_A = options->alpha;
2101 break;
2102 }
Matthew Sloyan7515d072020-12-16 12:50:01 +00002103 case ActivationFunction::Elu:
2104 {
2105 layerName += fmt::format("ELU:{}:{}", subgraphIndex, operatorIndex);
2106 activationDesc.m_A = 1.0f;
2107 break;
2108 }
Jan Eilers2f746b32020-07-28 14:00:06 +01002109 case ActivationFunction::HardSwish:
Matthew Sloyan7515d072020-12-16 12:50:01 +00002110 {
James Ward58dec6b2020-09-11 17:32:44 +01002111 layerName += fmt::format("HARDSWISH:{}:{}", subgraphIndex, operatorIndex);
Jan Eilers2f746b32020-07-28 14:00:06 +01002112 break;
Matthew Sloyan7515d072020-12-16 12:50:01 +00002113 }
Finn Williamsc42c3842019-01-22 14:18:11 +00002114 default:
2115 {
2116 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01002117 fmt::format("Unexpected ActivationFunction[{}] when creating layerName {} ",
2118 static_cast<int>(activationType), CHECK_LOCATION().AsString()));
Finn Williamsc42c3842019-01-22 14:18:11 +00002119 }
2120 }
2121
2122 IConnectableLayer* const layer = m_Network->AddActivationLayer(activationDesc, layerName.c_str());
Sadik Armagan58f39192018-09-17 14:14:39 +01002123
Sadik Armagand109a4d2020-07-28 10:42:13 +01002124 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Sadik Armagan58f39192018-09-17 14:14:39 +01002125 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2126
2127 // register the input connection slots for the layer, connections are made after all layers have been created
2128 // only the tensors for the inputs are relevant, exclude the const tensors
2129 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2130 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2131
2132 // register the output connection slots for the layer, connections are made after all layers have been created
2133 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2134 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2135}
Kevin May7d96b162021-02-03 17:38:41 +00002136armnn::TensorInfo TfLiteParserImpl::OutputShapeOfReshape(const armnn::TensorInfo & inputTensorInfo,
2137 const std::vector<int32_t> & targetDimsIn)
Sadikb94967b2018-09-19 15:30:00 +01002138{
2139 std::vector<unsigned int> outputDims(targetDimsIn.begin(), targetDimsIn.end());
2140 const auto stretchDim = std::find(targetDimsIn.begin(), targetDimsIn.end(), -1);
2141
2142 if (stretchDim != targetDimsIn.end())
2143 {
2144 if (std::find(std::next(stretchDim), targetDimsIn.end(), -1) != targetDimsIn.end())
2145 {
2146 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01002147 fmt::format("At most one component of shape can be -1 {}", CHECK_LOCATION().AsString()));
Sadikb94967b2018-09-19 15:30:00 +01002148 }
2149
2150 auto targetNumElements =
Matthew Sloyan589e3e82020-09-11 16:17:48 +01002151 armnn::numeric_cast<unsigned int>(
Sadikb94967b2018-09-19 15:30:00 +01002152 std::accumulate(targetDimsIn.begin(), targetDimsIn.end(), -1, std::multiplies<int32_t>()));
2153
2154 auto stretchIndex = static_cast<size_t>(std::distance(targetDimsIn.begin(), stretchDim));
2155 outputDims[stretchIndex] = inputTensorInfo.GetNumElements() / targetNumElements;
2156 }
2157
2158 TensorShape outputShape = TensorShape(static_cast<unsigned int>(outputDims.size()), outputDims.data());
2159
2160 TensorInfo reshapeInfo = inputTensorInfo;
2161 reshapeInfo.SetShape(outputShape);
2162
2163 return reshapeInfo;
2164}
2165
Kevin May7d96b162021-02-03 17:38:41 +00002166void TfLiteParserImpl::ParseReshape(size_t subgraphIndex, size_t operatorIndex)
Sadikb94967b2018-09-19 15:30:00 +01002167{
2168 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2169
2170 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Sadikb94967b2018-09-19 15:30:00 +01002171
2172 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2173 CHECK_VALID_SIZE(outputs.size(), 1);
2174
2175 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2176 const auto * options = operatorPtr->builtin_options.AsReshapeOptions();
James Ward58dec6b2020-09-11 17:32:44 +01002177 auto layerName = fmt::format("Reshape:{}:{}", subgraphIndex, operatorIndex);
Sadikb94967b2018-09-19 15:30:00 +01002178
2179 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
kevmay0171972a82018-12-17 14:28:03 +00002180 armnn::TensorInfo actualOutputTensorInfo = ToTensorInfo(outputs[0]);
James Conroy05102392020-06-24 15:39:55 +01002181 CheckMatchingQuantization(inputTensorInfo, actualOutputTensorInfo, layerName, "Input 0", "Output 0");
Derek Lambertic9e52792020-03-11 11:42:26 +00002182
Jan Eilersbac9b352020-07-13 13:40:24 +01002183 // Extracting new shape for the output
2184 // There are two ways it can be passed
2185 // * First is to define the target shape in the operator built-in options
2186 // * Second is to pass it as a second input tensor
Derek Lambertic9e52792020-03-11 11:42:26 +00002187 std::vector<int32_t> targetShape;
Jan Eilersbac9b352020-07-13 13:40:24 +01002188 bool targetShapeFound = false;
2189 // Check if built-in options were given
2190 if (options != nullptr)
Derek Lambertic9e52792020-03-11 11:42:26 +00002191 {
Jan Eilersbac9b352020-07-13 13:40:24 +01002192 // make sure the parameter is given
2193 if (options->new_shape.empty() == false)
Derek Lambertic9e52792020-03-11 11:42:26 +00002194 {
Jan Eilersbac9b352020-07-13 13:40:24 +01002195 targetShape = options->new_shape;
2196 targetShapeFound = true;
Derek Lambertif4a953f2020-03-17 14:25:57 +00002197 }
Derek Lambertic9e52792020-03-11 11:42:26 +00002198 }
Jan Eilersbac9b352020-07-13 13:40:24 +01002199
2200 // If there is no built-in option given or if the built-in new_shape parameter was empty
2201 if (!targetShapeFound)
Derek Lambertic9e52792020-03-11 11:42:26 +00002202 {
Jan Eilersbac9b352020-07-13 13:40:24 +01002203 // Check for a second input tensor
2204 if (inputs.size() > 1 && inputs[1] != nullptr)
2205 {
2206 if (inputs[1]->is_variable)
2207 {
2208 ARMNN_THROW_PARSE_EXCEPTION( "Target shapes defined in non-const input tensors is not supported");
2209 }
2210
2211 if (inputs[1]->shape.size() != 1)
2212 {
2213 ARMNN_THROW_PARSE_EXCEPTION("Target 'shape' input is not a 1D tensor");
2214 }
2215
2216 if (inputs[1]->type != tflite::TensorType_INT32)
2217 {
2218 ARMNN_THROW_PARSE_EXCEPTION("Target 'shape' input is not an int32 type");
2219 }
2220
2221 // Extract target shape from input
2222 auto bufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2223 auto values = reinterpret_cast<const int32_t*>(bufferPtr->data.data());
Sadik Armagan19a1c032021-01-20 12:17:00 +00002224 if (!values)
2225 {
2226 ARMNN_THROW_PARSE_EXCEPTION("Reshape operator target shape input buffer data is null");
2227 }
Jan Eilersbac9b352020-07-13 13:40:24 +01002228 for (int i=0; i < inputs[1]->shape[0]; ++i)
2229 {
2230 targetShape.push_back(values[i]);
2231 }
2232 }
2233 else
Derek Lambertic9e52792020-03-11 11:42:26 +00002234 {
2235 ARMNN_THROW_PARSE_EXCEPTION("Target shape not defined in reshape parameters or input tensor. "
2236 "At least one method required");
2237 }
Derek Lambertic9e52792020-03-11 11:42:26 +00002238 }
2239
kevmay0171972a82018-12-17 14:28:03 +00002240 armnn::TensorInfo reshapeOutputTensorInfo =
Kevin May7d96b162021-02-03 17:38:41 +00002241 TfLiteParserImpl::OutputShapeOfReshape(inputTensorInfo, targetShape);
Sadikb94967b2018-09-19 15:30:00 +01002242
kevmay0171972a82018-12-17 14:28:03 +00002243 // Check for valid input size and that reshape parameters equal output shape
Aron Virginas-Tar70672f62019-01-23 14:00:00 +00002244 const armnn::TensorShape& reshapeOutputTensorShape = reshapeOutputTensorInfo.GetShape();
2245 if (inputs.size() > 1 && !CheckShape(reshapeOutputTensorShape, outputs[0]->shape))
kevmay0171972a82018-12-17 14:28:03 +00002246 {
2247 std::stringstream ss;
2248 ss << "New shape defined in reshape parameters "
Aron Virginas-Tar70672f62019-01-23 14:00:00 +00002249 << reshapeOutputTensorShape
kevmay0171972a82018-12-17 14:28:03 +00002250 << " does not equal output shape "
2251 << actualOutputTensorInfo.GetShape()
2252 << ": "
2253 << CHECK_LOCATION().AsString();
2254 throw ParseException(ss.str());
2255 }
2256
Sadikb94967b2018-09-19 15:30:00 +01002257 ReshapeDescriptor reshapeDesc;
kevmay0171972a82018-12-17 14:28:03 +00002258 reshapeDesc.m_TargetShape = reshapeOutputTensorInfo.GetShape();
Sadikb94967b2018-09-19 15:30:00 +01002259
Sadikb94967b2018-09-19 15:30:00 +01002260 IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002261 ARMNN_ASSERT(layer != nullptr);
kevmay0171972a82018-12-17 14:28:03 +00002262 layer->GetOutputSlot(0).SetTensorInfo(reshapeOutputTensorInfo);
Sadikb94967b2018-09-19 15:30:00 +01002263
2264 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2265 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2266
2267 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2268 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2269}
2270
Kevin May7d96b162021-02-03 17:38:41 +00002271void TfLiteParserImpl::ParseResizeBilinear(size_t subgraphIndex, size_t operatorIndex)
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02002272{
Sadik Armagana3b31f02019-12-05 09:08:53 +00002273 ParseResize(subgraphIndex, operatorIndex, ResizeMethod::Bilinear);
2274}
2275
Kevin May7d96b162021-02-03 17:38:41 +00002276void TfLiteParserImpl::ParseResizeNearestNeighbor(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagana3b31f02019-12-05 09:08:53 +00002277{
2278 ParseResize(subgraphIndex, operatorIndex, ResizeMethod::NearestNeighbor);
2279}
2280
Kevin May7d96b162021-02-03 17:38:41 +00002281void TfLiteParserImpl::ParseResize(size_t subgraphIndex, size_t operatorIndex, ResizeMethod resizeMethod)
Sadik Armagana3b31f02019-12-05 09:08:53 +00002282{
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02002283 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2284
2285 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2286 CHECK_VALID_SIZE(inputs.size(), 2);
2287
2288 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2289 CHECK_VALID_SIZE(outputs.size(), 1);
2290
2291 armnn::TensorInfo sizeTensorInfo = ToTensorInfo(inputs[1]);
2292
2293 // Data for the parsed tensor args (size) must be stored locally.
2294 std::vector<int32_t> sizeTensorData(sizeTensorInfo.GetNumElements());
2295
2296 BufferRawPtr sizeBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
2297 ::memcpy(sizeTensorData.data(), sizeBufferPtr->data.data(), sizeTensorInfo.GetNumBytes());
2298
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01002299 ResizeDescriptor desc;
Sadik Armagana3b31f02019-12-05 09:08:53 +00002300 desc.m_Method = resizeMethod;
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02002301 desc.m_TargetHeight = static_cast<uint32_t> (sizeTensorData[0]);
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01002302 desc.m_TargetWidth = static_cast<uint32_t> (sizeTensorData[1]);
2303 desc.m_DataLayout = armnn::DataLayout::NHWC;
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02002304
James Ward58dec6b2020-09-11 17:32:44 +01002305 auto layerName = fmt::format("Resize:");
Sadik Armagana3b31f02019-12-05 09:08:53 +00002306
2307 switch (resizeMethod)
2308 {
2309 case ResizeMethod::Bilinear:
2310 {
James Ward58dec6b2020-09-11 17:32:44 +01002311 layerName += fmt::format("BILINEAR:{}:{}", subgraphIndex, operatorIndex);
Sang-Hoon Park820eb142020-01-08 10:25:24 +00002312
2313 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2314 const auto * options = operatorPtr->builtin_options.AsResizeBilinearOptions();
2315
David Monahan4a0c9b92020-05-30 09:48:39 +01002316 desc.m_AlignCorners = options->align_corners;
Sadik Armagana3b31f02019-12-05 09:08:53 +00002317 break;
2318 }
2319 case ResizeMethod::NearestNeighbor:
2320 {
James Ward58dec6b2020-09-11 17:32:44 +01002321 layerName += fmt::format("NEARESTNEIGHBOR:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagana3b31f02019-12-05 09:08:53 +00002322 break;
2323 }
2324 default:
2325 {
2326 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01002327 fmt::format("Unexpected ResizeMethod[{}] when creating layerName {} ",
2328 static_cast<int>(resizeMethod), CHECK_LOCATION().AsString()));
Sadik Armagana3b31f02019-12-05 09:08:53 +00002329 }
2330 }
2331
James Conroy05102392020-06-24 15:39:55 +01002332 TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
Sadik Armagand109a4d2020-07-28 10:42:13 +01002333 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01002334 CheckMatchingQuantization(inputTensorInfo, outputTensorInfo, layerName, "Input 0", "Output 0");
2335
2336 IConnectableLayer* layer = m_Network->AddResizeLayer(desc, layerName.c_str());
2337 ARMNN_ASSERT(layer != nullptr);
Bruno Goncalves3f58ddb2019-02-07 18:40:11 -02002338 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2339
2340 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2341 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2342
2343 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2344 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2345}
2346
Kevin May7d96b162021-02-03 17:38:41 +00002347void TfLiteParserImpl::ParseConcatenation(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan479045b2018-10-01 11:51:37 +01002348{
2349 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2350
2351 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2352 const auto * options = operatorPtr->builtin_options.AsConcatenationOptions();
2353
2354 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
2355
2356 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2357 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2358 CHECK_VALID_SIZE(outputs.size(), 1);
2359
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00002360 unsigned int numConcatView = static_cast<unsigned int>(inputs.size());
2361 uint32_t inputRank = ToTensorInfo(inputs[0]).GetNumDimensions();
Sadik Armagan479045b2018-10-01 11:51:37 +01002362
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00002363 const unsigned int concatDimInput = static_cast<unsigned int>(
2364 (static_cast<int>(inputRank) + options->axis) % static_cast<int>(inputRank));
Sadik Armagan479045b2018-10-01 11:51:37 +01002365
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00002366 OriginsDescriptor concatDescriptor(static_cast<uint32_t>(numConcatView), inputRank);
2367 concatDescriptor.SetConcatAxis(concatDimInput);
Sadik Armagan479045b2018-10-01 11:51:37 +01002368
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00002369 unsigned int mergeDimOrigin = 0;
Sadik Armagan479045b2018-10-01 11:51:37 +01002370
2371 for (unsigned int viewIndex = 0; viewIndex < numConcatView; ++viewIndex)
2372 {
2373 TensorInfo inputTensorInfo = ToTensorInfo(inputs[viewIndex]);
2374
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00002375 // This set up concatDescriptor view origin
2376 armnnUtils::ProcessConcatInputTensorInfo(
2377 inputTensorInfo, concatDescriptor, concatDimInput, viewIndex, mergeDimOrigin);
Sadik Armagan479045b2018-10-01 11:51:37 +01002378 }
2379
James Ward58dec6b2020-09-11 17:32:44 +01002380 auto layerName = fmt::format("Concatenation:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagand109a4d2020-07-28 10:42:13 +01002381 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
James Conroy05102392020-06-24 15:39:55 +01002382
Jim Flynn906f9462019-05-10 13:55:21 +01002383 IConnectableLayer* layer = m_Network->AddConcatLayer(concatDescriptor, layerName.c_str());
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01002384 ARMNN_ASSERT(layer != nullptr);
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00002385 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
Sadik Armagan479045b2018-10-01 11:51:37 +01002386
James Conroy05102392020-06-24 15:39:55 +01002387 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00002388 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes});
Sadik Armagan479045b2018-10-01 11:51:37 +01002389
Nattapat Chaimanowong5e9d2982019-01-25 13:20:39 +00002390 // add fused activation layer
2391 layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
Sadik Armagan479045b2018-10-01 11:51:37 +01002392
Sadik Armagan479045b2018-10-01 11:51:37 +01002393 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2394 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2395}
2396
Kevin May7d96b162021-02-03 17:38:41 +00002397void TfLiteParserImpl::ParseFullyConnected(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan8853c1f2018-10-22 09:04:18 +01002398{
2399 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2400
2401 const auto & operatorRfr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2402 const auto options = operatorRfr->builtin_options.AsFullyConnectedOptions();
2403
2404 CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
2405
2406 FullyConnectedDescriptor desc;
2407 desc.m_BiasEnabled = false;
Nattapat Chaimanowongd8eee592018-10-26 10:24:14 +01002408 desc.m_TransposeWeightMatrix = true;
Sadik Armagan8853c1f2018-10-22 09:04:18 +01002409
2410 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2411 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2412 CHECK_VALID_SIZE(outputs.size(), 1);
2413
2414 armnn::TensorInfo filterTensorInfo = ToTensorInfo(inputs[1]);
2415
2416 // Fully Connected Layer accepts two dimensional weights input
2417 int32_t weightsDimension = static_cast<int32_t>(filterTensorInfo.GetNumDimensions());
2418 if (weightsDimension != 2)
2419 {
2420 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01002421 fmt::format("Dimension {} for Fully Connected weights is not supported by Armnn. "
2422 "Node {}",
2423 weightsDimension,
2424 CHECK_LOCATION().AsString()));
Sadik Armagan8853c1f2018-10-22 09:04:18 +01002425 }
2426
Matthew Jackson74bf7da2019-08-16 16:51:42 +01002427 armnn::IConnectableLayer* layer = nullptr;
James Ward58dec6b2020-09-11 17:32:44 +01002428 auto layerName = fmt::format("FullyConnected:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan8853c1f2018-10-22 09:04:18 +01002429
Finn Williamsd4fa5452021-03-01 12:31:41 +00002430 Optional<ConstTensor> filterOptionalConstTensor;
2431
2432 desc.m_ConstantWeights = IsConstTensor(inputs[1]);
2433
Finn Williamsd4fa5452021-03-01 12:31:41 +00002434 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2435 std::vector<unsigned int> tensorIndexesToRegister = {inputTensorIndexes[0]};
2436 if (desc.m_ConstantWeights)
2437 {
2438 filterOptionalConstTensor = Optional<ConstTensor>(CreateConstTensorNonPermuted(inputs[1], filterTensorInfo));
Sadik Armagan8853c1f2018-10-22 09:04:18 +01002439 }
2440 else
2441 {
Finn Williamsd4fa5452021-03-01 12:31:41 +00002442 // Non const weights will need to be registered as inputs
2443 tensorIndexesToRegister.emplace_back(inputTensorIndexes[1]);
Sadik Armagan8853c1f2018-10-22 09:04:18 +01002444 }
Sadik Armagan8853c1f2018-10-22 09:04:18 +01002445
Finn Williamsd4fa5452021-03-01 12:31:41 +00002446 Optional<ConstTensor> biasOptionalConstTensor;
2447 if (inputs.size() == 3)
2448 {
2449 desc.m_BiasEnabled = true;
2450 if (desc.m_ConstantWeights)
2451 {
2452 TensorInfo biasTensorInfo = ToTensorInfo(inputs[2]);
2453 biasOptionalConstTensor = Optional<ConstTensor>(CreateConstTensorNonPermuted(inputs[2], biasTensorInfo));
2454 }
2455 else
2456 {
2457 // Non const biases will need to be registered as inputs
2458 tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
2459 }
2460 }
2461
2462 layer = m_Network->AddFullyConnectedLayer(desc,
2463 filterOptionalConstTensor,
2464 biasOptionalConstTensor,
2465 layerName.c_str());
2466
2467 ARMNN_ASSERT(layer != nullptr);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01002468 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
2469
Finn Williamsd4fa5452021-03-01 12:31:41 +00002470 unsigned int startingSlotIndex = 0;
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01002471 if (inputTensorInfo.GetNumDimensions() > 2)
2472 {
2473 // Add reshape to flatten to 2D [batch_size, input_size],
2474 // where "input_size" corresponds to the number of inputs to the layer,
2475 // matching the second dimension of weights,
2476 // and "batch_size" is calculated by dividing the number of elements by "input_size".
2477 std::vector<unsigned int> reshapedDimensions(2);
2478 reshapedDimensions[1] = filterTensorInfo.GetShape()[1];
2479 reshapedDimensions[0] = inputTensorInfo.GetNumElements() / reshapedDimensions[1];
2480
2481 if (inputTensorInfo.GetNumElements() % reshapedDimensions[1] != 0)
2482 {
2483 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01002484 fmt::format("Failed to deduce input tensor shape from filter size {} {}",
2485 reshapedDimensions[1],
2486 CHECK_LOCATION().AsString()));
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01002487 }
2488
2489 armnn::TensorInfo reshapedTensorInfo = ToTensorInfo(inputs[0]);
2490 reshapedTensorInfo.SetShape(armnn::TensorShape{ 2, reshapedDimensions.data() });
2491
James Ward58dec6b2020-09-11 17:32:44 +01002492 std::string reshapeLayerName = fmt::format("Reshape_for:{}", layer->GetName());
Finn Williamsd4fa5452021-03-01 12:31:41 +00002493 armnn::ReshapeDescriptor reshapeDescriptor;
2494 reshapeDescriptor.m_TargetShape = reshapedTensorInfo.GetShape();
2495 armnn::IConnectableLayer* reshapeLayer = m_Network->AddReshapeLayer(reshapeDescriptor, layerName.c_str());
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01002496
2497 reshapeLayer->GetOutputSlot(0).SetTensorInfo(reshapedTensorInfo);
2498 reshapeLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
2499
2500 RegisterInputSlots(subgraphIndex, operatorIndex, reshapeLayer, {inputTensorIndexes[0]});
Finn Williamsd4fa5452021-03-01 12:31:41 +00002501 // Fc layer connects to the reshape layer, so we skip the first input slot when registering fc's input slots
2502 tensorIndexesToRegister.erase(tensorIndexesToRegister.begin());
2503 startingSlotIndex = 1;
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01002504 }
Finn Williamsd4fa5452021-03-01 12:31:41 +00002505
2506 RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister, startingSlotIndex);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01002507
Sadik Armagand109a4d2020-07-28 10:42:13 +01002508 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Sadik Armagan8853c1f2018-10-22 09:04:18 +01002509 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2510
Sadik Armagan8853c1f2018-10-22 09:04:18 +01002511 // we need to add the activation layer and fortunately we don't need to care about the data layout
2512 armnn::IConnectableLayer* fusedActivationLayer = AddFusedActivationLayer(layer, 0,
2513 options->fused_activation_function);
Narumol Prangnawarat501f4d42019-04-24 15:52:20 +01002514
Sadik Armagan8853c1f2018-10-22 09:04:18 +01002515 // register the output connection slots for the layer, connections are made after all layers have been created
2516 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2517 RegisterOutputSlots(subgraphIndex, operatorIndex, fusedActivationLayer, {outputTensorIndexes[0]});
2518}
2519
Kevin May7d96b162021-02-03 17:38:41 +00002520void TfLiteParserImpl::ParseDetectionPostProcess(size_t subgraphIndex, size_t operatorIndex)
keidav011b3e2ea2019-02-21 10:07:37 +00002521{
2522 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2523
2524 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2525
2526 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2527 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2528 CHECK_VALID_SIZE(outputs.size(), 4);
2529
2530 // Obtain custom options from flexbuffers
2531 auto custom_options = operatorPtr->custom_options;
2532 const flexbuffers::Map& m = flexbuffers::GetRoot(custom_options.data(), custom_options.size()).AsMap();
2533
2534 // Obtain descriptor information from tf lite
2535 DetectionPostProcessDescriptor desc;
2536 desc.m_MaxDetections = m["max_detections"].AsUInt32();
2537 desc.m_MaxClassesPerDetection = m["max_classes_per_detection"].AsUInt32();
2538 desc.m_NmsScoreThreshold = m["nms_score_threshold"].AsFloat();
2539 desc.m_NmsIouThreshold = m["nms_iou_threshold"].AsFloat();
2540 desc.m_NumClasses = m["num_classes"].AsUInt32();
2541 desc.m_ScaleH = m["h_scale"].AsFloat();
2542 desc.m_ScaleW = m["w_scale"].AsFloat();
2543 desc.m_ScaleX = m["x_scale"].AsFloat();
2544 desc.m_ScaleY = m["y_scale"].AsFloat();
2545
keidav0107d58c72019-02-26 11:57:39 +00002546 if (!(m["use_regular_nms"].IsNull()))
keidav011b3e2ea2019-02-21 10:07:37 +00002547 {
keidav0107d58c72019-02-26 11:57:39 +00002548 desc.m_UseRegularNms = m["use_regular_nms"].AsBool();
keidav011b3e2ea2019-02-21 10:07:37 +00002549 }
2550 if (!(m["detections_per_class"].IsNull()))
2551 {
2552 desc.m_DetectionsPerClass = m["detections_per_class"].AsUInt32();
2553 }
2554
2555 if (desc.m_NmsIouThreshold <= 0.0f || desc.m_NmsIouThreshold > 1.0f)
2556 {
2557 throw InvalidArgumentException("DetectionPostProcessTFLiteParser: Intersection over union threshold "
2558 "must be positive and less than or equal to 1.");
2559 }
2560
2561 armnn::TensorInfo anchorTensorInfo = ToTensorInfo(inputs[2]);
Finn Williamsd4fa5452021-03-01 12:31:41 +00002562 auto anchorTensorAndData = CreateConstTensorNonPermuted(inputs[2], anchorTensorInfo);
keidav011b3e2ea2019-02-21 10:07:37 +00002563
James Ward58dec6b2020-09-11 17:32:44 +01002564 auto layerName = fmt::format("DetectionPostProcess:{}:{}", subgraphIndex, operatorIndex);
Finn Williamsd4fa5452021-03-01 12:31:41 +00002565 IConnectableLayer* layer = m_Network->AddDetectionPostProcessLayer(desc, anchorTensorAndData,
keidav011b3e2ea2019-02-21 10:07:37 +00002566 layerName.c_str());
2567
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01002568 ARMNN_ASSERT(layer != nullptr);
keidav011b3e2ea2019-02-21 10:07:37 +00002569
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00002570 // The model does not specify the output shapes.
2571 // The output shapes are calculated from the max_detection and max_classes_per_detection.
2572 unsigned int numDetectedBox = desc.m_MaxDetections * desc.m_MaxClassesPerDetection;
2573 m_OverridenOutputShapes.push_back({ 1, numDetectedBox, 4 });
2574 m_OverridenOutputShapes.push_back({ 1, numDetectedBox });
2575 m_OverridenOutputShapes.push_back({ 1, numDetectedBox });
2576 m_OverridenOutputShapes.push_back({ 1 });
2577
keidav011b3e2ea2019-02-21 10:07:37 +00002578 for (unsigned int i = 0 ; i < outputs.size() ; ++i)
2579 {
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00002580 armnn::TensorInfo detectionBoxOutputTensorInfo = ToTensorInfo(outputs[i], m_OverridenOutputShapes[i]);
keidav011b3e2ea2019-02-21 10:07:37 +00002581 layer->GetOutputSlot(i).SetTensorInfo(detectionBoxOutputTensorInfo);
2582 }
2583
2584 // Register the input connection slots for the layer, connections are made after all layers have been created
2585 // only the tensors for the inputs are relevant, exclude the const tensors
2586 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2587 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
2588
2589 // Register the output connection slots for the layer, connections are made after all layers have been created
2590 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2591 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0],
2592 outputTensorIndexes[1],
2593 outputTensorIndexes[2],
2594 outputTensorIndexes[3]});
2595}
2596
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01002597/// The TfLite Pack operator is equivalent to the ArmNN Stack operator
Kevin May7d96b162021-02-03 17:38:41 +00002598void TfLiteParserImpl::ParsePack(size_t subgraphIndex, size_t operatorIndex)
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01002599{
2600 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2601
2602 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2603 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2604 CHECK_VALID_SIZE(outputs.size(), 1);
2605
2606 if (inputs.size() < 1)
2607 {
2608 throw ParseException("Pack must have at least one input.");
2609 }
2610
2611 const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2612 const auto* options = operatorPtr->builtin_options.AsPackOptions();
2613
2614 StackDescriptor desc;
2615 desc.m_Axis = static_cast<uint32_t>(options->axis);
2616 desc.m_NumInputs = static_cast<uint32_t>(inputs.size());
2617
2618 // Use the tensor shape of the first input as the "correct" input shape in the descriptor
2619 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
2620 desc.m_InputShape = inputTensorInfo.GetShape();
2621
James Ward58dec6b2020-09-11 17:32:44 +01002622 auto layerName = fmt::format("Pack:{}:{}", subgraphIndex, operatorIndex);
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01002623 IConnectableLayer* layer = m_Network->AddStackLayer(desc, layerName.c_str());
2624
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01002625 ARMNN_ASSERT(layer != nullptr);
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01002626
Sadik Armagand109a4d2020-07-28 10:42:13 +01002627 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
Matthew Jacksonbcca1f42019-07-16 11:39:21 +01002628 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2629
2630 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2631 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes});
2632
2633 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2634 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
2635}
2636
Kevin May7d96b162021-02-03 17:38:41 +00002637void TfLiteParserImpl::ParseUnpack(size_t subgraphIndex, size_t operatorIndex)
Nina Drozd200e3802019-04-15 09:47:39 +01002638{
2639 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2640
2641 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2642 const auto * options = operatorPtr->builtin_options.AsUnpackOptions();
2643
2644 // This unpackAxis indicates the axis to unpack
2645 const unsigned int unpackAxis = CHECKED_NON_NEGATIVE(options->axis);
2646
2647 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2648 CHECK_VALID_SIZE(inputs.size(), 1);
2649
2650 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
Narumol Prangnawarat672de572019-04-23 15:28:06 +01002651
2652 if (unpackAxis >= inputTensorInfo.GetNumDimensions())
2653 {
2654 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01002655 fmt::format("The unpack axis: {} cannot be greater than or equal to "
2656 "the number of input dimension {} {}",
2657 unpackAxis,
2658 inputTensorInfo.GetNumDimensions(),
2659 CHECK_LOCATION().AsString()));
Narumol Prangnawarat672de572019-04-23 15:28:06 +01002660 }
2661
Nina Drozd200e3802019-04-15 09:47:39 +01002662 unsigned int unpackNum = CHECKED_NON_NEGATIVE(options->num);
2663 // If num is not defined, automatically infer from the length of the dimension axis.
2664 if(unpackNum == 0)
2665 {
2666 unpackNum = inputTensorInfo.GetShape()[unpackAxis];
2667 }
2668
2669 // If unpack number cannot be inferred and is still zero, throw ParseException.
2670 if(unpackNum == 0)
2671 {
2672 throw ParseException("Number to unpack must greater than zero.");
2673 }
2674
2675 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2676 CHECK_VALID_SIZE(outputs.size(), unpackNum);
2677
2678 auto inputDimSize = inputTensorInfo.GetNumDimensions();
2679 std::vector<unsigned int> unpackDimSizes(inputDimSize);
2680
2681 // Add current input shape to unpackDimSizes
2682 for (unsigned int i = 0; i < inputDimSize; ++i)
2683 {
2684 unpackDimSizes[i] = inputTensorInfo.GetShape()[i];
2685 }
2686
2687 if (unpackDimSizes[unpackAxis] != unpackNum)
2688 {
2689 throw ParseException("Number to unpack must be the same as length of the dimension to "
2690 "unpack along.");
2691 }
2692
2693 unpackDimSizes[unpackAxis] /= unpackNum;
2694
2695 SplitterDescriptor splitDesc(unpackNum, static_cast<unsigned int>(unpackDimSizes.size()));
2696 for (unsigned int j = 0; j < unpackNum; ++j)
2697 {
2698 // Set the size of the views.
2699 for (unsigned int dimIdx = 0; dimIdx < unpackDimSizes.size(); ++dimIdx)
2700 {
2701 splitDesc.SetViewSize(j, dimIdx, unpackDimSizes[dimIdx]);
2702 }
2703 splitDesc.SetViewOriginCoord(j, unpackAxis, unpackDimSizes[unpackAxis] * j);
2704 }
2705
James Ward58dec6b2020-09-11 17:32:44 +01002706 auto layerName = fmt::format("Unpack:{}:{}", subgraphIndex, operatorIndex);
Nina Drozd200e3802019-04-15 09:47:39 +01002707 IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002708 ARMNN_ASSERT(layer != nullptr);
Nina Drozd200e3802019-04-15 09:47:39 +01002709
Narumol Prangnawarat672de572019-04-23 15:28:06 +01002710 TensorShape splitOutShape = TensorShape(static_cast<unsigned int>(unpackDimSizes.size()),
2711 unpackDimSizes.data());
2712
Nina Drozd200e3802019-04-15 09:47:39 +01002713 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2714 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2715
Narumol Prangnawarat672de572019-04-23 15:28:06 +01002716 // Create reshape to remove the unpacked dimension for unpack operator of each output from Splitter.
2717 for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
2718 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01002719 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[k], true);
James Ward58dec6b2020-09-11 17:32:44 +01002720 std::string reshapeLayerName = fmt::format("Reshape_for:{}", layer->GetName());
Narumol Prangnawarat672de572019-04-23 15:28:06 +01002721 armnn::ReshapeDescriptor desc;
Narumol Prangnawarat2c526462019-10-21 14:58:26 +01002722 desc.m_TargetShape = outputTensorInfo.GetShape();
Narumol Prangnawarat672de572019-04-23 15:28:06 +01002723 armnn::IConnectableLayer* reshapeLayer = m_Network->AddReshapeLayer(desc, layerName.c_str());
2724
Narumol Prangnawarat2c526462019-10-21 14:58:26 +01002725 layer->GetOutputSlot(k).SetTensorInfo(armnn::TensorInfo(splitOutShape,
2726 outputTensorInfo.GetDataType(),
2727 outputTensorInfo.GetQuantizationScale(),
2728 outputTensorInfo.GetQuantizationOffset()));
Narumol Prangnawarat672de572019-04-23 15:28:06 +01002729 layer->GetOutputSlot(k).Connect(reshapeLayer->GetInputSlot(0));
2730
Narumol Prangnawarat2c526462019-10-21 14:58:26 +01002731 reshapeLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
Narumol Prangnawarat672de572019-04-23 15:28:06 +01002732
2733 uint32_t reshapedOutputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[k]);
2734 armnn::IOutputSlot* slot = &(reshapeLayer->GetOutputSlot(0));
2735 RegisterProducerOfTensor(subgraphIndex, reshapedOutputId, slot);
2736 }
Nina Drozd200e3802019-04-15 09:47:39 +01002737}
2738
Kevin May7d96b162021-02-03 17:38:41 +00002739void TfLiteParserImpl::ParseSplit(size_t subgraphIndex, size_t operatorIndex)
Nina Drozd0324f482019-04-08 10:52:10 +01002740{
2741 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2742
2743 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
2744 const auto * options = operatorPtr->builtin_options.AsSplitOptions();
2745
2746 const unsigned int numSplits = CHECKED_NON_NEGATIVE(options->num_splits);
2747
Nina Drozd200e3802019-04-15 09:47:39 +01002748 // If number of splits cannot be inferred and is zero, throw ParseException.
2749 if(numSplits == 0)
2750 {
2751 throw ParseException("Number to splits must greater than zero.");
2752 }
2753
Nina Drozd0324f482019-04-08 10:52:10 +01002754 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2755 CHECK_VALID_SIZE(inputs.size(), 2);
2756 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2757 CHECK_VALID_SIZE(outputs.size(), numSplits);
2758
Matthew Sloyaned7fce42021-04-15 20:46:24 +01002759 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[1]);
2760 armnn::TensorInfo axisTensorInfo = ToTensorInfo(inputs[0]);
2761 ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
Nina Drozd0324f482019-04-08 10:52:10 +01002762
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01002763 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[0]->buffer);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01002764 if (axisBufferPtr == nullptr)
2765 {
2766 throw ParseException(
2767 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
2768 CHECK_LOCATION().AsString()));
2769 }
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01002770
Matthew Sloyaned7fce42021-04-15 20:46:24 +01002771 std::vector<int32_t> axisData(axisTensorInfo.GetNumElements());
2772 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
2773 int32_t axis = axisData[0];
2774
2775 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
2776 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
2777 {
2778 // Square bracket denotes inclusive n while parenthesis denotes exclusive n
2779 // E.g. Rank 4 tensor can have axis in range [-4, 3)
2780 // -1 == 3, -2 == 2, -3 == 1, -4 == 0
2781 throw ParseException(
2782 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
2783 axis,
2784 CHECK_LOCATION().AsString()));
2785 }
2786
2787 const unsigned int splitDim = armnnUtils::GetUnsignedAxis(inputTensorInfo.GetNumDimensions(), axis);
Nina Drozd0324f482019-04-08 10:52:10 +01002788
Nina Drozd0324f482019-04-08 10:52:10 +01002789 auto inputDimSize = inputTensorInfo.GetNumDimensions();
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01002790 if (inputDimSize > MaxNumOfTensorDimensions)
Nina Drozd0324f482019-04-08 10:52:10 +01002791 {
2792 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01002793 fmt::format("The number of dimensions: {} for input tensors of the split op cannot be greater than {} {}",
2794 inputTensorInfo.GetNumDimensions(),
2795 MaxNumOfTensorDimensions,
2796 CHECK_LOCATION().AsString()));
Nina Drozd0324f482019-04-08 10:52:10 +01002797 }
2798
2799 std::vector<unsigned int> splitterDimSizes(inputDimSize);
2800
2801 // Add current input shape to splitterDimSizes
2802 for (unsigned int i = 0; i < inputDimSize; ++i)
2803 {
2804 splitterDimSizes[i] = inputTensorInfo.GetShape()[i];
2805 }
2806
2807 if (splitterDimSizes[splitDim] % numSplits != 0)
2808 {
2809 throw ParseException("Number of splits must evenly divide the dimension");
2810 }
2811 splitterDimSizes[splitDim] /= numSplits;
2812
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01002813 SplitterDescriptor splitDesc(numSplits, inputDimSize);
Nina Drozd0324f482019-04-08 10:52:10 +01002814 for (unsigned int j = 0; j < numSplits; ++j)
2815 {
2816 // Set the size of the views.
2817 for (unsigned int dimIdx = 0; dimIdx < splitterDimSizes.size(); ++dimIdx)
2818 {
2819 splitDesc.SetViewSize(j, dimIdx, splitterDimSizes[dimIdx]);
2820 }
2821 splitDesc.SetViewOriginCoord(j, splitDim, splitterDimSizes[splitDim] * j);
2822 }
2823
James Ward58dec6b2020-09-11 17:32:44 +01002824 auto layerName = fmt::format("Split:{}:{}", subgraphIndex, operatorIndex);
Nina Drozd0324f482019-04-08 10:52:10 +01002825 IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002826 ARMNN_ASSERT(layer != nullptr);
Nina Drozd0324f482019-04-08 10:52:10 +01002827
2828 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
Narumol Prangnawarat17660e62019-04-18 16:56:19 +01002829 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[1]});
Nina Drozd0324f482019-04-08 10:52:10 +01002830
Nina Drozd0324f482019-04-08 10:52:10 +01002831 for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
2832 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01002833 armnn::TensorInfo tensorInfo = ToTensorInfo(outputs[k], true);
Francis Murtagh98d6b3d2019-10-21 10:52:54 +01002834 layer->GetOutputSlot(k).SetTensorInfo(tensorInfo);
Nina Drozd0324f482019-04-08 10:52:10 +01002835 }
2836
2837 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
2838 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
2839}
2840
Derek Lambertif0176992020-04-28 13:37:49 +01002841unsigned int ComputeWrappedIndex(int idx, unsigned int numDimsIn)
2842{
2843 int numDims = armnn::numeric_cast<int>(numDimsIn);
2844 int v = idx < 0 ? numDims + idx : idx;
2845 ARMNN_ASSERT(v >= 0);
2846 ARMNN_ASSERT(v < numDims);
2847
2848 return static_cast<unsigned int>(v);
2849}
2850
Kevin May7d96b162021-02-03 17:38:41 +00002851void TfLiteParserImpl::ParseSplitV(size_t subgraphIndex, size_t operatorIndex)
Derek Lambertif0176992020-04-28 13:37:49 +01002852{
2853 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
2854
2855 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
Ryan OShea86704732020-05-26 11:41:04 +01002856 const auto * options = operatorPtr->builtin_options.AsSplitVOptions();
Derek Lambertif0176992020-04-28 13:37:49 +01002857
2858 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
2859 CHECK_VALID_SIZE(inputs.size(), 3);
2860
2861 auto& inputTensor = inputs[0];
2862 auto& splitsTensor = inputs[1];
2863 auto& axisTensor = inputs[2];
2864
2865 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputTensor);
2866 armnn::TensorInfo splitsInfo = ToTensorInfo(splitsTensor);
2867 armnn::TensorInfo axisTensorInfo = ToTensorInfo(axisTensor);
2868 ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
2869
2870 // Inputs
2871 auto inputDimSize = inputTensorInfo.GetNumDimensions();
2872 if (inputDimSize > MaxNumOfTensorDimensions)
2873 {
2874 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01002875 fmt::format("The number of dimensions: {} for input tensors of the "
2876 "SplitV op cannot be greater than {} {}",
2877 inputTensorInfo.GetNumDimensions(),
2878 MaxNumOfTensorDimensions,
2879 CHECK_LOCATION().AsString()));
Derek Lambertif0176992020-04-28 13:37:49 +01002880 }
2881
2882 // Get split axis
2883 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, axisTensor->buffer);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01002884 if (axisBufferPtr == nullptr)
2885 {
2886 throw ParseException(
2887 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
2888 CHECK_LOCATION().AsString()));
2889 }
2890
Derek Lambertif0176992020-04-28 13:37:49 +01002891 std::vector<int> axisData(axisTensorInfo.GetNumElements());
2892 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
Matthew Sloyaned7fce42021-04-15 20:46:24 +01002893 int32_t axis = axisData[0];
2894
2895 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
2896 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
2897 {
2898 // Square bracket denotes inclusive n while parenthesis denotes exclusive n
2899 // E.g. Rank 4 tensor can have axis in range [-4, 3)
2900 // -1 == 3, -2 == 2, -3 == 1, -4 == 0
2901 throw ParseException(
2902 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
2903 axis,
2904 CHECK_LOCATION().AsString()));
2905 }
2906 const unsigned int splitDim = ComputeWrappedIndex(axis, inputTensorInfo.GetNumDimensions());
Derek Lambertif0176992020-04-28 13:37:49 +01002907
Derek Lambertif0176992020-04-28 13:37:49 +01002908 // Set split sizes
Derek Lambertif0176992020-04-28 13:37:49 +01002909 CHECK_VALID_SIZE(splitsInfo.GetNumDimensions(), 1);
Ryan OShea86704732020-05-26 11:41:04 +01002910 unsigned int numSplits{0};
2911
2912 if(options)
Derek Lambertif0176992020-04-28 13:37:49 +01002913 {
2914 numSplits = CHECKED_NON_NEGATIVE(options->num_splits);
Derek Lambertif0176992020-04-28 13:37:49 +01002915 }
2916 else
2917 {
Ryan OShea86704732020-05-26 11:41:04 +01002918 numSplits = splitsInfo.GetNumElements();
Derek Lambertif0176992020-04-28 13:37:49 +01002919 }
2920
2921 if (numSplits <=0)
2922 {
2923 throw ParseException("SplitV has invalid number of splits");
2924 }
2925
Jan Eilersc0761e92020-06-29 16:48:44 +01002926 std::vector<int> splitsData(numSplits);
Ryan OShea86704732020-05-26 11:41:04 +01002927 BufferRawPtr splitsBufferPtr = GetBuffer(m_Model, splitsTensor->buffer);
Jan Eilersc0761e92020-06-29 16:48:44 +01002928 ::memcpy(splitsData.data(), splitsBufferPtr->data.data(), splitsInfo.GetNumBytes());
Ryan OShea86704732020-05-26 11:41:04 +01002929
Jan Eilersc0761e92020-06-29 16:48:44 +01002930 unsigned int idx = 0;
Ryan OShea86704732020-05-26 11:41:04 +01002931 int numInferred{0};
2932 unsigned int inferIdx{0};
2933 int splitSum{0};
2934 for (auto split : splitsData)
2935 {
2936 if (split < 0)
2937 {
2938 numInferred++;
2939 inferIdx = idx;
2940 }
2941 else
2942 {
2943 splitSum += split;
2944 }
2945 idx++;
2946 }
2947 // Check for inferred Axis
2948 if (numInferred == 0)
2949 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +01002950 if (splitSum != armnn::numeric_cast<int>(inputTensorInfo.GetShape()[splitDim]))
Ryan OShea86704732020-05-26 11:41:04 +01002951 {
2952 throw ParseException("SplitV split_sizes does not sum to the dimension of value along split_dim.");
2953 }
2954 }
2955 else if (numInferred == 1)
2956 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +01002957 splitsData[inferIdx] = armnn::numeric_cast<int>(inputTensorInfo.GetShape()[splitDim]) - splitSum;
Ryan OShea86704732020-05-26 11:41:04 +01002958 }
2959 else
2960 {
2961 throw ParseException("Cannot infer split size for more than one split");
2962 }
2963
Derek Lambertif0176992020-04-28 13:37:49 +01002964 //Ouput size validation
2965 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
2966 CHECK_VALID_SIZE(outputs.size(), numSplits);
2967
2968 // Setup Armnn descriptor
2969 SplitterDescriptor splitDesc(numSplits, inputDimSize);
2970 unsigned int accumSplit = 0;
2971 for (unsigned int j = 0; j < numSplits; ++j)
2972 {
Matthew Sloyan589e3e82020-09-11 16:17:48 +01002973 unsigned int splitSize = armnn::numeric_cast<unsigned int>(splitsData[j]);
Derek Lambertif0176992020-04-28 13:37:49 +01002974
2975 // Set the size of the views.
2976 for (unsigned int dimIdx = 0; dimIdx < inputTensorInfo.GetNumDimensions(); ++dimIdx)
2977 {
2978 unsigned int dimSize = inputTensorInfo.GetShape()[dimIdx];
2979 if (dimIdx == splitDim)
2980 {
2981 dimSize = splitSize;
2982 }
2983 splitDesc.SetViewSize(j, dimIdx, dimSize);
2984 }
2985
2986 splitDesc.SetViewOriginCoord(j, splitDim, accumSplit);
2987 accumSplit += splitSize;
2988 }
2989
James Ward58dec6b2020-09-11 17:32:44 +01002990 auto layerName = fmt::format("SplitV:{}:{}", subgraphIndex, operatorIndex);
Derek Lambertif0176992020-04-28 13:37:49 +01002991 IConnectableLayer* layer = m_Network->AddSplitterLayer(splitDesc, layerName.c_str());
James Conroy05102392020-06-24 15:39:55 +01002992 ARMNN_ASSERT(layer != nullptr);
Derek Lambertif0176992020-04-28 13:37:49 +01002993
2994 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
2995 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
2996
2997 for (unsigned int k = 0; k < layer->GetNumOutputSlots(); ++k)
2998 {
Sadik Armagand109a4d2020-07-28 10:42:13 +01002999 armnn::TensorInfo tensorInfo = ToTensorInfo(outputs[k], true);
Derek Lambertif0176992020-04-28 13:37:49 +01003000 layer->GetOutputSlot(k).SetTensorInfo(tensorInfo);
3001 }
3002
3003 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3004 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
3005}
3006
Matthew Sloyan28f177c2021-04-09 14:38:52 +01003007void TfLiteParserImpl::ParseArgMin(size_t subgraphIndex, size_t operatorIndex)
3008{
3009 ParseArgMinMax(subgraphIndex, operatorIndex, armnn::ArgMinMaxFunction::Min);
3010}
3011
Kevin May7d96b162021-02-03 17:38:41 +00003012void TfLiteParserImpl::ParseArgMax(size_t subgraphIndex, size_t operatorIndex)
Inki Daed4619e22020-09-10 15:33:54 +09003013{
Matthew Sloyan28f177c2021-04-09 14:38:52 +01003014 ParseArgMinMax(subgraphIndex, operatorIndex, armnn::ArgMinMaxFunction::Max);
3015}
3016
3017void TfLiteParserImpl::ParseArgMinMax(size_t subgraphIndex, size_t operatorIndex, ArgMinMaxFunction argMinMaxFunction)
3018{
Inki Daed4619e22020-09-10 15:33:54 +09003019 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3020 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3021 CHECK_VALID_SIZE(inputs.size(), 2);
3022
3023 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3024 CHECK_VALID_SIZE(outputs.size(), 1);
3025
Matthew Sloyan28f177c2021-04-09 14:38:52 +01003026 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
3027 armnn::TensorInfo axisTensorInfo = ToTensorInfo(inputs[1]);
Inki Daed4619e22020-09-10 15:33:54 +09003028 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
Matthew Sloyaned7fce42021-04-15 20:46:24 +01003029 ARMNN_ASSERT(axisTensorInfo.GetNumElements() == 1);
Matthew Sloyan28f177c2021-04-09 14:38:52 +01003030
3031 // Check if output tensor type is Signed32 or Signed64
Mike Kelly1f140f72021-04-06 12:25:55 +01003032 if (outputTensorInfo.GetDataType() != armnn::DataType::Signed32 &&
3033 outputTensorInfo.GetDataType() != armnn::DataType::Signed64)
3034 {
3035 throw ParseException(
3036 fmt::format(
3037 "Output tensor data type is not supported. (Supported types: Signed32 & Signed64) {}",
3038 CHECK_LOCATION().AsString()));
3039 }
Matthew Sloyan28f177c2021-04-09 14:38:52 +01003040
3041 // Get const axis value from model and set it to descriptor.
3042 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
3043 if (axisBufferPtr == nullptr)
3044 {
3045 throw ParseException(
3046 fmt::format("Operation has invalid inputs. Failed to read axis. {}",
3047 CHECK_LOCATION().AsString()));
3048 }
3049
3050 std::vector<int32_t> axisData(axisTensorInfo.GetNumElements());
3051 ::memcpy(axisData.data(), axisBufferPtr->data.data(), axisTensorInfo.GetNumBytes());
3052 int32_t axis = axisData.front();
3053
3054 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
3055 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
3056 {
3057 // Square bracket denotes inclusive n while parenthesis denotes exclusive n
3058 // E.g. Rank 4 tensor can have axis in range [-4, 3)
3059 // -1 == 3, -2 == 2, -3 == 1, -4 == 0
3060 throw ParseException(
3061 fmt::format("Operation has invalid axis: {}. Axis must be in range [-n, n) {}",
3062 axis,
3063 CHECK_LOCATION().AsString()));
3064 }
3065
3066 ArgMinMaxDescriptor desc;
3067 desc.m_Axis = axis;
3068 desc.m_Function = argMinMaxFunction;
3069
3070 // Register a ArgMin/ArgMax layer.
3071 auto layerName = argMinMaxFunction == ArgMinMaxFunction::Max ? "ArgMax:{}:{}" : "ArgMin:{}:{}";
3072 auto layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
3073 IConnectableLayer *layer = m_Network->AddArgMinMaxLayer(desc, layerNameFormatted.c_str());
3074 ARMNN_ASSERT(layer != nullptr);
Inki Daed4619e22020-09-10 15:33:54 +09003075 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3076
3077 // Register input tensor to the layer.
3078 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3079 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3080
3081 // Register output tensor to the layer.
3082 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3083 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
3084}
3085
Kevin May7d96b162021-02-03 17:38:41 +00003086void TfLiteParserImpl::ParseGather(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan26868492021-01-22 14:25:31 +00003087{
3088 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3089
Kevin May7d96b162021-02-03 17:38:41 +00003090 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00003091 CHECK_VALID_SIZE(inputs.size(), 2);
Kevin May7d96b162021-02-03 17:38:41 +00003092 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00003093 CHECK_VALID_SIZE(outputs.size(), 1);
3094
3095 armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
3096 armnn::TensorInfo indicesTensorInfo = ToTensorInfo(inputs[1]);
3097 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
3098
3099 armnn::GatherDescriptor gatherDescriptor;
3100
3101 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3102 const auto * options = operatorPtr->builtin_options.AsGatherOptions();
3103 auto axis = options->axis;
3104
3105 auto inputDimensions = static_cast<int32_t>(inputTensorInfo.GetNumDimensions());
3106 auto indicesDimensions = indicesTensorInfo.GetNumDimensions();
3107 auto outputDimensions = outputTensorInfo.GetNumDimensions();
3108 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
3109 {
3110 throw ParseException(
3111 fmt::format("Operation has invalid axis: {} It is out of bounds [ -{}, {} ) {}",
3112 axis,
3113 inputDimensions, inputDimensions,
3114 CHECK_LOCATION().AsString()));
3115 }
3116 if (outputDimensions != static_cast<unsigned int>(inputDimensions) + indicesDimensions - 1)
3117 {
3118 throw ParseException(
3119 fmt::format("Operation has invalid output dimensions: {} Output must be an ({} + {} - 1) -D tensor {}",
3120 outputDimensions,
3121 inputDimensions, indicesDimensions,
3122 CHECK_LOCATION().AsString()));
3123 }
3124
3125 gatherDescriptor.m_Axis = axis;
3126
3127 auto layerName = fmt::format("Gather:{}:{}", subgraphIndex, operatorIndex);
3128 IConnectableLayer* layer = m_Network->AddGatherLayer(gatherDescriptor, layerName.c_str());
3129 ARMNN_ASSERT(layer != nullptr);
3130 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3131
3132 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3133 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]});
3134
3135 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3136 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3137}
3138
Kevin May7d96b162021-02-03 17:38:41 +00003139void TfLiteParserImpl::ParseDepthToSpace(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan26868492021-01-22 14:25:31 +00003140{
3141 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3142
Kevin May7d96b162021-02-03 17:38:41 +00003143 TfLiteParserImpl::TensorRawPtrVector inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00003144 CHECK_VALID_SIZE(inputs.size(), 1);
Kevin May7d96b162021-02-03 17:38:41 +00003145 TfLiteParserImpl::TensorRawPtrVector outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
Sadik Armagan26868492021-01-22 14:25:31 +00003146 CHECK_VALID_SIZE(outputs.size(), 1);
3147
3148 armnn::DepthToSpaceDescriptor descriptor;
3149
3150 const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3151 const auto * options = operatorPtr->builtin_options.AsDepthToSpaceOptions();
3152 auto blockSize = options->block_size;
3153 if (blockSize < 2)
3154 {
3155 throw ParseException(
3156 fmt::format("Operation has invalid block size: {} Block size should be >= 2 {}",
3157 blockSize,
3158 CHECK_LOCATION().AsString()));
3159 }
3160 descriptor.m_BlockSize = armnn::numeric_cast<uint32_t>(blockSize);
3161
3162 auto layerName = fmt::format("DepthToSpace:{}:{}", subgraphIndex, operatorIndex);
3163 IConnectableLayer* layer = m_Network->AddDepthToSpaceLayer(descriptor, layerName.c_str());
3164 ARMNN_ASSERT(layer != nullptr);
3165 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
3166 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3167
3168 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3169 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3170
3171 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3172 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
3173}
3174
Kevin May7d96b162021-02-03 17:38:41 +00003175void TfLiteParserImpl::ParseSum(size_t subgraphIndex, size_t operatorIndex)
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00003176{
Sadik Armagana2747482021-02-09 10:28:54 +00003177 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Sum);
3178}
3179
3180void TfLiteParserImpl::ParseReduceMax(size_t subgraphIndex, size_t operatorIndex)
3181{
3182 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Max);
3183}
3184
3185void TfLiteParserImpl::ParseReduceMin(size_t subgraphIndex, size_t operatorIndex)
3186{
3187 ParseReduce(subgraphIndex, operatorIndex, armnn::ReduceOperation::Min);
3188}
3189
3190void TfLiteParserImpl::ParseReduce(size_t subgraphIndex, size_t operatorIndex, ReduceOperation reduceOperation)
3191{
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00003192 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3193
3194 const auto &operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex];
3195 const auto *options = operatorPtr->builtin_options.AsReducerOptions();
3196
3197 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3198 CHECK_VALID_SIZE(inputs.size(), 2);
3199
3200 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3201 CHECK_VALID_SIZE(outputs.size(), 1);
3202
Sadik Armagana2747482021-02-09 10:28:54 +00003203 auto layerName = fmt::format("Reduce:{}:{}", subgraphIndex, operatorIndex);
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00003204
3205 armnn::TensorInfo inputTensorInfo0 = ToTensorInfo(inputs[0]);
3206 armnn::TensorInfo inputTensorInfo1 = ToTensorInfo(inputs[1]);
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00003207
3208 ReduceDescriptor desc;
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00003209 BufferRawPtr axisBufferPtr = GetBuffer(m_Model, inputs[1]->buffer);
3210 // Get const axis value from model and set it to descriptor.
3211 if (axisBufferPtr != nullptr)
3212 {
Sadik Armagan49bdb792021-02-11 13:57:07 +00003213 std::vector<int32_t> axisData(inputTensorInfo1.GetNumElements());
3214 ::memcpy(axisData.data(), axisBufferPtr->data.data(), inputTensorInfo1.GetNumBytes());
3215
3216 // Convert the axis to unsigned int and remove duplicates.
3217 auto rank = static_cast<int32_t>(inputTensorInfo0.GetNumDimensions());
3218 std::set<unsigned int> uniqueAxis;
3219 std::transform(axisData.begin(),
3220 axisData.end(),
3221 std::inserter(uniqueAxis, uniqueAxis.begin()),
3222 [rank](int i)->unsigned int{
3223 return static_cast<uint32_t>(((i + rank) % rank)); });
3224 desc.m_vAxis.assign(uniqueAxis.begin(), uniqueAxis.end());
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00003225 }
Sadik Armagana2747482021-02-09 10:28:54 +00003226 else
3227 {
3228 for (uint32_t i = 0; i < inputTensorInfo0.GetNumDimensions(); ++i)
3229 {
3230 desc.m_vAxis.push_back(i);
3231 }
3232 }
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00003233
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00003234 desc.m_KeepDims = options->keep_dims;
Sadik Armagana2747482021-02-09 10:28:54 +00003235 desc.m_ReduceOperation = reduceOperation;
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00003236
3237 // Register a new layer object, Sum.
3238 IConnectableLayer *layer = m_Network->AddReduceLayer(desc, layerName.c_str());
3239
3240 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
3241 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3242
3243 // Register input tensor to the layer.
3244 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3245 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3246
3247 // Register output tensor to the layer.
3248 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3249 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
3250}
3251
Matthew Sloyaned7fce42021-04-15 20:46:24 +01003252void TfLiteParserImpl::ParseAbs(size_t subgraphIndex, size_t operatorIndex)
3253{
3254 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Abs);
3255}
3256
3257void TfLiteParserImpl::ParseExp(size_t subgraphIndex, size_t operatorIndex)
3258{
3259 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Exp);
3260}
3261
3262void TfLiteParserImpl::ParseLogicalNot(size_t subgraphIndex, size_t operatorIndex)
3263{
3264 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::LogicalNot);
3265}
3266
3267void TfLiteParserImpl::ParseNeg(size_t subgraphIndex, size_t operatorIndex)
3268{
3269 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Neg);
3270}
3271
3272void TfLiteParserImpl::ParseRsqrt(size_t subgraphIndex, size_t operatorIndex)
3273{
3274 ParseElementwiseUnary(subgraphIndex, operatorIndex, armnn::UnaryOperation::Rsqrt);
3275}
3276
3277void TfLiteParserImpl::ParseElementwiseUnary(size_t subgraphIndex, size_t operatorIndex, UnaryOperation unaryOperation)
3278{
3279 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
3280
3281 auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
3282 CHECK_VALID_SIZE(inputs.size(), 1);
3283
3284 auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
3285 CHECK_VALID_SIZE(outputs.size(), 1);
3286
3287 std::string layerName = std::string(GetUnaryOperationAsCString(unaryOperation)) + ":{}:{}";
3288 std::string layerNameFormatted = fmt::format(layerName, subgraphIndex, operatorIndex);
3289
3290 ElementwiseUnaryDescriptor desc;
3291 desc.m_Operation = unaryOperation;
3292 IConnectableLayer* layer = m_Network->AddElementwiseUnaryLayer(desc, layerNameFormatted.c_str());
3293 ARMNN_ASSERT(layer != nullptr);
3294
3295 TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
3296 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3297
3298 auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
3299 RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
3300
3301 auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
3302 RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
3303}
3304
Kevin May7d96b162021-02-03 17:38:41 +00003305armnn::IConnectableLayer* TfLiteParserImpl::AddFusedActivationLayer(armnn::IConnectableLayer* prevLayer,
3306 unsigned int outputSlot,
3307 tflite::ActivationFunctionType activationType)
telsoa01c577f2c2018-08-31 09:22:23 +01003308{
3309 ActivationDescriptor activationDesc;
3310 std::string layerName = prevLayer->GetName();
3311
3312 switch(activationType)
3313 {
3314 case tflite::ActivationFunctionType_NONE:
3315 {
3316 // this is a no-op: return previous layer
3317 return prevLayer;
3318 }
3319 case tflite::ActivationFunctionType_RELU:
3320 {
3321 activationDesc.m_Function = ActivationFunction::ReLu;
3322 layerName += ":RELU";
3323 break;
3324 }
3325 case tflite::ActivationFunctionType_RELU6:
3326 {
3327 activationDesc.m_Function = ActivationFunction::BoundedReLu;
3328 activationDesc.m_A = 6.0f;
3329 activationDesc.m_B = 0.0f;
3330 layerName += ":RELU6";
3331 break;
3332 }
3333 case tflite::ActivationFunctionType_TANH:
3334 {
3335 activationDesc.m_Function = ActivationFunction::TanH;
3336 activationDesc.m_A = 1.0f;
3337 activationDesc.m_B = 1.0f;
3338 layerName += ":TANH";
3339 break;
3340 }
3341
3342 // I only put these here as a reminder what others we could support
3343 case tflite::ActivationFunctionType_RELU_N1_TO_1:
3344 case tflite::ActivationFunctionType_SIGN_BIT:
3345 default:
3346 {
3347 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003348 fmt::format("TfLite parser doesn't suppport fused activation: "
3349 "{}/{} {} ",
3350 activationType,
3351 tflite::EnumNameActivationFunctionType(activationType),
3352 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01003353
3354 }
3355 }
3356
3357 IConnectableLayer* activationLayer =
3358 m_Network->AddActivationLayer(activationDesc, layerName.c_str());
3359
3360 auto & prevOutputSlot = prevLayer->GetOutputSlot(outputSlot);
3361 prevOutputSlot.Connect(activationLayer->GetInputSlot(0));
3362 activationLayer->GetOutputSlot(0).SetTensorInfo(prevOutputSlot.GetTensorInfo());
3363 return activationLayer;
3364}
3365
Kevin May7d96b162021-02-03 17:38:41 +00003366TfLiteParserImpl::ModelPtr TfLiteParserImpl::LoadModelFromFile(const char * fileName)
telsoa01c577f2c2018-08-31 09:22:23 +01003367{
3368 if (fileName == nullptr)
3369 {
James Ward58dec6b2020-09-11 17:32:44 +01003370 throw InvalidArgumentException(fmt::format("Invalid (null) file name {}",
telsoa01c577f2c2018-08-31 09:22:23 +01003371 CHECK_LOCATION().AsString()));
3372 }
Francis Murtagh532a29d2020-06-29 11:50:01 +01003373 std::error_code errorCode;
3374 fs::path pathToFile(fileName);
3375 if (!fs::exists(pathToFile, errorCode))
telsoa01c577f2c2018-08-31 09:22:23 +01003376 {
James Ward58dec6b2020-09-11 17:32:44 +01003377 //fmt::format() could not be used here (format error)
3378 std::stringstream msg;
3379 msg << "Cannot find the file (" << fileName << ") errorCode: " << errorCode
3380 << " " << CHECK_LOCATION().AsString();
3381
3382 throw FileNotFoundException(msg.str());
telsoa01c577f2c2018-08-31 09:22:23 +01003383 }
3384 std::ifstream file(fileName, std::ios::binary);
3385 std::string fileContent((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
3386 return LoadModelFromBinary(reinterpret_cast<const uint8_t *>(fileContent.c_str()),
3387 fileContent.size());
3388}
3389
Kevin May7d96b162021-02-03 17:38:41 +00003390TfLiteParserImpl::ModelPtr TfLiteParserImpl::LoadModelFromBinary(const uint8_t * binaryContent, size_t len)
telsoa01c577f2c2018-08-31 09:22:23 +01003391{
3392 if (binaryContent == nullptr)
3393 {
James Ward58dec6b2020-09-11 17:32:44 +01003394 throw InvalidArgumentException(fmt::format("Invalid (null) binary content {}",
telsoa01c577f2c2018-08-31 09:22:23 +01003395 CHECK_LOCATION().AsString()));
3396 }
3397 flatbuffers::Verifier verifier(binaryContent, len);
3398 if (verifier.VerifyBuffer<tflite::Model>() == false)
3399 {
3400 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003401 fmt::format("Buffer doesn't conform to the expected Tensorflow Lite "
3402 "flatbuffers format. size:{} {}",
3403 len,
3404 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01003405 }
3406 return tflite::UnPackModel(binaryContent);
3407}
3408
Kevin May7d96b162021-02-03 17:38:41 +00003409TfLiteParserImpl::TensorRawPtrVector TfLiteParserImpl::GetInputs(const ModelPtr & model,
3410 size_t subgraphIndex,
3411 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01003412{
3413 CHECK_MODEL(model, subgraphIndex, operatorIndex);
3414
Derek Lambertiff05cc52019-04-26 13:05:17 +01003415 const auto & subgraphPtr = model->subgraphs[subgraphIndex];
3416 const auto & operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01003417
3418 size_t inputCount = operatorPtr->inputs.size();
mathad01c21025d2021-04-26 10:09:37 +01003419 TensorRawPtrVector result;
telsoa01c577f2c2018-08-31 09:22:23 +01003420 for (size_t i=0; i<inputCount; ++i)
3421 {
mathad01c21025d2021-04-26 10:09:37 +01003422 // If the input location is -1 then assume input is turned off.
3423 if (operatorPtr->inputs[i] == -1)
3424 {
3425 continue;
3426 }
3427 else
3428 {
3429 uint32_t inputId = CHECKED_NON_NEGATIVE(operatorPtr->inputs[i]);
3430 result.push_back(subgraphPtr->tensors[inputId].get());
3431 }
telsoa01c577f2c2018-08-31 09:22:23 +01003432 }
3433 return result;
3434}
3435
Kevin May7d96b162021-02-03 17:38:41 +00003436TfLiteParserImpl::TensorRawPtrVector TfLiteParserImpl::GetOutputs(const ModelPtr & model,
3437 size_t subgraphIndex,
3438 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01003439{
3440 CHECK_MODEL(model, subgraphIndex, operatorIndex);
3441
Derek Lambertiff05cc52019-04-26 13:05:17 +01003442 const auto & subgraphPtr = model->subgraphs[subgraphIndex];
3443 const auto & operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01003444
3445 size_t outputCount = operatorPtr->outputs.size();
3446 TensorRawPtrVector result(outputCount);
3447 for (size_t i=0; i<outputCount; ++i)
3448 {
3449 uint32_t outputId = CHECKED_NON_NEGATIVE(operatorPtr->outputs[i]);
3450 CHECK_TENSOR(model, subgraphIndex, outputId);
Derek Lambertiff05cc52019-04-26 13:05:17 +01003451 result[i] = subgraphPtr->tensors[outputId].get();
telsoa01c577f2c2018-08-31 09:22:23 +01003452 }
3453 return result;
3454}
3455
Kevin May7d96b162021-02-03 17:38:41 +00003456TfLiteParserImpl::TensorIdRawPtrVector TfLiteParserImpl::GetSubgraphInputs(const ModelPtr & model,
3457 size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01003458{
3459 CHECK_SUBGRAPH(model, subgraphIndex);
Derek Lambertiff05cc52019-04-26 13:05:17 +01003460 const auto & subgraphPtr = model->subgraphs[subgraphIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01003461
Derek Lambertiff05cc52019-04-26 13:05:17 +01003462 size_t inputCount = subgraphPtr->inputs.size();
telsoa01c577f2c2018-08-31 09:22:23 +01003463 TensorIdRawPtrVector result(inputCount);
3464 for (size_t i=0; i<inputCount; ++i)
3465 {
Derek Lambertiff05cc52019-04-26 13:05:17 +01003466 uint32_t inputId = CHECKED_NON_NEGATIVE(subgraphPtr->inputs[i]);
telsoa01c577f2c2018-08-31 09:22:23 +01003467 CHECK_TENSOR(model, subgraphIndex, inputId);
Derek Lambertiff05cc52019-04-26 13:05:17 +01003468 result[i] = std::make_pair(inputId, subgraphPtr->tensors[inputId].get());
telsoa01c577f2c2018-08-31 09:22:23 +01003469 }
3470 return result;
3471}
3472
Kevin May7d96b162021-02-03 17:38:41 +00003473TfLiteParserImpl::TensorIdRawPtrVector TfLiteParserImpl::GetSubgraphOutputs(const ModelPtr & model,
3474 size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01003475{
3476 CHECK_SUBGRAPH(model, subgraphIndex);
Derek Lambertiff05cc52019-04-26 13:05:17 +01003477 const auto & subgraphPtr = model->subgraphs[subgraphIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01003478
Derek Lambertiff05cc52019-04-26 13:05:17 +01003479 size_t outputCount = subgraphPtr->outputs.size();
telsoa01c577f2c2018-08-31 09:22:23 +01003480 TensorIdRawPtrVector result(outputCount);
3481 for (size_t i=0; i<outputCount; ++i)
3482 {
Derek Lambertiff05cc52019-04-26 13:05:17 +01003483 uint32_t outputId = CHECKED_NON_NEGATIVE(subgraphPtr->outputs[i]);
3484 result[i] = std::make_pair(outputId, subgraphPtr->tensors[outputId].get());
telsoa01c577f2c2018-08-31 09:22:23 +01003485 }
3486 return result;
3487}
3488
Kevin May7d96b162021-02-03 17:38:41 +00003489std::vector<int32_t>& TfLiteParserImpl::GetInputTensorIds(const ModelPtr& model,
3490 size_t subgraphIndex,
3491 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01003492{
3493 CHECK_MODEL(model, subgraphIndex, operatorIndex);
Derek Lambertiff05cc52019-04-26 13:05:17 +01003494 const auto & subgraphPtr = model->subgraphs[subgraphIndex];
3495 const auto & operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01003496 return operatorPtr->inputs;
3497}
3498
Kevin May7d96b162021-02-03 17:38:41 +00003499std::vector<int32_t>& TfLiteParserImpl::GetOutputTensorIds(const ModelPtr& model,
3500 size_t subgraphIndex,
3501 size_t operatorIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01003502{
3503 CHECK_MODEL(model, subgraphIndex, operatorIndex);
Derek Lambertiff05cc52019-04-26 13:05:17 +01003504 const auto & subgraphPtr = model->subgraphs[subgraphIndex];
3505 const auto & operatorPtr = subgraphPtr->operators[operatorIndex];
telsoa01c577f2c2018-08-31 09:22:23 +01003506 return operatorPtr->outputs;
3507}
3508
Kevin May7d96b162021-02-03 17:38:41 +00003509void TfLiteParserImpl::RegisterInputSlots(size_t subgraphIndex,
3510 size_t operatorIndex,
3511 IConnectableLayer* layer,
Finn Williamsd4fa5452021-03-01 12:31:41 +00003512 const std::vector<unsigned int>& tensorIndexes,
3513 unsigned int startingSlotIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01003514{
3515 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01003516 ARMNN_ASSERT(layer != nullptr);
Finn Williamsd4fa5452021-03-01 12:31:41 +00003517 if (tensorIndexes.size() + startingSlotIndex != layer->GetNumInputSlots())
telsoa01c577f2c2018-08-31 09:22:23 +01003518 {
3519 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003520 fmt::format("The number of tensor inputs ({}) does not match the number expected ({})"
3521 " for subgraph:{} operator index:{} {}",
3522 tensorIndexes.size(),
3523 layer->GetNumInputSlots(),
3524 subgraphIndex,
3525 operatorIndex,
3526 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01003527 }
3528
Finn Williamsd4fa5452021-03-01 12:31:41 +00003529 for (unsigned int index = 0; index < tensorIndexes.size() ; ++index)
telsoa01c577f2c2018-08-31 09:22:23 +01003530 {
Finn Williamsd4fa5452021-03-01 12:31:41 +00003531 unsigned int tensorIndex = tensorIndexes[index];
3532 armnn::IInputSlot* slot = &(layer->GetInputSlot(startingSlotIndex + index));
telsoa01c577f2c2018-08-31 09:22:23 +01003533 RegisterConsumerOfTensor(subgraphIndex, tensorIndex, slot);
3534 }
3535}
3536
Kevin May7d96b162021-02-03 17:38:41 +00003537void TfLiteParserImpl::RegisterOutputSlots(size_t subgraphIndex,
3538 size_t operatorIndex,
3539 IConnectableLayer* layer,
3540 const std::vector<unsigned int>& tensorIndexes)
telsoa01c577f2c2018-08-31 09:22:23 +01003541{
3542 CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01003543 ARMNN_ASSERT(layer != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +01003544 if (tensorIndexes.size() != layer->GetNumOutputSlots())
3545 {
3546 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003547 fmt::format("The number of tensor outputs ({}) does not match the number expected ({})"
3548 " for subgraph:{} operator index:{} {}",
3549 tensorIndexes.size(),
3550 layer->GetNumOutputSlots(),
3551 subgraphIndex,
3552 operatorIndex,
3553 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01003554 }
3555
3556 for (unsigned int slotIndex = 0; slotIndex < layer->GetNumOutputSlots(); ++slotIndex)
3557 {
3558 unsigned int tensorIndex = tensorIndexes[slotIndex];
3559 armnn::IOutputSlot* slot = &(layer->GetOutputSlot(slotIndex));
3560 RegisterProducerOfTensor(subgraphIndex, tensorIndex, slot);
3561 }
3562}
3563
Kevin May7d96b162021-02-03 17:38:41 +00003564void TfLiteParserImpl::SetupInputLayers(size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01003565{
3566 CHECK_SUBGRAPH(m_Model, subgraphIndex);
3567
3568 auto inputs = GetSubgraphInputs(m_Model, subgraphIndex);
3569 for (auto const & tensorIdAndPtr : inputs)
3570 {
3571 auto bindingId = GenerateLayerBindingId(subgraphIndex, tensorIdAndPtr.first);
3572 IConnectableLayer* layer =
3573 m_Network->AddInputLayer(bindingId, tensorIdAndPtr.second->name.c_str());
3574
3575 auto tensorInfo = ToTensorInfo(tensorIdAndPtr.second);
3576 layer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
3577
3578 RegisterOutputSlots(subgraphIndex,
3579 VIRTUAL_OPERATOR_ID,
3580 layer,
3581 { static_cast<uint32_t>(tensorIdAndPtr.first) });
3582 }
3583}
3584
Kevin May7d96b162021-02-03 17:38:41 +00003585void TfLiteParserImpl::SetupOutputLayers(size_t subgraphIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01003586{
3587 CHECK_SUBGRAPH(m_Model, subgraphIndex);
3588
3589 auto outputs = GetSubgraphOutputs(m_Model, subgraphIndex);
3590 for (auto const & tensorIdAndPtr : outputs)
3591 {
3592 auto bindingId = GenerateLayerBindingId(subgraphIndex, tensorIdAndPtr.first);
3593 IConnectableLayer* layer =
3594 m_Network->AddOutputLayer(bindingId, tensorIdAndPtr.second->name.c_str());
3595
3596 RegisterInputSlots(subgraphIndex,
3597 VIRTUAL_OPERATOR_ID,
3598 layer,
3599 { static_cast<uint32_t>(tensorIdAndPtr.first) });
3600 }
3601}
3602
Kevin May7d96b162021-02-03 17:38:41 +00003603void TfLiteParserImpl::SetupConstantLayers(size_t subgraphIndex)
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02003604{
3605 CHECK_SUBGRAPH(m_Model, subgraphIndex);
3606
Derek Lambertiff05cc52019-04-26 13:05:17 +01003607 const auto & subgraphPtr = m_Model->subgraphs[subgraphIndex];
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02003608 for (unsigned int subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex)
3609 {
3610 for (unsigned int tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex)
3611 {
3612 if (m_SubgraphConnections[subgraphIndex][tensorIndex].outputSlot == nullptr &&
3613 m_SubgraphConnections[subgraphIndex][tensorIndex].inputSlots.size() > 0)
3614 {
Derek Lambertiff05cc52019-04-26 13:05:17 +01003615 TensorRawPtr tensorPtr = subgraphPtr->tensors[tensorIndex].get();
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02003616 armnn::TensorInfo tensorInfo = ToTensorInfo(tensorPtr);
Finn Williamsd4fa5452021-03-01 12:31:41 +00003617 auto tensorAndData = CreateConstTensorNonPermuted(tensorPtr, tensorInfo);
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02003618
James Ward58dec6b2020-09-11 17:32:44 +01003619 std::string layerName = fmt::format("Constant:{}", tensorPtr->name);
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02003620 IConnectableLayer *layer =
Finn Williamsd4fa5452021-03-01 12:31:41 +00003621 m_Network->AddConstantLayer(tensorAndData, layerName.c_str());
Bruno Goncalves3d7efe92018-12-27 14:21:43 -02003622
3623 layer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
3624 RegisterOutputSlots(subgraphIndex,
3625 VIRTUAL_OPERATOR_ID,
3626 layer,
3627 { tensorIndex });
3628
3629 }
3630 }
3631 }
3632}
3633
telsoa01c577f2c2018-08-31 09:22:23 +01003634// example usage: BufferRawPtr bufferPtr = GetBuffer(m_Model, inputs[0]->buffer);
Kevin May7d96b162021-02-03 17:38:41 +00003635TfLiteParserImpl::BufferRawPtr TfLiteParserImpl::GetBuffer(const ModelPtr& model, size_t bufferIndex)
telsoa01c577f2c2018-08-31 09:22:23 +01003636{
3637 CHECK_BUFFER(model, bufferIndex);
3638 return model->buffers[bufferIndex].get();
3639}
3640
Matteo Martincigh747ef822018-12-18 09:26:39 +00003641template<typename T>
Kevin May7d96b162021-02-03 17:38:41 +00003642std::pair<armnn::ConstTensor, TfLiteParserImpl::SupportedDataStorage>
3643TfLiteParserImpl::CreateConstTensorAndStoreData(TfLiteParserImpl::BufferRawPtr bufferPtr,
3644 TfLiteParserImpl::TensorRawPtr tensorPtr,
Matteo Martincigh747ef822018-12-18 09:26:39 +00003645 armnn::TensorInfo& tensorInfo,
3646 armnn::Optional<armnn::PermutationVector&> permutationVector)
3647{
3648 auto constData = CreateConstTensorImpl<T>(bufferPtr,
3649 tensorPtr,
3650 tensorInfo,
3651 permutationVector);
Kevin May7d96b162021-02-03 17:38:41 +00003652 TfLiteParserImpl::SupportedDataStorage storage(std::move(constData.second));
Matteo Martincigh747ef822018-12-18 09:26:39 +00003653 return std::make_pair(constData.first, std::move(storage));
3654}
3655
Finn Williamsd4fa5452021-03-01 12:31:41 +00003656bool TfLiteParserImpl::IsConstTensor(TensorRawPtr tensorPtr)
3657{
3658 CHECK_TENSOR_PTR(tensorPtr);
mathad01bf7edb62021-04-20 16:12:45 +01003659 bool isConst = true;
3660
3661 auto buffer = GetBuffer(m_Model, tensorPtr->buffer);
3662 if (buffer->data.size() == 0)
3663 {
3664 isConst = false;
3665 }
3666
3667 return isConst;
Finn Williamsd4fa5452021-03-01 12:31:41 +00003668}
3669
3670
Kevin May7d96b162021-02-03 17:38:41 +00003671std::pair<armnn::ConstTensor, TfLiteParserImpl::SupportedDataStorage>
Finn Williamsd4fa5452021-03-01 12:31:41 +00003672TfLiteParserImpl::CreateConstTensorPermuted(TensorRawPtr tensorPtr,
3673 armnn::TensorInfo& tensorInfo,
3674 armnn::Optional<armnn::PermutationVector&> permutationVector)
telsoa01c577f2c2018-08-31 09:22:23 +01003675{
3676 CHECK_TENSOR_PTR(tensorPtr);
3677 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
3678 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
3679
3680 switch (tensorInfo.GetDataType())
3681 {
3682 case armnn::DataType::Float32:
Matteo Martincigh747ef822018-12-18 09:26:39 +00003683 return CreateConstTensorAndStoreData<float>(bufferPtr,
3684 tensorPtr,
3685 tensorInfo,
3686 permutationVector);
Derek Lambertif90c56d2020-01-10 17:14:08 +00003687 case armnn::DataType::QAsymmU8:
Matteo Martincigh747ef822018-12-18 09:26:39 +00003688 return CreateConstTensorAndStoreData<uint8_t>(bufferPtr,
3689 tensorPtr,
3690 tensorInfo,
3691 permutationVector);
Keith Davisd305e1a2020-01-22 11:57:54 +00003692 case armnn::DataType::QSymmS8:
3693 return CreateConstTensorAndStoreData<int8_t>(bufferPtr,
3694 tensorPtr,
3695 tensorInfo,
3696 permutationVector);
Keith Davis67e6c542020-02-19 10:08:33 +00003697 case armnn::DataType::QAsymmS8:
3698 return CreateConstTensorAndStoreData<int8_t>(bufferPtr,
3699 tensorPtr,
3700 tensorInfo,
3701 permutationVector);
telsoa01c577f2c2018-08-31 09:22:23 +01003702 case armnn::DataType::Signed32:
Matteo Martincigh747ef822018-12-18 09:26:39 +00003703 return CreateConstTensorAndStoreData<int32_t>(bufferPtr,
3704 tensorPtr,
3705 tensorInfo,
3706 permutationVector);
telsoa01c577f2c2018-08-31 09:22:23 +01003707 default:
3708 {
3709 std::stringstream errString;
3710 errString << "Unexpected datatype when creating const tensor: "
3711 << armnn::GetDataTypeName(tensorInfo.GetDataType())
3712 << " shape:" << tensorInfo.GetShape()
3713 << CHECK_LOCATION().AsString();
3714 throw ParseException(errString.str());
3715 }
3716 }
3717}
3718
Finn Williamsd4fa5452021-03-01 12:31:41 +00003719armnn::ConstTensor TfLiteParserImpl::CreateConstTensorNonPermuted(TensorRawPtr tensorPtr,
3720 armnn::TensorInfo& tensorInfo)
3721{
3722 CHECK_TENSOR_PTR(tensorPtr);
3723 auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
3724 CHECK_BUFFER_SIZE(bufferPtr, tensorInfo, tensorPtr->buffer);
3725
3726 return ConstTensor(tensorInfo, bufferPtr->data.data());
3727}
3728
Kevin May7d96b162021-02-03 17:38:41 +00003729BindingPointInfo TfLiteParserImpl::GetNetworkInputBindingInfo(size_t subgraphId,
3730 const std::string& name) const
telsoa01c577f2c2018-08-31 09:22:23 +01003731{
3732 CHECK_SUBGRAPH(m_Model, subgraphId);
3733 auto inputs = GetSubgraphInputs(m_Model, subgraphId);
3734 for (auto const & input : inputs)
3735 {
3736 if (input.second->name == name)
3737 {
3738 auto bindingId = GenerateLayerBindingId(subgraphId, input.first);
3739 return std::make_pair(bindingId, ToTensorInfo(input.second));
3740 }
3741 }
3742
3743 std::stringstream bindings;
3744 for (auto const & input : inputs)
3745 {
3746 bindings << "'" << input.second->name << "' ";
3747 }
3748
3749 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003750 fmt::format("No input binding found for subgraph:{} and name:{}. "
3751 "Possible inputs are: [{}] {}",
3752 subgraphId,
3753 name,
3754 bindings.str(),
3755 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01003756}
3757
Kevin May7d96b162021-02-03 17:38:41 +00003758BindingPointInfo TfLiteParserImpl::GetNetworkOutputBindingInfo(size_t subgraphId,
3759 const std::string& name) const
telsoa01c577f2c2018-08-31 09:22:23 +01003760{
3761 CHECK_SUBGRAPH(m_Model, subgraphId);
3762 auto outputs = GetSubgraphOutputs(m_Model, subgraphId);
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00003763 for (unsigned int i = 0; i < outputs.size(); ++i)
telsoa01c577f2c2018-08-31 09:22:23 +01003764 {
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00003765 auto const output = outputs[i];
telsoa01c577f2c2018-08-31 09:22:23 +01003766 if (output.second->name == name)
3767 {
3768 auto bindingId = GenerateLayerBindingId(subgraphId, output.first);
Narumol Prangnawarat4628d052019-02-25 17:26:05 +00003769 std::vector<unsigned int> shape = m_OverridenOutputShapes.size() > 0 ?
3770 m_OverridenOutputShapes[i] : AsUnsignedVector(output.second->shape);
3771 return std::make_pair(bindingId, ToTensorInfo(output.second, shape));
telsoa01c577f2c2018-08-31 09:22:23 +01003772 }
3773 }
3774
3775 std::stringstream bindings;
3776 for (auto const & output : outputs)
3777 {
3778 bindings << "'" << output.second->name << "' ";
3779 }
3780
3781 throw ParseException(
James Ward58dec6b2020-09-11 17:32:44 +01003782 fmt::format("No output binding found for subgraph:{} and name:{}. "
3783 "Possible outputs are: [{}] {}",
3784 subgraphId,
3785 name,
3786 bindings.str(),
3787 CHECK_LOCATION().AsString()));
telsoa01c577f2c2018-08-31 09:22:23 +01003788}
3789
Kevin May7d96b162021-02-03 17:38:41 +00003790size_t TfLiteParserImpl::GetSubgraphCount() const
telsoa01c577f2c2018-08-31 09:22:23 +01003791{
3792 return m_Model->subgraphs.size();
3793}
3794
Kevin May7d96b162021-02-03 17:38:41 +00003795std::vector<std::string> TfLiteParserImpl::GetSubgraphInputTensorNames(size_t subgraphId) const
telsoa01c577f2c2018-08-31 09:22:23 +01003796{
3797 CHECK_SUBGRAPH(m_Model, subgraphId);
3798 auto inputs = GetSubgraphInputs(m_Model, subgraphId);
3799 std::vector<std::string> result;
3800 result.reserve(inputs.size());
3801 for (auto const & input : inputs)
3802 {
3803 result.push_back(input.second->name);
3804 }
3805 return result;
3806}
3807
Kevin May7d96b162021-02-03 17:38:41 +00003808std::vector<std::string> TfLiteParserImpl::GetSubgraphOutputTensorNames(size_t subgraphId) const
telsoa01c577f2c2018-08-31 09:22:23 +01003809{
3810 CHECK_SUBGRAPH(m_Model, subgraphId);
3811 auto outputs = GetSubgraphOutputs(m_Model, subgraphId);
3812 std::vector<std::string> result;
3813 result.reserve(outputs.size());
3814 for (auto const & output : outputs)
3815 {
3816 result.push_back(output.second->name);
3817 }
3818 return result;
3819}
3820
Matthew Sloyanac001ee2021-02-03 10:43:04 +00003821const std::string TfLiteParserImpl::GetVersion()
3822{
3823 return TFLITE_PARSER_VERSION;
3824}
3825
Kevin May7d96b162021-02-03 17:38:41 +00003826TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<float[]> && data)
telsoa01c577f2c2018-08-31 09:22:23 +01003827: m_FloatData(std::move(data))
3828, m_Uint8Data(nullptr)
Keith Davisd305e1a2020-01-22 11:57:54 +00003829, m_Int8Data(nullptr)
telsoa01c577f2c2018-08-31 09:22:23 +01003830, m_Int32Data(nullptr)
3831{
3832}
3833
Kevin May7d96b162021-02-03 17:38:41 +00003834TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<uint8_t[]> && data)
telsoa01c577f2c2018-08-31 09:22:23 +01003835: m_FloatData(nullptr)
3836, m_Uint8Data(std::move(data))
Keith Davisd305e1a2020-01-22 11:57:54 +00003837, m_Int8Data(nullptr)
3838, m_Int32Data(nullptr)
3839{
3840}
3841
Kevin May7d96b162021-02-03 17:38:41 +00003842TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<int8_t[]> && data)
Keith Davisd305e1a2020-01-22 11:57:54 +00003843: m_FloatData(nullptr)
3844, m_Uint8Data(nullptr)
3845, m_Int8Data(std::move(data))
telsoa01c577f2c2018-08-31 09:22:23 +01003846, m_Int32Data(nullptr)
3847{
3848}
3849
Kevin May7d96b162021-02-03 17:38:41 +00003850TfLiteParserImpl::SupportedDataStorage::SupportedDataStorage(std::unique_ptr<int32_t[]> && data)
telsoa01c577f2c2018-08-31 09:22:23 +01003851: m_FloatData(nullptr)
3852, m_Uint8Data(nullptr)
Keith Davisd305e1a2020-01-22 11:57:54 +00003853, m_Int8Data(nullptr)
telsoa01c577f2c2018-08-31 09:22:23 +01003854, m_Int32Data(std::move(data))
3855{
3856}
3857
3858} // armnnTfLiteParser