• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
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>
11 #include <armnn/utility/NumericCast.hpp>
12 
13 #include <armnnUtils/Permute.hpp>
14 
15 #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 
20 #include "tensorflow/lite/kernels/kernel_util.h"
21 
22 namespace
23 {
24 
25 // Macro to call an Is<layer_name>Supported function and log caller name together with reason for lack of support
26 #define FORWARD_LAYER_SUPPORT_FUNC(funcName, tfLiteContext, func, backends, supported, ...) \
27 try \
28 { \
29     for (auto&& backendId : backends) \
30     { \
31         auto layerSupportObject = armnn::GetILayerSupportByBackendId(backendId); \
32         if (layerSupportObject) \
33         { \
34             std::string reasonIfUnsupported; \
35             supported = \
36                 layerSupportObject->func(__VA_ARGS__, armnn::Optional<std::string&>(reasonIfUnsupported)); \
37             if (supported) \
38             { \
39                 break; \
40             } \
41             else \
42             { \
43                 if (reasonIfUnsupported.size() > 0) \
44                 { \
45                     TF_LITE_KERNEL_LOG( \
46                         tfLiteContext, "%s: not supported by armnn: %s", funcName, reasonIfUnsupported.c_str()); \
47                 } \
48                 else \
49                 { \
50                     TF_LITE_KERNEL_LOG(tfLiteContext, "%s: not supported by armnn", funcName); \
51                 } \
52             } \
53         } \
54         else \
55         { \
56             TF_LITE_KERNEL_LOG(tfLiteContext, "%s: backend not registered: %s", funcName, backendId.Get().c_str()); \
57         } \
58     } \
59     if (!supported) \
60     { \
61         TF_LITE_KERNEL_LOG(tfLiteContext, "%s: not supported by any specified backend", funcName); \
62     } \
63 } \
64 catch (const armnn::InvalidArgumentException &e) \
65 { \
66     throw armnn::InvalidArgumentException(e, "Failed to check layer support", CHECK_LOCATION()); \
67 }
68 
ValidateNumInputs(TfLiteContext * tfLiteContext,TfLiteNode * tfLiteNode,const unsigned int expectedSize,int nodeIndex)69 TfLiteStatus ValidateNumInputs(TfLiteContext* tfLiteContext,
70                                TfLiteNode* tfLiteNode,
71                                const unsigned int expectedSize,
72                                int nodeIndex)
73 {
74     auto numInputs = tfLiteNode->inputs->size;
75     if (static_cast<unsigned int >(numInputs) != expectedSize)
76     {
77         TF_LITE_MAYBE_KERNEL_LOG(
78             tfLiteContext, "TfLiteArmnnDelegate: Unexpected number of inputs (%d != %d) in node #%d",
79             numInputs, expectedSize, nodeIndex);
80         return kTfLiteError;
81     }
82     return kTfLiteOk;
83 }
84 
ValidateNumOutputs(TfLiteContext * tfLiteContext,TfLiteNode * tfLiteNode,const unsigned int expectedSize,int nodeIndex)85 TfLiteStatus ValidateNumOutputs(TfLiteContext* tfLiteContext,
86                                 TfLiteNode* tfLiteNode,
87                                 const unsigned int expectedSize,
88                                 int nodeIndex)
89 {
90     auto numOutputs = tfLiteNode->outputs->size;
91     if (static_cast<unsigned int >(numOutputs) != expectedSize)
92     {
93         TF_LITE_MAYBE_KERNEL_LOG(
94             tfLiteContext, "TfLiteArmnnDelegate: Unexpected number of outputs (%d != %d) in node #%d",
95             numOutputs, expectedSize, nodeIndex);
96         return kTfLiteError;
97     }
98     return kTfLiteOk;
99 }
100 
IsValid(const TfLiteTensor * tfLiteTensor)101 bool IsValid(const TfLiteTensor* tfLiteTensor)
102 {
103     return tfLiteTensor == nullptr ? false : true;
104 }
105 
NonNegative(int32_t value,int nodeIndex)106 uint32_t NonNegative(int32_t value, int nodeIndex)
107 {
108     if (value < 0)
109     {
110         throw armnn::Exception("TfLiteArmnnDelegate: Non-negative value in node " + nodeIndex);
111     }
112     else
113     {
114         return static_cast<uint32_t>(value);
115     }
116 }
117 
IsDynamicTensor(const TfLiteTensor & tfLiteTensor)118 bool IsDynamicTensor(const TfLiteTensor& tfLiteTensor)
119 {
120     auto tensorAllocationType = tfLiteTensor.allocation_type;
121     if (tensorAllocationType == kTfLiteDynamic)
122     {
123         return true;
124     }
125     return false;
126 }
127 
IsAffineQuantization(const TfLiteTensor & tfLiteTensor)128 bool IsAffineQuantization(const TfLiteTensor& tfLiteTensor)
129 {
130     auto quantizationInfo = tfLiteTensor.quantization;
131     if (quantizationInfo.type == kTfLiteAffineQuantization)
132     {
133         return true;
134     }
135     return false;
136 }
137 
Connect(armnn::IConnectableLayer * layer,TfLiteNode * tfLiteNode,armnnDelegate::DelegateData & data)138 TfLiteStatus Connect(armnn::IConnectableLayer* layer,
139                      TfLiteNode* tfLiteNode,
140                      armnnDelegate::DelegateData& data)
141 {
142     ARMNN_ASSERT(static_cast<unsigned int >(tfLiteNode->outputs->size) == layer->GetNumOutputSlots());
143 
144     // Connect the input slots
145     for (unsigned int inputIndex = 0; inputIndex < layer->GetNumInputSlots(); ++inputIndex)
146     {
147         if (data.m_OutputSlotForNode[tfLiteNode->inputs->data[inputIndex]] != nullptr)
148         {
149             data.m_OutputSlotForNode[tfLiteNode->inputs->data[inputIndex]]->Connect(layer->GetInputSlot(inputIndex));
150         }
151     }
152 
153     // Prepare output slots
154     for (unsigned int outputIndex = 0; outputIndex < layer->GetNumOutputSlots(); ++outputIndex)
155     {
156         armnn::IOutputSlot& outputSlot = layer->GetOutputSlot(outputIndex);
157         data.m_OutputSlotForNode[static_cast<unsigned long>(tfLiteNode->outputs->data[outputIndex])] = &outputSlot;
158     }
159 
160     return kTfLiteOk;
161 }
162 
BroadcastTensor(const armnn::TensorInfo & inputInfo0,const armnn::TensorInfo & inputInfo1,armnn::IConnectableLayer * startLayer,TfLiteContext * tfLiteContext,TfLiteNode * tfLiteNode,armnnDelegate::DelegateData & delegateData)163 armnn::IConnectableLayer* BroadcastTensor(const armnn::TensorInfo& inputInfo0,
164                                           const armnn::TensorInfo& inputInfo1,
165                                           armnn::IConnectableLayer* startLayer,
166                                           TfLiteContext* tfLiteContext,
167                                           TfLiteNode* tfLiteNode,
168                                           armnnDelegate::DelegateData& delegateData)
169 {
170     unsigned int inputDimensions0 = inputInfo0.GetNumDimensions();
171     unsigned int inputDimensions1 = inputInfo1.GetNumDimensions();
172 
173     if (inputDimensions0 == inputDimensions1)
174     {
175         auto status = Connect(startLayer, tfLiteNode, delegateData);
176         return status == kTfLiteOk ? startLayer : nullptr;
177     }
178 
179     unsigned int biggerInputDimensions = std::max(inputDimensions0, inputDimensions1);
180     unsigned int dimDifference = static_cast<unsigned int>(std::abs(armnn::numeric_cast<int>(inputDimensions0) -
181                                                                     armnn::numeric_cast<int>(inputDimensions1)));
182 
183     bool input0IsSmaller = inputDimensions0 < inputDimensions1;
184     const armnn::TensorInfo& smallInfo = input0IsSmaller ? inputInfo0 : inputInfo1;
185     const armnn::TensorShape& smallShape = smallInfo.GetShape();
186 
187     std::vector<unsigned int> reshapedDimensions(biggerInputDimensions, 1);
188     for (unsigned int i = dimDifference; i < biggerInputDimensions; ++i)
189     {
190         reshapedDimensions[i] = smallShape[i - dimDifference];
191     }
192 
193     armnn::TensorInfo reshapedInfo = smallInfo;
194     reshapedInfo.SetShape(armnn::TensorShape{ armnn::numeric_cast<unsigned int>(reshapedDimensions.size()),
195                                               reshapedDimensions.data() });
196 
197     armnn::ReshapeDescriptor reshapeDescriptor;
198     bool isSupported = false;
199     FORWARD_LAYER_SUPPORT_FUNC(__func__,
200                                tfLiteContext,
201                                IsReshapeSupported,
202                                delegateData.m_Backends,
203                                isSupported,
204                                smallInfo,
205                                reshapedInfo,
206                                reshapeDescriptor);
207     if (!isSupported)
208     {
209         return nullptr;
210     }
211 
212     ARMNN_ASSERT(delegateData.m_Network != nullptr);
213     // Add Reshape layer
214     reshapeDescriptor.m_TargetShape = reshapedInfo.GetShape();
215 
216     armnn::IConnectableLayer* reshapeLayer = delegateData.m_Network->AddReshapeLayer(reshapeDescriptor);
217     ARMNN_ASSERT(reshapeLayer != nullptr);
218     reshapeLayer->GetOutputSlot(0).SetTensorInfo(reshapedInfo);
219 
220     if (input0IsSmaller)
221     {
222         delegateData.m_OutputSlotForNode[static_cast<unsigned long>(tfLiteNode->inputs->data[0])]
223             ->Connect(reshapeLayer->GetInputSlot(0));
224         reshapeLayer->GetOutputSlot(0).Connect(startLayer->GetInputSlot(0));
225         delegateData.m_OutputSlotForNode[static_cast<unsigned long>(tfLiteNode->inputs->data[1])]
226             ->Connect(startLayer->GetInputSlot(1));
227     }
228     else
229     {
230         delegateData.m_OutputSlotForNode[static_cast<unsigned long>(tfLiteNode->inputs->data[1])]
231             ->Connect(reshapeLayer->GetInputSlot(0));
232         reshapeLayer->GetOutputSlot(0).Connect(startLayer->GetInputSlot(1));
233         delegateData.m_OutputSlotForNode[static_cast<unsigned long>(tfLiteNode->inputs->data[0])]
234             ->Connect(startLayer->GetInputSlot(0));
235     }
236 
237     // Prepare output slots
238     for (unsigned int outputIndex = 0; outputIndex < startLayer->GetNumOutputSlots(); ++outputIndex)
239     {
240         armnn::IOutputSlot& outputSlot = startLayer->GetOutputSlot(outputIndex);
241         delegateData.m_OutputSlotForNode
242             [static_cast<unsigned long>(tfLiteNode->outputs->data[outputIndex])] = &outputSlot;
243     }
244 
245     return reshapeLayer;
246 }
247 
FusedActivation(TfLiteContext * tfLiteContext,TfLiteNode * tfLiteNode,TfLiteFusedActivation activationType,armnn::IConnectableLayer * prevLayer,unsigned int outputSlotIndex,armnnDelegate::DelegateData & data)248 TfLiteStatus FusedActivation(TfLiteContext* tfLiteContext,
249                              TfLiteNode* tfLiteNode,
250                              TfLiteFusedActivation activationType,
251                              armnn::IConnectableLayer* prevLayer,
252                              unsigned int outputSlotIndex,
253                              armnnDelegate::DelegateData& data)
254 {
255 
256     const armnn::TensorInfo& activationOutputInfo = prevLayer->GetOutputSlot(outputSlotIndex).GetTensorInfo();
257 
258     armnn::ActivationDescriptor activationDesc;
259 
260     switch (activationType)
261     {
262         case kTfLiteActNone:
263         {
264             // No Activation
265             return kTfLiteOk;
266         }
267         case kTfLiteActRelu:
268         {
269             activationDesc.m_Function = armnn::ActivationFunction::ReLu;
270             break;
271         }
272         case kTfLiteActRelu1:
273         {
274             activationDesc.m_Function = armnn::ActivationFunction::BoundedReLu;
275             activationDesc.m_A = 1.0f;
276             activationDesc.m_B = -1.0f;
277             break;
278         }
279         case kTfLiteActRelu6:
280         {
281             activationDesc.m_Function = armnn::ActivationFunction::BoundedReLu;
282             activationDesc.m_A = 6.0f;
283             activationDesc.m_B = 0.0f;
284             break;
285         }
286         case kTfLiteActSigmoid:
287         {
288             activationDesc.m_Function = armnn::ActivationFunction::Sigmoid;
289             break;
290         }
291         case kTfLiteActTanh:
292         {
293             activationDesc.m_Function = armnn::ActivationFunction::TanH;
294             activationDesc.m_A = 1.0f;
295             activationDesc.m_B = 1.0f;
296             break;
297         }
298         default:
299             return kTfLiteError;
300     }
301 
302     bool isSupported = false;
303     FORWARD_LAYER_SUPPORT_FUNC(__func__,
304                                tfLiteContext,
305                                IsActivationSupported,
306                                data.m_Backends,
307                                isSupported,
308                                prevLayer->GetOutputSlot(0).GetTensorInfo(),
309                                activationOutputInfo,
310                                activationDesc);
311     if (!isSupported)
312     {
313         return kTfLiteError;
314     }
315     armnn::IConnectableLayer* activationLayer = data.m_Network->AddActivationLayer(activationDesc);
316 
317     ARMNN_ASSERT(activationLayer != nullptr);
318     activationLayer->GetOutputSlot(0).SetTensorInfo(activationOutputInfo);
319 
320     // Connect and prepare output slots
321     for (unsigned int outputIndex = 0; outputIndex < activationLayer->GetNumOutputSlots(); ++outputIndex)
322     {
323         data.m_OutputSlotForNode[static_cast<unsigned long>(
324                 tfLiteNode->outputs->data[outputIndex])]->Connect(activationLayer->GetInputSlot(0));
325         armnn::IOutputSlot& outputSlot = activationLayer->GetOutputSlot(outputIndex);
326         data.m_OutputSlotForNode[static_cast<unsigned long>(
327                 tfLiteNode->outputs->data[outputIndex])] = &outputSlot;
328     }
329     return kTfLiteOk;
330 }
331 
GetDataType(const TfLiteTensor & tfLiteTensor)332 armnn::DataType GetDataType(const TfLiteTensor& tfLiteTensor)
333 {
334     switch (tfLiteTensor.type)
335     {
336         case kTfLiteBool:
337             return armnn::DataType::Boolean;
338         case kTfLiteFloat32:
339             return armnn::DataType::Float32;
340         case kTfLiteFloat16:
341             return armnn::DataType::Float16;
342         case kTfLiteUInt8:
343             return armnn::DataType::QAsymmU8;
344         case kTfLiteInt8:
345         {
346             auto quantizationInfo = tfLiteTensor.quantization;
347             if (quantizationInfo.type == kTfLiteAffineQuantization)
348             {
349                 auto* quantization =
350                     reinterpret_cast<TfLiteAffineQuantization*>(tfLiteTensor.quantization.params);
351                 if (quantization->zero_point != nullptr && quantization->zero_point->size == 1)
352                 {
353                     return armnn::DataType::QAsymmS8;
354                 }
355                 else
356                 {
357                     return armnn::DataType::QSymmS8;
358                 }
359             }
360             else
361             {
362                 return armnn::DataType::QAsymmS8;
363             }
364         }
365         case kTfLiteInt16:
366             return armnn::DataType::QSymmS16;
367         case kTfLiteInt32:
368             return armnn::DataType::Signed32;
369         default:
370             throw armnn::Exception(&"TfLiteArmnnDelegate: Unsupported data type: " [ tfLiteTensor.type]);
371     }
372 }
373 
GetTensorInfoForTfLiteTensor(const TfLiteTensor & tfLiteTensor,const armnn::PermutationVector & dimensionMappings={0, 1, 2, 3})374 armnn::TensorInfo GetTensorInfoForTfLiteTensor(const TfLiteTensor& tfLiteTensor,
375                                                const armnn::PermutationVector& dimensionMappings = {0, 1, 2, 3})
376 {
377     armnn::DataType type = GetDataType(tfLiteTensor);
378     armnn::TensorInfo ret;
379     auto tensorDimensionSize = tfLiteTensor.dims->size;
380     if (tensorDimensionSize == 0)
381     {
382         if(tflite::IsConstantTensor(&tfLiteTensor))
383         {
384             std::vector<unsigned int> safeShape = { 1 };
385             bool dimensionsSpecificity[1] = { true };
386             armnn::TensorShape tensorShape(armnn::numeric_cast<unsigned int>(safeShape.size()),
387                                            safeShape.data(),
388                                            dimensionsSpecificity);
389             ret = armnn::TensorInfo(tensorShape, type);
390         }
391         else
392         {
393             armnn::TensorShape tensorShape(armnn::Dimensionality::NotSpecified);
394             ret = armnn::TensorInfo(tensorShape, type);
395         }
396     }
397     else
398     {
399         std::vector<unsigned int> tensorDims(static_cast<unsigned int>(tensorDimensionSize));
400         bool dimensionsSpecificity[5] = { true, true, true, true, true };
401         for (unsigned int i = 0; i < static_cast<unsigned int>(tensorDimensionSize); ++i) {
402             auto dim = tfLiteTensor.dims->data[i];
403             if (dim == 0)
404             {
405                 dimensionsSpecificity[i] = false;
406             }
407             tensorDims[i] = static_cast<unsigned int>(dim);
408         }
409         armnn::TensorShape tensorShape(static_cast<unsigned int>(tensorDimensionSize),
410                                        tensorDims.data(),
411                                        dimensionsSpecificity);
412         ret = armnn::TensorInfo(tensorShape, type);
413     }
414 
415     auto quantizationInfo = tfLiteTensor.quantization;
416     if (quantizationInfo.type == kTfLiteAffineQuantization)
417     {
418         // get per-channel quantization parameters
419         const auto* affineQuantization =
420             reinterpret_cast<TfLiteAffineQuantization*>(tfLiteTensor.quantization.params);
421         if (affineQuantization->scale->size > 1)
422         {
423             std::vector<float> quantizationScales;
424             for (unsigned int i = 1; i < static_cast<unsigned int>(affineQuantization->scale->size); ++i)
425             {
426                 quantizationScales.push_back(affineQuantization->scale->data[i]);
427             }
428             ret.SetQuantizationScales(quantizationScales);
429             ret.SetQuantizationDim(dimensionMappings[armnn::numeric_cast<unsigned int>(
430                 affineQuantization->quantized_dimension)]);
431         }
432         else
433         {
434             ret.SetQuantizationScale(affineQuantization->scale->data[0]);
435             ret.SetQuantizationOffset(affineQuantization->zero_point->data[0]);
436         }
437     }
438     else
439     {
440         auto quantizationParameters = tfLiteTensor.params;
441         ret.SetQuantizationScale(quantizationParameters.scale);
442         ret.SetQuantizationOffset(quantizationParameters.zero_point);
443     }
444 
445     return ret;
446 }
447 
CreateConstTensor(const TfLiteTensor * tfLiteTensor,armnn::TensorInfo & tensorInfo,armnn::Optional<armnn::PermutationVector &> permutationVector,void * permutationData=nullptr)448 armnn::ConstTensor CreateConstTensor(const TfLiteTensor* tfLiteTensor,
449                                      armnn::TensorInfo& tensorInfo,
450                                      armnn::Optional<armnn::PermutationVector&> permutationVector,
451                                      void* permutationData = nullptr)
452 {
453     if (tfLiteTensor->allocation_type != kTfLiteMmapRo)
454     {
455         throw armnn::Exception("TfLiteArmnnDelegate: Not constant allocation type: " + tfLiteTensor->allocation_type);
456     }
457 
458     if (permutationVector.has_value() && permutationVector.value().GetSize() > 0 && permutationData != nullptr)
459     {
460         armnnUtils::Permute(armnnUtils::Permuted(tensorInfo.GetShape(), permutationVector.value()),
461                             permutationVector.value(),
462                             tfLiteTensor->data.data,
463                             permutationData,
464                             armnn::GetDataTypeSize(tensorInfo.GetDataType()));
465 
466         return armnn::ConstTensor(armnnUtils::Permuted(tensorInfo, permutationVector.value()), permutationData);
467     }
468     else
469     {
470         return armnn::ConstTensor(tensorInfo, tfLiteTensor->data.data);
471     }
472 }
473 
CalcPadding(uint32_t inputSize,uint32_t filterSize,uint32_t stride,uint32_t dilation,uint32_t & paddingFront,uint32_t & paddingBack,TfLitePadding padding)474 void CalcPadding(uint32_t inputSize,
475                  uint32_t filterSize,
476                  uint32_t stride,
477                  uint32_t dilation,
478                  uint32_t& paddingFront,
479                  uint32_t& paddingBack,
480                  TfLitePadding padding)
481 {
482     paddingFront = 0;
483     paddingBack = 0;
484     if (padding == kTfLitePaddingSame)
485     {
486         uint32_t outputSize = (inputSize + stride - 1) / stride;
487         uint32_t dilatedSize = filterSize + (dilation - 1) * (filterSize - 1);
488         uint32_t temp = (outputSize - 1) * stride + dilatedSize;
489         if (temp > inputSize)
490         {
491             paddingFront = (temp - inputSize) / 2;
492             paddingBack = (temp - inputSize) - paddingFront;
493         }
494     }
495 }
496 
ConnectConstant(armnn::IConnectableLayer * layer,armnn::TensorInfo & constTensorInfo,TfLiteContext * tfLiteContext,const TfLiteTensor & tfLiteTensor,armnnDelegate::DelegateData & data,unsigned int slotIndex)497 TfLiteStatus ConnectConstant(armnn::IConnectableLayer* layer,
498                              armnn::TensorInfo& constTensorInfo,
499                              TfLiteContext* tfLiteContext,
500                              const TfLiteTensor& tfLiteTensor,
501                              armnnDelegate::DelegateData& data,
502                              unsigned int slotIndex)
503 {
504     bool isSupported = false;
505     FORWARD_LAYER_SUPPORT_FUNC(__func__,
506                                tfLiteContext,
507                                IsConstantSupported,
508                                data.m_Backends,
509                                isSupported,
510                                constTensorInfo);
511     if (!isSupported)
512     {
513         return kTfLiteError;
514     }
515 
516     auto constantInput = CreateConstTensor(&tfLiteTensor,
517                                            constTensorInfo,
518                                            armnn::Optional<armnn::PermutationVector&>());
519     armnn::IConnectableLayer* constantLayer = data.m_Network->AddConstantLayer(constantInput);
520     armnn::IOutputSlot& outputSlot = constantLayer->GetOutputSlot(0);
521     outputSlot.SetTensorInfo(constTensorInfo);
522 
523     data.m_OutputSlotForNode[static_cast<unsigned long>(slotIndex)] = &outputSlot;
524 
525     return kTfLiteOk;
526 }
527 
528 } // namespace anonymous
529