blob: 0a0c630697a27750aa1b8fd1b2d0416284ed49d9 [file] [log] [blame]
Matthew Sloyan080ffd82023-04-24 12:53:04 +01001//
2// Copyright © 2023 Arm Ltd and Contributors. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#include "SharedFunctions.hpp"
7
8#include <OpaqueDelegateUtils.hpp>
9
10namespace armnnOpaqueDelegate
11{
12
13TfLiteStatus ValidateFloorOperator(DelegateData& delegateData,
14 TfLiteOpaqueContext* tfLiteContext,
15 const armnn::TensorInfo& inputTensorInfo,
16 const armnn::TensorInfo& outputTensorInfo)
17{
18 bool isSupported = false;
19 auto validateFunc = [&](const armnn::TensorInfo& outInfo, bool& isSupported)
20 {
21 FORWARD_LAYER_OPAQUE_SUPPORT_FUNC("FLOOR",
22 tfLiteContext,
23 IsFloorSupported,
24 delegateData.m_Backends,
25 isSupported,
26 armnn::BackendId(),
27 inputTensorInfo,
28 outInfo);
29 };
30 validateFunc(outputTensorInfo, isSupported);
31 return isSupported ? kTfLiteOk : kTfLiteError;
32}
33
34TfLiteStatus ValidateFusedActivationOperator(DelegateData& delegateData,
35 TfLiteOpaqueContext* tfLiteContext,
36 const armnn::TensorInfo& inputInfo,
37 const armnn::TensorInfo& outputInfo,
38 TfLiteFusedActivation activationType)
39{
40 armnn::ActivationDescriptor activationDesc;
41
42 switch (activationType)
43 {
44 case kTfLiteActNone:
45 {
46 // No Activation
47 return kTfLiteOk;
48 }
49 case kTfLiteActRelu:
50 {
51 activationDesc.m_Function = armnn::ActivationFunction::ReLu;
52 break;
53 }
54 case kTfLiteActReluN1To1:
55 {
56 activationDesc.m_Function = armnn::ActivationFunction::BoundedReLu;
57 activationDesc.m_A = 1.0f;
58 activationDesc.m_B = -1.0f;
59 break;
60 }
61 case kTfLiteActRelu6:
62 {
63 activationDesc.m_Function = armnn::ActivationFunction::BoundedReLu;
64 activationDesc.m_A = 6.0f;
65 activationDesc.m_B = 0.0f;
66 break;
67 }
68 case kTfLiteActSigmoid:
69 {
70 activationDesc.m_Function = armnn::ActivationFunction::Sigmoid;
71 break;
72 }
73 case kTfLiteActTanh:
74 {
75 activationDesc.m_Function = armnn::ActivationFunction::TanH;
76 activationDesc.m_A = 1.0f;
77 activationDesc.m_B = 1.0f;
78 break;
79 }
80 default:
81 return kTfLiteError;
82 }
83
84 bool isSupported = false;
85 armnn::BackendId setBackend;
86
87 auto validateFunc = [&](const armnn::TensorInfo& outputInfo, bool& isSupported)
88 {
89 FORWARD_LAYER_OPAQUE_SUPPORT_FUNC("ACTIVATION",
90 tfLiteContext,
91 IsActivationSupported,
92 delegateData.m_Backends,
93 isSupported,
94 armnn::BackendId(),
95 inputInfo,
96 outputInfo,
97 activationDesc);
98 };
99 validateFunc(outputInfo, isSupported);
100 return isSupported ? kTfLiteOk : kTfLiteError;
101}
102
Mike Kelly080d45d2023-11-10 17:11:53 +0000103TfLiteOpaqueNode* GetNodeConnectedToInput(TfLiteOpaqueContext* tfLiteContext,
104 int32_t& connectedIndex,
105 int32_t inputIdx)
106{
107 TfLiteIntArray* executionPlan = nullptr;
108 if (TfLiteOpaqueContextGetExecutionPlan(tfLiteContext, &executionPlan) != kTfLiteOk)
109 {
110 TF_LITE_OPAQUE_MAYBE_KERNEL_LOG(tfLiteContext, "TfLiteArmnnDelegate: Unable to get graph execution plan.");
111 return nullptr;
112 }
113
114 for (int i = 0; i < executionPlan->size; ++i)
115 {
116 connectedIndex = executionPlan->data[i];
117
118 // If TfLite nodes can be delegated to ArmNN
119 TfLiteOpaqueNode* connectedNode = nullptr;
120 TfLiteRegistrationExternal* tfLiteRegistration = nullptr;
121 if (TfLiteOpaqueContextGetNodeAndRegistration(
122 tfLiteContext, connectedIndex, &connectedNode, &tfLiteRegistration) != kTfLiteOk)
123 {
124 TF_LITE_OPAQUE_MAYBE_KERNEL_LOG(tfLiteContext,
125 "TfLiteArmnnOpaqueDelegate: Unable to get node and registration for node "
126 "%d.", connectedIndex);
127 continue;
128 }
129 int numOutputs = 0;
130 const int* outputTensors;
131
132 if (TfLiteOpaqueNodeOutputs(connectedNode, &outputTensors, &numOutputs) != kTfLiteOk)
133 {
134 TF_LITE_OPAQUE_MAYBE_KERNEL_LOG(
135 tfLiteContext,
136 "TfLiteArmnnOpaqueDelegate: Unable to gather output tensor indices from node #%d: ",
137 connectedIndex);
138 continue;
139 }
140
141 for (int j= 0; j < numOutputs; ++j)
142 {
143 if (outputTensors[j] == inputIdx)
144 {
145 return connectedNode;
146 }
147 }
148 }
149 // No node found so set connectedIndex to -1
150 connectedIndex = -1;
151 return nullptr;
152}
153
154bool WillInputBeOptimizedToConst(TfLiteOpaqueContext* tfLiteContext, int32_t inputIdx)
155{
156 int32_t connectedIndex;
157 TfLiteOpaqueNode* connectedNode = GetNodeConnectedToInput(tfLiteContext, connectedIndex, inputIdx);
158
159 if (connectedNode)
160 {
161 TfLiteRegistrationExternal* tfLiteRegistration = nullptr;
162
163 if (TfLiteOpaqueContextGetNodeAndRegistration(tfLiteContext, connectedIndex, &connectedNode,
164 &tfLiteRegistration) == kTfLiteOk)
165 {
166 switch (TfLiteRegistrationExternalGetBuiltInCode(tfLiteRegistration))
167 {
168 case kTfLiteBuiltinDequantize:
169 {
170 auto numInputs = TfLiteOpaqueNodeNumberOfInputs(connectedNode);
171 if (numInputs >= 1)
172 {
173 const int* inputTensors;
174 if (TfLiteOpaqueNodeInputs(connectedNode, &inputTensors, &numInputs) != kTfLiteOk)
175 {
176 TF_LITE_OPAQUE_MAYBE_KERNEL_LOG(
177 tfLiteContext,
178 "TfLiteArmnnOpaqueDelegate: Unable to gather input tensor indices from node #%d: ",
179 connectedIndex);
180 return kTfLiteError;
181 }
182 const TfLiteOpaqueTensor* tfLiteInputTensor = TfLiteOpaqueContextGetOpaqueTensor(tfLiteContext,
183 inputTensors[0]);
184
185 // If the input to the Dequantize is a Constant then both that Constant layer and the Dequantize
186 // layer will be replaced by a single Constant layer containing the dequantized values.
187 if (IsConstantTensor(tfLiteInputTensor))
188 {
189 return true;
190 }
191 }
192 break;
193 }
194 default:
195 {
196 }
197 }
198 }
199 }
200 return false;
201}
202
Matthew Sloyan080ffd82023-04-24 12:53:04 +0100203} // namespace armnnDelegate
204