blob: ad242e579948afc713e3be7325142ae2f607aa84 [file] [log] [blame]
Francis Murtaghc4fb0dd2023-03-16 17:01:56 +00001//
2// Copyright © 2023 Arm Ltd and Contributors. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
Matthew Sloyan0bd4c622023-04-27 11:48:26 +01005
6#pragma once
7
8#include <OpaqueDelegateUtils.hpp>
9
10namespace armnnOpaqueDelegate
11{
12
Teresa Charlinf69ae562023-04-27 14:42:23 +010013std::string GetLayerName(armnn::ActivationFunction activationFunction)
14{
15 std::string layerName = "ACTIVATION";
16 switch (activationFunction)
17 {
18 case armnn::ActivationFunction::Abs:
19 layerName += " ABS";
20 break;
21 case armnn::ActivationFunction::BoundedReLu:
22 layerName += " BOUNDED_RELU";
23 break;
24 case armnn::ActivationFunction::Elu:
25 layerName += " ELU";
26 break;
Teresa Charlin077cddb2023-09-15 15:19:21 +010027 case armnn::ActivationFunction::Gelu:
28 layerName += " GELU";
29 break;
Teresa Charlinf69ae562023-04-27 14:42:23 +010030 case armnn::ActivationFunction::HardSwish:
31 layerName += " HARD_SWISH";
32 break;
33 case armnn::ActivationFunction::LeakyReLu:
34 layerName += " LEAKY_RELU";
35 break;
36 case armnn::ActivationFunction::Linear:
37 layerName += " LINEAR";
38 break;
39 case armnn::ActivationFunction::ReLu:
40 layerName += " RELU";
41 break;
42 case armnn::ActivationFunction::Sigmoid:
43 layerName += " SIGMOID";
44 break;
45 case armnn::ActivationFunction::SoftReLu:
46 layerName += " SOFT_RELU";
47 break;
48 case armnn::ActivationFunction::Square:
49 layerName += " SQUARE";
50 break;
51 case armnn::ActivationFunction::Sqrt:
52 layerName += " SQRT";
53 break;
54 case armnn::ActivationFunction::TanH:
55 layerName += " TANH";
56 break;
57 default:
58 layerName += " UNKNOWN";
59 }
60 return layerName;
61}
62
Matthew Sloyan0bd4c622023-04-27 11:48:26 +010063TfLiteStatus ValidateActivationOperator(DelegateData& delegateData,
64 TfLiteOpaqueContext* tfLiteContext,
65 const armnn::TensorInfo& inputInfo,
66 const armnn::TensorInfo& outputInfo,
67 armnn::ActivationDescriptor& activationDesc)
68{
69 bool isSupported = false;
Teresa Charlinf69ae562023-04-27 14:42:23 +010070 auto validateFunc = [&](const armnn::TensorInfo& outputInfo, bool& isSupported, std::string layerName)
Matthew Sloyan0bd4c622023-04-27 11:48:26 +010071 {
Teresa Charlinf69ae562023-04-27 14:42:23 +010072 FORWARD_LAYER_OPAQUE_SUPPORT_FUNC(layerName.c_str(),
Matthew Sloyan0bd4c622023-04-27 11:48:26 +010073 tfLiteContext,
74 IsActivationSupported,
75 delegateData.m_Backends,
76 isSupported,
77 armnn::BackendId(),
78 inputInfo,
79 outputInfo,
80 activationDesc);
81 };
82
Teresa Charlinf69ae562023-04-27 14:42:23 +010083 validateFunc(outputInfo, isSupported, GetLayerName(activationDesc.m_Function));
Matthew Sloyan0bd4c622023-04-27 11:48:26 +010084 return isSupported ? kTfLiteOk : kTfLiteError;
85}
86
87TfLiteStatus VisitActivationOperator(DelegateData& delegateData,
88 TfLiteOpaqueContext* tfLiteContext,
89 TfLiteOpaqueNode* tfLiteNode,
90 int nodeIndex,
91 int32_t operatorCode)
92{
93 TF_LITE_ENSURE_STATUS(ValidateNumInputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
94 TF_LITE_ENSURE_STATUS(ValidateNumOutputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
95
96 // Gather input indices and use to get input tensor.
97 int numInputs = 0;
98 const int* inputTensors;
99 if (TfLiteOpaqueNodeInputs(tfLiteNode, &inputTensors, &numInputs) != kTfLiteOk)
100 {
101 TF_LITE_OPAQUE_MAYBE_KERNEL_LOG(
102 tfLiteContext,
103 "TfLiteArmnnOpaqueDelegate: Unable to gather input tensor indices from node #%d: ",
104 nodeIndex);
105 return kTfLiteError;
106 }
107
108 const TfLiteOpaqueTensor* tfLiteInputTensor = TfLiteOpaqueContextGetOpaqueTensor(tfLiteContext, inputTensors[0]);
109 if (!IsValid(tfLiteContext, tfLiteInputTensor, operatorCode, nodeIndex))
110 {
111 return kTfLiteError;
112 }
113
114 // Gather output indices and use to get output tensors.
115 int numOutputs = 0;
116 const int* outputTensors;
117 if (TfLiteOpaqueNodeOutputs(tfLiteNode, &outputTensors, &numOutputs) != kTfLiteOk)
118 {
119 TF_LITE_OPAQUE_MAYBE_KERNEL_LOG(
120 tfLiteContext,
121 "TfLiteArmnnOpaqueDelegate: Unable to gather output tensor indices from node #%d: ",
122 nodeIndex);
123 return kTfLiteError;
124 }
125
126 const TfLiteOpaqueTensor* tfLiteOutputTensor = TfLiteOpaqueContextGetOpaqueTensor(tfLiteContext, outputTensors[0]);
127 if (!IsValid(tfLiteContext, tfLiteOutputTensor, operatorCode, nodeIndex))
128 {
129 return kTfLiteError;
130 }
131
132 const armnn::TensorInfo& inputTensorInfo = GetTensorInfoForTfLiteOpaqueTensor(tfLiteInputTensor);
133 const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteOpaqueTensor(tfLiteOutputTensor, true);
134
135 armnn::ActivationDescriptor activationDesc;
136 switch(operatorCode)
137 {
138 case kTfLiteBuiltinRelu:
139 {
140 activationDesc.m_Function = armnn::ActivationFunction::ReLu;
141 break;
142 }
143 case kTfLiteBuiltinRelu6:
144 {
145 activationDesc.m_Function = armnn::ActivationFunction::BoundedReLu;
146 activationDesc.m_A = 6.0f;
147 break;
148 }
149 case kTfLiteBuiltinLogistic:
150 {
151 activationDesc.m_Function = armnn::ActivationFunction::Sigmoid;
152 break;
153 }
154 case kTfLiteBuiltinTanh:
155 {
156 activationDesc.m_Function = armnn::ActivationFunction::TanH;
157 activationDesc.m_A = 1.0f;
158 activationDesc.m_B = 1.0f;
159 break;
160 }
161 case kTfLiteBuiltinElu:
162 {
163 activationDesc.m_Function = armnn::ActivationFunction::Elu;
164 activationDesc.m_A = 1.0f;
165 break;
166 }
167 case kTfLiteBuiltinHardSwish:
168 {
169 activationDesc.m_Function = armnn::ActivationFunction::HardSwish;
170 break;
171 }
Tianle Chengae931732023-07-28 11:53:04 +0100172 case kTfLiteBuiltinLeakyRelu:
173 {
174 // Get alpha param from builtin data
175 auto* leakyReluParameters =
176 reinterpret_cast<TfLiteLeakyReluParams*>(TfLiteOpaqueNodeGetBuiltinData(tfLiteNode));
177 activationDesc.m_Function = armnn::ActivationFunction::LeakyReLu;
178 activationDesc.m_A = leakyReluParameters->alpha;
179 break;
180 }
Teresa Charlin077cddb2023-09-15 15:19:21 +0100181 case kTfLiteBuiltinGelu:
182 {
183 activationDesc.m_Function = armnn::ActivationFunction::Gelu;
184 break;
185 }
Matthew Sloyan0bd4c622023-04-27 11:48:26 +0100186 default:
187 {
188 return kTfLiteError;
189 }
190 }
191 if (!delegateData.m_Network)
192 {
193 return ValidateActivationOperator(delegateData,
194 tfLiteContext,
195 inputTensorInfo,
196 outputTensorInfo,
197 activationDesc);
198 }
Mike Kellya2806502023-08-03 10:42:11 +0100199 auto layerName = GetName(activationDesc.m_Function, nodeIndex);
200 armnn::IConnectableLayer* activationLayer = delegateData.m_Network->AddActivationLayer(activationDesc,
201 layerName.c_str());
Matthew Sloyan0bd4c622023-04-27 11:48:26 +0100202 ARMNN_ASSERT(activationLayer != nullptr);
203
204 armnn::IOutputSlot& outputSlot = activationLayer->GetOutputSlot(0);
205 outputSlot.SetTensorInfo(outputTensorInfo);
206
207 // try to connect the Constant Inputs if there are any
Mike Kellya2806502023-08-03 10:42:11 +0100208 if (ProcessInputs(activationLayer, delegateData, tfLiteContext, tfLiteNode, nodeIndex) != kTfLiteOk)
Matthew Sloyan0bd4c622023-04-27 11:48:26 +0100209 {
210 return kTfLiteError;
211 }
212
213 // Connect
214 return Connect(activationLayer, tfLiteContext, tfLiteNode, delegateData);
215}
216
217} // namespace armnnDelegate