blob: fb3f9982831df78d080347da872a5478302af6fd [file] [log] [blame]
Sadik Armagan62483be2020-10-23 17:14:43 +01001//
2// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#pragma once
7
8#include <armnn/ArmNN.hpp>
9#include <armnn/BackendHelper.hpp>
10#include <armnn/utility/Assert.hpp>
Sadik Armagan67e95f22020-10-29 16:14:54 +000011#include <armnn/utility/NumericCast.hpp>
Sadik Armagan62483be2020-10-23 17:14:43 +010012
Sadik Armagan6e36a642020-11-10 21:18:41 +000013#include <armnnUtils/Permute.hpp>
14
Sadik Armagan62483be2020-10-23 17:14:43 +010015#include <tensorflow/lite/builtin_ops.h>
16#include <tensorflow/lite/c/builtin_op_data.h>
17#include <tensorflow/lite/c/common.h>
18#include <tensorflow/lite/minimal_logging.h>
19
20namespace
21{
22
23// Macro to call an Is<layer_name>Supported function and log caller name together with reason for lack of support
24#define FORWARD_LAYER_SUPPORT_FUNC(funcName, tfLiteContext, func, backends, supported, ...) \
25try \
26{ \
27 for (auto&& backendId : backends) \
28 { \
29 auto layerSupportObject = armnn::GetILayerSupportByBackendId(backendId); \
30 if (layerSupportObject) \
31 { \
32 std::string reasonIfUnsupported; \
33 supported = \
34 layerSupportObject->func(__VA_ARGS__, armnn::Optional<std::string&>(reasonIfUnsupported)); \
35 if (supported) \
36 { \
37 break; \
38 } \
39 else \
40 { \
41 if (reasonIfUnsupported.size() > 0) \
42 { \
43 TF_LITE_KERNEL_LOG( \
44 tfLiteContext, "%s: not supported by armnn: %s", funcName, reasonIfUnsupported.c_str()); \
45 } \
46 else \
47 { \
48 TF_LITE_KERNEL_LOG(tfLiteContext, "%s: not supported by armnn", funcName); \
49 } \
50 } \
51 } \
52 else \
53 { \
54 TF_LITE_KERNEL_LOG(tfLiteContext, "%s: backend not registered: %s", funcName, backendId.Get().c_str()); \
55 } \
56 } \
57 if (!supported) \
58 { \
59 TF_LITE_KERNEL_LOG(tfLiteContext, "%s: not supported by any specified backend", funcName); \
60 } \
61} \
62catch (const armnn::InvalidArgumentException &e) \
63{ \
64 throw armnn::InvalidArgumentException(e, "Failed to check layer support", CHECK_LOCATION()); \
65}
66
67TfLiteStatus ValidateNumInputs(TfLiteContext* tfLiteContext,
68 TfLiteNode* tfLiteNode,
69 const unsigned int expectedSize,
70 int nodeIndex)
71{
72 auto numInputs = tfLiteNode->inputs->size;
73 if (numInputs != expectedSize)
74 {
75 TF_LITE_MAYBE_KERNEL_LOG(
76 tfLiteContext, "TfLiteArmnnDelegate: Unexpected number of inputs (%d != %d) in node #%d",
77 numInputs, expectedSize, nodeIndex);
78 return kTfLiteError;
79 }
80 return kTfLiteOk;
81}
82
83TfLiteStatus ValidateNumOutputs(TfLiteContext* tfLiteContext,
84 TfLiteNode* tfLiteNode,
85 const unsigned int expectedSize,
86 int nodeIndex)
87{
88 auto numOutputs = tfLiteNode->outputs->size;
89 if (numOutputs != expectedSize)
90 {
91 TF_LITE_MAYBE_KERNEL_LOG(
92 tfLiteContext, "TfLiteArmnnDelegate: Unexpected number of outputs (%d != %d) in node #%d",
93 numOutputs, expectedSize, nodeIndex);
94 return kTfLiteError;
95 }
96 return kTfLiteOk;
97}
98
Sadik Armagan6e36a642020-11-10 21:18:41 +000099bool IsValid(const TfLiteTensor* tfLiteTensor)
100{
101 return tfLiteTensor == nullptr ? false : true;
102}
103
Sadik Armagan62483be2020-10-23 17:14:43 +0100104bool IsDynamicTensor(const TfLiteTensor& tfLiteTensor)
105{
106 auto tensorAllocationType = tfLiteTensor.allocation_type;
107 if (tensorAllocationType == kTfLiteDynamic)
108 {
109 return true;
110 }
111 return false;
112}
113
Matthew Sloyan0d35a932020-11-09 12:25:05 +0000114bool IsAffineQuantization(const TfLiteTensor& tfLiteTensor)
115{
116 auto quantizationInfo = tfLiteTensor.quantization;
117 if (quantizationInfo.type == kTfLiteAffineQuantization)
118 {
119 return true;
120 }
121 return false;
122}
123
Sadik Armagan67e95f22020-10-29 16:14:54 +0000124TfLiteStatus Connect(armnn::IConnectableLayer* layer,
125 TfLiteNode* tfLiteNode,
126 armnnDelegate::DelegateData& data)
127{
Sadik Armagan67e95f22020-10-29 16:14:54 +0000128 ARMNN_ASSERT(tfLiteNode->outputs->size == layer->GetNumOutputSlots());
129
130 // Connect the input slots
131 for (unsigned int inputIndex = 0; inputIndex < layer->GetNumInputSlots(); ++inputIndex)
132 {
Sadik Armagan6e36a642020-11-10 21:18:41 +0000133 if (data.m_OutputSlotForNode[tfLiteNode->inputs->data[inputIndex]] != nullptr)
134 {
135 data.m_OutputSlotForNode[tfLiteNode->inputs->data[inputIndex]]->Connect(layer->GetInputSlot(inputIndex));
136 }
Sadik Armagan67e95f22020-10-29 16:14:54 +0000137 }
138
139 // Prepare output slots
140 for (unsigned int outputIndex = 0; outputIndex < layer->GetNumOutputSlots(); ++outputIndex)
141 {
142 armnn::IOutputSlot& outputSlot = layer->GetOutputSlot(outputIndex);
143 data.m_OutputSlotForNode[tfLiteNode->outputs->data[outputIndex]] = &outputSlot;
144 }
Sadik Armagan6e36a642020-11-10 21:18:41 +0000145
Sadik Armagan67e95f22020-10-29 16:14:54 +0000146 return kTfLiteOk;
147}
148
149armnn::IConnectableLayer* BroadcastTensor(const armnn::TensorInfo& inputInfo0,
150 const armnn::TensorInfo& inputInfo1,
151 armnn::IConnectableLayer* startLayer,
152 TfLiteContext* tfLiteContext,
153 TfLiteNode* tfLiteNode,
154 armnnDelegate::DelegateData& delegateData)
155{
156 unsigned int inputDimensions0 = inputInfo0.GetNumDimensions();
157 unsigned int inputDimensions1 = inputInfo1.GetNumDimensions();
158
159 if (inputDimensions0 == inputDimensions1)
160 {
161 auto status = Connect(startLayer, tfLiteNode, delegateData);
Sadik Armagan8b9858d2020-11-09 08:26:22 +0000162 return status == kTfLiteOk ? startLayer : nullptr;
Sadik Armagan67e95f22020-10-29 16:14:54 +0000163 }
164
165 unsigned int biggerInputDimensions = std::max(inputDimensions0, inputDimensions1);
166 unsigned int dimDifference =
167 std::abs(armnn::numeric_cast<int>(inputDimensions0) - armnn::numeric_cast<int>(inputDimensions1));
168
169 bool input0IsSmaller = inputDimensions0 < inputDimensions1;
170 const armnn::TensorInfo& smallInfo = input0IsSmaller ? inputInfo0 : inputInfo1;
171 const armnn::TensorShape& smallShape = smallInfo.GetShape();
172
173 std::vector<unsigned int> reshapedDimensions(biggerInputDimensions, 1);
174 for (unsigned int i = dimDifference; i < biggerInputDimensions; ++i)
175 {
176 reshapedDimensions[i] = smallShape[i - dimDifference];
177 }
178
179 armnn::TensorInfo reshapedInfo = smallInfo;
180 reshapedInfo.SetShape(armnn::TensorShape{ armnn::numeric_cast<unsigned int>(reshapedDimensions.size()),
181 reshapedDimensions.data() });
182
183 armnn::ReshapeDescriptor reshapeDescriptor;
184 bool isSupported = false;
185 FORWARD_LAYER_SUPPORT_FUNC(__func__,
186 tfLiteContext,
187 IsReshapeSupported,
188 delegateData.m_Backends,
189 isSupported,
190 smallInfo,
191 reshapedInfo,
192 reshapeDescriptor);
193 if (!isSupported)
194 {
195 return nullptr;
196 }
197
198 ARMNN_ASSERT(delegateData.m_Network != nullptr);
199 // Add Reshape layer
200 reshapeDescriptor.m_TargetShape = reshapedInfo.GetShape();
201
202 armnn::IConnectableLayer* reshapeLayer = delegateData.m_Network->AddReshapeLayer(reshapeDescriptor);
203 ARMNN_ASSERT(reshapeLayer != nullptr);
204 reshapeLayer->GetOutputSlot(0).SetTensorInfo(reshapedInfo);
205
206 if (input0IsSmaller)
207 {
208 delegateData.m_OutputSlotForNode[tfLiteNode->inputs->data[0]]->Connect(reshapeLayer->GetInputSlot(0));
209 reshapeLayer->GetOutputSlot(0).Connect(startLayer->GetInputSlot(0));
210 delegateData.m_OutputSlotForNode[tfLiteNode->inputs->data[1]]->Connect(startLayer->GetInputSlot(1));
211 }
212 else
213 {
214 delegateData.m_OutputSlotForNode[tfLiteNode->inputs->data[1]]->Connect(reshapeLayer->GetInputSlot(0));
215 reshapeLayer->GetOutputSlot(0).Connect(startLayer->GetInputSlot(1));
216 delegateData.m_OutputSlotForNode[tfLiteNode->inputs->data[0]]->Connect(startLayer->GetInputSlot(0));
217 }
218
219 // Prepare output slots
220 for (unsigned int outputIndex = 0; outputIndex < startLayer->GetNumOutputSlots(); ++outputIndex)
221 {
222 armnn::IOutputSlot& outputSlot = startLayer->GetOutputSlot(outputIndex);
223 delegateData.m_OutputSlotForNode[tfLiteNode->outputs->data[outputIndex]] = &outputSlot;
224 }
225
226 return reshapeLayer;
227}
228
229TfLiteStatus FusedActivation(TfLiteContext* tfLiteContext,
230 TfLiteNode* tfLiteNode,
231 TfLiteFusedActivation activationType,
232 armnn::IConnectableLayer* prevLayer,
233 unsigned int outputSlotIndex,
234 armnnDelegate::DelegateData& data)
235{
236
237 armnn::IOutputSlot& outputSlot = prevLayer->GetOutputSlot(outputSlotIndex);
238 const armnn::TensorInfo& activationOutputInfo = outputSlot.GetTensorInfo();
239
240 armnn::ActivationDescriptor activationDesc;
241
242 switch (activationType)
243 {
244 case kTfLiteActNone:
245 {
246 // No Activation
247 return kTfLiteOk;
248 }
249 case kTfLiteActRelu:
250 {
251 activationDesc.m_Function = armnn::ActivationFunction::ReLu;
252 break;
253 }
254 case kTfLiteActRelu1:
255 {
256 activationDesc.m_Function = armnn::ActivationFunction::BoundedReLu;
257 activationDesc.m_A = 1.0f;
258 activationDesc.m_B = -1.0f;
259 break;
260 }
261 case kTfLiteActRelu6:
262 {
263 activationDesc.m_Function = armnn::ActivationFunction::BoundedReLu;
264 activationDesc.m_A = 6.0f;
265 activationDesc.m_B = 0.0f;
266 break;
267 }
268 case kTfLiteActSigmoid:
269 {
270 activationDesc.m_Function = armnn::ActivationFunction::Sigmoid;
271 break;
272 }
273 case kTfLiteActTanh:
274 {
275 activationDesc.m_Function = armnn::ActivationFunction::TanH;
276 activationDesc.m_A = 1.0f;
277 activationDesc.m_B = 1.0f;
278 break;
279 }
280 default:
281 return kTfLiteError;
282 }
283
284 bool isSupported = false;
285 FORWARD_LAYER_SUPPORT_FUNC(__func__,
286 tfLiteContext,
287 IsActivationSupported,
288 data.m_Backends,
289 isSupported,
290 prevLayer->GetOutputSlot(0).GetTensorInfo(),
291 activationOutputInfo,
292 activationDesc);
293 if (!isSupported)
294 {
295 return kTfLiteError;
296 }
297 armnn::IConnectableLayer* activationLayer = data.m_Network->AddActivationLayer(activationDesc);
298
299 ARMNN_ASSERT(activationLayer != nullptr);
300 activationLayer->GetOutputSlot(0).SetTensorInfo(activationOutputInfo);
301
302 // Connect and prepare output slots
303 for (unsigned int outputIndex = 0; outputIndex < activationLayer->GetNumOutputSlots(); ++outputIndex)
304 {
305 data.m_OutputSlotForNode[tfLiteNode->outputs->data[outputIndex]]->Connect(activationLayer->GetInputSlot(0));
306 armnn::IOutputSlot& outputSlot = activationLayer->GetOutputSlot(outputIndex);
307 data.m_OutputSlotForNode[tfLiteNode->outputs->data[outputIndex]] = &outputSlot;
308 }
309 return kTfLiteOk;
310}
311
Sadik Armagan6e36a642020-11-10 21:18:41 +0000312armnn::DataType GetDataType(const TfLiteTensor& tfLiteTensor)
Sadik Armagan62483be2020-10-23 17:14:43 +0100313{
Sadik Armagan62483be2020-10-23 17:14:43 +0100314 switch (tfLiteTensor.type)
315 {
316 case kTfLiteBool:
Sadik Armagan6e36a642020-11-10 21:18:41 +0000317 return armnn::DataType::Boolean;
Sadik Armagan62483be2020-10-23 17:14:43 +0100318 case kTfLiteFloat32:
Sadik Armagan6e36a642020-11-10 21:18:41 +0000319 return armnn::DataType::Float32;
Sadik Armagan62483be2020-10-23 17:14:43 +0100320 case kTfLiteFloat16:
Sadik Armagan6e36a642020-11-10 21:18:41 +0000321 return armnn::DataType::Float16;
Sadik Armagan62483be2020-10-23 17:14:43 +0100322 case kTfLiteUInt8:
Sadik Armagan6e36a642020-11-10 21:18:41 +0000323 return armnn::DataType::QAsymmU8;
Sadik Armagan62483be2020-10-23 17:14:43 +0100324 case kTfLiteInt8:
Narumol Prangnawarat50c87d32020-11-09 18:42:11 +0000325 if (tfLiteTensor.params.zero_point == 0)
326 {
Sadik Armagan6e36a642020-11-10 21:18:41 +0000327 return armnn::DataType::QSymmS8;
Narumol Prangnawarat50c87d32020-11-09 18:42:11 +0000328 }
329 else
330 {
Sadik Armagan6e36a642020-11-10 21:18:41 +0000331 return armnn::DataType::QAsymmS8;
Narumol Prangnawarat50c87d32020-11-09 18:42:11 +0000332 }
Sadik Armagan62483be2020-10-23 17:14:43 +0100333 case kTfLiteInt16:
Sadik Armagan6e36a642020-11-10 21:18:41 +0000334 return armnn::DataType::QSymmS16;
Sadik Armagan62483be2020-10-23 17:14:43 +0100335 case kTfLiteInt32:
Sadik Armagan6e36a642020-11-10 21:18:41 +0000336 return armnn::DataType::Signed32;
Sadik Armagan62483be2020-10-23 17:14:43 +0100337 default:
338 throw armnn::Exception("TfLiteArmnnDelegate: Unsupported data type: " + tfLiteTensor.type);
339 }
Sadik Armagan6e36a642020-11-10 21:18:41 +0000340}
Sadik Armagan62483be2020-10-23 17:14:43 +0100341
Sadik Armagan6e36a642020-11-10 21:18:41 +0000342armnn::TensorInfo GetTensorInfoForTfLiteTensor(const TfLiteTensor& tfLiteTensor)
343{
344 armnn::DataType type = GetDataType(tfLiteTensor);
Sadik Armagan62483be2020-10-23 17:14:43 +0100345 armnn::TensorInfo ret;
346 auto tensorDimensionSize = tfLiteTensor.dims->size;
347 if (tensorDimensionSize == 0)
348 {
349 armnn::TensorShape tensorShape(armnn::Dimensionality::NotSpecified);
350 ret = armnn::TensorInfo(tensorShape, type);
351 }
352 else
353 {
354 std::vector<unsigned int> tensorDims(tensorDimensionSize);
355 bool dimensionsSpecificity[5] = { true, true, true, true, true };
356 for (unsigned int i = 0; i < tensorDimensionSize; ++i) {
357 auto dim = tfLiteTensor.dims->data[i];
358 if (dim == 0)
359 {
360 dimensionsSpecificity[i] = false;
361 }
362 tensorDims[i] = dim;
363 }
364 armnn::TensorShape tensorShape(tensorDimensionSize, tensorDims.data(), dimensionsSpecificity);
365 ret = armnn::TensorInfo(tensorShape, type);
366 }
367
368 auto quantizationInfo = tfLiteTensor.quantization;
369 if (quantizationInfo.type == kTfLiteAffineQuantization)
370 {
371 // get per-channel quantization parameters
372 const auto* affineQuantization =
373 reinterpret_cast<TfLiteAffineQuantization*>(tfLiteTensor.quantization.params);
Sadik Armagan67e95f22020-10-29 16:14:54 +0000374 if (affineQuantization->scale->size > 1)
Sadik Armagan62483be2020-10-23 17:14:43 +0100375 {
Sadik Armagan67e95f22020-10-29 16:14:54 +0000376 std::vector<float> quantizationScales;
377 for (unsigned int i = 1; i < affineQuantization->scale->size; ++i)
378 {
379 quantizationScales.push_back(affineQuantization->scale->data[i]);
380 }
381 ret.SetQuantizationScales(quantizationScales);
382 ret.SetQuantizationDim(armnn::MakeOptional<unsigned int>(affineQuantization->quantized_dimension));
Sadik Armagan62483be2020-10-23 17:14:43 +0100383 }
Sadik Armagan67e95f22020-10-29 16:14:54 +0000384 else
385 {
386 ret.SetQuantizationScale(affineQuantization->scale->data[0]);
387 ret.SetQuantizationOffset(affineQuantization->zero_point->data[0]);
388 }
Sadik Armagan62483be2020-10-23 17:14:43 +0100389 }
390 else
391 {
392 auto quantizationParameters = tfLiteTensor.params;
393 ret.SetQuantizationScale(quantizationParameters.scale);
394 ret.SetQuantizationOffset(quantizationParameters.zero_point);
395 }
396
397 return ret;
398}
399
Sadik Armagan6e36a642020-11-10 21:18:41 +0000400struct DataHolder
401{
402public:
403 DataHolder()
404 : m_Fp32Data(nullptr), m_Uint8Data(nullptr),
405 m_Int8Data(nullptr), m_Int16Data(nullptr), m_Int32Data(nullptr) {}
406
407 DataHolder(std::unique_ptr<float[]>&& data)
408 : m_Fp32Data(std::move(data)), m_Uint8Data(nullptr),
409 m_Int8Data(nullptr), m_Int16Data(nullptr), m_Int32Data(nullptr) {}
410
411 DataHolder(std::unique_ptr<uint8_t[]>&& data)
412 : m_Fp32Data(nullptr), m_Uint8Data(std::move(data)),
413 m_Int8Data(nullptr), m_Int16Data(nullptr), m_Int32Data(nullptr) {}
414
415 DataHolder(std::unique_ptr<int8_t[]>&& data)
416 : m_Fp32Data(nullptr), m_Uint8Data(nullptr),
417 m_Int8Data(std::move(data)), m_Int16Data(nullptr), m_Int32Data(nullptr) {}
418
419 DataHolder(std::unique_ptr<int16_t[]>&& data)
420 : m_Fp32Data(nullptr), m_Uint8Data(nullptr),
421 m_Int8Data(nullptr), m_Int16Data(std::move(data)), m_Int32Data(nullptr) {}
422
423 DataHolder(std::unique_ptr<int32_t[]>&& data)
424 : m_Fp32Data(nullptr), m_Uint8Data(nullptr),
425 m_Int8Data(nullptr), m_Int16Data(nullptr), m_Int32Data(std::move(data)) {}
426
427private:
428 std::unique_ptr<float[]> m_Fp32Data;
429 std::unique_ptr<uint8_t[]> m_Uint8Data;
430 std::unique_ptr<int8_t[]> m_Int8Data;
431 std::unique_ptr<int16_t[]> m_Int16Data;
432 std::unique_ptr<int32_t[]> m_Int32Data;
433};
434
435template <typename T>
436std::pair<armnn::ConstTensor, DataHolder> CreateConstTensorImpl(
437 const TfLiteTensor* tensor,
438 armnn::TensorInfo& tensorInfo,
439 armnn::Optional<armnn::PermutationVector&> permutationVector)
440{
441 std::unique_ptr<T[]> data(new T[tensorInfo.GetNumElements()]);
442 if (permutationVector.has_value() && permutationVector.value().GetSize() > 0)
443 {
444 tensorInfo = armnnUtils::Permuted(tensorInfo, permutationVector.value());
445 armnnUtils::Permute(tensorInfo.GetShape(),
446 permutationVector.value(),
447 reinterpret_cast<const T*>(tensor->data.raw), data.get(), sizeof(T));
448 }
449 else
450 {
451 ::memcpy(data.get(), tensor->data.raw, tensorInfo.GetNumBytes());
452 }
453
454 auto constData = std::make_pair(armnn::ConstTensor(tensorInfo, data.get()), std::move(data));
455
456 DataHolder storedData(std::move(constData.second));
457 return std::make_pair(constData.first, std::move(storedData));
458}
459
460std::pair<armnn::ConstTensor, DataHolder> CreateConstTensor(
461 const TfLiteTensor* tfLiteTensor,
462 armnn::TensorInfo& tensorInfo,
463 armnn::Optional<armnn::PermutationVector&> permutationVector)
464{
465 switch (tensorInfo.GetDataType())
466 {
467 case armnn::DataType::Float32:
468 return CreateConstTensorImpl<float>(tfLiteTensor, tensorInfo, permutationVector);
469 case armnn::DataType::QAsymmU8:
470 return CreateConstTensorImpl<uint8_t>(tfLiteTensor, tensorInfo, permutationVector);
471 case armnn::DataType::QSymmS8:
472 return CreateConstTensorImpl<int8_t>(tfLiteTensor, tensorInfo, permutationVector);
473 case armnn::DataType::QAsymmS8:
474 return CreateConstTensorImpl<int8_t>(tfLiteTensor, tensorInfo, permutationVector);
475 case armnn::DataType::QSymmS16:
476 return CreateConstTensorImpl<int16_t>(tfLiteTensor, tensorInfo, permutationVector);
477 case armnn::DataType::Signed32:
478 return CreateConstTensorImpl<int32_t>(tfLiteTensor, tensorInfo, permutationVector);
479 default:
480 {
481 throw armnn::Exception(
482 "TfLiteArmnnDelegate: Unsupported data type when creating const tensor: "
483 + std::string(armnn::GetDataTypeName(tensorInfo.GetDataType())));
484 }
485 }
486}
487
Sadik Armagan62483be2020-10-23 17:14:43 +0100488} // namespace anonymous