blob: c6ac6761d8ba3aeb8f53a2627ff081e6501cfa2a [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//
Teresa Charlinf69ae562023-04-27 14:42:23 +01005
6#pragma once
7
8#include <OpaqueDelegateUtils.hpp>
9
10namespace armnnOpaqueDelegate
11{
12
13TfLiteStatus VisitL2NormalizationOperator(DelegateData& delegateData,
14 TfLiteOpaqueContext* tfLiteContext,
15 TfLiteOpaqueNode* tfLiteNode,
16 int nodeIndex,
17 int32_t tfLiteL2NormalizationOperatorCode)
18{
19 TF_LITE_ENSURE_STATUS(ValidateNumInputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
20 TF_LITE_ENSURE_STATUS(ValidateNumOutputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
21
22 // Gather input indices and use to get input tensor.
23 int numInputs = 0;
24 const int* inputTensors;
25 if (TfLiteOpaqueNodeInputs(tfLiteNode, &inputTensors, &numInputs) != kTfLiteOk)
26 {
27 TF_LITE_OPAQUE_MAYBE_KERNEL_LOG(
28 tfLiteContext,
29 "TfLiteArmnnOpaqueDelegate: Unable to gather input tensor indices from node #%d: ",
30 nodeIndex);
31 return kTfLiteError;
32 }
33 // Use input indices to get input tensor.
34 const TfLiteOpaqueTensor* tfLiteInputTensor = TfLiteOpaqueContextGetOpaqueTensor(tfLiteContext, inputTensors[0]);
35 if (!IsValid(tfLiteContext, tfLiteInputTensor, tfLiteL2NormalizationOperatorCode, nodeIndex))
36 {
37 return kTfLiteError;
38 }
39 // Gather output indices and use to get output tensor.
40 int numOutputs = 0;
41 const int* outputTensors;
42 if (TfLiteOpaqueNodeOutputs(tfLiteNode, &outputTensors, &numOutputs) != kTfLiteOk)
43 {
44 TF_LITE_OPAQUE_MAYBE_KERNEL_LOG(
45 tfLiteContext,
46 "TfLiteArmnnOpaqueDelegate: Unable to gather output tensor indices from node #%d: ",
47 nodeIndex);
48 return kTfLiteError;
49 }
50 // Use output indices to get output tensor.
51 const TfLiteOpaqueTensor* tfLiteOutputTensor = TfLiteOpaqueContextGetOpaqueTensor(tfLiteContext, outputTensors[0]);
52 if (!IsValid(tfLiteContext, tfLiteOutputTensor, tfLiteL2NormalizationOperatorCode, nodeIndex))
53 {
54 return kTfLiteError;
55 }
56
57 const armnn::TensorInfo& inputTensorInfo = GetTensorInfoForTfLiteOpaqueTensor(tfLiteInputTensor);
58 const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteOpaqueTensor(tfLiteOutputTensor, true);
59
60 armnn::L2NormalizationDescriptor descriptor;
61 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
62
63 bool isSupported = false;
64 armnn::BackendId setBackend;
65 auto validateFunc = [&](const armnn::TensorInfo& outInfo, bool& isSupported)
66 {
67 FORWARD_LAYER_OPAQUE_SUPPORT_FUNC("L2_NORMALIZATION",
68 tfLiteContext,
69 IsL2NormalizationSupported,
70 delegateData.m_Backends,
71 isSupported,
72 setBackend,
73 inputTensorInfo,
74 outInfo,
75 descriptor);
76 };
77
78 if (!delegateData.m_Network)
79 {
80 validateFunc(outputTensorInfo, isSupported);
81 return isSupported ? kTfLiteOk : kTfLiteError;
82 }
83
84 // Add a L2Normalization layer
85 armnn::IConnectableLayer* layer = delegateData.m_Network->AddL2NormalizationLayer(descriptor);
86 layer->SetBackendId(setBackend);
87 ARMNN_ASSERT(layer != nullptr);
88
89 armnn::IOutputSlot& outputSlot = layer->GetOutputSlot(0);
90 outputSlot.SetTensorInfo(outputTensorInfo);
91
92 // try to connect the Constant Inputs if there are any
93 if(ProcessInputs(layer,delegateData, tfLiteContext, tfLiteNode) != kTfLiteOk )
94 {
95 return kTfLiteError;
96 }
97
98 // Connect
99 return Connect(layer, tfLiteContext, tfLiteNode, delegateData);
100}
101
102
103TfLiteStatus VisitLocalResponseNormalizationOperator(DelegateData& delegateData,
104 TfLiteOpaqueContext* tfLiteContext,
105 TfLiteOpaqueNode* tfLiteNode,
106 int nodeIndex,
107 int32_t tfLiteNormalizationOperatorCode)
108{
109 TF_LITE_ENSURE_STATUS(ValidateNumInputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
110 TF_LITE_ENSURE_STATUS(ValidateNumOutputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
111
112 // Gather input indices and use to get input tensor.
113 int numInputs = 0;
114 const int* inputTensors;
115 if (TfLiteOpaqueNodeInputs(tfLiteNode, &inputTensors, &numInputs) != kTfLiteOk)
116 {
117 TF_LITE_OPAQUE_MAYBE_KERNEL_LOG(
118 tfLiteContext,
119 "TfLiteArmnnOpaqueDelegate: Unable to gather input tensor indices from node #%d: ",
120 nodeIndex);
121 return kTfLiteError;
122 }
123 // Use input indices to get input tensor.
124 const TfLiteOpaqueTensor* tfLiteInputTensor = TfLiteOpaqueContextGetOpaqueTensor(tfLiteContext, inputTensors[0]);
125 if (!IsValid(tfLiteContext, tfLiteInputTensor, tfLiteNormalizationOperatorCode, nodeIndex))
126 {
127 return kTfLiteError;
128 }
129 // Gather output indices and use to get output tensor.
130 int numOutputs = 0;
131 const int* outputTensors;
132 if (TfLiteOpaqueNodeOutputs(tfLiteNode, &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 nodeIndex);
138 return kTfLiteError;
139 }
140 // Use output indices to get output tensor.
141 const TfLiteOpaqueTensor* tfLiteOutputTensor = TfLiteOpaqueContextGetOpaqueTensor(tfLiteContext, outputTensors[0]);
142 if (!IsValid(tfLiteContext, tfLiteOutputTensor, tfLiteNormalizationOperatorCode, nodeIndex))
143 {
144 return kTfLiteError;
145 }
146
147 const armnn::TensorInfo& inputTensorInfo = GetTensorInfoForTfLiteOpaqueTensor(tfLiteInputTensor);
148 const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteOpaqueTensor(tfLiteOutputTensor, true);
149
150 armnn::NormalizationDescriptor descriptor;
151 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
152 descriptor.m_NormChannelType = armnn::NormalizationAlgorithmChannel::Across;
153 descriptor.m_NormMethodType = armnn::NormalizationAlgorithmMethod::LocalBrightness;
154
155 auto* nodeParams = reinterpret_cast<TfLiteLocalResponseNormParams*>(TfLiteOpaqueNodeGetBuiltinData(tfLiteNode));
156 descriptor.m_NormSize = nodeParams->radius;
157 descriptor.m_K = nodeParams->bias;
158 descriptor.m_Alpha = nodeParams->alpha;
159 descriptor.m_Beta = nodeParams->beta;
160
161 // ArmNN expects normSize to be the full size of the normalization window
162 descriptor.m_NormSize = 1 + (2 * descriptor.m_NormSize);
163
164 bool isSupported = false;
165 armnn::BackendId setBackend;
166 auto validateFunc = [&](const armnn::TensorInfo& outInfo, bool& isSupported)
167 {
168 FORWARD_LAYER_OPAQUE_SUPPORT_FUNC("NORMALIZATION",
169 tfLiteContext,
170 IsNormalizationSupported,
171 delegateData.m_Backends,
172 isSupported,
173 setBackend,
174 inputTensorInfo,
175 outInfo,
176 descriptor);
177 };
178
179 if (!delegateData.m_Network)
180 {
181 validateFunc(outputTensorInfo, isSupported);
182 return isSupported ? kTfLiteOk : kTfLiteError;
183 }
184
185 // Add a Normalization layer
186 armnn::IConnectableLayer* layer = delegateData.m_Network->AddNormalizationLayer(descriptor);
187 layer->SetBackendId(setBackend);
188 ARMNN_ASSERT(layer != nullptr);
189
190 armnn::IOutputSlot& outputSlot = layer->GetOutputSlot(0);
191 outputSlot.SetTensorInfo(outputTensorInfo);
192
193 // try to connect the Constant Inputs if there are any
194 if(ProcessInputs(layer,delegateData, tfLiteContext, tfLiteNode) != kTfLiteOk )
195 {
196 return kTfLiteError;
197 }
198
199 // Connect
200 return Connect(layer, tfLiteContext, tfLiteNode, delegateData);
201}
202
203} // namespace armnnOpaqueDelegate