blob: 82918543839fe452f092a9508536e2d51157f15a [file] [log] [blame]
Sadik Armagan62483be2020-10-23 17:14:43 +01001//
Ryan OShea4c231de2023-01-17 15:19:20 +00002// Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved.
Sadik Armagan62483be2020-10-23 17:14:43 +01003// SPDX-License-Identifier: MIT
4//
5
6#pragma once
7
Finn Williams6f9f9902020-11-13 13:23:15 +00008#include <armnn/utility/IgnoreUnused.hpp>
9
Sadik Armagan62483be2020-10-23 17:14:43 +010010#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
15namespace armnnDelegate
16{
17
Sadik Armagan62483be2020-10-23 17:14:43 +010018TfLiteStatus VisitDequantizeOperator(DelegateData& delegateData,
19 TfLiteContext* tfLiteContext,
20 TfLiteNode* tfLiteNode,
21 int nodeIndex,
Matthew Sloyan0d35a932020-11-09 12:25:05 +000022 int32_t tfLiteDequantizeOperatorCode)
Sadik Armagan62483be2020-10-23 17:14:43 +010023{
Matthew Sloyan0d35a932020-11-09 12:25:05 +000024 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);
Finn Williams6f9f9902020-11-13 13:23:15 +000045
Matthew Sloyan0d35a932020-11-09 12:25:05 +000046 return kTfLiteError;
47 }
Matthew Sloyan0d35a932020-11-09 12:25:05 +000048 const armnn::TensorInfo& inputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteInputTensor);
Sadik Armagan90a119b2022-08-05 16:12:49 +010049 armnn::TensorInfo outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor, true);
50
51 UpdateConstantTensorOutputs(inputTensorInfo, outputTensorInfo);
Matthew Sloyan0d35a932020-11-09 12:25:05 +000052
53 bool isSupported = false;
Cathal Corbett53837672022-09-01 11:34:37 +010054 armnn::BackendId setBackend;
Matthew Sloyan0d35a932020-11-09 12:25:05 +000055 auto validateFunc = [&](const armnn::TensorInfo& outputTensorInfo, bool& isSupported)
56 {
Sadik Armaganbfa767c2022-02-09 14:58:03 +000057 FORWARD_LAYER_SUPPORT_FUNC("DEQUANTIZE",
Matthew Sloyan0d35a932020-11-09 12:25:05 +000058 tfLiteContext,
59 IsDequantizeSupported,
60 delegateData.m_Backends,
61 isSupported,
Cathal Corbett53837672022-09-01 11:34:37 +010062 setBackend,
Matthew Sloyan0d35a932020-11-09 12:25:05 +000063 inputTensorInfo,
64 outputTensorInfo);
65 };
66
67 if (!delegateData.m_Network)
68 {
69 validateFunc(outputTensorInfo, isSupported);
70 return isSupported ? kTfLiteOk : kTfLiteError;
71 }
72
Mike Kelly07169c82023-08-02 13:23:09 +010073 auto layerName = GetLayerName(armnn::LayerType::Dequantize, nodeIndex);
74 armnn::IConnectableLayer* dequantizeLayer = delegateData.m_Network->AddDequantizeLayer(layerName.c_str());
Cathal Corbett53837672022-09-01 11:34:37 +010075 dequantizeLayer->SetBackendId(setBackend);
Matthew Sloyan0d35a932020-11-09 12:25:05 +000076 ARMNN_ASSERT(dequantizeLayer != nullptr);
77
78 armnn::IOutputSlot& outputSlot = dequantizeLayer->GetOutputSlot(0);
79 outputSlot.SetTensorInfo(outputTensorInfo);
80
Sadik Armaganf7ac72c2021-05-05 15:03:50 +010081 auto inputsTensorsProcess = ProcessInputs(dequantizeLayer,
82 delegateData,
83 tfLiteContext,
Mike Kelly07169c82023-08-02 13:23:09 +010084 tfLiteNode,
85 nodeIndex);
Sadik Armaganf7ac72c2021-05-05 15:03:50 +010086 if (inputsTensorsProcess == kTfLiteError)
87 {
88 return inputsTensorsProcess;
89 }
90
Matthew Sloyan0d35a932020-11-09 12:25:05 +000091 return Connect(dequantizeLayer, tfLiteNode, delegateData);
92}
93
94TfLiteStatus VisitQuantizeOperator(DelegateData& delegateData,
95 TfLiteContext* tfLiteContext,
96 TfLiteNode* tfLiteNode,
97 int nodeIndex,
98 int32_t tfLiteQuantizeOperatorCode)
99{
100 TF_LITE_ENSURE_STATUS(ValidateNumInputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
101 TF_LITE_ENSURE_STATUS(ValidateNumOutputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
102
103 const TfLiteTensor* tfLiteTensors = tfLiteContext->tensors;
104 const TfLiteTensor& tfLiteInputTensor = tfLiteTensors[tfLiteNode->inputs->data[0]];
105 if (IsDynamicTensor(tfLiteInputTensor))
106 {
107 TF_LITE_MAYBE_KERNEL_LOG(
108 tfLiteContext,
109 "TfLiteArmnnDelegate: Dynamic input tensors are not supported in operator #%d node #%d: ",
110 tfLiteQuantizeOperatorCode, nodeIndex);
111 return kTfLiteError;
112 }
113
114 const TfLiteTensor& tfLiteOutputTensor = tfLiteTensors[tfLiteNode->outputs->data[0]];
115 if (IsDynamicTensor(tfLiteOutputTensor))
116 {
117 TF_LITE_MAYBE_KERNEL_LOG(
118 tfLiteContext,
119 "TfLiteArmnnDelegate: Dynamic output tensors are not supported in operator #%d node #%d: ",
120 tfLiteQuantizeOperatorCode, nodeIndex);
121 return kTfLiteError;
122 }
123
124 // Only affine per-layer quantization is supported.
125 if (!IsAffineQuantization(tfLiteOutputTensor))
126 {
127 TF_LITE_MAYBE_KERNEL_LOG(
128 tfLiteContext,
129 "TfLiteArmnnDelegate: Only affine per-layer quantization is supported in operator #%d node #%d: ",
130 tfLiteQuantizeOperatorCode, nodeIndex);
131 return kTfLiteError;
132 }
133
134 const armnn::TensorInfo& inputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteInputTensor);
Sadik Armagan90a119b2022-08-05 16:12:49 +0100135 const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor, true);
Matthew Sloyan0d35a932020-11-09 12:25:05 +0000136
137 bool isSupported = false;
Cathal Corbett53837672022-09-01 11:34:37 +0100138 armnn::BackendId setBackend;
Matthew Sloyan0d35a932020-11-09 12:25:05 +0000139 auto validateFunc = [&](const armnn::TensorInfo& outputTensorInfo, bool& isSupported)
140 {
Sadik Armaganbfa767c2022-02-09 14:58:03 +0000141 FORWARD_LAYER_SUPPORT_FUNC("QUANTIZE",
Matthew Sloyan0d35a932020-11-09 12:25:05 +0000142 tfLiteContext,
143 IsQuantizeSupported,
144 delegateData.m_Backends,
145 isSupported,
Cathal Corbett53837672022-09-01 11:34:37 +0100146 setBackend,
Matthew Sloyan0d35a932020-11-09 12:25:05 +0000147 inputTensorInfo,
148 outputTensorInfo);
149 };
150
151 if (!delegateData.m_Network)
152 {
153 validateFunc(outputTensorInfo, isSupported);
154 return isSupported ? kTfLiteOk : kTfLiteError;
155 }
156
Mike Kelly07169c82023-08-02 13:23:09 +0100157 auto layerName = GetLayerName(armnn::LayerType::Quantize, nodeIndex);
158 armnn::IConnectableLayer* quantizeLayer = delegateData.m_Network->AddQuantizeLayer(layerName.c_str());
Cathal Corbett53837672022-09-01 11:34:37 +0100159 quantizeLayer->SetBackendId(setBackend);
Matthew Sloyan0d35a932020-11-09 12:25:05 +0000160 ARMNN_ASSERT(quantizeLayer != nullptr);
161
162 armnn::IOutputSlot& outputSlot = quantizeLayer->GetOutputSlot(0);
163 outputSlot.SetTensorInfo(outputTensorInfo);
164
Ryan OShea4c231de2023-01-17 15:19:20 +0000165 // try to connect the Constant Inputs if there are any
Mike Kelly07169c82023-08-02 13:23:09 +0100166 if (ProcessInputs(quantizeLayer, delegateData, tfLiteContext, tfLiteNode, nodeIndex) != kTfLiteOk)
Ryan OShea4c231de2023-01-17 15:19:20 +0000167 {
168 return kTfLiteError;
169 }
170
Matthew Sloyan0d35a932020-11-09 12:25:05 +0000171 return Connect(quantizeLayer, tfLiteNode, delegateData);
Sadik Armagan62483be2020-10-23 17:14:43 +0100172}
173
174} // namespace armnnDelegate