xref: /aosp_15_r20/external/armnn/delegate/classic/src/Resize.hpp (revision 89c4ff92f2867872bb9e2354d150bf0c8c502810)
1 //
2 // Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #pragma once
7 
8 #include <ClassicDelegateUtils.hpp>
9 
10 #include <armnn/utility/IgnoreUnused.hpp>
11 #include <armnn/Descriptors.hpp>
12 
13 #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>
17 #include <tensorflow/lite/kernels/internal/tensor_ctypes.h>
18 
19 namespace armnnDelegate
20 {
21 
22 
23 
ValidateResizeOperator(DelegateData & delegateData,TfLiteContext * tfLiteContext,const armnn::TensorInfo & inputInfo,const armnn::TensorInfo & outputInfo,const armnn::ResizeDescriptor & descriptor)24 TfLiteStatus 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;
31     FORWARD_LAYER_SUPPORT_FUNC("RESIZE",
32                                tfLiteContext,
33                                IsResizeSupported,
34                                delegateData.m_Backends,
35                                isSupported,
36                                armnn::BackendId(),
37                                inputInfo,
38                                outputInfo,
39                                descriptor);
40 
41     return isSupported ? kTfLiteOk : kTfLiteError;
42 }
43 
VisitResizeOperator(DelegateData & delegateData,TfLiteContext * tfLiteContext,TfLiteNode * tfLiteNode,int nodeIndex,int32_t resizeOperatorCode)44 TfLiteStatus VisitResizeOperator(DelegateData& delegateData,
45                                  TfLiteContext* tfLiteContext,
46                                  TfLiteNode* tfLiteNode,
47                                  int nodeIndex,
48                                  int32_t resizeOperatorCode)
49 {
50     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);
90     const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor, true);
91 
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 
102             layerName += "Bilinear:" + std::to_string(nodeIndex);
103 
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;
114             layerName += "NearestNeighbor:" + std::to_string(nodeIndex);
115 
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 
194     // try to connect the Constant Inputs if there are any
195     if(ProcessInputs(resizeLayer,delegateData, tfLiteContext, tfLiteNode) != kTfLiteOk )
196     {
197         return kTfLiteError;
198     }
199 
200     ARMNN_ASSERT(resizeLayer != nullptr);
201 
202     return Connect(resizeLayer, tfLiteNode, delegateData);
203 }
204 
205 } // namespace armnnDelegate
206