1 //
2 // Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5
6 #pragma once
7
8 #include <armnn/utility/IgnoreUnused.hpp>
9
10 #include <tensorflow/lite/builtin_ops.h>
11 #include <tensorflow/lite/c/builtin_op_data.h>
12 #include <tensorflow/lite/c/common.h>
13 #include <tensorflow/lite/minimal_logging.h>
14
15 namespace armnnDelegate
16 {
17
VisitDequantizeOperator(DelegateData & delegateData,TfLiteContext * tfLiteContext,TfLiteNode * tfLiteNode,int nodeIndex,int32_t tfLiteDequantizeOperatorCode)18 TfLiteStatus VisitDequantizeOperator(DelegateData& delegateData,
19 TfLiteContext* tfLiteContext,
20 TfLiteNode* tfLiteNode,
21 int nodeIndex,
22 int32_t tfLiteDequantizeOperatorCode)
23 {
24 TF_LITE_ENSURE_STATUS(ValidateNumInputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
25 TF_LITE_ENSURE_STATUS(ValidateNumOutputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
26
27 const TfLiteTensor* tfLiteTensors = tfLiteContext->tensors;
28 const TfLiteTensor& tfLiteInputTensor = tfLiteTensors[tfLiteNode->inputs->data[0]];
29 if (IsDynamicTensor(tfLiteInputTensor))
30 {
31 TF_LITE_MAYBE_KERNEL_LOG(
32 tfLiteContext,
33 "TfLiteArmnnDelegate: Dynamic input tensors are not supported in operator #%d node #%d: ",
34 tfLiteDequantizeOperatorCode, nodeIndex);
35 return kTfLiteError;
36 }
37
38 const TfLiteTensor& tfLiteOutputTensor = tfLiteTensors[tfLiteNode->outputs->data[0]];
39 if (IsDynamicTensor(tfLiteOutputTensor))
40 {
41 TF_LITE_MAYBE_KERNEL_LOG(
42 tfLiteContext,
43 "TfLiteArmnnDelegate: Dynamic output tensors are not supported in operator #%d node #%d: ",
44 tfLiteDequantizeOperatorCode, nodeIndex);
45
46 return kTfLiteError;
47 }
48 const armnn::TensorInfo& inputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteInputTensor);
49 armnn::TensorInfo outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor, true);
50
51 UpdateConstantTensorOutputs(inputTensorInfo, outputTensorInfo);
52
53 bool isSupported = false;
54 armnn::BackendId setBackend;
55 auto validateFunc = [&](const armnn::TensorInfo& outputTensorInfo, bool& isSupported)
56 {
57 FORWARD_LAYER_SUPPORT_FUNC("DEQUANTIZE",
58 tfLiteContext,
59 IsDequantizeSupported,
60 delegateData.m_Backends,
61 isSupported,
62 setBackend,
63 inputTensorInfo,
64 outputTensorInfo);
65 };
66
67 if (!delegateData.m_Network)
68 {
69 validateFunc(outputTensorInfo, isSupported);
70 return isSupported ? kTfLiteOk : kTfLiteError;
71 }
72
73 armnn::IConnectableLayer* dequantizeLayer = delegateData.m_Network->AddDequantizeLayer();
74 dequantizeLayer->SetBackendId(setBackend);
75 ARMNN_ASSERT(dequantizeLayer != nullptr);
76
77 armnn::IOutputSlot& outputSlot = dequantizeLayer->GetOutputSlot(0);
78 outputSlot.SetTensorInfo(outputTensorInfo);
79
80 auto inputsTensorsProcess = ProcessInputs(dequantizeLayer,
81 delegateData,
82 tfLiteContext,
83 tfLiteNode);
84 if (inputsTensorsProcess == kTfLiteError)
85 {
86 return inputsTensorsProcess;
87 }
88
89 return Connect(dequantizeLayer, tfLiteNode, delegateData);
90 }
91
VisitQuantizeOperator(DelegateData & delegateData,TfLiteContext * tfLiteContext,TfLiteNode * tfLiteNode,int nodeIndex,int32_t tfLiteQuantizeOperatorCode)92 TfLiteStatus VisitQuantizeOperator(DelegateData& delegateData,
93 TfLiteContext* tfLiteContext,
94 TfLiteNode* tfLiteNode,
95 int nodeIndex,
96 int32_t tfLiteQuantizeOperatorCode)
97 {
98 TF_LITE_ENSURE_STATUS(ValidateNumInputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
99 TF_LITE_ENSURE_STATUS(ValidateNumOutputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
100
101 const TfLiteTensor* tfLiteTensors = tfLiteContext->tensors;
102 const TfLiteTensor& tfLiteInputTensor = tfLiteTensors[tfLiteNode->inputs->data[0]];
103 if (IsDynamicTensor(tfLiteInputTensor))
104 {
105 TF_LITE_MAYBE_KERNEL_LOG(
106 tfLiteContext,
107 "TfLiteArmnnDelegate: Dynamic input tensors are not supported in operator #%d node #%d: ",
108 tfLiteQuantizeOperatorCode, nodeIndex);
109 return kTfLiteError;
110 }
111
112 const TfLiteTensor& tfLiteOutputTensor = tfLiteTensors[tfLiteNode->outputs->data[0]];
113 if (IsDynamicTensor(tfLiteOutputTensor))
114 {
115 TF_LITE_MAYBE_KERNEL_LOG(
116 tfLiteContext,
117 "TfLiteArmnnDelegate: Dynamic output tensors are not supported in operator #%d node #%d: ",
118 tfLiteQuantizeOperatorCode, nodeIndex);
119 return kTfLiteError;
120 }
121
122 // Only affine per-layer quantization is supported.
123 if (!IsAffineQuantization(tfLiteOutputTensor))
124 {
125 TF_LITE_MAYBE_KERNEL_LOG(
126 tfLiteContext,
127 "TfLiteArmnnDelegate: Only affine per-layer quantization is supported in operator #%d node #%d: ",
128 tfLiteQuantizeOperatorCode, nodeIndex);
129 return kTfLiteError;
130 }
131
132 const armnn::TensorInfo& inputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteInputTensor);
133 const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor, true);
134
135 bool isSupported = false;
136 armnn::BackendId setBackend;
137 auto validateFunc = [&](const armnn::TensorInfo& outputTensorInfo, bool& isSupported)
138 {
139 FORWARD_LAYER_SUPPORT_FUNC("QUANTIZE",
140 tfLiteContext,
141 IsQuantizeSupported,
142 delegateData.m_Backends,
143 isSupported,
144 setBackend,
145 inputTensorInfo,
146 outputTensorInfo);
147 };
148
149 if (!delegateData.m_Network)
150 {
151 validateFunc(outputTensorInfo, isSupported);
152 return isSupported ? kTfLiteOk : kTfLiteError;
153 }
154
155 armnn::IConnectableLayer* quantizeLayer = delegateData.m_Network->AddQuantizeLayer();
156 quantizeLayer->SetBackendId(setBackend);
157 ARMNN_ASSERT(quantizeLayer != nullptr);
158
159 armnn::IOutputSlot& outputSlot = quantizeLayer->GetOutputSlot(0);
160 outputSlot.SetTensorInfo(outputTensorInfo);
161
162 // try to connect the Constant Inputs if there are any
163 if(ProcessInputs(quantizeLayer,delegateData, tfLiteContext, tfLiteNode) != kTfLiteOk )
164 {
165 return kTfLiteError;
166 }
167
168 return Connect(quantizeLayer, tfLiteNode, delegateData);
169 }
170
171 } // namespace armnnDelegate
172