xref: /aosp_15_r20/external/armnn/delegate/classic/src/Quantization.hpp (revision 89c4ff92f2867872bb9e2354d150bf0c8c502810)
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