blob: 370f1ab2d25d9a1c778c008609cd417a6b23c482 [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
Jan Eilerse339bf62020-11-10 18:43:23 +00008#include "DelegateUtils.hpp"
Finn Williams6f9f9902020-11-13 13:23:15 +00009#include <armnn/utility/IgnoreUnused.hpp>
Jan Eilerse339bf62020-11-10 18:43:23 +000010
11#include <armnn/Descriptors.hpp>
12
Sadik Armagan62483be2020-10-23 17:14:43 +010013#include <tensorflow/lite/builtin_ops.h>
14#include <tensorflow/lite/c/builtin_op_data.h>
15#include <tensorflow/lite/c/common.h>
16#include <tensorflow/lite/minimal_logging.h>
Jan Eilerse339bf62020-11-10 18:43:23 +000017#include <tensorflow/lite/kernels/internal/tensor_ctypes.h>
Sadik Armagan62483be2020-10-23 17:14:43 +010018
19namespace armnnDelegate
20{
21
Jan Eilerse339bf62020-11-10 18:43:23 +000022
23
24TfLiteStatus ValidateResizeOperator(DelegateData& delegateData,
25 TfLiteContext* tfLiteContext,
26 const armnn::TensorInfo& inputInfo,
27 const armnn::TensorInfo& outputInfo,
28 const armnn::ResizeDescriptor& descriptor)
29{
30 bool isSupported = false;
Sadik Armaganbfa767c2022-02-09 14:58:03 +000031 FORWARD_LAYER_SUPPORT_FUNC("RESIZE",
Jan Eilerse339bf62020-11-10 18:43:23 +000032 tfLiteContext,
33 IsResizeSupported,
34 delegateData.m_Backends,
35 isSupported,
Cathal Corbett53837672022-09-01 11:34:37 +010036 armnn::BackendId(),
Jan Eilerse339bf62020-11-10 18:43:23 +000037 inputInfo,
38 outputInfo,
39 descriptor);
40
41 return isSupported ? kTfLiteOk : kTfLiteError;
42}
43
Sadik Armagan62483be2020-10-23 17:14:43 +010044TfLiteStatus VisitResizeOperator(DelegateData& delegateData,
45 TfLiteContext* tfLiteContext,
46 TfLiteNode* tfLiteNode,
47 int nodeIndex,
48 int32_t resizeOperatorCode)
49{
Jan Eilerse339bf62020-11-10 18:43:23 +000050 TF_LITE_ENSURE_STATUS(ValidateNumInputs(tfLiteContext, tfLiteNode, 2, nodeIndex));
51 TF_LITE_ENSURE_STATUS(ValidateNumOutputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
52
53 const TfLiteTensor* tfLiteTensors = tfLiteContext->tensors;
54
55 // The first input contains the data of the image that should be resized [batch, height, width, channels]
56 const TfLiteTensor& tfLiteInputTensor = tfLiteTensors[tfLiteNode->inputs->data[0]];
57 if (IsDynamicTensor(tfLiteInputTensor))
58 {
59 TF_LITE_MAYBE_KERNEL_LOG(
60 tfLiteContext,
61 "TfLiteArmnnDelegate: Dynamic input tensors are not supported in operator #%d node #%d: ",
62 resizeOperatorCode, nodeIndex);
63 return kTfLiteError;
64 }
65
66 // The second input contains a size tensor. The size tensor contains two integer values
67 // that describe the new height and width of the image [new_height, new_width]
68 const TfLiteTensor& tfLiteSizeTensor = tfLiteTensors[tfLiteNode->inputs->data[1]];
69 if (IsDynamicTensor(tfLiteSizeTensor))
70 {
71 TF_LITE_MAYBE_KERNEL_LOG(
72 tfLiteContext,
73 "TfLiteArmnnDelegate: Dynamic input tensors are not supported in operator #%d node #%d: ",
74 resizeOperatorCode, nodeIndex);
75 return kTfLiteError;
76 }
77
78 // The output tensor should have the shape [batch, new_height, new_width, channels]
79 const TfLiteTensor& tfLiteOutputTensor = tfLiteTensors[tfLiteNode->outputs->data[0]];
80 if (IsDynamicTensor(tfLiteOutputTensor))
81 {
82 TF_LITE_MAYBE_KERNEL_LOG(
83 tfLiteContext,
84 "TfLiteArmnnDelegate: Dynamic output tensors are not supported in operator #%d node #%d: ",
85 resizeOperatorCode, nodeIndex);
86 return kTfLiteError;
87 }
88
89 const armnn::TensorInfo& inputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteInputTensor);
Sadik Armagan90a119b2022-08-05 16:12:49 +010090 const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor, true);
Jan Eilerse339bf62020-11-10 18:43:23 +000091
92 std::string layerName("Resize");
93
94 // Fill descriptor
95 armnn::ResizeDescriptor desc;
96 switch (resizeOperatorCode)
97 {
98 case kTfLiteBuiltinResizeBilinear:
99 {
100 desc.m_Method = armnn::ResizeMethod::Bilinear;
101
Keith Davis892fafe2020-11-26 17:40:35 +0000102 layerName += "Bilinear:" + std::to_string(nodeIndex);
Jan Eilerse339bf62020-11-10 18:43:23 +0000103
104 TfLiteResizeBilinearParams* biliniarOptions =
105 reinterpret_cast<TfLiteResizeBilinearParams*>(tfLiteNode->builtin_data);
106
107 desc.m_AlignCorners = biliniarOptions->align_corners;
108 desc.m_HalfPixelCenters = biliniarOptions->half_pixel_centers;
109 break;
110 }
111 case kTfLiteBuiltinResizeNearestNeighbor:
112 {
113 desc.m_Method = armnn::ResizeMethod::NearestNeighbor;
Keith Davis892fafe2020-11-26 17:40:35 +0000114 layerName += "NearestNeighbor:" + std::to_string(nodeIndex);
Jan Eilerse339bf62020-11-10 18:43:23 +0000115
116 TfLiteResizeNearestNeighborParams* nearestNeighborOptions =
117 reinterpret_cast<TfLiteResizeNearestNeighborParams*>(tfLiteNode->builtin_data);
118
119 desc.m_AlignCorners = nearestNeighborOptions->align_corners;
120 desc.m_HalfPixelCenters = nearestNeighborOptions->half_pixel_centers;
121 break;
122 }
123 default:
124 {
125 TF_LITE_MAYBE_KERNEL_LOG(
126 tfLiteContext,
127 "TfLiteArmnnDelegate: Unknown TfLite built in operation for Resize. Given operator: #%d node #%d: ",
128 resizeOperatorCode, nodeIndex);
129 return kTfLiteError;
130 }
131 }
132
133 // In armnn the values of the size input tensor [new_hight, new_width] is saved in the operator
134 // descriptor. We have to read it from the input tensor and write it to the descriptor.
135
136 auto* sizeTensorDataPtr = tflite::GetTensorData<int32_t>(&tfLiteSizeTensor);
137 auto sizeTensorNumDimensions = tfLiteSizeTensor.dims->size;
138 // The size tensor is only a 1D tensor -> [new_hight, new width]
139 if (sizeTensorNumDimensions != 1)
140 {
141 TF_LITE_MAYBE_KERNEL_LOG(
142 tfLiteContext,
143 "TfLiteArmnnDelegate: The Size-Input-Tensor of the Resize operation is not allowed to be a "
144 "dynamic tensor. Operator: #%d node #%d: ",
145 resizeOperatorCode, nodeIndex);
146 return kTfLiteError;
147 }
148
149 // Get number of values in the size tensor
150 auto sizeTensorNumValues = tfLiteSizeTensor.dims->data[0];
151 if (sizeTensorNumValues == 0)
152 {
153 TF_LITE_MAYBE_KERNEL_LOG(
154 tfLiteContext,
155 "TfLiteArmnnDelegate: The Size-Input-Tensor of the Resize operation is not allowed to be a "
156 "dynamic tensor. Operator: #%d node #%d: ",
157 resizeOperatorCode, nodeIndex);
158 return kTfLiteError;
159 }
160 else if (sizeTensorNumValues != 2)
161 {
162 TF_LITE_MAYBE_KERNEL_LOG(
163 tfLiteContext,
164 "TfLiteArmnnDelegate: The Size-Input-Tensor of the Resize operation requires to "
165 "have a dimension of 2 [new_hight, new width] but a tensor with a dimension of #%d was given. "
166 "Operator: #%d node #%d: ",
167 sizeTensorNumValues, resizeOperatorCode, nodeIndex);
168 return kTfLiteError;
169 }
170 // get size tensor data
171 std::vector<int32_t> sizeTensorData(sizeTensorDataPtr, sizeTensorDataPtr+sizeTensorNumValues);
172
173 desc.m_TargetHeight = static_cast<uint32_t> (sizeTensorData[0]);
174 desc.m_TargetWidth = static_cast<uint32_t> (sizeTensorData[1]);
175 desc.m_DataLayout = armnn::DataLayout::NHWC;
176
177 // No network pointer indicates that only support for this operator should be checked
178 if (!delegateData.m_Network)
179 {
180 return ValidateResizeOperator(delegateData,
181 tfLiteContext,
182 inputTensorInfo,
183 outputTensorInfo,
184 desc);
185 }
186
187
188 armnn::IConnectableLayer* resizeLayer = nullptr;
189 resizeLayer = delegateData.m_Network->AddResizeLayer(desc, layerName.c_str());
190
191 armnn::IOutputSlot& outputSlot = resizeLayer->GetOutputSlot(0);
192 outputSlot.SetTensorInfo(outputTensorInfo);
193
Ryan OShea4c231de2023-01-17 15:19:20 +0000194 // try to connect the Constant Inputs if there are any
195 if(ProcessInputs(resizeLayer,delegateData, tfLiteContext, tfLiteNode) != kTfLiteOk )
196 {
197 return kTfLiteError;
198 }
199
Jan Eilerse339bf62020-11-10 18:43:23 +0000200 ARMNN_ASSERT(resizeLayer != nullptr);
201
202 return Connect(resizeLayer, tfLiteNode, delegateData);
Sadik Armagan62483be2020-10-23 17:14:43 +0100203}
204
205} // namespace armnnDelegate