blob: 3d3f1a07991edf855c1becb035b47857ff96e3cc [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
Sadik Armagan67e95f22020-10-29 16:14:54 +00008#include "DelegateUtils.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 Armagan67e95f22020-10-29 16:14:54 +000018TfLiteStatus ValidateAddOperator(DelegateData& delegateData,
19 TfLiteContext* tfLiteContext,
20 const armnn::TensorInfo& inputInfo1,
21 const armnn::TensorInfo& inputInfo2,
22 const armnn::TensorInfo& outputInfo)
23{
24 bool isSupported = false;
25 auto validateFunc = [&](const armnn::TensorInfo& outputTensorInfo, bool& isSupported)
26 {
27 FORWARD_LAYER_SUPPORT_FUNC(__func__,
28 tfLiteContext,
29 IsAdditionSupported,
30 delegateData.m_Backends,
31 isSupported,
32 inputInfo1,
33 inputInfo2,
34 outputTensorInfo);
35 };
36
37 validateFunc(outputInfo, isSupported);
38 return isSupported ? kTfLiteOk : kTfLiteError;
39}
40
Sadik Armagan21a94ff2020-11-09 08:38:30 +000041TfLiteStatus ValidateDivOperator(DelegateData& delegateData,
42 TfLiteContext* tfLiteContext,
43 const armnn::TensorInfo& inputInfo1,
44 const armnn::TensorInfo& inputInfo2,
45 const armnn::TensorInfo& outputInfo)
Sadik Armagan67e95f22020-10-29 16:14:54 +000046{
Sadik Armagan21a94ff2020-11-09 08:38:30 +000047 bool isSupported = false;
48 auto validateFunc = [&](const armnn::TensorInfo& outputTensorInfo, bool& isSupported)
Sadik Armagan67e95f22020-10-29 16:14:54 +000049 {
Sadik Armagan21a94ff2020-11-09 08:38:30 +000050 FORWARD_LAYER_SUPPORT_FUNC(__func__,
51 tfLiteContext,
52 IsDivisionSupported,
53 delegateData.m_Backends,
54 isSupported,
55 inputInfo1,
56 inputInfo2,
57 outputTensorInfo);
58 };
Sadik Armagan67e95f22020-10-29 16:14:54 +000059
Sadik Armagan21a94ff2020-11-09 08:38:30 +000060 validateFunc(outputInfo, isSupported);
61 return isSupported ? kTfLiteOk : kTfLiteError;
62}
63
64TfLiteStatus ValidateMaximumOperator(DelegateData& delegateData,
65 TfLiteContext* tfLiteContext,
66 const armnn::TensorInfo& inputInfo1,
67 const armnn::TensorInfo& inputInfo2,
68 const armnn::TensorInfo& outputInfo)
69{
70 bool isSupported = false;
71 auto validateFunc = [&](const armnn::TensorInfo& outputTensorInfo, bool& isSupported)
72 {
73 FORWARD_LAYER_SUPPORT_FUNC(__func__,
74 tfLiteContext,
75 IsMaximumSupported,
76 delegateData.m_Backends,
77 isSupported,
78 inputInfo1,
79 inputInfo2,
80 outputTensorInfo);
81 };
82
83 validateFunc(outputInfo, isSupported);
84 return isSupported ? kTfLiteOk : kTfLiteError;
85}
86
87TfLiteStatus ValidateMinimumOperator(DelegateData& delegateData,
88 TfLiteContext* tfLiteContext,
89 const armnn::TensorInfo& inputInfo1,
90 const armnn::TensorInfo& inputInfo2,
91 const armnn::TensorInfo& outputInfo)
92{
93 bool isSupported = false;
94 auto validateFunc = [&](const armnn::TensorInfo& outputTensorInfo, bool& isSupported)
95 {
96 FORWARD_LAYER_SUPPORT_FUNC(__func__,
97 tfLiteContext,
98 IsMinimumSupported,
99 delegateData.m_Backends,
100 isSupported,
101 inputInfo1,
102 inputInfo2,
103 outputTensorInfo);
104 };
105
106 validateFunc(outputInfo, isSupported);
107 return isSupported ? kTfLiteOk : kTfLiteError;
108}
109
110TfLiteStatus ValidateMulOperator(DelegateData& delegateData,
111 TfLiteContext* tfLiteContext,
112 const armnn::TensorInfo& inputInfo1,
113 const armnn::TensorInfo& inputInfo2,
114 const armnn::TensorInfo& outputInfo)
115{
116 bool isSupported = false;
117 auto validateFunc = [&](const armnn::TensorInfo& outputTensorInfo, bool& isSupported)
118 {
119 FORWARD_LAYER_SUPPORT_FUNC(__func__,
120 tfLiteContext,
121 IsMultiplicationSupported,
122 delegateData.m_Backends,
123 isSupported,
124 inputInfo1,
125 inputInfo2,
126 outputTensorInfo);
127 };
128
129 validateFunc(outputInfo, isSupported);
130 return isSupported ? kTfLiteOk : kTfLiteError;
131}
132
133TfLiteStatus ValidateSubOperator(DelegateData& delegateData,
134 TfLiteContext* tfLiteContext,
135 const armnn::TensorInfo& inputInfo1,
136 const armnn::TensorInfo& inputInfo2,
137 const armnn::TensorInfo& outputInfo)
138{
139 bool isSupported = false;
140 auto validateFunc = [&](const armnn::TensorInfo& outputTensorInfo, bool& isSupported)
141 {
142 FORWARD_LAYER_SUPPORT_FUNC(__func__,
143 tfLiteContext,
144 IsSubtractionSupported,
145 delegateData.m_Backends,
146 isSupported,
147 inputInfo1,
148 inputInfo2,
149 outputTensorInfo);
150 };
151
152 validateFunc(outputInfo, isSupported);
153 return isSupported ? kTfLiteOk : kTfLiteError;
Sadik Armagan67e95f22020-10-29 16:14:54 +0000154}
155
Sadik Armagan62483be2020-10-23 17:14:43 +0100156TfLiteStatus VisitElementwiseBinaryOperator(DelegateData& delegateData,
157 TfLiteContext* tfLiteContext,
158 TfLiteNode* tfLiteNode,
159 int nodeIndex,
160 int32_t elementwiseBinaryOperatorCode)
161{
Sadik Armagan67e95f22020-10-29 16:14:54 +0000162 TF_LITE_ENSURE_STATUS(ValidateNumInputs(tfLiteContext, tfLiteNode, 2, nodeIndex));
163 TF_LITE_ENSURE_STATUS(ValidateNumOutputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
164
165 const TfLiteTensor* tfLiteTensors = tfLiteContext->tensors;
166 const TfLiteTensor& tfLiteInputTensor0 = tfLiteTensors[tfLiteNode->inputs->data[0]];
167 if (IsDynamicTensor(tfLiteInputTensor0))
168 {
169 TF_LITE_MAYBE_KERNEL_LOG(
170 tfLiteContext,
171 "TfLiteArmnnDelegate: Dynamic input tensors are not supported in operator #%d node #%d: ",
172 elementwiseBinaryOperatorCode, nodeIndex);
173 return kTfLiteError;
174 }
175
176 const TfLiteTensor& tfLiteInputTensor1 = tfLiteTensors[tfLiteNode->inputs->data[1]];
177 if (IsDynamicTensor(tfLiteInputTensor1))
178 {
179 TF_LITE_MAYBE_KERNEL_LOG(
180 tfLiteContext,
181 "TfLiteArmnnDelegate: Dynamic input tensors are not supported in operator #%d node #%d: ",
182 elementwiseBinaryOperatorCode, nodeIndex);
183 return kTfLiteError;
184 }
185
186 const TfLiteTensor& tfLiteOutputTensor = tfLiteTensors[tfLiteNode->outputs->data[0]];
187 if (IsDynamicTensor(tfLiteOutputTensor))
188 {
189 TF_LITE_MAYBE_KERNEL_LOG(
190 tfLiteContext,
191 "TfLiteArmnnDelegate: Dynamic output tensors are not supported in operator #%d node #%d: ",
192 elementwiseBinaryOperatorCode, nodeIndex);
193 return kTfLiteError;
194 }
195
196 const armnn::TensorInfo& inputTensorInfo0 = GetTensorInfoForTfLiteTensor(tfLiteInputTensor0);
197 const armnn::TensorInfo& inputTensorInfo1 = GetTensorInfoForTfLiteTensor(tfLiteInputTensor1);
198 const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor);
199
200 if (!delegateData.m_Network)
201 {
202 switch(elementwiseBinaryOperatorCode)
203 {
204 case kTfLiteBuiltinAdd:
205 return ValidateAddOperator(delegateData,
206 tfLiteContext,
207 inputTensorInfo0,
208 inputTensorInfo1,
209 outputTensorInfo);
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000210 case kTfLiteBuiltinDiv:
211 return ValidateDivOperator(delegateData,
212 tfLiteContext,
213 inputTensorInfo0,
214 inputTensorInfo1,
215 outputTensorInfo);
216 case kTfLiteBuiltinMaximum:
217 return ValidateMaximumOperator(delegateData,
218 tfLiteContext,
219 inputTensorInfo0,
220 inputTensorInfo1,
221 outputTensorInfo);
222 case kTfLiteBuiltinMinimum:
223 return ValidateMinimumOperator(delegateData,
224 tfLiteContext,
225 inputTensorInfo0,
226 inputTensorInfo1,
227 outputTensorInfo);
228 case kTfLiteBuiltinMul:
229 return ValidateDivOperator(delegateData,
230 tfLiteContext,
231 inputTensorInfo0,
232 inputTensorInfo1,
233 outputTensorInfo);
234 case kTfLiteBuiltinSub:
235 return ValidateDivOperator(delegateData,
236 tfLiteContext,
237 inputTensorInfo0,
238 inputTensorInfo1,
239 outputTensorInfo);
Sadik Armagan67e95f22020-10-29 16:14:54 +0000240 default:
241 return kTfLiteError;
242 }
243 }
244
245 armnn::IConnectableLayer* elementwiseBinaryLayer = nullptr;
246
247 switch(elementwiseBinaryOperatorCode)
248 {
249 case kTfLiteBuiltinAdd:
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000250 elementwiseBinaryLayer = delegateData.m_Network->AddAdditionLayer();
251 break;
252 case kTfLiteBuiltinDiv:
253 elementwiseBinaryLayer = delegateData.m_Network->AddDivisionLayer();
254 break;
255 case kTfLiteBuiltinMaximum:
256 elementwiseBinaryLayer = delegateData.m_Network->AddMaximumLayer();
257 break;
258 case kTfLiteBuiltinMinimum:
259 elementwiseBinaryLayer = delegateData.m_Network->AddMinimumLayer();
260 break;
261 case kTfLiteBuiltinMul:
262 elementwiseBinaryLayer = delegateData.m_Network->AddMultiplicationLayer();
263 break;
264 case kTfLiteBuiltinSub:
265 elementwiseBinaryLayer = delegateData.m_Network->AddSubtractionLayer();
Sadik Armagan67e95f22020-10-29 16:14:54 +0000266 break;
267 default:
268 return kTfLiteError;
269 }
270 ARMNN_ASSERT(elementwiseBinaryLayer != nullptr);
271
272 armnn::IOutputSlot& outputSlot = elementwiseBinaryLayer->GetOutputSlot(0);
273 outputSlot.SetTensorInfo(outputTensorInfo);
274
275 auto reshapeLayer = BroadcastTensor(inputTensorInfo0,
276 inputTensorInfo1,
277 elementwiseBinaryLayer,
278 tfLiteContext,
279 tfLiteNode,
280 delegateData);
281 if (!reshapeLayer)
282 {
283 return kTfLiteError;
284 }
285
286 auto* tfLiteNodeParameters = reinterpret_cast<TfLiteAddParams*>(tfLiteNode->builtin_data);
287 if (!tfLiteNodeParameters)
288 {
289 // No Activation
290 return kTfLiteOk;
291 }
292 // Check activation
293 TfLiteFusedActivation activationType = tfLiteNodeParameters->activation;
294 return FusedActivation(tfLiteContext, tfLiteNode, activationType, reshapeLayer, 0, delegateData);
Sadik Armagan62483be2020-10-23 17:14:43 +0100295}
296
297} // namespace armnnDelegate