blob: 26a933953a2b13ac2f483a738530bd7f3eef5f64 [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
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 }
48
49 const armnn::TensorInfo& inputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteInputTensor);
50 const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor);
51
52 bool isSupported = false;
53 auto validateFunc = [&](const armnn::TensorInfo& outputTensorInfo, bool& isSupported)
54 {
Sadik Armaganbfa767c2022-02-09 14:58:03 +000055 FORWARD_LAYER_SUPPORT_FUNC("DEQUANTIZE",
Matthew Sloyan0d35a932020-11-09 12:25:05 +000056 tfLiteContext,
57 IsDequantizeSupported,
58 delegateData.m_Backends,
59 isSupported,
60 inputTensorInfo,
61 outputTensorInfo);
62 };
63
64 if (!delegateData.m_Network)
65 {
66 validateFunc(outputTensorInfo, isSupported);
67 return isSupported ? kTfLiteOk : kTfLiteError;
68 }
69
70 armnn::IConnectableLayer* dequantizeLayer = delegateData.m_Network->AddDequantizeLayer();
71 ARMNN_ASSERT(dequantizeLayer != nullptr);
72
73 armnn::IOutputSlot& outputSlot = dequantizeLayer->GetOutputSlot(0);
74 outputSlot.SetTensorInfo(outputTensorInfo);
75
Sadik Armaganf7ac72c2021-05-05 15:03:50 +010076 auto inputsTensorsProcess = ProcessInputs(dequantizeLayer,
77 delegateData,
78 tfLiteContext,
79 tfLiteNode);
80 if (inputsTensorsProcess == kTfLiteError)
81 {
82 return inputsTensorsProcess;
83 }
84
Matthew Sloyan0d35a932020-11-09 12:25:05 +000085 return Connect(dequantizeLayer, tfLiteNode, delegateData);
86}
87
88TfLiteStatus VisitQuantizeOperator(DelegateData& delegateData,
89 TfLiteContext* tfLiteContext,
90 TfLiteNode* tfLiteNode,
91 int nodeIndex,
92 int32_t tfLiteQuantizeOperatorCode)
93{
94 TF_LITE_ENSURE_STATUS(ValidateNumInputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
95 TF_LITE_ENSURE_STATUS(ValidateNumOutputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
96
97 const TfLiteTensor* tfLiteTensors = tfLiteContext->tensors;
98 const TfLiteTensor& tfLiteInputTensor = tfLiteTensors[tfLiteNode->inputs->data[0]];
99 if (IsDynamicTensor(tfLiteInputTensor))
100 {
101 TF_LITE_MAYBE_KERNEL_LOG(
102 tfLiteContext,
103 "TfLiteArmnnDelegate: Dynamic input tensors are not supported in operator #%d node #%d: ",
104 tfLiteQuantizeOperatorCode, nodeIndex);
105 return kTfLiteError;
106 }
107
108 const TfLiteTensor& tfLiteOutputTensor = tfLiteTensors[tfLiteNode->outputs->data[0]];
109 if (IsDynamicTensor(tfLiteOutputTensor))
110 {
111 TF_LITE_MAYBE_KERNEL_LOG(
112 tfLiteContext,
113 "TfLiteArmnnDelegate: Dynamic output tensors are not supported in operator #%d node #%d: ",
114 tfLiteQuantizeOperatorCode, nodeIndex);
115 return kTfLiteError;
116 }
117
118 // Only affine per-layer quantization is supported.
119 if (!IsAffineQuantization(tfLiteOutputTensor))
120 {
121 TF_LITE_MAYBE_KERNEL_LOG(
122 tfLiteContext,
123 "TfLiteArmnnDelegate: Only affine per-layer quantization is supported in operator #%d node #%d: ",
124 tfLiteQuantizeOperatorCode, nodeIndex);
125 return kTfLiteError;
126 }
127
128 const armnn::TensorInfo& inputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteInputTensor);
129 const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor);
130
131 bool isSupported = false;
132 auto validateFunc = [&](const armnn::TensorInfo& outputTensorInfo, bool& isSupported)
133 {
Sadik Armaganbfa767c2022-02-09 14:58:03 +0000134 FORWARD_LAYER_SUPPORT_FUNC("QUANTIZE",
Matthew Sloyan0d35a932020-11-09 12:25:05 +0000135 tfLiteContext,
136 IsQuantizeSupported,
137 delegateData.m_Backends,
138 isSupported,
139 inputTensorInfo,
140 outputTensorInfo);
141 };
142
143 if (!delegateData.m_Network)
144 {
145 validateFunc(outputTensorInfo, isSupported);
146 return isSupported ? kTfLiteOk : kTfLiteError;
147 }
148
149 armnn::IConnectableLayer* quantizeLayer = delegateData.m_Network->AddQuantizeLayer();
150 ARMNN_ASSERT(quantizeLayer != nullptr);
151
152 armnn::IOutputSlot& outputSlot = quantizeLayer->GetOutputSlot(0);
153 outputSlot.SetTensorInfo(outputTensorInfo);
154
155 return Connect(quantizeLayer, tfLiteNode, delegateData);
Sadik Armagan62483be2020-10-23 17:14:43 +0100156}
157
158} // namespace armnnDelegate