• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #pragma once
7 
8 #include "DelegateUtils.hpp"
9 #include <armnn/utility/IgnoreUnused.hpp>
10 
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(__func__,
32                                tfLiteContext,
33                                IsResizeSupported,
34                                delegateData.m_Backends,
35                                isSupported,
36                                inputInfo,
37                                outputInfo,
38                                descriptor);
39 
40     return isSupported ? kTfLiteOk : kTfLiteError;
41 }
42 
VisitResizeOperator(DelegateData & delegateData,TfLiteContext * tfLiteContext,TfLiteNode * tfLiteNode,int nodeIndex,int32_t resizeOperatorCode)43 TfLiteStatus VisitResizeOperator(DelegateData& delegateData,
44                                  TfLiteContext* tfLiteContext,
45                                  TfLiteNode* tfLiteNode,
46                                  int nodeIndex,
47                                  int32_t resizeOperatorCode)
48 {
49     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);
89     const armnn::TensorInfo& sizeTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteSizeTensor);
90     const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor);
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:" + 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:" + 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     ARMNN_ASSERT(resizeLayer != nullptr);
195 
196     return Connect(resizeLayer, tfLiteNode, delegateData);
197 }
198 
199 } // namespace armnnDelegate
200