blob: 41c62c33c832dbbf26542d1b73947217177848bd [file] [log] [blame]
Sadik Armagan62483be2020-10-23 17:14:43 +01001//
Ryan OShea4c231de2023-01-17 15:19:20 +00002// Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved.
Sadik Armagan62483be2020-10-23 17:14:43 +01003// SPDX-License-Identifier: MIT
4//
5
6#pragma once
7
Finn Williams6f9f9902020-11-13 13:23:15 +00008#include <armnn/utility/IgnoreUnused.hpp>
9
Matthew Sloyan11572322023-03-16 10:17:51 +000010#include <ClassicDelegateUtils.hpp>
David Monahan1670b0c2020-11-18 14:40:27 +000011
Sadik Armagan62483be2020-10-23 17:14:43 +010012#include <tensorflow/lite/builtin_ops.h>
13#include <tensorflow/lite/c/builtin_op_data.h>
14#include <tensorflow/lite/c/common.h>
15#include <tensorflow/lite/minimal_logging.h>
16
17namespace armnnDelegate
18{
19
Sadik Armagan937565b2021-04-21 14:03:28 +010020TfLiteStatus VisitCastOperator(DelegateData& delegateData,
21 TfLiteContext* tfLiteContext,
22 TfLiteNode* tfLiteNode,
23 int nodeIndex,
24 int32_t operatorCode)
25{
26 TF_LITE_ENSURE_STATUS(ValidateNumInputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
27 TF_LITE_ENSURE_STATUS(ValidateNumOutputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
28
29 const TfLiteTensor* tfLiteTensors = tfLiteContext->tensors;
30 const TfLiteTensor& tfLiteInputTensor = tfLiteTensors[tfLiteNode->inputs->data[0]];
31 if (!IsValid(tfLiteContext, tfLiteInputTensor, operatorCode, nodeIndex))
32 {
33 return kTfLiteError;
34 }
35
36 const TfLiteTensor& tfLiteOutputTensor = tfLiteTensors[tfLiteNode->outputs->data[0]];
37 if (!IsValid(tfLiteContext, tfLiteOutputTensor, operatorCode, nodeIndex))
38 {
39 return kTfLiteError;
40 }
41
42 const armnn::TensorInfo& inputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteInputTensor);
Sadik Armagan90a119b2022-08-05 16:12:49 +010043 const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor, true);
Sadik Armagan937565b2021-04-21 14:03:28 +010044
45 bool isSupported = false;
Cathal Corbett53837672022-09-01 11:34:37 +010046 armnn::BackendId setBackend;
Sadik Armagan937565b2021-04-21 14:03:28 +010047 auto validateFunc = [&](const armnn::TensorInfo& outInfo, bool& isSupported)
48 {
Sadik Armaganbfa767c2022-02-09 14:58:03 +000049 FORWARD_LAYER_SUPPORT_FUNC("CAST",
Sadik Armagan937565b2021-04-21 14:03:28 +010050 tfLiteContext,
51 IsCastSupported,
52 delegateData.m_Backends,
53 isSupported,
Cathal Corbett53837672022-09-01 11:34:37 +010054 setBackend,
Sadik Armagan937565b2021-04-21 14:03:28 +010055 inputTensorInfo,
56 outInfo);
57 };
58
59 // If the m_Network is a nullptr, this signals that a prerequisite TfLite callback is required to clarify the
60 // support for the operator
61 // If supported, VisitCastOperator will be called again to add the layer to the network as seen further below
62 if (!delegateData.m_Network)
63 {
64 validateFunc(outputTensorInfo, isSupported);
65 return isSupported ? kTfLiteOk : kTfLiteError;
66 }
67
68 // Add a Cast layer
69 armnn::IConnectableLayer* layer = delegateData.m_Network->AddCastLayer();
Cathal Corbett53837672022-09-01 11:34:37 +010070 layer->SetBackendId(setBackend);
Sadik Armagan937565b2021-04-21 14:03:28 +010071 ARMNN_ASSERT(layer != nullptr);
72
73 armnn::IOutputSlot& outputSlot = layer->GetOutputSlot(0);
74 outputSlot.SetTensorInfo(outputTensorInfo);
75
Ryan OShea4c231de2023-01-17 15:19:20 +000076 // try to connect the Constant Inputs if there are any
77 if(ProcessInputs(layer,delegateData, tfLiteContext, tfLiteNode) != kTfLiteOk )
78 {
79 return kTfLiteError;
80 }
81
Sadik Armagan937565b2021-04-21 14:03:28 +010082 // Connect
83 return Connect(layer, tfLiteNode, delegateData);
84}
85
Sadik Armagan62483be2020-10-23 17:14:43 +010086TfLiteStatus VisitReshapeOperator(DelegateData& delegateData,
87 TfLiteContext* tfLiteContext,
88 TfLiteNode* tfLiteNode,
89 int nodeIndex,
90 int32_t operatorCode)
91{
David Monahan1670b0c2020-11-18 14:40:27 +000092 auto numInputs = tfLiteNode->inputs->size;
Finn Williams6f9f9902020-11-13 13:23:15 +000093
David Monahan1670b0c2020-11-18 14:40:27 +000094 if (numInputs == 2)
95 {
96 TF_LITE_ENSURE_STATUS(ValidateNumInputs(tfLiteContext, tfLiteNode, 2, nodeIndex));
97 }
98 else
99 {
100 TF_LITE_ENSURE_STATUS(ValidateNumInputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
101 }
102 TF_LITE_ENSURE_STATUS(ValidateNumOutputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
103
104 const TfLiteTensor* tfLiteTensors = tfLiteContext->tensors;
105 const TfLiteTensor& tfLiteInputTensor0 = tfLiteTensors[tfLiteNode->inputs->data[0]];
Matthew Sloyanf00f6c22020-12-07 13:33:24 +0000106 if (!IsValid(tfLiteContext, tfLiteInputTensor0, operatorCode, nodeIndex))
David Monahan1670b0c2020-11-18 14:40:27 +0000107 {
David Monahan1670b0c2020-11-18 14:40:27 +0000108 return kTfLiteError;
109 }
110
111 const TfLiteTensor& tfLiteOutputTensor = tfLiteTensors[tfLiteNode->outputs->data[0]];
Matthew Sloyanf00f6c22020-12-07 13:33:24 +0000112 if (!IsValid(tfLiteContext, tfLiteOutputTensor, operatorCode, nodeIndex))
David Monahan1670b0c2020-11-18 14:40:27 +0000113 {
David Monahan1670b0c2020-11-18 14:40:27 +0000114 return kTfLiteError;
115 }
116
117 const armnn::TensorInfo& inputTensorInfo0 = GetTensorInfoForTfLiteTensor(tfLiteInputTensor0);
Sadik Armagan90a119b2022-08-05 16:12:49 +0100118 const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor, true);
David Monahan1670b0c2020-11-18 14:40:27 +0000119
120 armnn::ReshapeDescriptor reshapeDesc;
Narumol Prangnawarat7f6c6672020-11-24 18:40:42 +0000121 std::vector<int32_t> targetShape;
Finn Williamsf806c4d2021-02-22 15:13:12 +0000122
123 TfLiteReshapeParams* reshapeOptions = reinterpret_cast<TfLiteReshapeParams*>(tfLiteNode->builtin_data);
David Monahan1670b0c2020-11-18 14:40:27 +0000124
125 // The new shape can be defined by either a second input tensor or by a builtin option, we need to check for both.
Finn Williamsf806c4d2021-02-22 15:13:12 +0000126 // Options might be set without valid data. we need to check the dimensions are in a valid range.
127 if (reshapeOptions && reshapeOptions->num_dimensions > 0 && reshapeOptions->num_dimensions <= 8)
128 {
129 for (int i=0; i < reshapeOptions->num_dimensions; ++i)
130 {
131 targetShape.push_back(reshapeOptions->shape[i]);
132 }
133 }
134 else if (numInputs == 2)
David Monahan1670b0c2020-11-18 14:40:27 +0000135 {
Narumol Prangnawarat7f6c6672020-11-24 18:40:42 +0000136 // Get shape from the second input tensor
137 const TfLiteTensor& tfLiteShapeInputTensor = tfLiteTensors[tfLiteNode->inputs->data[1]];
Matthew Sloyanf00f6c22020-12-07 13:33:24 +0000138 if (!IsValid(tfLiteContext, tfLiteShapeInputTensor, operatorCode, nodeIndex))
David Monahane03d9c22020-11-20 09:58:54 +0000139 {
Narumol Prangnawarat7f6c6672020-11-24 18:40:42 +0000140 return kTfLiteError;
141 }
142
143 if (tfLiteShapeInputTensor.dims->size != 1)
144 {
145 TF_LITE_MAYBE_KERNEL_LOG(tfLiteContext,
146 "TfLiteArmnnDelegate: Target 'shape' input is not a 1D tensor in "
Matthew Sloyanf00f6c22020-12-07 13:33:24 +0000147 "operator #%d node #%d: Falling back to TfLiteOptions.",
Narumol Prangnawarat7f6c6672020-11-24 18:40:42 +0000148 operatorCode, nodeIndex);
Narumol Prangnawarat7f6c6672020-11-24 18:40:42 +0000149 }
Matthew Sloyanf00f6c22020-12-07 13:33:24 +0000150 else
Narumol Prangnawarat7f6c6672020-11-24 18:40:42 +0000151 {
Matthew Sloyanf00f6c22020-12-07 13:33:24 +0000152 // Get the shape data out of the input tensor
153 auto* shapeTensorDataPtr = tflite::GetTensorData<int32_t>(&tfLiteShapeInputTensor);
154 auto shapeTensorNumValues = tfLiteShapeInputTensor.dims->data[0];
155 for (auto i=0; i < shapeTensorNumValues; ++i)
156 {
157 targetShape.push_back(*(shapeTensorDataPtr+i));
158 }
David Monahane03d9c22020-11-20 09:58:54 +0000159 }
160 }
Finn Williamsf806c4d2021-02-22 15:13:12 +0000161 else
David Monahane03d9c22020-11-20 09:58:54 +0000162 {
Finn Williamsf806c4d2021-02-22 15:13:12 +0000163 TF_LITE_MAYBE_KERNEL_LOG(tfLiteContext,
164 "Target shape not defined in reshape parameters or input tensor. "
165 "At least one method required in operator #%d node #%d: ",
166 operatorCode, nodeIndex);
167 return kTfLiteError;
David Monahan1670b0c2020-11-18 14:40:27 +0000168 }
David Monahane03d9c22020-11-20 09:58:54 +0000169
170 // Use the data to create the required tensor shape.
171 if (CreateOutputTensorShape(inputTensorInfo0, targetShape, reshapeDesc) != kTfLiteOk)
David Monahan1670b0c2020-11-18 14:40:27 +0000172 {
173 TF_LITE_MAYBE_KERNEL_LOG(tfLiteContext,
David Monahane03d9c22020-11-20 09:58:54 +0000174 "TfLiteArmnnDelegate: At most one component of shape can be -1 in: "
175 "operator #%d node #%d: ",
David Monahan1670b0c2020-11-18 14:40:27 +0000176 operatorCode, nodeIndex);
David Monahane03d9c22020-11-20 09:58:54 +0000177 return kTfLiteError;
178 }
179
180 if (reshapeDesc.m_TargetShape.GetNumElements() != inputTensorInfo0.GetNumElements())
181 {
Narumol Prangnawarat7f6c6672020-11-24 18:40:42 +0000182 TF_LITE_MAYBE_KERNEL_LOG(
183 tfLiteContext,
184 "TfLiteArmnnDelegate: Reshape, number of elements in output shape does not match input "
185 "operator #%d node #%d: ",
186 operatorCode, nodeIndex);
David Monahane03d9c22020-11-20 09:58:54 +0000187 return kTfLiteError;
David Monahan1670b0c2020-11-18 14:40:27 +0000188 }
189
190 bool isSupported = false;
Cathal Corbett53837672022-09-01 11:34:37 +0100191 armnn::BackendId setBackend;
David Monahan1670b0c2020-11-18 14:40:27 +0000192 auto validateFunc = [&](const armnn::TensorInfo& outInfo, bool& isSupported)
193 {
Sadik Armaganbfa767c2022-02-09 14:58:03 +0000194 FORWARD_LAYER_SUPPORT_FUNC("RESHAPE",
David Monahan1670b0c2020-11-18 14:40:27 +0000195 tfLiteContext,
196 IsReshapeSupported,
197 delegateData.m_Backends,
198 isSupported,
Cathal Corbett53837672022-09-01 11:34:37 +0100199 setBackend,
David Monahan1670b0c2020-11-18 14:40:27 +0000200 inputTensorInfo0,
201 outInfo,
202 reshapeDesc);
203 };
204
205 if (!delegateData.m_Network)
206 {
207 validateFunc(outputTensorInfo, isSupported);
208 return isSupported ? kTfLiteOk : kTfLiteError;
209 }
210
211 armnn::IConnectableLayer* layer = delegateData.m_Network->AddReshapeLayer(reshapeDesc);
Cathal Corbett53837672022-09-01 11:34:37 +0100212 layer->SetBackendId(setBackend);
David Monahan1670b0c2020-11-18 14:40:27 +0000213 ARMNN_ASSERT(layer != nullptr);
214
215 armnn::IOutputSlot& outputSlot = layer->GetOutputSlot(0);
216 outputSlot.SetTensorInfo(outputTensorInfo);
217
Ryan OShea4c231de2023-01-17 15:19:20 +0000218 // try to connect the Constant Inputs if there are any
219 if(ProcessInputs(layer,delegateData, tfLiteContext, tfLiteNode) != kTfLiteOk )
220 {
221 return kTfLiteError;
222 }
223
David Monahan1670b0c2020-11-18 14:40:27 +0000224 // Connect
225 return Connect(layer, tfLiteNode, delegateData);
Sadik Armagan62483be2020-10-23 17:14:43 +0100226}
227
228TfLiteStatus VisitSqueezeOperator(DelegateData& delegateData,
229 TfLiteContext* tfLiteContext,
230 TfLiteNode* tfLiteNode,
231 int nodeIndex,
232 int32_t operatorCode)
233{
Finn Williams6f9f9902020-11-13 13:23:15 +0000234 armnn::IgnoreUnused(delegateData,
235 tfLiteContext,
236 tfLiteNode,
237 nodeIndex,
238 operatorCode);
239
Sadik Armagan62483be2020-10-23 17:14:43 +0100240 return kTfLiteError;
241}
242
243TfLiteStatus VisitExpandDimsOperator(DelegateData& delegateData,
244 TfLiteContext* tfLiteContext,
245 TfLiteNode* tfLiteNode,
246 int nodeIndex,
247 int32_t operatorCode)
248{
Finn Williams6f9f9902020-11-13 13:23:15 +0000249 armnn::IgnoreUnused(delegateData,
250 tfLiteContext,
251 tfLiteNode,
252 nodeIndex,
253 operatorCode);
254
Sadik Armagan62483be2020-10-23 17:14:43 +0100255 return kTfLiteError;
256}
257
258} // namespace armnnDelegate