blob: 63f8e6871ed4cff1bf92186265fb7b02ae45ffd5 [file] [log] [blame]
Sadik Armagan62483be2020-10-23 17:14:43 +01001//
2// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
3// 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,
36 inputInfo,
37 outputInfo,
38 descriptor);
39
40 return isSupported ? kTfLiteOk : kTfLiteError;
41}
42
Sadik Armagan62483be2020-10-23 17:14:43 +010043TfLiteStatus VisitResizeOperator(DelegateData& delegateData,
44 TfLiteContext* tfLiteContext,
45 TfLiteNode* tfLiteNode,
46 int nodeIndex,
47 int32_t resizeOperatorCode)
48{
Jan Eilerse339bf62020-11-10 18:43:23 +000049 TF_LITE_ENSURE_STATUS(ValidateNumInputs(tfLiteContext, tfLiteNode, 2, nodeIndex));
50 TF_LITE_ENSURE_STATUS(ValidateNumOutputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
51
52 const TfLiteTensor* tfLiteTensors = tfLiteContext->tensors;
53
54 // The first input contains the data of the image that should be resized [batch, height, width, channels]
55 const TfLiteTensor& tfLiteInputTensor = tfLiteTensors[tfLiteNode->inputs->data[0]];
56 if (IsDynamicTensor(tfLiteInputTensor))
57 {
58 TF_LITE_MAYBE_KERNEL_LOG(
59 tfLiteContext,
60 "TfLiteArmnnDelegate: Dynamic input tensors are not supported in operator #%d node #%d: ",
61 resizeOperatorCode, nodeIndex);
62 return kTfLiteError;
63 }
64
65 // The second input contains a size tensor. The size tensor contains two integer values
66 // that describe the new height and width of the image [new_height, new_width]
67 const TfLiteTensor& tfLiteSizeTensor = tfLiteTensors[tfLiteNode->inputs->data[1]];
68 if (IsDynamicTensor(tfLiteSizeTensor))
69 {
70 TF_LITE_MAYBE_KERNEL_LOG(
71 tfLiteContext,
72 "TfLiteArmnnDelegate: Dynamic input tensors are not supported in operator #%d node #%d: ",
73 resizeOperatorCode, nodeIndex);
74 return kTfLiteError;
75 }
76
77 // The output tensor should have the shape [batch, new_height, new_width, channels]
78 const TfLiteTensor& tfLiteOutputTensor = tfLiteTensors[tfLiteNode->outputs->data[0]];
79 if (IsDynamicTensor(tfLiteOutputTensor))
80 {
81 TF_LITE_MAYBE_KERNEL_LOG(
82 tfLiteContext,
83 "TfLiteArmnnDelegate: Dynamic output tensors are not supported in operator #%d node #%d: ",
84 resizeOperatorCode, nodeIndex);
85 return kTfLiteError;
86 }
87
88 const armnn::TensorInfo& inputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteInputTensor);
Jan Eilerse339bf62020-11-10 18:43:23 +000089 const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor);
90
91 std::string layerName("Resize");
92
93 // Fill descriptor
94 armnn::ResizeDescriptor desc;
95 switch (resizeOperatorCode)
96 {
97 case kTfLiteBuiltinResizeBilinear:
98 {
99 desc.m_Method = armnn::ResizeMethod::Bilinear;
100
Keith Davis892fafe2020-11-26 17:40:35 +0000101 layerName += "Bilinear:" + std::to_string(nodeIndex);
Jan Eilerse339bf62020-11-10 18:43:23 +0000102
103 TfLiteResizeBilinearParams* biliniarOptions =
104 reinterpret_cast<TfLiteResizeBilinearParams*>(tfLiteNode->builtin_data);
105
106 desc.m_AlignCorners = biliniarOptions->align_corners;
107 desc.m_HalfPixelCenters = biliniarOptions->half_pixel_centers;
108 break;
109 }
110 case kTfLiteBuiltinResizeNearestNeighbor:
111 {
112 desc.m_Method = armnn::ResizeMethod::NearestNeighbor;
Keith Davis892fafe2020-11-26 17:40:35 +0000113 layerName += "NearestNeighbor:" + std::to_string(nodeIndex);
Jan Eilerse339bf62020-11-10 18:43:23 +0000114
115 TfLiteResizeNearestNeighborParams* nearestNeighborOptions =
116 reinterpret_cast<TfLiteResizeNearestNeighborParams*>(tfLiteNode->builtin_data);
117
118 desc.m_AlignCorners = nearestNeighborOptions->align_corners;
119 desc.m_HalfPixelCenters = nearestNeighborOptions->half_pixel_centers;
120 break;
121 }
122 default:
123 {
124 TF_LITE_MAYBE_KERNEL_LOG(
125 tfLiteContext,
126 "TfLiteArmnnDelegate: Unknown TfLite built in operation for Resize. Given operator: #%d node #%d: ",
127 resizeOperatorCode, nodeIndex);
128 return kTfLiteError;
129 }
130 }
131
132 // In armnn the values of the size input tensor [new_hight, new_width] is saved in the operator
133 // descriptor. We have to read it from the input tensor and write it to the descriptor.
134
135 auto* sizeTensorDataPtr = tflite::GetTensorData<int32_t>(&tfLiteSizeTensor);
136 auto sizeTensorNumDimensions = tfLiteSizeTensor.dims->size;
137 // The size tensor is only a 1D tensor -> [new_hight, new width]
138 if (sizeTensorNumDimensions != 1)
139 {
140 TF_LITE_MAYBE_KERNEL_LOG(
141 tfLiteContext,
142 "TfLiteArmnnDelegate: The Size-Input-Tensor of the Resize operation is not allowed to be a "
143 "dynamic tensor. Operator: #%d node #%d: ",
144 resizeOperatorCode, nodeIndex);
145 return kTfLiteError;
146 }
147
148 // Get number of values in the size tensor
149 auto sizeTensorNumValues = tfLiteSizeTensor.dims->data[0];
150 if (sizeTensorNumValues == 0)
151 {
152 TF_LITE_MAYBE_KERNEL_LOG(
153 tfLiteContext,
154 "TfLiteArmnnDelegate: The Size-Input-Tensor of the Resize operation is not allowed to be a "
155 "dynamic tensor. Operator: #%d node #%d: ",
156 resizeOperatorCode, nodeIndex);
157 return kTfLiteError;
158 }
159 else if (sizeTensorNumValues != 2)
160 {
161 TF_LITE_MAYBE_KERNEL_LOG(
162 tfLiteContext,
163 "TfLiteArmnnDelegate: The Size-Input-Tensor of the Resize operation requires to "
164 "have a dimension of 2 [new_hight, new width] but a tensor with a dimension of #%d was given. "
165 "Operator: #%d node #%d: ",
166 sizeTensorNumValues, resizeOperatorCode, nodeIndex);
167 return kTfLiteError;
168 }
169 // get size tensor data
170 std::vector<int32_t> sizeTensorData(sizeTensorDataPtr, sizeTensorDataPtr+sizeTensorNumValues);
171
172 desc.m_TargetHeight = static_cast<uint32_t> (sizeTensorData[0]);
173 desc.m_TargetWidth = static_cast<uint32_t> (sizeTensorData[1]);
174 desc.m_DataLayout = armnn::DataLayout::NHWC;
175
176 // No network pointer indicates that only support for this operator should be checked
177 if (!delegateData.m_Network)
178 {
179 return ValidateResizeOperator(delegateData,
180 tfLiteContext,
181 inputTensorInfo,
182 outputTensorInfo,
183 desc);
184 }
185
186
187 armnn::IConnectableLayer* resizeLayer = nullptr;
188 resizeLayer = delegateData.m_Network->AddResizeLayer(desc, layerName.c_str());
189
190 armnn::IOutputSlot& outputSlot = resizeLayer->GetOutputSlot(0);
191 outputSlot.SetTensorInfo(outputTensorInfo);
192
193 ARMNN_ASSERT(resizeLayer != nullptr);
194
195 return Connect(resizeLayer, tfLiteNode, delegateData);
Sadik Armagan62483be2020-10-23 17:14:43 +0100196}
197
198} // namespace armnnDelegate